Merge "Use string resources for clipboard access notifications." into sc-dev
diff --git a/Android.bp b/Android.bp
index 72fc103..c5980b9 100644
--- a/Android.bp
+++ b/Android.bp
@@ -932,18 +932,21 @@
     ],
 }
 
-// keep these files in sync with the package/Tethering/jarjar-rules.txt for the tethering module.
+// keep these files in sync with the package/Tethering/jarjar-rules.txt and
+// package/Connectivity/jarjar-rules.txt for the tethering module and connectivity module.
 filegroup {
-    name: "framework-tethering-shared-srcs",
+    name: "framework-connectivity-shared-srcs",
     srcs: [
         "core/java/android/util/IndentingPrintWriter.java",
         "core/java/android/util/LocalLog.java",
+        // This should be android.util.IndentingPrintWriter, but it's not available in all branches.
         "core/java/com/android/internal/util/IndentingPrintWriter.java",
         "core/java/com/android/internal/util/IState.java",
         "core/java/com/android/internal/util/MessageUtils.java",
         "core/java/com/android/internal/util/State.java",
         "core/java/com/android/internal/util/StateMachine.java",
         "core/java/com/android/internal/util/TrafficStatsConstants.java",
+        "core/java/com/android/internal/util/WakeupMessage.java",
     ],
 }
 
@@ -1279,6 +1282,21 @@
     ],
 }
 
+// Build Rust bindings for PermissionController. Needed by keystore2.
+aidl_interface {
+    name: "android.os.permissions_aidl",
+    unstable: true,
+    local_include_dir: "core/java",
+    srcs: [
+        "core/java/android/os/IPermissionController.aidl",
+    ],
+    backend: {
+        rust: {
+            enabled: true,
+        },
+    },
+}
+
 // TODO(b/77285514): remove this once the last few hidl interfaces have been
 // updated to use hwbinder.stubs.
 java_library {
diff --git a/apex/jobscheduler/framework/java/com/android/server/DeviceIdleInternal.java b/apex/jobscheduler/framework/java/com/android/server/DeviceIdleInternal.java
index 0dde546..9bd57a1 100644
--- a/apex/jobscheduler/framework/java/com/android/server/DeviceIdleInternal.java
+++ b/apex/jobscheduler/framework/java/com/android/server/DeviceIdleInternal.java
@@ -17,6 +17,7 @@
 package com.android.server;
 
 import android.annotation.Nullable;
+import android.os.PowerWhitelistManager;
 import android.os.PowerWhitelistManager.ReasonCode;
 import android.os.PowerWhitelistManager.TempAllowListType;
 
@@ -32,11 +33,22 @@
 
     void exitIdle(String reason);
 
+    /**
+     * Same as {@link #addPowerSaveTempWhitelistApp(int, String, long, int, boolean, int, String)}
+     * with {@link PowerWhitelistManager#TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED}.
+     */
     void addPowerSaveTempWhitelistApp(int callingUid, String packageName,
             long durationMs, int userId, boolean sync, @ReasonCode int reasonCode,
             @Nullable String reason);
 
     /**
+     * Put a package in the temp-allowlist.
+     */
+    void addPowerSaveTempWhitelistApp(int callingUid, String packageName,
+            long durationMs, @TempAllowListType int tempAllowListType, int userId, boolean sync,
+            @ReasonCode int reasonCode, @Nullable String reason);
+
+    /**
      * Called by ActivityManagerService to directly add UID to DeviceIdleController's temp
      * allowlist.
      * @param uid
diff --git a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
index 84fb39b..119dcb6 100644
--- a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
+++ b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
@@ -1942,22 +1942,29 @@
             exitIdleInternal(reason);
         }
 
-        // duration in milliseconds
         @Override
         public void addPowerSaveTempWhitelistApp(int callingUid, String packageName,
                 long durationMs, int userId, boolean sync, @ReasonCode int reasonCode,
                 @Nullable String reason) {
             addPowerSaveTempAllowlistAppInternal(callingUid, packageName, durationMs,
+                    TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
                     userId, sync, reasonCode, reason);
         }
 
-        // duration in milliseconds
         @Override
-        public void addPowerSaveTempWhitelistAppDirect(int uid, long duration,
-                @TempAllowListType int type, boolean sync, @ReasonCode int reasonCode,
+        public void addPowerSaveTempWhitelistApp(int callingUid, String packageName,
+                long durationMs, @TempAllowListType int tempAllowListType, int userId, boolean sync,
+                @ReasonCode int reasonCode, @Nullable String reason) {
+            addPowerSaveTempAllowlistAppInternal(callingUid, packageName, durationMs,
+                    tempAllowListType, userId, sync, reasonCode, reason);
+        }
+
+        @Override
+        public void addPowerSaveTempWhitelistAppDirect(int uid, long durationMs,
+                @TempAllowListType int tempAllowListType, boolean sync, @ReasonCode int reasonCode,
                 @Nullable String reason, int callingUid) {
-            addPowerSaveTempWhitelistAppDirectInternal(callingUid, uid, duration, type, sync,
-                    reasonCode, reason);
+            addPowerSaveTempWhitelistAppDirectInternal(callingUid, uid, durationMs,
+                    tempAllowListType, sync, reasonCode, reason);
         }
 
         // duration in milliseconds
@@ -2699,7 +2706,8 @@
         final long token = Binder.clearCallingIdentity();
         try {
             addPowerSaveTempAllowlistAppInternal(callingUid,
-                    packageName, duration, userId, true, reasonCode, reason);
+                    packageName, duration, TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
+                    userId, true, reasonCode, reason);
         } finally {
             Binder.restoreCallingIdentity(token);
         }
@@ -2731,8 +2739,8 @@
      * app an exemption to access network and acquire wakelocks.
      */
     void addPowerSaveTempAllowlistAppInternal(int callingUid, String packageName,
-            long duration, int userId, boolean sync, @ReasonCode int reasonCode,
-            @Nullable String reason) {
+            long durationMs, @TempAllowListType int tempAllowListType, int userId, boolean sync,
+            @ReasonCode int reasonCode, @Nullable String reason) {
         synchronized (this) {
             int callingAppId = UserHandle.getAppId(callingUid);
             if (callingAppId >= Process.FIRST_APPLICATION_UID) {
@@ -2745,8 +2753,8 @@
         }
         try {
             int uid = getContext().getPackageManager().getPackageUidAsUser(packageName, userId);
-            addPowerSaveTempWhitelistAppDirectInternal(callingUid, uid, duration,
-                    TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED, sync, reasonCode, reason);
+            addPowerSaveTempWhitelistAppDirectInternal(callingUid, uid, durationMs,
+                    tempAllowListType, sync, reasonCode, reason);
         } catch (NameNotFoundException e) {
         }
     }
@@ -2756,8 +2764,8 @@
      * app an exemption to access network and acquire wakelocks.
      */
     void addPowerSaveTempWhitelistAppDirectInternal(int callingUid, int uid,
-            long duration, @TempAllowListType int type, boolean sync, @ReasonCode int reasonCode,
-            @Nullable String reason) {
+            long duration, @TempAllowListType int tempAllowListType, boolean sync,
+            @ReasonCode int reasonCode, @Nullable String reason) {
         final long timeNow = SystemClock.elapsedRealtime();
         boolean informWhitelistChanged = false;
         int appId = UserHandle.getAppId(uid);
@@ -2782,8 +2790,8 @@
                 } catch (RemoteException e) {
                 }
                 postTempActiveTimeoutMessage(uid, duration);
-                updateTempWhitelistAppIdsLocked(uid, true, duration, type, reasonCode,
-                        reason, callingUid);
+                updateTempWhitelistAppIdsLocked(uid, true, duration, tempAllowListType,
+                        reasonCode, reason, callingUid);
                 if (sync) {
                     informWhitelistChanged = true;
                 } else {
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 2b2918c..33f6e06 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
@@ -24,6 +24,7 @@
 import static android.app.AlarmManager.FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED;
 import static android.app.AlarmManager.FLAG_IDLE_UNTIL;
 import static android.app.AlarmManager.FLAG_WAKE_FROM_IDLE;
+import static android.app.AlarmManager.INTERVAL_DAY;
 import static android.app.AlarmManager.INTERVAL_HOUR;
 import static android.app.AlarmManager.RTC;
 import static android.app.AlarmManager.RTC_WAKEUP;
@@ -88,7 +89,6 @@
 import android.system.Os;
 import android.text.TextUtils;
 import android.text.format.DateFormat;
-import android.text.format.DateUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.IndentingPrintWriter;
@@ -168,8 +168,7 @@
     static final String TIMEZONE_PROPERTY = "persist.sys.timezone";
 
     static final int TICK_HISTORY_DEPTH = 10;
-    static final long MILLIS_IN_DAY = 24 * 60 * 60 * 1000;
-    static final long INDEFINITE_DELAY = 365 * MILLIS_IN_DAY;
+    static final long INDEFINITE_DELAY = 365 * INTERVAL_DAY;
 
     // Indices into the KEYS_APP_STANDBY_QUOTAS array.
     static final int ACTIVE_INDEX = 0;
@@ -423,13 +422,17 @@
 
         @VisibleForTesting
         static final String KEY_ALLOW_WHILE_IDLE_COMPAT_QUOTA = "allow_while_idle_compat_quota";
-        private static final String KEY_ALLOW_WHILE_IDLE_WINDOW = "allow_while_idle_window";
+
+        @VisibleForTesting
+        static final String KEY_ALLOW_WHILE_IDLE_WINDOW = "allow_while_idle_window";
+        @VisibleForTesting
+        static final String KEY_ALLOW_WHILE_IDLE_COMPAT_WINDOW = "allow_while_idle_compat_window";
 
         private static final String KEY_CRASH_NON_CLOCK_APPS = "crash_non_clock_apps";
 
         private static final long DEFAULT_MIN_FUTURITY = 5 * 1000;
         private static final long DEFAULT_MIN_INTERVAL = 60 * 1000;
-        private static final long DEFAULT_MAX_INTERVAL = 365 * DateUtils.DAY_IN_MILLIS;
+        private static final long DEFAULT_MAX_INTERVAL = 365 * INTERVAL_DAY;
         private static final long DEFAULT_ALLOW_WHILE_IDLE_WHITELIST_DURATION = 10 * 1000;
         private static final long DEFAULT_LISTENER_TIMEOUT = 5 * 1000;
         private static final int DEFAULT_MAX_ALARMS_PER_UID = 500;
@@ -445,19 +448,21 @@
                 0       // Never
         };
         private static final int DEFAULT_APP_STANDBY_RESTRICTED_QUOTA = 1;
-        private static final long DEFAULT_APP_STANDBY_RESTRICTED_WINDOW = MILLIS_IN_DAY;
+        private static final long DEFAULT_APP_STANDBY_RESTRICTED_WINDOW = INTERVAL_DAY;
 
         private static final boolean DEFAULT_LAZY_BATCHING = true;
         private static final boolean DEFAULT_TIME_TICK_ALLOWED_WHILE_IDLE = true;
 
         /**
-         * Default quota for pre-S apps. Enough to accommodate the existing policy of an alarm
+         * Default quota for pre-S apps. The same as allowing an alarm slot once
          * every ALLOW_WHILE_IDLE_LONG_DELAY, which was 9 minutes.
          */
-        private static final int DEFAULT_ALLOW_WHILE_IDLE_COMPAT_QUOTA = 7;
+        private static final int DEFAULT_ALLOW_WHILE_IDLE_COMPAT_QUOTA = 1;
         private static final int DEFAULT_ALLOW_WHILE_IDLE_QUOTA = 72;
 
         private static final long DEFAULT_ALLOW_WHILE_IDLE_WINDOW = 60 * 60 * 1000; // 1 hour.
+        private static final long DEFAULT_ALLOW_WHILE_IDLE_COMPAT_WINDOW = 9 * 60 * 1000; // 9 mins.
+
         // TODO (b/171306433): Change to true by default.
         private static final boolean DEFAULT_CRASH_NON_CLOCK_APPS = false;
 
@@ -495,9 +500,14 @@
         public int ALLOW_WHILE_IDLE_COMPAT_QUOTA = DEFAULT_ALLOW_WHILE_IDLE_COMPAT_QUOTA;
 
         /**
-         * The window used for enforcing {@link #ALLOW_WHILE_IDLE_QUOTA} and
-         * {@link #ALLOW_WHILE_IDLE_COMPAT_QUOTA}. Can be configured, but only recommended for
-         * testing.
+         * The window used for enforcing {@link #ALLOW_WHILE_IDLE_COMPAT_QUOTA}.
+         * Can be configured, but only recommended for testing.
+         */
+        public long ALLOW_WHILE_IDLE_COMPAT_WINDOW = DEFAULT_ALLOW_WHILE_IDLE_COMPAT_WINDOW;
+
+        /**
+         * The window used for enforcing {@link #ALLOW_WHILE_IDLE_COMPAT_QUOTA}.
+         * Can be configured, but only recommended for testing.
          */
         public long ALLOW_WHILE_IDLE_WINDOW = DEFAULT_ALLOW_WHILE_IDLE_WINDOW;
 
@@ -561,7 +571,7 @@
                             ALLOW_WHILE_IDLE_QUOTA = properties.getInt(KEY_ALLOW_WHILE_IDLE_QUOTA,
                                     DEFAULT_ALLOW_WHILE_IDLE_QUOTA);
                             if (ALLOW_WHILE_IDLE_QUOTA <= 0) {
-                                Slog.w(TAG, "Cannot have allow-while-idle quota lower than 1.");
+                                Slog.w(TAG, "Must have positive allow_while_idle quota");
                                 ALLOW_WHILE_IDLE_QUOTA = 1;
                             }
                             break;
@@ -570,22 +580,38 @@
                                     KEY_ALLOW_WHILE_IDLE_COMPAT_QUOTA,
                                     DEFAULT_ALLOW_WHILE_IDLE_COMPAT_QUOTA);
                             if (ALLOW_WHILE_IDLE_COMPAT_QUOTA <= 0) {
-                                Slog.w(TAG, "Cannot have quota lower than 1.");
+                                Slog.w(TAG, "Must have positive allow_while_idle_compat quota");
                                 ALLOW_WHILE_IDLE_COMPAT_QUOTA = 1;
                             }
                             break;
                         case KEY_ALLOW_WHILE_IDLE_WINDOW:
                             ALLOW_WHILE_IDLE_WINDOW = properties.getLong(
                                     KEY_ALLOW_WHILE_IDLE_WINDOW, DEFAULT_ALLOW_WHILE_IDLE_WINDOW);
-                            if (ALLOW_WHILE_IDLE_WINDOW > DEFAULT_ALLOW_WHILE_IDLE_WINDOW) {
+
+                            if (ALLOW_WHILE_IDLE_WINDOW > INTERVAL_HOUR) {
                                 Slog.w(TAG, "Cannot have allow_while_idle_window > "
-                                        + DEFAULT_ALLOW_WHILE_IDLE_WINDOW);
-                                ALLOW_WHILE_IDLE_WINDOW = DEFAULT_ALLOW_WHILE_IDLE_WINDOW;
-                            } else if (ALLOW_WHILE_IDLE_WINDOW < DEFAULT_ALLOW_WHILE_IDLE_WINDOW) {
+                                        + INTERVAL_HOUR);
+                                ALLOW_WHILE_IDLE_WINDOW = INTERVAL_HOUR;
+                            } else if (ALLOW_WHILE_IDLE_WINDOW != DEFAULT_ALLOW_WHILE_IDLE_WINDOW) {
                                 Slog.w(TAG, "Using a non-default allow_while_idle_window = "
                                         + ALLOW_WHILE_IDLE_WINDOW);
                             }
                             break;
+                        case KEY_ALLOW_WHILE_IDLE_COMPAT_WINDOW:
+                            ALLOW_WHILE_IDLE_COMPAT_WINDOW = properties.getLong(
+                                    KEY_ALLOW_WHILE_IDLE_COMPAT_WINDOW,
+                                    DEFAULT_ALLOW_WHILE_IDLE_COMPAT_WINDOW);
+
+                            if (ALLOW_WHILE_IDLE_COMPAT_WINDOW > INTERVAL_HOUR) {
+                                Slog.w(TAG, "Cannot have allow_while_idle_compat_window > "
+                                        + INTERVAL_HOUR);
+                                ALLOW_WHILE_IDLE_COMPAT_WINDOW = INTERVAL_HOUR;
+                            } else if (ALLOW_WHILE_IDLE_COMPAT_WINDOW
+                                    != DEFAULT_ALLOW_WHILE_IDLE_COMPAT_WINDOW) {
+                                Slog.w(TAG, "Using a non-default allow_while_idle_compat_window = "
+                                        + ALLOW_WHILE_IDLE_COMPAT_WINDOW);
+                            }
+                            break;
                         case KEY_ALLOW_WHILE_IDLE_WHITELIST_DURATION:
                             ALLOW_WHILE_IDLE_WHITELIST_DURATION = properties.getLong(
                                     KEY_ALLOW_WHILE_IDLE_WHITELIST_DURATION,
@@ -717,6 +743,9 @@
             TimeUtils.formatDuration(LISTENER_TIMEOUT, pw);
             pw.println();
 
+            pw.print(KEY_ALLOW_WHILE_IDLE_QUOTA, ALLOW_WHILE_IDLE_QUOTA);
+            pw.println();
+
             pw.print(KEY_ALLOW_WHILE_IDLE_WINDOW);
             pw.print("=");
             TimeUtils.formatDuration(ALLOW_WHILE_IDLE_WINDOW, pw);
@@ -725,7 +754,9 @@
             pw.print(KEY_ALLOW_WHILE_IDLE_COMPAT_QUOTA, ALLOW_WHILE_IDLE_COMPAT_QUOTA);
             pw.println();
 
-            pw.print(KEY_ALLOW_WHILE_IDLE_QUOTA, ALLOW_WHILE_IDLE_QUOTA);
+            pw.print(KEY_ALLOW_WHILE_IDLE_COMPAT_WINDOW);
+            pw.print("=");
+            TimeUtils.formatDuration(ALLOW_WHILE_IDLE_COMPAT_WINDOW, pw);
             pw.println();
 
             pw.print(KEY_ALLOW_WHILE_IDLE_WHITELIST_DURATION);
@@ -1330,8 +1361,7 @@
             mAlarmStore.setAlarmClockRemovalListener(mAlarmClockUpdater);
 
             mAppWakeupHistory = new AppWakeupHistory(Constants.DEFAULT_APP_STANDBY_WINDOW);
-            mAllowWhileIdleHistory = new AppWakeupHistory(
-                    Constants.DEFAULT_ALLOW_WHILE_IDLE_WINDOW);
+            mAllowWhileIdleHistory = new AppWakeupHistory(INTERVAL_HOUR);
 
             mNextWakeup = mNextNonWakeup = 0;
 
@@ -1730,9 +1760,15 @@
         } else if (isAllowedWhileIdleRestricted(alarm)) {
             // Allowed but limited.
             final int userId = UserHandle.getUserId(alarm.creatorUid);
-            final int quota = ((alarm.flags & FLAG_ALLOW_WHILE_IDLE) != 0)
-                    ? mConstants.ALLOW_WHILE_IDLE_QUOTA
-                    : mConstants.ALLOW_WHILE_IDLE_COMPAT_QUOTA;
+            final int quota;
+            final long window;
+            if ((alarm.flags & FLAG_ALLOW_WHILE_IDLE) != 0) {
+                quota = mConstants.ALLOW_WHILE_IDLE_QUOTA;
+                window = mConstants.ALLOW_WHILE_IDLE_WINDOW;
+            } else {
+                quota = mConstants.ALLOW_WHILE_IDLE_COMPAT_QUOTA;
+                window = mConstants.ALLOW_WHILE_IDLE_COMPAT_WINDOW;
+            }
             final int dispatchesInWindow = mAllowWhileIdleHistory.getTotalWakeupsInWindow(
                     alarm.sourcePackage, userId);
             if (dispatchesInWindow < quota) {
@@ -1740,7 +1776,7 @@
                 batterySaverPolicyElapsed = nowElapsed;
             } else {
                 batterySaverPolicyElapsed = mAllowWhileIdleHistory.getNthLastWakeupForPackage(
-                        alarm.sourcePackage, userId, quota) + mConstants.ALLOW_WHILE_IDLE_WINDOW;
+                        alarm.sourcePackage, userId, quota) + window;
             }
         } else {
             // Not allowed.
@@ -1778,9 +1814,15 @@
         } else if (isAllowedWhileIdleRestricted(alarm)) {
             // Allowed but limited.
             final int userId = UserHandle.getUserId(alarm.creatorUid);
-            final int quota = ((alarm.flags & FLAG_ALLOW_WHILE_IDLE) != 0)
-                    ? mConstants.ALLOW_WHILE_IDLE_QUOTA
-                    : mConstants.ALLOW_WHILE_IDLE_COMPAT_QUOTA;
+            final int quota;
+            final long window;
+            if ((alarm.flags & FLAG_ALLOW_WHILE_IDLE) != 0) {
+                quota = mConstants.ALLOW_WHILE_IDLE_QUOTA;
+                window = mConstants.ALLOW_WHILE_IDLE_WINDOW;
+            } else {
+                quota = mConstants.ALLOW_WHILE_IDLE_COMPAT_QUOTA;
+                window = mConstants.ALLOW_WHILE_IDLE_COMPAT_WINDOW;
+            }
             final int dispatchesInWindow = mAllowWhileIdleHistory.getTotalWakeupsInWindow(
                     alarm.sourcePackage, userId);
             if (dispatchesInWindow < quota) {
@@ -1788,7 +1830,7 @@
                 deviceIdlePolicyTime = nowElapsed;
             } else {
                 final long whenInQuota = mAllowWhileIdleHistory.getNthLastWakeupForPackage(
-                        alarm.sourcePackage, userId, quota) + mConstants.ALLOW_WHILE_IDLE_WINDOW;
+                        alarm.sourcePackage, userId, quota) + window;
                 deviceIdlePolicyTime = Math.min(whenInQuota, mPendingIdleUntil.getWhenElapsed());
             }
         } else {
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 6802b6b..9ef46df 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
@@ -34,6 +34,7 @@
 import android.content.ServiceConnection;
 import android.net.Uri;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
@@ -77,9 +78,9 @@
 
     private static final String TAG = "JobServiceContext";
     /** Amount of time the JobScheduler waits for the initial service launch+bind. */
-    private static final long OP_BIND_TIMEOUT_MILLIS = 18 * 1000;
+    private static final long OP_BIND_TIMEOUT_MILLIS = 18 * 1000 * Build.HW_TIMEOUT_MULTIPLIER;
     /** Amount of time the JobScheduler will wait for a response from an app for a message. */
-    private static final long OP_TIMEOUT_MILLIS = 8 * 1000;
+    private static final long OP_TIMEOUT_MILLIS = 8 * 1000 * Build.HW_TIMEOUT_MULTIPLIER;
 
     private static final String[] VERB_STRINGS = {
             "VERB_BINDING", "VERB_STARTING", "VERB_EXECUTING", "VERB_STOPPING", "VERB_FINISHED"
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 dd1a0e2..1a808c9 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
@@ -2042,7 +2042,9 @@
                 if (activityManager.isLowRamDevice() || ActivityManager.isSmallBatteryDevice()) {
                     mAutoRestrictedBucketDelayMs = 12 * ONE_HOUR;
                 }
-
+            } else if (phase == PHASE_BOOT_COMPLETED) {
+                // mWellbeingApp needs to be initialized lazily after boot to allow for roles to be
+                // parsed and the wellbeing role-holder to be assigned
                 final PackageManager packageManager = mContext.getPackageManager();
                 mWellbeingApp = packageManager.getWellbeingPackageName();
             }
diff --git a/apex/media/framework/Android.bp b/apex/media/framework/Android.bp
index 1d6f20d..3d129d8 100644
--- a/apex/media/framework/Android.bp
+++ b/apex/media/framework/Android.bp
@@ -120,7 +120,6 @@
         "java/android/media/ApplicationMediaCapabilities.java",
         "java/android/media/MediaFeature.java",
         "java/android/media/MediaTranscodeManager.java",
-        "java/android/media/MediaTranscodingException.java",
     ],
     path: "java",
 }
diff --git a/apex/media/framework/api/current.txt b/apex/media/framework/api/current.txt
index 1beef40..80698f7 100644
--- a/apex/media/framework/api/current.txt
+++ b/apex/media/framework/api/current.txt
@@ -210,12 +210,6 @@
     method public int getNotificationId();
   }
 
-  public class MediaTranscodingException extends java.lang.Exception {
-  }
-
-  public static final class MediaTranscodingException.ServiceNotAvailableException extends android.media.MediaTranscodingException {
-  }
-
   public final class Session2Command implements android.os.Parcelable {
     ctor public Session2Command(int);
     ctor public Session2Command(@NonNull String, @Nullable android.os.Bundle);
diff --git a/apex/media/framework/api/system-current.txt b/apex/media/framework/api/system-current.txt
index ae604f6..af2d2f7 100644
--- a/apex/media/framework/api/system-current.txt
+++ b/apex/media/framework/api/system-current.txt
@@ -2,7 +2,7 @@
 package android.media {
 
   public final class MediaTranscodeManager {
-    method @NonNull public android.media.MediaTranscodeManager.TranscodingSession enqueueRequest(@NonNull android.media.MediaTranscodeManager.TranscodingRequest, @NonNull java.util.concurrent.Executor, @NonNull android.media.MediaTranscodeManager.OnTranscodingFinishedListener) throws java.io.FileNotFoundException, android.media.MediaTranscodingException.ServiceNotAvailableException;
+    method @Nullable public android.media.MediaTranscodeManager.TranscodingSession enqueueRequest(@NonNull android.media.MediaTranscodeManager.TranscodingRequest, @NonNull java.util.concurrent.Executor, @NonNull android.media.MediaTranscodeManager.OnTranscodingFinishedListener);
     field public static final int PRIORITY_REALTIME = 1; // 0x1
     field public static final int TRANSCODING_TYPE_VIDEO = 1; // 0x1
   }
diff --git a/apex/media/framework/java/android/media/MediaTranscodeManager.java b/apex/media/framework/java/android/media/MediaTranscodeManager.java
index ca5aeb8..b29bed9 100644
--- a/apex/media/framework/java/android/media/MediaTranscodeManager.java
+++ b/apex/media/framework/java/android/media/MediaTranscodeManager.java
@@ -1338,19 +1338,16 @@
          * could be retried only once. After that, Client need to enqueue a new request if they want
          * to try again.
          *
-         * @throws MediaTranscodingException.ServiceNotAvailableException if the service
-         *         is temporarily unavailable due to internal service rebooting. Client could retry
-         *         again after receiving this exception.
+         * @return true if successfully resubmit the job to service. False otherwise.
          * @throws UnsupportedOperationException if the retry could not be fulfilled.
          * @hide
          */
-        public void retry() throws MediaTranscodingException.ServiceNotAvailableException {
-            retryInternal(true /*setHasRetried*/);
+        public boolean retry() {
+            return retryInternal(true /*setHasRetried*/);
         }
 
         // TODO(hkuang): Add more test for it.
-        private void retryInternal(boolean setHasRetried)
-                throws MediaTranscodingException.ServiceNotAvailableException {
+        private boolean retryInternal(boolean setHasRetried) {
             synchronized (mLock) {
                 if (mStatus == STATUS_PENDING || mStatus == STATUS_RUNNING) {
                     throw new UnsupportedOperationException(
@@ -1364,8 +1361,8 @@
                 // Get the client interface.
                 ITranscodingClient client = mManager.getTranscodingClient();
                 if (client == null) {
-                    throw new MediaTranscodingException.ServiceNotAvailableException(
-                            "Service rebooting. Try again later");
+                    Log.e(TAG, "Service rebooting. Try again later");
+                    return false;
                 }
 
                 synchronized (mManager.mPendingTranscodingSessions) {
@@ -1383,13 +1380,13 @@
                         // Adds the new session back into pending sessions.
                         mManager.mPendingTranscodingSessions.put(mSessionId, this);
                     } catch (RemoteException re) {
-                        throw new MediaTranscodingException.ServiceNotAvailableException(
-                                "Failed to resubmit request to Transcoding service");
+                        return false;
                     }
                     mStatus = STATUS_PENDING;
                     mHasRetried = setHasRetried ? true : false;
                 }
             }
+            return true;
         }
 
         /**
@@ -1529,24 +1526,20 @@
      * <p> Upon successfully accepting the request, MediaTranscodeManager will return a
      * {@link TranscodingSession} to the client. Client should use {@link TranscodingSession} to
      * track the progress and get the result.
+     * <p> MediaTranscodeManager will return null if fails to accept the request due to service
+     * rebooting. Client could retry again after receiving null.
      *
      * @param transcodingRequest The TranscodingRequest to enqueue.
      * @param listenerExecutor   Executor on which the listener is notified.
      * @param listener           Listener to get notified when the transcoding session is finished.
      * @return A TranscodingSession for this operation.
-     * @throws FileNotFoundException if the source Uri or destination Uri could not be opened.
      * @throws UnsupportedOperationException if the request could not be fulfilled.
-     * @throws MediaTranscodingException.ServiceNotAvailableException if the service
-     *         is temporarily unavailable due to internal service rebooting. Client could retry
-     *         again after receiving this exception.
      */
-    @NonNull
+    @Nullable
     public TranscodingSession enqueueRequest(
             @NonNull TranscodingRequest transcodingRequest,
             @NonNull @CallbackExecutor Executor listenerExecutor,
-            @NonNull OnTranscodingFinishedListener listener)
-            throws FileNotFoundException,
-            MediaTranscodingException.ServiceNotAvailableException {
+            @NonNull OnTranscodingFinishedListener listener) {
         Log.i(TAG, "enqueueRequest called.");
         Objects.requireNonNull(transcodingRequest, "transcodingRequest must not be null");
         Objects.requireNonNull(listenerExecutor, "listenerExecutor must not be null");
@@ -1568,14 +1561,14 @@
                         // Try to register with the service again.
                         IMediaTranscodingService service = getService(false /*retry*/);
                         if (service == null) {
-                            throw new MediaTranscodingException.ServiceNotAvailableException(
-                                    "Service rebooting. Try again later");
+                            Log.w(TAG, "Service rebooting. Try again later");
+                            return null;
                         }
                         mTranscodingClient = registerClient(service);
                         // If still fails, throws an exception to tell client to try later.
                         if (mTranscodingClient == null) {
-                            throw new MediaTranscodingException.ServiceNotAvailableException(
-                                    "Service rebooting. Try again later");
+                            Log.w(TAG, "Service rebooting. Try again later");
+                            return null;
                         }
                     }
 
@@ -1595,9 +1588,12 @@
                 mPendingTranscodingSessions.put(session.getSessionId(), session);
                 return session;
             }
-        } catch (RemoteException | ServiceSpecificException ex) {
+        } catch (RemoteException ex) {
+            Log.w(TAG, "Service rebooting. Try again later");
+            return null;
+        } catch (ServiceSpecificException ex) {
             throw new UnsupportedOperationException(
-                    "Failed to submit request to Transcoding service");
+                    "Failed to submit request to Transcoding service. Error: " + ex);
         }
     }
 }
diff --git a/apex/media/framework/java/android/media/MediaTranscodingException.java b/apex/media/framework/java/android/media/MediaTranscodingException.java
deleted file mode 100644
index 50cc9c4..0000000
--- a/apex/media/framework/java/android/media/MediaTranscodingException.java
+++ /dev/null
@@ -1,38 +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.media;
-
-/**
- * Base class for MediaTranscoding exceptions
- */
-public class MediaTranscodingException extends Exception {
-    private MediaTranscodingException(String detailMessage) {
-        super(detailMessage);
-    }
-
-    /**
-     * Exception thrown when the service is rebooting and MediaTranscodeManager is temporarily
-     * unavailable for accepting new request. It's likely that retrying will be successful.
-     */
-    public static final class ServiceNotAvailableException extends
-            MediaTranscodingException {
-        /** @hide */
-        public ServiceNotAvailableException(String detailMessage) {
-            super(detailMessage);
-        }
-    }
-}
diff --git a/core/api/current.txt b/core/api/current.txt
index 57e2561..2e0282a 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -158,6 +158,7 @@
     field public static final String SET_WALLPAPER_HINTS = "android.permission.SET_WALLPAPER_HINTS";
     field public static final String SIGNAL_PERSISTENT_PROCESSES = "android.permission.SIGNAL_PERSISTENT_PROCESSES";
     field @Deprecated public static final String SMS_FINANCIAL_TRANSACTIONS = "android.permission.SMS_FINANCIAL_TRANSACTIONS";
+    field public static final String START_FOREGROUND_SERVICES_FROM_BACKGROUND = "android.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND";
     field public static final String START_VIEW_PERMISSION_USAGE = "android.permission.START_VIEW_PERMISSION_USAGE";
     field public static final String STATUS_BAR = "android.permission.STATUS_BAR";
     field public static final String SYSTEM_ALERT_WINDOW = "android.permission.SYSTEM_ALERT_WINDOW";
@@ -817,6 +818,7 @@
     field public static final int installLocation = 16843447; // 0x10102b7
     field public static final int interactiveUiTimeout = 16844181; // 0x1010595
     field public static final int interpolator = 16843073; // 0x1010141
+    field public static final int isAccessibilityTool = 16844353; // 0x1010641
     field public static final int isAlwaysSyncable = 16843571; // 0x1010333
     field public static final int isAsciiCapable = 16843753; // 0x10103e9
     field public static final int isAuxiliary = 16843647; // 0x101037f
@@ -1259,6 +1261,7 @@
     field public static final int segmentedButtonStyle = 16843568; // 0x1010330
     field public static final int selectAllOnFocus = 16843102; // 0x101015e
     field public static final int selectable = 16843238; // 0x10101e6
+    field public static final int selectableAsDefault = 16844352; // 0x1010640
     field public static final int selectableItemBackground = 16843534; // 0x101030e
     field public static final int selectableItemBackgroundBorderless = 16843868; // 0x101045c
     field @Deprecated public static final int selectedDateVerticalBar = 16843591; // 0x1010347
@@ -3100,6 +3103,7 @@
     method public int getNonInteractiveUiTimeoutMillis();
     method public android.content.pm.ResolveInfo getResolveInfo();
     method public String getSettingsActivityName();
+    method public boolean isAccessibilityTool();
     method public String loadDescription(android.content.pm.PackageManager);
     method public CharSequence loadSummary(android.content.pm.PackageManager);
     method public void setInteractiveUiTimeoutMillis(@IntRange(from=0) int);
@@ -5818,6 +5822,8 @@
     method @Nullable public android.graphics.drawable.Icon getIcon();
     method @Nullable public android.app.PendingIntent getIntent();
     method @Nullable public String getShortcutId();
+    method public boolean isBubbleSuppressable();
+    method public boolean isBubbleSuppressed();
     method public boolean isNotificationSuppressed();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.app.Notification.BubbleMetadata> CREATOR;
@@ -5834,6 +5840,7 @@
     method @NonNull public android.app.Notification.BubbleMetadata.Builder setDesiredHeightResId(@DimenRes int);
     method @NonNull public android.app.Notification.BubbleMetadata.Builder setIcon(@NonNull android.graphics.drawable.Icon);
     method @NonNull public android.app.Notification.BubbleMetadata.Builder setIntent(@NonNull android.app.PendingIntent);
+    method @NonNull public android.app.Notification.BubbleMetadata.Builder setSuppressBubble(boolean);
     method @NonNull public android.app.Notification.BubbleMetadata.Builder setSuppressNotification(boolean);
   }
 
@@ -10568,9 +10575,10 @@
 
   public static final class ContextParams.Builder {
     ctor public ContextParams.Builder();
+    ctor public ContextParams.Builder(@NonNull android.content.ContextParams);
     method @NonNull public android.content.ContextParams build();
-    method @NonNull public android.content.ContextParams.Builder setAttributionTag(@NonNull String);
-    method @NonNull public android.content.ContextParams.Builder setReceiverPackage(@NonNull String, @Nullable String);
+    method @NonNull public android.content.ContextParams.Builder setAttributionTag(@Nullable String);
+    method @NonNull public android.content.ContextParams.Builder setReceiverPackage(@Nullable String, @Nullable String);
   }
 
   public class ContextWrapper extends android.content.Context {
@@ -11719,6 +11727,7 @@
     field public static final int FLAG_STATE_NOT_NEEDED = 16; // 0x10
     field public static final int LAUNCH_MULTIPLE = 0; // 0x0
     field public static final int LAUNCH_SINGLE_INSTANCE = 3; // 0x3
+    field public static final int LAUNCH_SINGLE_INSTANCE_PER_TASK = 4; // 0x4
     field public static final int LAUNCH_SINGLE_TASK = 2; // 0x2
     field public static final int LAUNCH_SINGLE_TOP = 1; // 0x1
     field public static final int PERSIST_ACROSS_REBOOTS = 2; // 0x2
@@ -11962,6 +11971,14 @@
     field public static final String ACTION_CAN_INTERACT_ACROSS_PROFILES_CHANGED = "android.content.pm.action.CAN_INTERACT_ACROSS_PROFILES_CHANGED";
   }
 
+  public class DataLoaderParams {
+    method @NonNull public static final android.content.pm.DataLoaderParams forIncremental(@NonNull android.content.ComponentName, @NonNull String);
+    method @NonNull public static final android.content.pm.DataLoaderParams forStreaming(@NonNull android.content.ComponentName, @NonNull String);
+    method @NonNull public final String getArguments();
+    method @NonNull public final android.content.ComponentName getComponentName();
+    method @NonNull public final int getType();
+  }
+
   public final class FeatureGroupInfo implements android.os.Parcelable {
     ctor public FeatureGroupInfo();
     ctor public FeatureGroupInfo(android.content.pm.FeatureGroupInfo);
@@ -12190,6 +12207,10 @@
     field public static final String ACTION_SESSION_COMMITTED = "android.content.pm.action.SESSION_COMMITTED";
     field public static final String ACTION_SESSION_DETAILS = "android.content.pm.action.SESSION_DETAILS";
     field public static final String ACTION_SESSION_UPDATED = "android.content.pm.action.SESSION_UPDATED";
+    field public static final int DATA_LOADER_TYPE_INCREMENTAL = 2; // 0x2
+    field public static final int DATA_LOADER_TYPE_NONE = 0; // 0x0
+    field public static final int DATA_LOADER_TYPE_STREAMING = 1; // 0x1
+    field public static final String EXTRA_DATA_LOADER_TYPE = "android.content.pm.extra.DATA_LOADER_TYPE";
     field public static final String EXTRA_OTHER_PACKAGE_NAME = "android.content.pm.extra.OTHER_PACKAGE_NAME";
     field public static final String EXTRA_PACKAGE_NAME = "android.content.pm.extra.PACKAGE_NAME";
     field public static final String EXTRA_SESSION = "android.content.pm.extra.SESSION";
@@ -12197,6 +12218,9 @@
     field public static final String EXTRA_STATUS = "android.content.pm.extra.STATUS";
     field public static final String EXTRA_STATUS_MESSAGE = "android.content.pm.extra.STATUS_MESSAGE";
     field public static final String EXTRA_STORAGE_PATH = "android.content.pm.extra.STORAGE_PATH";
+    field public static final int LOCATION_DATA_APP = 0; // 0x0
+    field public static final int LOCATION_MEDIA_DATA = 2; // 0x2
+    field public static final int LOCATION_MEDIA_OBB = 1; // 0x1
     field public static final int STATUS_FAILURE = 1; // 0x1
     field public static final int STATUS_FAILURE_ABORTED = 3; // 0x3
     field public static final int STATUS_FAILURE_BLOCKED = 2; // 0x2
@@ -12204,6 +12228,7 @@
     field public static final int STATUS_FAILURE_INCOMPATIBLE = 7; // 0x7
     field public static final int STATUS_FAILURE_INVALID = 4; // 0x4
     field public static final int STATUS_FAILURE_STORAGE = 6; // 0x6
+    field public static final int STATUS_PENDING_STREAMING = -2; // 0xfffffffe
     field public static final int STATUS_PENDING_USER_ACTION = -1; // 0xffffffff
     field public static final int STATUS_SUCCESS = 0; // 0x0
   }
@@ -12211,10 +12236,12 @@
   public static class PackageInstaller.Session implements java.io.Closeable {
     method public void abandon();
     method public void addChildSessionId(int);
+    method public void addFile(int, @NonNull String, long, @NonNull byte[], @Nullable byte[]);
     method public void close();
     method public void commit(@NonNull android.content.IntentSender);
     method public void fsync(@NonNull java.io.OutputStream) throws java.io.IOException;
     method @NonNull public int[] getChildSessionIds();
+    method @Nullable public android.content.pm.DataLoaderParams getDataLoaderParams();
     method @NonNull public String[] getNames() throws java.io.IOException;
     method public int getParentSessionId();
     method public boolean isMultiPackage();
@@ -12288,6 +12315,7 @@
     method public void setAppLabel(@Nullable CharSequence);
     method public void setAppPackageName(@Nullable String);
     method public void setAutoRevokePermissionsMode(boolean);
+    method public void setDataLoaderParams(@NonNull android.content.pm.DataLoaderParams);
     method public void setInstallLocation(int);
     method public void setInstallReason(int);
     method public void setInstallScenario(int);
@@ -18758,7 +18786,7 @@
   public final class InputManager {
     method public android.view.InputDevice getInputDevice(int);
     method public int[] getInputDeviceIds();
-    method public float getMaximumObscuringOpacityForTouch();
+    method @FloatRange(from=0, to=1) public float getMaximumObscuringOpacityForTouch();
     method public void registerInputDeviceListener(android.hardware.input.InputManager.InputDeviceListener, android.os.Handler);
     method public void unregisterInputDeviceListener(android.hardware.input.InputManager.InputDeviceListener);
     method @Nullable public android.view.VerifiedInputEvent verifyInputEvent(@NonNull android.view.InputEvent);
@@ -34745,6 +34773,7 @@
     field public static final String ACTION_APP_NOTIFICATION_SETTINGS = "android.settings.APP_NOTIFICATION_SETTINGS";
     field public static final String ACTION_APP_SEARCH_SETTINGS = "android.settings.APP_SEARCH_SETTINGS";
     field public static final String ACTION_APP_USAGE_SETTINGS = "android.settings.action.APP_USAGE_SETTINGS";
+    field public static final String ACTION_AUTO_ROTATE_SETTINGS = "android.settings.AUTO_ROTATE_SETTINGS";
     field public static final String ACTION_BATTERY_SAVER_SETTINGS = "android.settings.BATTERY_SAVER_SETTINGS";
     field public static final String ACTION_BIOMETRIC_ENROLL = "android.settings.BIOMETRIC_ENROLL";
     field public static final String ACTION_BLUETOOTH_SETTINGS = "android.settings.BLUETOOTH_SETTINGS";
@@ -41630,7 +41659,7 @@
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field public static final int BAND_UNKNOWN = 0; // 0x0
     field public static final int CELL_BANDWIDTH_UNKNOWN = 0; // 0x0
-    field public static final int CHANNEL_NUMBER_UNKNOWN = -1; // 0xffffffff
+    field public static final int CHANNEL_NUMBER_UNKNOWN = 2147483647; // 0x7fffffff
     field public static final int CONNECTION_PRIMARY_SERVING = 1; // 0x1
     field public static final int CONNECTION_SECONDARY_SERVING = 2; // 0x2
     field public static final int CONNECTION_UNKNOWN = -1; // 0xffffffff
@@ -46400,8 +46429,8 @@
     method @Deprecated public int getPixelFormat();
     method @Nullable public android.graphics.ColorSpace getPreferredWideGamutColorSpace();
     method public long getPresentationDeadlineNanos();
-    method public void getRealMetrics(android.util.DisplayMetrics);
-    method public void getRealSize(android.graphics.Point);
+    method @Deprecated public void getRealMetrics(android.util.DisplayMetrics);
+    method @Deprecated public void getRealSize(android.graphics.Point);
     method @Deprecated public void getRectSize(android.graphics.Rect);
     method public float getRefreshRate();
     method public int getRotation();
@@ -50896,6 +50925,7 @@
 
   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();
@@ -50921,6 +50951,7 @@
     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 void unregisterCallback(@Nullable android.view.autofill.AutofillManager.AutofillCallback);
     field public static final String EXTRA_ASSIST_STRUCTURE = "android.view.autofill.extra.ASSIST_STRUCTURE";
@@ -50939,6 +50970,10 @@
     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);
@@ -52262,9 +52297,8 @@
   }
 
   public final class TextServicesManager {
-    method @Nullable public android.view.textservice.SpellCheckerInfo getCurrentSpellChecker();
-    method @Nullable public android.view.textservice.SpellCheckerSubtype getCurrentSpellCheckerSubtype(boolean);
-    method @Nullable public java.util.List<android.view.textservice.SpellCheckerInfo> getEnabledSpellCheckersList();
+    method @Nullable public android.view.textservice.SpellCheckerInfo getCurrentSpellCheckerInfo();
+    method @Nullable public java.util.List<android.view.textservice.SpellCheckerInfo> getEnabledSpellCheckerInfos();
     method public boolean isSpellCheckerEnabled();
     method @Nullable public android.view.textservice.SpellCheckerSession newSpellCheckerSession(@Nullable android.os.Bundle, @Nullable java.util.Locale, @NonNull android.view.textservice.SpellCheckerSession.SpellCheckerSessionListener, boolean);
     method @Nullable public android.view.textservice.SpellCheckerSession newSpellCheckerSession(@Nullable android.os.Bundle, @Nullable java.util.Locale, @NonNull android.view.textservice.SpellCheckerSession.SpellCheckerSessionListener, boolean, int);
@@ -52280,38 +52314,77 @@
   }
 
   public final class TranslationRequest implements android.os.Parcelable {
-    ctor public TranslationRequest(@Nullable CharSequence);
     method public int describeContents();
-    method @Nullable public android.view.autofill.AutofillId getAutofillId();
-    method @Nullable public CharSequence getTranslationText();
+    method public int getFlags();
+    method @NonNull public java.util.List<android.view.translation.TranslationRequestValue> getTranslationRequestValues();
+    method @NonNull public java.util.List<android.view.translation.ViewTranslationRequest> getViewTranslationRequests();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.view.translation.TranslationRequest> CREATOR;
+    field public static final int FLAG_DICTIONARY_RESULT = 2; // 0x2
+    field public static final int FLAG_PARTIAL_RESPONSES = 8; // 0x8
+    field public static final int FLAG_TRANSLATION_RESULT = 1; // 0x1
+    field public static final int FLAG_TRANSLITERATION_RESULT = 4; // 0x4
   }
 
   public static final class TranslationRequest.Builder {
     ctor public TranslationRequest.Builder();
+    method @NonNull public android.view.translation.TranslationRequest.Builder addTranslationRequestValue(@NonNull android.view.translation.TranslationRequestValue);
+    method @NonNull public android.view.translation.TranslationRequest.Builder addViewTranslationRequest(@NonNull android.view.translation.ViewTranslationRequest);
     method @NonNull public android.view.translation.TranslationRequest build();
-    method @NonNull public android.view.translation.TranslationRequest.Builder setAutofillId(@NonNull android.view.autofill.AutofillId);
-    method @NonNull public android.view.translation.TranslationRequest.Builder setTranslationText(@NonNull CharSequence);
+    method @NonNull public android.view.translation.TranslationRequest.Builder setFlags(int);
+    method @NonNull public android.view.translation.TranslationRequest.Builder setTranslationRequestValues(@NonNull java.util.List<android.view.translation.TranslationRequestValue>);
+    method @NonNull public android.view.translation.TranslationRequest.Builder setViewTranslationRequests(@NonNull java.util.List<android.view.translation.ViewTranslationRequest>);
+  }
+
+  public final class TranslationRequestValue implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public static android.view.translation.TranslationRequestValue forText(@NonNull CharSequence);
+    method @NonNull public CharSequence getText();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.view.translation.TranslationRequestValue> CREATOR;
   }
 
   public final class TranslationResponse implements android.os.Parcelable {
     method public int describeContents();
+    method @NonNull public android.util.SparseArray<android.view.translation.TranslationResponseValue> getTranslationResponseValues();
     method public int getTranslationStatus();
-    method @NonNull public java.util.List<android.view.translation.TranslationRequest> getTranslations();
+    method @NonNull public android.util.SparseArray<android.view.translation.ViewTranslationResponse> getViewTranslationResponses();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.view.translation.TranslationResponse> CREATOR;
-    field public static final int TRANSLATION_STATUS_LANGUAGE_UNAVAILABLE = 2; // 0x2
+    field public static final int TRANSLATION_STATUS_CONTEXT_UNSUPPORTED = 2; // 0x2
     field public static final int TRANSLATION_STATUS_SUCCESS = 0; // 0x0
     field public static final int TRANSLATION_STATUS_UNKNOWN_ERROR = 1; // 0x1
   }
 
   public static final class TranslationResponse.Builder {
     ctor public TranslationResponse.Builder(int);
-    method @NonNull public android.view.translation.TranslationResponse.Builder addTranslations(@NonNull android.view.translation.TranslationRequest);
     method @NonNull public android.view.translation.TranslationResponse build();
+    method @NonNull public android.view.translation.TranslationResponse.Builder setTranslationResponseValue(int, @NonNull android.view.translation.TranslationResponseValue);
+    method @NonNull public android.view.translation.TranslationResponse.Builder setTranslationResponseValues(@NonNull android.util.SparseArray<android.view.translation.TranslationResponseValue>);
     method @NonNull public android.view.translation.TranslationResponse.Builder setTranslationStatus(int);
-    method @NonNull public android.view.translation.TranslationResponse.Builder setTranslations(@NonNull java.util.List<android.view.translation.TranslationRequest>);
+    method @NonNull public android.view.translation.TranslationResponse.Builder setViewTranslationResponse(int, @NonNull android.view.translation.ViewTranslationResponse);
+    method @NonNull public android.view.translation.TranslationResponse.Builder setViewTranslationResponses(@NonNull android.util.SparseArray<android.view.translation.ViewTranslationResponse>);
+  }
+
+  public final class TranslationResponseValue implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public static android.view.translation.TranslationResponseValue forError();
+    method @Nullable public CharSequence getDictionaryDescription();
+    method public int getStatusCode();
+    method @Nullable public CharSequence getText();
+    method @Nullable public CharSequence getTransliteration();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.view.translation.TranslationResponseValue> CREATOR;
+    field public static final int STATUS_ERROR = 1; // 0x1
+    field public static final int STATUS_SUCCESS = 0; // 0x0
+  }
+
+  public static final class TranslationResponseValue.Builder {
+    ctor public TranslationResponseValue.Builder(int);
+    method @NonNull public android.view.translation.TranslationResponseValue build();
+    method @NonNull public android.view.translation.TranslationResponseValue.Builder setDictionaryDescription(@NonNull CharSequence);
+    method @NonNull public android.view.translation.TranslationResponseValue.Builder setText(@NonNull CharSequence);
+    method @NonNull public android.view.translation.TranslationResponseValue.Builder setTransliteration(@NonNull CharSequence);
   }
 
   public final class TranslationSpec implements android.os.Parcelable {
@@ -52330,6 +52403,37 @@
     method @Nullable @WorkerThread public android.view.translation.TranslationResponse translate(@NonNull android.view.translation.TranslationRequest);
   }
 
+  public final class ViewTranslationRequest implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public android.view.autofill.AutofillId getAutofillId();
+    method @NonNull public java.util.Set<java.lang.String> getKeys();
+    method @NonNull public android.view.translation.TranslationRequestValue getValue(@NonNull String);
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.view.translation.ViewTranslationRequest> CREATOR;
+    field public static final String ID_TEXT = "text";
+  }
+
+  public static final class ViewTranslationRequest.Builder {
+    ctor public ViewTranslationRequest.Builder(@NonNull android.view.autofill.AutofillId);
+    method @NonNull public android.view.translation.ViewTranslationRequest build();
+    method public android.view.translation.ViewTranslationRequest.Builder setValue(String, android.view.translation.TranslationRequestValue);
+  }
+
+  public final class ViewTranslationResponse implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public android.view.autofill.AutofillId getAutofillId();
+    method @NonNull public java.util.Set<java.lang.String> getKeys();
+    method @NonNull public android.view.translation.TranslationResponseValue getValue(@NonNull String);
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.view.translation.ViewTranslationResponse> CREATOR;
+  }
+
+  public static final class ViewTranslationResponse.Builder {
+    ctor public ViewTranslationResponse.Builder(@NonNull android.view.autofill.AutofillId);
+    method @NonNull public android.view.translation.ViewTranslationResponse build();
+    method public android.view.translation.ViewTranslationResponse.Builder setValue(String, android.view.translation.TranslationResponseValue);
+  }
+
 }
 
 package android.webkit {
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index f7e6e03..c7d4058 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -35,6 +35,7 @@
   }
 
   public final class PendingIntent implements android.os.Parcelable {
+    method @RequiresPermission(android.Manifest.permission.GET_INTENT_SENDER_INTENT) public boolean intentFilterEquals(@Nullable android.app.PendingIntent);
     method @NonNull @RequiresPermission(android.Manifest.permission.GET_INTENT_SENDER_INTENT) public java.util.List<android.content.pm.ResolveInfo> queryIntentComponents(int);
   }
 
@@ -170,6 +171,14 @@
 
 package android.net {
 
+  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 static final class IpSecManager.UdpEncapsulationSocket implements java.lang.AutoCloseable {
     method public int getResourceId();
   }
@@ -208,6 +217,10 @@
 
 package android.os {
 
+  public final class BatteryStatsManager {
+    method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public void reportNetworkInterfaceForTransports(@NonNull String, @NonNull int[]) throws java.lang.RuntimeException;
+  }
+
   public class Binder implements android.os.IBinder {
     method public final void markVintfStability();
   }
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index ab00aff..5ca4d35 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -260,7 +260,6 @@
     field public static final String SIGNAL_REBOOT_READINESS = "android.permission.SIGNAL_REBOOT_READINESS";
     field public static final String SOUND_TRIGGER_RUN_IN_BATTERY_SAVER = "android.permission.SOUND_TRIGGER_RUN_IN_BATTERY_SAVER";
     field public static final String START_ACTIVITIES_FROM_BACKGROUND = "android.permission.START_ACTIVITIES_FROM_BACKGROUND";
-    field public static final String START_FOREGROUND_SERVICES_FROM_BACKGROUND = "android.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND";
     field public static final String STATUS_BAR_SERVICE = "android.permission.STATUS_BAR_SERVICE";
     field public static final String STOP_APP_SWITCHES = "android.permission.STOP_APP_SWITCHES";
     field public static final String SUBSTITUTE_NOTIFICATION_APP_NAME = "android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME";
@@ -360,6 +359,7 @@
     field public static final int config_systemGallery = 17039399; // 0x1040027
     field public static final int config_systemShell = 17039402; // 0x104002a
     field public static final int config_systemSpeechRecognizer = 17039406; // 0x104002e
+    field public static final int config_systemWellbeing = 17039408; // 0x1040030
     field public static final int config_systemWifiCoexManager = 17039407; // 0x104002f
   }
 
@@ -2195,7 +2195,7 @@
   }
 
   public static final class ContextParams.Builder {
-    method @NonNull @RequiresPermission(android.Manifest.permission.RENOUNCE_PERMISSIONS) public android.content.ContextParams.Builder setRenouncedPermissions(@NonNull java.util.Set<java.lang.String>);
+    method @NonNull @RequiresPermission(android.Manifest.permission.RENOUNCE_PERMISSIONS) public android.content.ContextParams.Builder setRenouncedPermissions(@Nullable java.util.Set<java.lang.String>);
   }
 
   public class ContextWrapper extends android.content.Context {
@@ -2381,14 +2381,6 @@
     method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_PROFILES) public void startActivity(@NonNull android.content.ComponentName, @NonNull android.os.UserHandle);
   }
 
-  public class DataLoaderParams {
-    method @NonNull public static final android.content.pm.DataLoaderParams forIncremental(@NonNull android.content.ComponentName, @NonNull String);
-    method @NonNull public static final android.content.pm.DataLoaderParams forStreaming(@NonNull android.content.ComponentName, @NonNull String);
-    method @NonNull public final String getArguments();
-    method @NonNull public final android.content.ComponentName getComponentName();
-    method @NonNull public final int getType();
-  }
-
   public final class InstallationFile {
     method public long getLengthBytes();
     method public int getLocation();
@@ -2487,19 +2479,10 @@
 
   public class PackageInstaller {
     method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void setPermissionsResult(int, boolean);
-    field public static final int DATA_LOADER_TYPE_INCREMENTAL = 2; // 0x2
-    field public static final int DATA_LOADER_TYPE_NONE = 0; // 0x0
-    field public static final int DATA_LOADER_TYPE_STREAMING = 1; // 0x1
-    field public static final String EXTRA_DATA_LOADER_TYPE = "android.content.pm.extra.DATA_LOADER_TYPE";
-    field public static final int LOCATION_DATA_APP = 0; // 0x0
-    field public static final int LOCATION_MEDIA_DATA = 2; // 0x2
-    field public static final int LOCATION_MEDIA_OBB = 1; // 0x1
   }
 
   public static class PackageInstaller.Session implements java.io.Closeable {
-    method public void addFile(int, @NonNull String, long, @NonNull byte[], @Nullable byte[]);
     method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void commitTransferred(@NonNull android.content.IntentSender);
-    method @Nullable public android.content.pm.DataLoaderParams getDataLoaderParams();
     method public void removeFile(int, @NonNull String);
   }
 
@@ -2521,7 +2504,6 @@
   public static class PackageInstaller.SessionParams implements android.os.Parcelable {
     method @RequiresPermission(android.Manifest.permission.ALLOCATE_AGGRESSIVE) public void setAllocateAggressive(boolean);
     method @Deprecated public void setAllowDowngrade(boolean);
-    method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void setDataLoaderParams(@NonNull android.content.pm.DataLoaderParams);
     method public void setDontKillApp(boolean);
     method public void setEnableRollback(boolean);
     method public void setEnableRollback(boolean, int);
@@ -2703,7 +2685,7 @@
     field public static final int PROTECTION_FLAG_RETAIL_DEMO = 16777216; // 0x1000000
     field public static final int PROTECTION_FLAG_ROLE = 67108864; // 0x4000000
     field public static final int PROTECTION_FLAG_SYSTEM_TEXT_CLASSIFIER = 65536; // 0x10000
-    field public static final int PROTECTION_FLAG_WELLBEING = 131072; // 0x20000
+    field @Deprecated public static final int PROTECTION_FLAG_WELLBEING = 131072; // 0x20000
     field @Nullable public final String backgroundPermission;
     field @StringRes public int requestRes;
   }
@@ -4343,7 +4325,7 @@
 
   public final class CorrelationVector implements android.os.Parcelable {
     method public int describeContents();
-    method @IntRange(from=0) public int getFrequencyOffsetMetersPerSecond();
+    method @FloatRange(from=0.0f) public double getFrequencyOffsetMetersPerSecond();
     method @NonNull public int[] getMagnitude();
     method @FloatRange(from=0.0f) public double getSamplingStartMeters();
     method @FloatRange(from=0.0f, fromInclusive=false) public double getSamplingWidthMeters();
@@ -4354,7 +4336,7 @@
   public static final class CorrelationVector.Builder {
     ctor public CorrelationVector.Builder();
     method @NonNull public android.location.CorrelationVector build();
-    method @NonNull public android.location.CorrelationVector.Builder setFrequencyOffsetMetersPerSecond(@IntRange(from=0) int);
+    method @NonNull public android.location.CorrelationVector.Builder setFrequencyOffsetMetersPerSecond(@FloatRange(from=0.0f) double);
     method @NonNull public android.location.CorrelationVector.Builder setMagnitude(@NonNull int[]);
     method @NonNull public android.location.CorrelationVector.Builder setSamplingStartMeters(@FloatRange(from=0.0f) double);
     method @NonNull public android.location.CorrelationVector.Builder setSamplingWidthMeters(@FloatRange(from=0.0f, fromInclusive=false) double);
@@ -10118,27 +10100,6 @@
 
 package android.service.translation {
 
-  public final class TranslationRequest implements android.os.Parcelable {
-    ctor public TranslationRequest(int, @NonNull android.view.translation.TranslationSpec, @NonNull android.view.translation.TranslationSpec, @NonNull java.util.List<android.view.translation.TranslationRequest>);
-    method public int describeContents();
-    method @NonNull public android.view.translation.TranslationSpec getDestSpec();
-    method public int getRequestId();
-    method @NonNull public android.view.translation.TranslationSpec getSourceSpec();
-    method @NonNull public java.util.List<android.view.translation.TranslationRequest> getTranslationRequests();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.service.translation.TranslationRequest> CREATOR;
-  }
-
-  public static final class TranslationRequest.Builder {
-    ctor public TranslationRequest.Builder(int, @NonNull android.view.translation.TranslationSpec, @NonNull android.view.translation.TranslationSpec, @NonNull java.util.List<android.view.translation.TranslationRequest>);
-    method @NonNull public android.service.translation.TranslationRequest.Builder addTranslationRequests(@NonNull android.view.translation.TranslationRequest);
-    method @NonNull public android.service.translation.TranslationRequest build();
-    method @NonNull public android.service.translation.TranslationRequest.Builder setDestSpec(@NonNull android.view.translation.TranslationSpec);
-    method @NonNull public android.service.translation.TranslationRequest.Builder setRequestId(int);
-    method @NonNull public android.service.translation.TranslationRequest.Builder setSourceSpec(@NonNull android.view.translation.TranslationSpec);
-    method @NonNull public android.service.translation.TranslationRequest.Builder setTranslationRequests(@NonNull java.util.List<android.view.translation.TranslationRequest>);
-  }
-
   public abstract class TranslationService extends android.app.Service {
     ctor public TranslationService();
     method @Nullable public final android.os.IBinder onBind(@NonNull android.content.Intent);
@@ -10146,7 +10107,7 @@
     method public abstract void onCreateTranslationSession(@NonNull android.view.translation.TranslationSpec, @NonNull android.view.translation.TranslationSpec, int);
     method public void onDisconnected();
     method public abstract void onFinishTranslationSession(int);
-    method public abstract void onTranslationRequest(@NonNull android.service.translation.TranslationRequest, int, @NonNull android.os.CancellationSignal, @NonNull android.service.translation.TranslationService.OnTranslationResultCallback);
+    method public abstract void onTranslationRequest(@NonNull android.view.translation.TranslationRequest, int, @NonNull android.os.CancellationSignal, @NonNull android.service.translation.TranslationService.OnTranslationResultCallback);
     field public static final String SERVICE_INTERFACE = "android.service.translation.TranslationService";
     field public static final String SERVICE_META_DATA = "android.translation_service";
   }
@@ -13000,7 +12961,7 @@
     method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION}) public boolean isRcsVolteSingleRegistrationCapable() throws android.telephony.ims.ImsException;
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void notifyRcsAutoConfigurationReceived(@NonNull byte[], boolean);
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerProvisioningChangedCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ProvisioningManager.Callback) throws android.telephony.ims.ImsException;
-    method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION}) public void registerRcsProvisioningChangedCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ProvisioningManager.RcsProvisioningCallback) throws android.telephony.ims.ImsException;
+    method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION}) public void registerRcsProvisioningCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ProvisioningManager.RcsProvisioningCallback) throws android.telephony.ims.ImsException;
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public int setProvisioningIntValue(int, int);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public void setProvisioningStatusForCapability(int, int, boolean);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public int setProvisioningStringValue(int, @NonNull String);
@@ -13008,7 +12969,7 @@
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public void setRcsProvisioningStatusForCapability(int, boolean);
     method @RequiresPermission(android.Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION) public void triggerRcsReconfiguration();
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void unregisterProvisioningChangedCallback(@NonNull android.telephony.ims.ProvisioningManager.Callback);
-    method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION}) public void unregisterRcsProvisioningChangedCallback(@NonNull android.telephony.ims.ProvisioningManager.RcsProvisioningCallback);
+    method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION}) public void unregisterRcsProvisioningCallback(@NonNull android.telephony.ims.ProvisioningManager.RcsProvisioningCallback);
     field @RequiresPermission(android.Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION) public static final String ACTION_RCS_SINGLE_REGISTRATION_CAPABILITY_UPDATE = "android.telephony.ims.action.RCS_SINGLE_REGISTRATION_CAPABILITY_UPDATE";
     field public static final String EXTRA_STATUS = "android.telephony.ims.extra.STATUS";
     field public static final String EXTRA_SUBSCRIPTION_ID = "android.telephony.ims.extra.SUBSCRIPTION_ID";
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 75b9525..7b5b198 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -302,6 +302,7 @@
   }
 
   public final class PendingIntent implements android.os.Parcelable {
+    method @RequiresPermission("android.permission.GET_INTENT_SENDER_INTENT") public boolean intentFilterEquals(@Nullable android.app.PendingIntent);
     method @NonNull @RequiresPermission("android.permission.GET_INTENT_SENDER_INTENT") public java.util.List<android.content.pm.ResolveInfo> queryIntentComponents(int);
     field @Deprecated public static final int FLAG_MUTABLE_UNAUDITED = 33554432; // 0x2000000
   }
@@ -1127,7 +1128,7 @@
   public final class InputManager {
     method public int getBlockUntrustedTouchesMode(@NonNull android.content.Context);
     method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void setBlockUntrustedTouchesMode(@NonNull android.content.Context, int);
-    method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void setMaximumObscuringOpacityForTouch(float);
+    method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void setMaximumObscuringOpacityForTouch(@FloatRange(from=0, to=1) float);
     field public static final long BLOCK_UNTRUSTED_TOUCHES = 158002302L; // 0x96aec7eL
   }
 
diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
index b15fa27..856ed50 100644
--- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
@@ -580,6 +580,13 @@
     private int mHtmlDescriptionRes;
 
     /**
+     * Whether the service is for accessibility.
+     *
+     * @hide
+     */
+    private boolean mIsAccessibilityTool = false;
+
+    /**
      * Creates a new instance.
      */
     public AccessibilityServiceInfo() {
@@ -708,6 +715,8 @@
             if (peekedValue != null) {
                 mHtmlDescriptionRes = peekedValue.resourceId;
             }
+            mIsAccessibilityTool = asAttributes.getBoolean(
+                    R.styleable.AccessibilityService_isAccessibilityTool, false);
             asAttributes.recycle();
         } catch (NameNotFoundException e) {
             throw new XmlPullParserException( "Unable to create context for: "
@@ -1036,6 +1045,15 @@
     }
 
     /**
+     * Indicates if the service is used to assist users with disabilities.
+     *
+     * @return {@code true} if the property is set to true.
+     */
+    public boolean isAccessibilityTool() {
+        return mIsAccessibilityTool;
+    }
+
+    /**
      * {@inheritDoc}
      */
     public int describeContents() {
@@ -1061,6 +1079,7 @@
         parcel.writeInt(mAnimatedImageRes);
         parcel.writeInt(mHtmlDescriptionRes);
         parcel.writeString(mNonLocalizedDescription);
+        parcel.writeBoolean(mIsAccessibilityTool);
     }
 
     private void initFromParcel(Parcel parcel) {
@@ -1082,6 +1101,7 @@
         mAnimatedImageRes = parcel.readInt();
         mHtmlDescriptionRes = parcel.readInt();
         mNonLocalizedDescription = parcel.readString();
+        mIsAccessibilityTool = parcel.readBoolean();
     }
 
     @Override
@@ -1136,6 +1156,8 @@
         stringBuilder.append(", ");
         stringBuilder.append("summary: ").append(mNonLocalizedSummary);
         stringBuilder.append(", ");
+        stringBuilder.append("isAccessibilityTool: ").append(mIsAccessibilityTool);
+        stringBuilder.append(", ");
         appendCapabilities(stringBuilder, mCapabilities);
         return stringBuilder.toString();
     }
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index e7751b8..0b59586 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -17,6 +17,8 @@
 package android.app;
 
 import static android.app.ActivityManager.PROCESS_STATE_UNKNOWN;
+import static android.app.ConfigurationController.createNewConfigAndUpdateIfNotNull;
+import static android.app.ConfigurationController.freeTextLayoutCachesIfNeeded;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 import static android.app.servertransaction.ActivityLifecycleItem.ON_CREATE;
@@ -79,7 +81,6 @@
 import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
 import android.content.res.Resources;
-import android.content.res.Resources.Theme;
 import android.content.res.loader.ResourcesLoader;
 import android.database.sqlite.SQLiteDatabase;
 import android.database.sqlite.SQLiteDebug;
@@ -162,7 +163,6 @@
 import android.util.UtilConfig;
 import android.util.proto.ProtoOutputStream;
 import android.view.Choreographer;
-import android.view.ContextThemeWrapper;
 import android.view.Display;
 import android.view.DisplayAdjustments;
 import android.view.DisplayAdjustments.FixedRotationAdjustments;
@@ -228,7 +228,6 @@
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
-import java.util.Locale;
 import java.util.Map;
 import java.util.Objects;
 import java.util.TimeZone;
@@ -251,7 +250,8 @@
  *
  * {@hide}
  */
-public final class ActivityThread extends ClientTransactionHandler {
+public final class ActivityThread extends ClientTransactionHandler
+        implements ActivityThreadInternal {
     /** @hide */
     public static final String TAG = "ActivityThread";
     private static final android.graphics.Bitmap.Config THUMBNAIL_FORMAT = Bitmap.Config.RGB_565;
@@ -363,13 +363,15 @@
     @UnsupportedAppUsage
     AppBindData mBoundApplication;
     Profiler mProfiler;
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553,
+            publicAlternatives = "Use {@code Context#getResources()#getConfiguration()#densityDpi} "
+                    + "instead.")
     int mCurDefaultDisplayDpi;
     @UnsupportedAppUsage
     boolean mDensityCompatMode;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(trackingBug = 176961850, maxTargetSdk = Build.VERSION_CODES.R,
+            publicAlternatives = "Use {@code Context#getResources()#getConfiguration()} instead.")
     Configuration mConfiguration;
-    Configuration mCompatConfiguration;
     @UnsupportedAppUsage
     Application mInitialApplication;
     @UnsupportedAppUsage
@@ -420,7 +422,8 @@
     @GuardedBy("mResourcesManager")
     final ArrayList<ActivityClientRecord> mRelaunchingActivities = new ArrayList<>();
     @GuardedBy("mResourcesManager")
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(trackingBug = 176961850, maxTargetSdk = Build.VERSION_CODES.R,
+            publicAlternatives = "Use {@code Context#getResources()#getConfiguration()} instead.")
     Configuration mPendingConfiguration = null;
     // An executor that performs multi-step transactions.
     private final TransactionExecutor mTransactionExecutor = new TransactionExecutor(this);
@@ -516,6 +519,9 @@
 
     private IContentCaptureOptionsCallback.Stub mContentCaptureOptionsCallback = null;
 
+    /** A client side controller to handle process level configuration changes. */
+    private ConfigurationController mConfigurationController;
+
     /** Activity client record, used for bookkeeping for the real {@link Activity} instance. */
     public static final class ActivityClientRecord {
         @UnsupportedAppUsage
@@ -2058,7 +2064,7 @@
                     Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                     break;
                 case CONFIGURATION_CHANGED:
-                    handleConfigurationChanged((Configuration) msg.obj);
+                    mConfigurationController.handleConfigurationChanged((Configuration) msg.obj);
                     break;
                 case CLEAN_UP_CONTEXT:
                     ContextCleanupInfo cci = (ContextCleanupInfo)msg.obj;
@@ -2539,6 +2545,7 @@
         return mExecutor;
     }
 
+    @Override
     @UnsupportedAppUsage
     public Application getApplication() {
         return mInitialApplication;
@@ -2549,6 +2556,7 @@
         return mBoundApplication.processName;
     }
 
+    @Override
     @UnsupportedAppUsage
     public ContextImpl getSystemContext() {
         synchronized (this) {
@@ -2559,6 +2567,7 @@
         }
     }
 
+    @Override
     public ContextImpl getSystemUiContext() {
         synchronized (this) {
             if (mSystemUiContext == null) {
@@ -3217,15 +3226,16 @@
 
     @VisibleForTesting(visibility = PACKAGE)
     public Configuration getConfiguration() {
-        return mConfiguration;
+        return mConfigurationController.getConfiguration();
     }
 
     @Override
     public void updatePendingConfiguration(Configuration config) {
-        synchronized (mResourcesManager) {
-            if (mPendingConfiguration == null || mPendingConfiguration.isOtherSeqNewer(config)) {
-                mPendingConfiguration = config;
-            }
+        final Configuration updatedConfig =
+                mConfigurationController.updatePendingConfiguration(config);
+        // This is only done to maintain @UnsupportedAppUsage and should be removed someday.
+        if (updatedConfig != null) {
+            mPendingConfiguration = updatedConfig;
         }
     }
 
@@ -3233,6 +3243,7 @@
      * Returns {@code true} if the {@link android.app.ActivityManager.ProcessState} of the current
      * process is cached.
      */
+    @Override
     @VisibleForTesting
     public boolean isCachedProcessState() {
         synchronized (mAppThread) {
@@ -3269,10 +3280,8 @@
         // non-cached. Except the case where there is a launching activity because the
         // LaunchActivityItem will handle it.
         if (wasCached && !isCachedProcessState() && mNumLaunchingActivities.get() == 0) {
-            final Configuration pendingConfig;
-            synchronized (mResourcesManager) {
-                pendingConfig = mPendingConfiguration;
-            }
+            final Configuration pendingConfig =
+                    mConfigurationController.getPendingConfiguration(false /* clearPending */);
             if (pendingConfig == null) {
                 return;
             }
@@ -3498,7 +3507,8 @@
 
             if (activity != null) {
                 CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
-                Configuration config = new Configuration(mCompatConfiguration);
+                Configuration config =
+                        new Configuration(mConfigurationController.getCompatConfiguration());
                 if (r.overrideConfig != null) {
                     config.updateFrom(r.overrideConfig);
                 }
@@ -3711,7 +3721,7 @@
         }
 
         // Make sure we are running with the most recent config.
-        handleConfigurationChanged(null, null);
+        mConfigurationController.handleConfigurationChanged(null, null);
 
         if (localLOGV) Slog.v(
             TAG, "Handling launch of " + r);
@@ -3729,7 +3739,7 @@
         final Activity a = performLaunchActivity(r, customIntent);
 
         if (a != null) {
-            r.createdConfig = new Configuration(mConfiguration);
+            r.createdConfig = new Configuration(mConfigurationController.getConfiguration());
             reportSizeConfigurations(r);
             if (!r.activity.mFinished && pendingActions != null) {
                 pendingActions.setOldState(r.state);
@@ -4962,10 +4972,10 @@
         r.setState(ON_PAUSE);
     }
 
-    // TODO(b/127877792): Make LocalActivityManager call performStopActivityInner. We cannot remove
+    // TODO(b/176961850): Make LocalActivityManager call performStopActivityInner. We cannot remove
     // this since it's a high usage hidden API.
     /** Called from {@link LocalActivityManager}. */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 127877792,
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 176961850,
             publicAlternatives = "{@code N/A}")
     final void performStopActivity(IBinder token, boolean saveState, String reason) {
         ActivityClientRecord r = mActivities.get(token);
@@ -5193,8 +5203,7 @@
         if (apk != null) {
             apk.setCompatibilityInfo(data.info);
         }
-        handleConfigurationChanged(mConfiguration, data.info);
-        WindowManagerGlobal.getInstance().reportNewConfiguration(mConfiguration);
+        mConfigurationController.handleConfigurationChanged(data.info);
     }
 
     private void deliverResults(ActivityClientRecord r, List<ResultInfo> results, String reason) {
@@ -5451,7 +5460,6 @@
         unscheduleGcIdler();
         mSomeActivitiesChanged = true;
 
-        Configuration changedConfig = null;
         int configChanges = 0;
 
         // First: make sure we have the most recent configuration and most
@@ -5480,20 +5488,20 @@
             if (DEBUG_CONFIGURATION) Slog.v(TAG, "Relaunching activity "
                     + tmp.token + " with configChanges=0x"
                     + Integer.toHexString(configChanges));
-
-            if (mPendingConfiguration != null) {
-                changedConfig = mPendingConfiguration;
-                mPendingConfiguration = null;
-            }
         }
 
+        Configuration changedConfig = mConfigurationController.getPendingConfiguration(
+                true /* clearPending */);
+        mPendingConfiguration = null;
+
         if (tmp.createdConfig != null) {
             // If the activity manager is passing us its current config,
             // assume that is really what we want regardless of what we
             // may have pending.
-            if (mConfiguration == null
-                    || (tmp.createdConfig.isOtherSeqNewer(mConfiguration)
-                            && mConfiguration.diff(tmp.createdConfig) != 0)) {
+            final Configuration config = mConfigurationController.getConfiguration();
+            if (config == null
+                    || (tmp.createdConfig.isOtherSeqNewer(config)
+                            && config.diff(tmp.createdConfig) != 0)) {
                 if (changedConfig == null
                         || tmp.createdConfig.isOtherSeqNewer(changedConfig)) {
                     changedConfig = tmp.createdConfig;
@@ -5506,9 +5514,12 @@
 
         // If there was a pending configuration change, execute it first.
         if (changedConfig != null) {
-            mCurDefaultDisplayDpi = changedConfig.densityDpi;
-            updateDefaultDensity();
-            handleConfigurationChanged(changedConfig, null);
+            mConfigurationController.updateDefaultDensity(changedConfig.densityDpi);
+            mConfigurationController.handleConfigurationChanged(changedConfig, null);
+
+            // These are only done to maintain @UnsupportedAppUsage and should be removed someday.
+            mCurDefaultDisplayDpi = mConfigurationController.getCurDefaultDisplayDpi();
+            mConfiguration = mConfigurationController.getConfiguration();
         }
 
         ActivityClientRecord r = mActivities.get(tmp.token);
@@ -5596,7 +5607,8 @@
 
         // Initialize a relaunch request.
         final MergedConfiguration mergedConfiguration = new MergedConfiguration(
-                r.createdConfig != null ? r.createdConfig : mConfiguration,
+                r.createdConfig != null
+                        ? r.createdConfig : mConfigurationController.getConfiguration(),
                 r.overrideConfig);
         final ActivityRelaunchItem activityRelaunchItem = ActivityRelaunchItem.obtain(
                 null /* pendingResults */, null /* pendingIntents */, 0 /* configChanges */,
@@ -5672,7 +5684,8 @@
         }
     }
 
-    ArrayList<ComponentCallbacks2> collectComponentCallbacks(boolean includeActivities) {
+    @Override
+    public ArrayList<ComponentCallbacks2> collectComponentCallbacks(boolean includeActivities) {
         ArrayList<ComponentCallbacks2> callbacks
                 = new ArrayList<ComponentCallbacks2>();
 
@@ -5732,44 +5745,6 @@
     }
 
     /**
-     * Creates a new Configuration only if override would modify base. Otherwise returns base.
-     * @param base The base configuration.
-     * @param override The update to apply to the base configuration. Can be null.
-     * @return A Configuration representing base with override applied.
-     */
-    private static Configuration createNewConfigAndUpdateIfNotNull(@NonNull Configuration base,
-            @Nullable Configuration override) {
-        if (override == null) {
-            return base;
-        }
-        Configuration newConfig = new Configuration(base);
-        newConfig.updateFrom(override);
-        return newConfig;
-    }
-
-    /**
-     * Decides whether to update a component's configuration and whether to inform it.
-     * @param cb The component callback to notify of configuration change.
-     * @param newConfig The new configuration.
-     */
-    private void performConfigurationChanged(ComponentCallbacks2 cb, Configuration newConfig) {
-        // ContextThemeWrappers may override the configuration for that context. We must check and
-        // apply any overrides defined.
-        Configuration contextThemeWrapperOverrideConfig = null;
-        if (cb instanceof ContextThemeWrapper) {
-            final ContextThemeWrapper contextThemeWrapper = (ContextThemeWrapper) cb;
-            contextThemeWrapperOverrideConfig = contextThemeWrapper.getOverrideConfiguration();
-        }
-
-        // Apply the ContextThemeWrapper override if necessary.
-        // NOTE: Make sure the configurations are not modified, as they are treated as immutable
-        // in many places.
-        final Configuration configToReport = createNewConfigAndUpdateIfNotNull(
-                newConfig, contextThemeWrapperOverrideConfig);
-        cb.onConfigurationChanged(configToReport);
-    }
-
-    /**
      * Decides whether to update an Activity's configuration and whether to inform it.
      * @param activity The activity to notify of configuration change.
      * @param newConfig The new configuration.
@@ -5887,128 +5862,15 @@
         }
     }
 
-    final Configuration applyCompatConfiguration(int displayDensity) {
-        Configuration config = mConfiguration;
-        if (mCompatConfiguration == null) {
-            mCompatConfiguration = new Configuration();
-        }
-        mCompatConfiguration.setTo(mConfiguration);
-        if (mResourcesManager.applyCompatConfigurationLocked(displayDensity,
-                mCompatConfiguration)) {
-            config = mCompatConfiguration;
-        }
-        return config;
-    }
-
     @Override
     public void handleConfigurationChanged(Configuration config) {
-        if (isCachedProcessState()) {
-            updatePendingConfiguration(config);
-            // If the process is in a cached state, delay the handling until the process is no
-            // longer cached.
-            return;
-        }
-        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "configChanged");
-        mCurDefaultDisplayDpi = config.densityDpi;
-        handleConfigurationChanged(config, null /* compat */);
-        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
-    }
+        mConfigurationController.handleConfigurationChanged(config);
 
-    private void handleConfigurationChanged(Configuration config, CompatibilityInfo compat) {
-
-        int configDiff;
-        boolean equivalent;
-
-        final Theme systemTheme = getSystemContext().getTheme();
-        final Theme systemUiTheme = getSystemUiContext().getTheme();
-
-        synchronized (mResourcesManager) {
-            if (mPendingConfiguration != null) {
-                if (!mPendingConfiguration.isOtherSeqNewer(config)) {
-                    config = mPendingConfiguration;
-                    mCurDefaultDisplayDpi = config.densityDpi;
-                    updateDefaultDensity();
-                }
-                mPendingConfiguration = null;
-            }
-
-            if (config == null) {
-                // TODO (b/135719017): Temporary log for debugging IME service.
-                if (Build.IS_DEBUGGABLE && mHasImeComponent) {
-                    Log.w(TAG, "handleConfigurationChanged for IME app but config is null");
-                }
-                return;
-            }
-
-            // This flag tracks whether the new configuration is fundamentally equivalent to the
-            // existing configuration. This is necessary to determine whether non-activity callbacks
-            // should receive notice when the only changes are related to non-public fields.
-            // We do not gate calling {@link #performActivityConfigurationChanged} based on this
-            // flag as that method uses the same check on the activity config override as well.
-            equivalent = mConfiguration != null && (0 == mConfiguration.diffPublicOnly(config));
-
-            if (DEBUG_CONFIGURATION) Slog.v(TAG, "Handle configuration changed: "
-                    + config);
-
-            final Resources appResources = mInitialApplication.getResources();
-            if (appResources.hasOverrideDisplayAdjustments()) {
-                // The value of Display#getRealSize will be adjusted by FixedRotationAdjustments,
-                // but Display#getSize refers to DisplayAdjustments#mConfiguration. So the rotated
-                // configuration also needs to set to the adjustments for consistency.
-                appResources.getDisplayAdjustments().getConfiguration().updateFrom(config);
-            }
-            mResourcesManager.applyConfigurationToResourcesLocked(config, compat,
-                    appResources.getDisplayAdjustments());
-            updateLocaleListFromAppContext(mInitialApplication.getApplicationContext(),
-                    mResourcesManager.getConfiguration().getLocales());
-
-            if (mConfiguration == null) {
-                mConfiguration = new Configuration();
-            }
-            if (!mConfiguration.isOtherSeqNewer(config) && compat == null) {
-                // TODO (b/135719017): Temporary log for debugging IME service.
-                if (Build.IS_DEBUGGABLE && mHasImeComponent) {
-                    Log.w(TAG, "handleConfigurationChanged for IME app but config seq is obsolete "
-                            + ", config=" + config
-                            + ", mConfiguration=" + mConfiguration);
-                }
-                return;
-            }
-
-            configDiff = mConfiguration.updateFrom(config);
-            config = applyCompatConfiguration(mCurDefaultDisplayDpi);
-            HardwareRenderer.sendDeviceConfigurationForDebugging(config);
-
-            if ((systemTheme.getChangingConfigurations() & configDiff) != 0) {
-                systemTheme.rebase();
-            }
-
-            if ((systemUiTheme.getChangingConfigurations() & configDiff) != 0) {
-                systemUiTheme.rebase();
-            }
-        }
-
-        final ArrayList<ComponentCallbacks2> callbacks =
-                collectComponentCallbacks(false /* includeActivities */);
-
-        freeTextLayoutCachesIfNeeded(configDiff);
-
-        if (callbacks != null) {
-            final int N = callbacks.size();
-            for (int i=0; i<N; i++) {
-                ComponentCallbacks2 cb = callbacks.get(i);
-                if (!equivalent) {
-                    performConfigurationChanged(cb, config);
-                } else {
-                    // TODO (b/135719017): Temporary log for debugging IME service.
-                    if (Build.IS_DEBUGGABLE && cb instanceof InputMethodService) {
-                        Log.w(TAG, "performConfigurationChanged didn't callback to IME "
-                                + ", configDiff=" + configDiff
-                                + ", mConfiguration=" + mConfiguration);
-                    }
-                }
-            }
-        }
+        // These are only done to maintain @UnsupportedAppUsage and should be removed someday.
+        mCurDefaultDisplayDpi = mConfigurationController.getCurDefaultDisplayDpi();
+        mConfiguration = mConfigurationController.getConfiguration();
+        mPendingConfiguration = mConfigurationController.getPendingConfiguration(
+                false /* clearPending */);
     }
 
     /**
@@ -6093,25 +5955,15 @@
         // so that we actually call through to all components.
         // TODO(adamlesinski): Change this to make use of ActivityManager's upcoming ability to
         // store configurations per-process.
+        final Configuration config = mConfigurationController.getConfiguration();
         Configuration newConfig = new Configuration();
-        newConfig.assetsSeq = (mConfiguration != null ? mConfiguration.assetsSeq : 0) + 1;
-        handleConfigurationChanged(newConfig, null);
+        newConfig.assetsSeq = (config != null ? config.assetsSeq : 0) + 1;
+        mConfigurationController.handleConfigurationChanged(newConfig, null /* compat */);
 
         // Preserve windows to avoid black flickers when overlays change.
         relaunchAllActivities(true /* preserveWindows */, "handleApplicationInfoChanged");
     }
 
-    static void freeTextLayoutCachesIfNeeded(int configDiff) {
-        if (configDiff != 0) {
-            // Ask text layout engine to free its caches if there is a locale change
-            boolean hasLocaleConfigChange = ((configDiff & ActivityInfo.CONFIG_LOCALE) != 0);
-            if (hasLocaleConfigChange) {
-                Canvas.freeTextLayoutCaches();
-                if (DEBUG_CONFIGURATION) Slog.v(TAG, "Cleared TextLayout Caches");
-            }
-        }
-    }
-
     /**
      * Sets the supplied {@code overrideConfig} as pending for the {@code activityToken}. Calling
      * this method prevents any calls to
@@ -6188,7 +6040,7 @@
                     + ", config=" + overrideConfig);
         }
         final Configuration reportedConfig = performConfigurationChangedForActivity(r,
-                mCompatConfiguration,
+                mConfigurationController.getCompatConfiguration(),
                 movedToDifferentDisplay ? displayId : r.activity.getDisplayId());
         // Notify the ViewRootImpl instance about configuration changes. It may have initiated this
         // update to make sure that resources are updated before updating itself.
@@ -6483,16 +6335,6 @@
         Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
     }
 
-    private void updateDefaultDensity() {
-        final int densityDpi = mCurDefaultDisplayDpi;
-        if (!mDensityCompatMode
-                && densityDpi != Configuration.DENSITY_DPI_UNDEFINED
-                && densityDpi != DisplayMetrics.DENSITY_DEVICE) {
-            DisplayMetrics.DENSITY_DEVICE = densityDpi;
-            Bitmap.setDefaultDensity(densityDpi);
-        }
-    }
-
     /**
      * Returns the correct library directory for the current ABI.
      * <p>
@@ -6519,27 +6361,6 @@
         return insInfo.nativeLibraryDir;
     }
 
-    /**
-     * The LocaleList set for the app's resources may have been shuffled so that the preferred
-     * Locale is at position 0. We must find the index of this preferred Locale in the
-     * original LocaleList.
-     */
-    private void updateLocaleListFromAppContext(Context context, LocaleList newLocaleList) {
-        final Locale bestLocale = context.getResources().getConfiguration().getLocales().get(0);
-        final int newLocaleListSize = newLocaleList.size();
-        for (int i = 0; i < newLocaleListSize; i++) {
-            if (bestLocale.equals(newLocaleList.get(i))) {
-                LocaleList.setDefault(newLocaleList, i);
-                return;
-            }
-        }
-
-        // The app may have overridden the LocaleList with its own Locale
-        // (not present in the available list). Push the chosen Locale
-        // to the front of the list.
-        LocaleList.setDefault(new LocaleList(bestLocale, newLocaleList));
-    }
-
     @UnsupportedAppUsage
     private void handleBindApplication(AppBindData data) {
         // Register the UI Thread as a sensitive thread to the runtime.
@@ -6560,8 +6381,9 @@
         AppSpecializationHooks.handleCompatChangesBeforeBindingApplication();
 
         mBoundApplication = data;
-        mConfiguration = new Configuration(data.config);
-        mCompatConfiguration = new Configuration(data.config);
+        mConfigurationController.setConfiguration(data.config);
+        mConfigurationController.setCompatConfiguration(data.config);
+        mConfiguration = mConfigurationController.getConfiguration();
 
         mProfiler = new Profiler();
         String agent = null;
@@ -6641,7 +6463,7 @@
             mCurDefaultDisplayDpi = data.config.densityDpi;
 
             // This calls mResourcesManager so keep it within the synchronized block.
-            applyCompatConfiguration(mCurDefaultDisplayDpi);
+            mConfigurationController.applyCompatConfiguration();
         }
 
         data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo);
@@ -6658,7 +6480,7 @@
             mDensityCompatMode = true;
             Bitmap.setDefaultDensity(DisplayMetrics.DENSITY_DEFAULT);
         }
-        updateDefaultDensity();
+        mConfigurationController.updateDefaultDensity(data.config.densityDpi);
 
         // mCoreSettings is only updated from the main thread, while this function is only called
         // from main thread as well, so no need to lock here.
@@ -6735,8 +6557,7 @@
         }
 
         final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);
-        updateLocaleListFromAppContext(appContext,
-                mResourcesManager.getConfiguration().getLocales());
+        mConfigurationController.updateLocaleListFromAppContext(appContext);
 
         // Initialize the default http proxy in this process.
         Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Setup proxies");
@@ -7611,6 +7432,7 @@
     @UnsupportedAppUsage
     private void attach(boolean system, long startSeq) {
         sCurrentActivityThread = this;
+        mConfigurationController = new ConfigurationController(this);
         mSystemThread = system;
         if (!system) {
             android.ddm.DdmHandleAppName.setAppName("<pre-initialized>",
@@ -7662,8 +7484,7 @@
             }
         }
 
-        ViewRootImpl.ConfigChangedCallback configChangedCallback
-                = (Configuration globalConfig) -> {
+        ViewRootImpl.ConfigChangedCallback configChangedCallback = (Configuration globalConfig) -> {
             synchronized (mResourcesManager) {
                 // TODO (b/135719017): Temporary log for debugging IME service.
                 if (Build.IS_DEBUGGABLE && mHasImeComponent) {
@@ -7676,14 +7497,15 @@
                 if (mResourcesManager.applyConfigurationToResourcesLocked(globalConfig,
                         null /* compat */,
                         mInitialApplication.getResources().getDisplayAdjustments())) {
-                    updateLocaleListFromAppContext(mInitialApplication.getApplicationContext(),
-                            mResourcesManager.getConfiguration().getLocales());
+                    mConfigurationController.updateLocaleListFromAppContext(
+                            mInitialApplication.getApplicationContext());
 
                     // This actually changed the resources! Tell everyone about it.
-                    if (mPendingConfiguration == null
-                            || mPendingConfiguration.isOtherSeqNewer(globalConfig)) {
-                        mPendingConfiguration = globalConfig;
+                    final Configuration updatedConfig =
+                            mConfigurationController.updatePendingConfiguration(globalConfig);
+                    if (updatedConfig != null) {
                         sendMessage(H.CONFIGURATION_CHANGED, globalConfig);
+                        mPendingConfiguration = updatedConfig;
                     }
                 }
             }
@@ -8019,6 +7841,16 @@
         return false;
     }
 
+    @Override
+    public boolean isInDensityCompatMode() {
+        return mDensityCompatMode;
+    }
+
+    @Override
+    public boolean hasImeComponent() {
+        return mHasImeComponent;
+    }
+
     // ------------------ Regular JNI ------------------------
     private native void nPurgePendingResources();
     private native void nDumpGraphicsInfo(FileDescriptor fd);
diff --git a/core/java/android/app/ActivityThreadInternal.java b/core/java/android/app/ActivityThreadInternal.java
new file mode 100644
index 0000000..d91933c
--- /dev/null
+++ b/core/java/android/app/ActivityThreadInternal.java
@@ -0,0 +1,42 @@
+/*
+ * 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.app;
+
+import android.content.ComponentCallbacks2;
+
+import java.util.ArrayList;
+
+/**
+ * ActivityThread internal interface.
+ * It is a subset of ActivityThread and used for communicating with
+ * {@link ConfigurationController}.
+ */
+interface ActivityThreadInternal {
+    ContextImpl getSystemContext();
+
+    ContextImpl getSystemUiContext();
+
+    boolean isInDensityCompatMode();
+
+    boolean hasImeComponent();
+
+    boolean isCachedProcessState();
+
+    Application getApplication();
+
+    ArrayList<ComponentCallbacks2> collectComponentCallbacks(boolean includeActivities);
+}
diff --git a/core/java/android/app/ConfigurationController.java b/core/java/android/app/ConfigurationController.java
new file mode 100644
index 0000000..0dbe3ba
--- /dev/null
+++ b/core/java/android/app/ConfigurationController.java
@@ -0,0 +1,343 @@
+/*
+ * 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.app;
+
+import static android.app.ActivityThread.DEBUG_CONFIGURATION;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ComponentCallbacks2;
+import android.content.Context;
+import android.content.pm.ActivityInfo;
+import android.content.res.CompatibilityInfo;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.HardwareRenderer;
+import android.inputmethodservice.InputMethodService;
+import android.os.Build;
+import android.os.LocaleList;
+import android.os.Trace;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.util.Slog;
+import android.view.ContextThemeWrapper;
+import android.view.WindowManagerGlobal;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.ArrayList;
+import java.util.Locale;
+
+/**
+ * A client side controller to handle process level configuration changes.
+ * @hide
+ */
+class ConfigurationController {
+    private static final String TAG = "ConfigurationController";
+
+    private final ActivityThreadInternal mActivityThread;
+
+    private final ResourcesManager mResourcesManager = ResourcesManager.getInstance();
+
+    @GuardedBy("mResourcesManager")
+    private @Nullable Configuration mPendingConfiguration;
+    private @Nullable Configuration mCompatConfiguration;
+    private @Nullable Configuration mConfiguration;
+
+    ConfigurationController(@NonNull ActivityThreadInternal activityThread) {
+        mActivityThread = activityThread;
+    }
+
+    /** Update the pending configuration. */
+    Configuration updatePendingConfiguration(@NonNull Configuration config) {
+        synchronized (mResourcesManager) {
+            if (mPendingConfiguration == null || mPendingConfiguration.isOtherSeqNewer(config)) {
+                mPendingConfiguration = config;
+                return mPendingConfiguration;
+            }
+        }
+        return null;
+    }
+
+    /** Get the pending configuration. */
+    Configuration getPendingConfiguration(boolean clearPending) {
+        Configuration outConfig = null;
+        synchronized (mResourcesManager) {
+            if (mPendingConfiguration != null) {
+                outConfig = mPendingConfiguration;
+                if (clearPending) {
+                    mPendingConfiguration = null;
+                }
+            }
+        }
+        return outConfig;
+    }
+
+    /** Set the compatibility configuration. */
+    void setCompatConfiguration(@NonNull Configuration config) {
+        mCompatConfiguration = new Configuration(config);
+    }
+
+    /** Get the compatibility configuration. */
+    Configuration getCompatConfiguration() {
+        return mCompatConfiguration;
+    }
+
+    /** Apply the global compatibility configuration. */
+    final Configuration applyCompatConfiguration() {
+        Configuration config = mConfiguration;
+        final int displayDensity = config.densityDpi;
+        if (mCompatConfiguration == null) {
+            mCompatConfiguration = new Configuration();
+        }
+        mCompatConfiguration.setTo(mConfiguration);
+        if (mResourcesManager.applyCompatConfigurationLocked(displayDensity,
+                mCompatConfiguration)) {
+            config = mCompatConfiguration;
+        }
+        return config;
+    }
+
+    /** Set the configuration. */
+    void setConfiguration(@NonNull Configuration config) {
+        mConfiguration = new Configuration(config);
+    }
+
+    /** Get current configuration. */
+    Configuration getConfiguration() {
+        return mConfiguration;
+    }
+
+    /**
+     * Update the configuration to latest.
+     * @param config The new configuration.
+     */
+    void handleConfigurationChanged(@NonNull Configuration config) {
+        if (mActivityThread.isCachedProcessState()) {
+            updatePendingConfiguration(config);
+            // If the process is in a cached state, delay the handling until the process is no
+            // longer cached.
+            return;
+        }
+        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "configChanged");
+        handleConfigurationChanged(config, null /* compat */);
+        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
+    }
+
+    /**
+     * Update the configuration to latest.
+     * @param compat The new compatibility information.
+     */
+    void handleConfigurationChanged(@NonNull CompatibilityInfo compat) {
+        handleConfigurationChanged(mConfiguration, compat);
+        WindowManagerGlobal.getInstance().reportNewConfiguration(mConfiguration);
+    }
+
+    /**
+     * Update the configuration to latest.
+     * @param config The new configuration.
+     * @param compat The new compatibility information.
+     */
+    void handleConfigurationChanged(@Nullable Configuration config,
+            @Nullable CompatibilityInfo compat) {
+        int configDiff;
+        boolean equivalent;
+
+        final Resources.Theme systemTheme = mActivityThread.getSystemContext().getTheme();
+        final Resources.Theme systemUiTheme = mActivityThread.getSystemUiContext().getTheme();
+
+        synchronized (mResourcesManager) {
+            if (mPendingConfiguration != null) {
+                if (!mPendingConfiguration.isOtherSeqNewer(config)) {
+                    config = mPendingConfiguration;
+                    updateDefaultDensity(config.densityDpi);
+                }
+                mPendingConfiguration = null;
+            }
+
+            final boolean hasIme = mActivityThread.hasImeComponent();
+            if (config == null) {
+                // TODO (b/135719017): Temporary log for debugging IME service.
+                if (Build.IS_DEBUGGABLE && hasIme) {
+                    Log.w(TAG, "handleConfigurationChanged for IME app but config is null");
+                }
+                return;
+            }
+
+            // This flag tracks whether the new configuration is fundamentally equivalent to the
+            // existing configuration. This is necessary to determine whether non-activity callbacks
+            // should receive notice when the only changes are related to non-public fields.
+            // We do not gate calling {@link #performActivityConfigurationChanged} based on this
+            // flag as that method uses the same check on the activity config override as well.
+            equivalent = mConfiguration != null && (0 == mConfiguration.diffPublicOnly(config));
+
+            if (DEBUG_CONFIGURATION) {
+                Slog.v(TAG, "Handle configuration changed: " + config);
+            }
+
+            final Application app = mActivityThread.getApplication();
+            final Resources appResources = app.getResources();
+            if (appResources.hasOverrideDisplayAdjustments()) {
+                // The value of Display#getRealSize will be adjusted by FixedRotationAdjustments,
+                // but Display#getSize refers to DisplayAdjustments#mConfiguration. So the rotated
+                // configuration also needs to set to the adjustments for consistency.
+                appResources.getDisplayAdjustments().getConfiguration().updateFrom(config);
+            }
+            mResourcesManager.applyConfigurationToResourcesLocked(config, compat,
+                    appResources.getDisplayAdjustments());
+            updateLocaleListFromAppContext(app.getApplicationContext());
+
+            if (mConfiguration == null) {
+                mConfiguration = new Configuration();
+            }
+            if (!mConfiguration.isOtherSeqNewer(config) && compat == null) {
+                // TODO (b/135719017): Temporary log for debugging IME service.
+                if (Build.IS_DEBUGGABLE && hasIme) {
+                    Log.w(TAG, "handleConfigurationChanged for IME app but config seq is obsolete "
+                            + ", config=" + config
+                            + ", mConfiguration=" + mConfiguration);
+                }
+                return;
+            }
+
+            configDiff = mConfiguration.updateFrom(config);
+            config = applyCompatConfiguration();
+            HardwareRenderer.sendDeviceConfigurationForDebugging(config);
+
+            if ((systemTheme.getChangingConfigurations() & configDiff) != 0) {
+                systemTheme.rebase();
+            }
+
+            if ((systemUiTheme.getChangingConfigurations() & configDiff) != 0) {
+                systemUiTheme.rebase();
+            }
+        }
+
+        final ArrayList<ComponentCallbacks2> callbacks =
+                mActivityThread.collectComponentCallbacks(false /* includeActivities */);
+
+        freeTextLayoutCachesIfNeeded(configDiff);
+
+        if (callbacks != null) {
+            final int size = callbacks.size();
+            for (int i = 0; i < size; i++) {
+                ComponentCallbacks2 cb = callbacks.get(i);
+                if (!equivalent) {
+                    performConfigurationChanged(cb, config);
+                } else {
+                    // TODO (b/135719017): Temporary log for debugging IME service.
+                    if (Build.IS_DEBUGGABLE && cb instanceof InputMethodService) {
+                        Log.w(TAG, "performConfigurationChanged didn't callback to IME "
+                                + ", configDiff=" + configDiff
+                                + ", mConfiguration=" + mConfiguration);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Decides whether to update a component's configuration and whether to inform it.
+     * @param cb The component callback to notify of configuration change.
+     * @param newConfig The new configuration.
+     */
+    void performConfigurationChanged(@NonNull ComponentCallbacks2 cb,
+            @NonNull Configuration newConfig) {
+        // ContextThemeWrappers may override the configuration for that context. We must check and
+        // apply any overrides defined.
+        Configuration contextThemeWrapperOverrideConfig = null;
+        if (cb instanceof ContextThemeWrapper) {
+            final ContextThemeWrapper contextThemeWrapper = (ContextThemeWrapper) cb;
+            contextThemeWrapperOverrideConfig = contextThemeWrapper.getOverrideConfiguration();
+        }
+
+        // Apply the ContextThemeWrapper override if necessary.
+        // NOTE: Make sure the configurations are not modified, as they are treated as immutable
+        // in many places.
+        final Configuration configToReport = createNewConfigAndUpdateIfNotNull(
+                newConfig, contextThemeWrapperOverrideConfig);
+        cb.onConfigurationChanged(configToReport);
+    }
+
+    /** Update default density. */
+    void updateDefaultDensity(int densityDpi) {
+        if (!mActivityThread.isInDensityCompatMode()
+                && densityDpi != Configuration.DENSITY_DPI_UNDEFINED
+                && densityDpi != DisplayMetrics.DENSITY_DEVICE) {
+            DisplayMetrics.DENSITY_DEVICE = densityDpi;
+            Bitmap.setDefaultDensity(densityDpi);
+        }
+    }
+
+    /** Get current default display dpi. This is only done to maintain @UnsupportedAppUsage. */
+    int getCurDefaultDisplayDpi() {
+        return mConfiguration.densityDpi;
+    }
+
+    /**
+     * The LocaleList set for the app's resources may have been shuffled so that the preferred
+     * Locale is at position 0. We must find the index of this preferred Locale in the
+     * original LocaleList.
+     */
+    void updateLocaleListFromAppContext(@NonNull Context context) {
+        final Locale bestLocale = context.getResources().getConfiguration().getLocales().get(0);
+        final LocaleList newLocaleList = mResourcesManager.getConfiguration().getLocales();
+        final int newLocaleListSize = newLocaleList.size();
+        for (int i = 0; i < newLocaleListSize; i++) {
+            if (bestLocale.equals(newLocaleList.get(i))) {
+                LocaleList.setDefault(newLocaleList, i);
+                return;
+            }
+        }
+
+        // The app may have overridden the LocaleList with its own Locale
+        // (not present in the available list). Push the chosen Locale
+        // to the front of the list.
+        LocaleList.setDefault(new LocaleList(bestLocale, newLocaleList));
+    }
+
+    /**
+     * Creates a new Configuration only if override would modify base. Otherwise returns base.
+     * @param base The base configuration.
+     * @param override The update to apply to the base configuration. Can be null.
+     * @return A Configuration representing base with override applied.
+     */
+    static Configuration createNewConfigAndUpdateIfNotNull(@NonNull Configuration base,
+            @Nullable Configuration override) {
+        if (override == null) {
+            return base;
+        }
+        Configuration newConfig = new Configuration(base);
+        newConfig.updateFrom(override);
+        return newConfig;
+    }
+
+    /** Ask test layout engine to free its caches if there is a locale change. */
+    static void freeTextLayoutCachesIfNeeded(int configDiff) {
+        if (configDiff != 0) {
+            boolean hasLocaleConfigChange = ((configDiff & ActivityInfo.CONFIG_LOCALE) != 0);
+            if (hasLocaleConfigChange) {
+                Canvas.freeTextLayoutCaches();
+                if (DEBUG_CONFIGURATION) {
+                    Slog.v(TAG, "Cleared TextLayout Caches");
+                }
+            }
+        }
+    }
+}
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index d040938..3af0763 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1995,7 +1995,7 @@
                 final String errorMessage = "Tried to access visual service "
                         + SystemServiceRegistry.getSystemServiceClassName(name)
                         + " from a non-visual Context:" + getOuterContext();
-                final String message = "Visual services, such as WindowManager, WallpaperService "
+                final String message = "Visual services, such as WindowManager"
                         + "or LayoutInflater should be accessed from Activity or other visual "
                         + "Context. Use an Activity or a Context created with "
                         + "Context#createWindowContext(int, Bundle), which are adjusted to "
@@ -2635,7 +2635,8 @@
 
     @Override
     public @NonNull Context createAttributionContext(@Nullable String attributionTag) {
-        return createContext(new ContextParams.Builder().setAttributionTag(attributionTag).build());
+        return createContext(
+                new ContextParams.Builder(mParams).setAttributionTag(attributionTag).build());
     }
 
     @Override
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 4ebed7a..b00cfcb 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -6254,6 +6254,9 @@
             if (rawColor == COLOR_DEFAULT) {
                 ensureColors(p);
                 color = ContrastColorUtil.resolveDefaultColor(mContext, background, mInNightMode);
+                if (mTintWithThemeAccent) {
+                    color = obtainThemeColor(R.attr.colorAccent, color);
+                }
             } else {
                 color = ContrastColorUtil.resolveContrastColor(mContext, rawColor,
                         background, mInNightMode);
@@ -9904,6 +9907,22 @@
          */
         public static final int FLAG_SUPPRESS_NOTIFICATION = 0x00000002;
 
+        /**
+         * Indicates whether the bubble should be visually suppressed from the bubble stack if the
+         * user is viewing the same content outside of the bubble. For example, the user has a
+         * bubble with Alice and then opens up the main app and navigates to Alice's page.
+         *
+         * @hide
+         */
+        public static final int FLAG_SHOULD_SUPPRESS_BUBBLE = 0x00000004;
+
+        /**
+         * Indicates whether the bubble is visually suppressed from the bubble stack.
+         *
+         * @hide
+         */
+        public static final int FLAG_SUPPRESS_BUBBLE = 0x00000008;
+
         private BubbleMetadata(PendingIntent expandIntent, PendingIntent deleteIntent,
                 Icon icon, int height, @DimenRes int heightResId, String shortcutId) {
             mPendingIntent = expandIntent;
@@ -10046,6 +10065,32 @@
             return (mFlags & FLAG_SUPPRESS_NOTIFICATION) != 0;
         }
 
+        /**
+         * Indicates whether the bubble should be visually suppressed from the bubble stack if the
+         * user is viewing the same content outside of the bubble. For example, the user has a
+         * bubble with Alice and then opens up the main app and navigates to Alice's page.
+         *
+         * To match the activity and the bubble notification, the bubble notification should
+         * have a locus id set that matches a locus id set on the activity.
+         *
+         * @return whether this bubble should be suppressed when the same content is visible
+         * outside of the bubble.
+         *
+         * @see BubbleMetadata.Builder#setSuppressBubble(boolean)
+         */
+        public boolean isBubbleSuppressable() {
+            return (mFlags & FLAG_SHOULD_SUPPRESS_BUBBLE) != 0;
+        }
+
+        /**
+         * Indicates whether the bubble is currently visually suppressed from the bubble stack.
+         *
+         * @see BubbleMetadata.Builder#setSuppressBubble(boolean)
+         */
+        public boolean isBubbleSuppressed() {
+            return (mFlags & FLAG_SUPPRESS_BUBBLE) != 0;
+        }
+
         public static final @android.annotation.NonNull Parcelable.Creator<BubbleMetadata> CREATOR =
                 new Parcelable.Creator<BubbleMetadata>() {
 
@@ -10388,6 +10433,23 @@
             }
 
             /**
+             * Indicates whether the bubble should be visually suppressed from the bubble stack if
+             * the user is viewing the same content outside of the bubble. For example, the user has
+             * a bubble with Alice and then opens up the main app and navigates to Alice's page.
+             *
+             * To match the activity and the bubble notification, the bubble notification should
+             * have a locus id set that matches a locus id set on the activity.
+             *
+             * {@link Notification.Builder#setLocusId(LocusId)}
+             * {@link Activity#setLocusContext(LocusId, Bundle)}
+             */
+            @NonNull
+            public BubbleMetadata.Builder setSuppressBubble(boolean suppressBubble) {
+                setFlag(FLAG_SHOULD_SUPPRESS_BUBBLE, suppressBubble);
+                return this;
+            }
+
+            /**
              * Sets an intent to send when this bubble is explicitly removed by the user.
              *
              * <p>Setting a delete intent is optional.</p>
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index 009c936..11adc5a 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -1257,6 +1257,30 @@
     }
 
     /**
+     * Comparison operator on two PendingIntent objects, such that true is returned when they
+     * represent {@link Intent}s that are equal as per {@link Intent#filterEquals}.
+     *
+     * @param other The other PendingIntent to compare against.
+     * @return True if action, data, type, class, and categories on two intents are the same.
+     *
+     * @hide
+     */
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    @TestApi
+    @RequiresPermission(android.Manifest.permission.GET_INTENT_SENDER_INTENT)
+    public boolean intentFilterEquals(@Nullable PendingIntent other) {
+        if (other == null) {
+            return false;
+        }
+        try {
+            return ActivityManager.getService().getIntentForIntentSender(other.mTarget)
+                    .filterEquals(getIntent());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Comparison operator on two PendingIntent objects, such that true
      * is returned then they both represent the same operation from the
      * same package.  This allows you to use {@link #getActivity},
diff --git a/core/java/android/app/TaskInfo.java b/core/java/android/app/TaskInfo.java
index 9019ddf..6ad5eea 100644
--- a/core/java/android/app/TaskInfo.java
+++ b/core/java/android/app/TaskInfo.java
@@ -24,6 +24,7 @@
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.Intent;
+import android.content.LocusId;
 import android.content.pm.ActivityInfo;
 import android.content.res.Configuration;
 import android.graphics.Point;
@@ -123,6 +124,13 @@
     public ActivityManager.TaskDescription taskDescription;
 
     /**
+     * The locusId of the task.
+     * @hide
+     */
+    @Nullable
+    public LocusId mTopActivityLocusId;
+
+    /**
      * True if the task can go in the split-screen primary stack.
      * @hide
      */
@@ -381,6 +389,7 @@
         isVisible = source.readBoolean();
         topActivityToken = source.readStrongBinder();
         topActivityInSizeCompat = source.readBoolean();
+        mTopActivityLocusId = source.readTypedObject(LocusId.CREATOR);
     }
 
     /**
@@ -417,6 +426,7 @@
         dest.writeBoolean(isVisible);
         dest.writeStrongBinder(topActivityToken);
         dest.writeBoolean(topActivityInSizeCompat);
+        dest.writeTypedObject(mTopActivityLocusId, flags);
     }
 
     @Override
@@ -443,6 +453,7 @@
                 + " isVisible=" + isVisible
                 + " topActivityToken=" + topActivityToken
                 + " topActivityInSizeCompat=" + topActivityInSizeCompat
+                + " locusId= " + mTopActivityLocusId
                 + "}";
     }
 }
diff --git a/core/java/android/app/WallpaperColors.java b/core/java/android/app/WallpaperColors.java
index 0a8a734..6b2e649 100644
--- a/core/java/android/app/WallpaperColors.java
+++ b/core/java/android/app/WallpaperColors.java
@@ -32,6 +32,7 @@
 import com.android.internal.graphics.ColorUtils;
 import com.android.internal.graphics.palette.CelebiQuantizer;
 import com.android.internal.graphics.palette.Palette;
+import com.android.internal.graphics.palette.VariationalKMeansQuantizer;
 import com.android.internal.util.ContrastColorUtil;
 
 import java.io.FileOutputStream;
@@ -178,11 +179,20 @@
                     optimalSize.getHeight(), true /* filter */);
         }
 
-        final Palette palette = Palette
-                .from(bitmap, new CelebiQuantizer())
-                .maximumColorCount(256)
-                .resizeBitmapArea(MAX_WALLPAPER_EXTRACTION_AREA)
-                .generate();
+        final Palette palette;
+        if (ActivityManager.isLowRamDeviceStatic()) {
+            palette = Palette
+                    .from(bitmap, new VariationalKMeansQuantizer())
+                    .maximumColorCount(5)
+                    .resizeBitmapArea(MAX_WALLPAPER_EXTRACTION_AREA)
+                    .generate();
+        } else {
+            palette = Palette
+                    .from(bitmap, new CelebiQuantizer())
+                    .maximumColorCount(256)
+                    .resizeBitmapArea(MAX_WALLPAPER_EXTRACTION_AREA)
+                    .generate();
+        }
         // Remove insignificant colors and sort swatches by population
         final ArrayList<Palette.Swatch> swatches = new ArrayList<>(palette.getSwatches());
         swatches.sort((a, b) -> b.getPopulation() - a.getPopulation());
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index bd99348..8e53b5b 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -650,7 +650,6 @@
      */
     @RequiresPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE)
     public Drawable getDrawable() {
-        assertUiContext("getDrawable");
         final ColorManagementProxy cmProxy = getColorManagementProxy();
         Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, true, FLAG_SYSTEM, cmProxy);
         if (bm != null) {
@@ -718,7 +717,6 @@
      */
     public Drawable getBuiltInDrawable(int outWidth, int outHeight, boolean scaleToFit,
             float horizontalAlignment, float verticalAlignment, @SetWallpaperFlags int which) {
-        assertUiContext("getBuiltInDrawable");
         if (sGlobals.mService == null) {
             Log.w(TAG, "WallpaperService not running");
             throw new RuntimeException(new DeadSystemException());
@@ -884,7 +882,6 @@
      * null pointer if these is none.
      */
     public Drawable peekDrawable() {
-        assertUiContext("peekDrawable");
         final ColorManagementProxy cmProxy = getColorManagementProxy();
         Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, false, FLAG_SYSTEM, cmProxy);
         if (bm != null) {
@@ -927,7 +924,6 @@
      */
     @RequiresPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE)
     public Drawable peekFastDrawable() {
-        assertUiContext("peekFastDrawable");
         final ColorManagementProxy cmProxy = getColorManagementProxy();
         Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, false, FLAG_SYSTEM, cmProxy);
         if (bm != null) {
@@ -1084,6 +1080,7 @@
         return getWallpaperColors(which, mContext.getUserId());
     }
 
+    // TODO(b/181083333): add multiple root display area support on this API.
     /**
      * Get the primary colors of the wallpaper configured in the given user.
      * @param which wallpaper type. Must be either {@link #FLAG_SYSTEM} or
@@ -1094,7 +1091,7 @@
      */
     @UnsupportedAppUsage
     public @Nullable WallpaperColors getWallpaperColors(int which, int userId) {
-        assertUiContext("getWallpaperColors");
+        StrictMode.assertUiContext(mContext, "getWallpaperColors");
         return sGlobals.getWallpaperColors(which, userId, mContext.getDisplayId());
     }
 
@@ -1333,7 +1330,6 @@
     @RequiresPermission(android.Manifest.permission.SET_WALLPAPER)
     public int setResource(@RawRes int resid, @SetWallpaperFlags int which)
             throws IOException {
-        assertUiContext("setResource");
         if (sGlobals.mService == null) {
             Log.w(TAG, "WallpaperService not running");
             throw new RuntimeException(new DeadSystemException());
@@ -1637,6 +1633,7 @@
         }
     }
 
+    // TODO(b/181083333): add multiple root display area support on this API.
     /**
      * Returns the desired minimum width for the wallpaper. Callers of
      * {@link #setBitmap(android.graphics.Bitmap)} or
@@ -1654,7 +1651,7 @@
      * @see #getDesiredMinimumHeight()
      */
     public int getDesiredMinimumWidth() {
-        assertUiContext("getDesiredMinimumWidth");
+        StrictMode.assertUiContext(mContext, "getDesiredMinimumWidth");
         if (sGlobals.mService == null) {
             Log.w(TAG, "WallpaperService not running");
             throw new RuntimeException(new DeadSystemException());
@@ -1666,6 +1663,7 @@
         }
     }
 
+    // TODO(b/181083333): add multiple root display area support on this API.
     /**
      * Returns the desired minimum height for the wallpaper. Callers of
      * {@link #setBitmap(android.graphics.Bitmap)} or
@@ -1683,7 +1681,7 @@
      * @see #getDesiredMinimumWidth()
      */
     public int getDesiredMinimumHeight() {
-        assertUiContext("getDesiredMinimumHeight");
+        StrictMode.assertUiContext(mContext, "getDesiredMinimumHeight");
         if (sGlobals.mService == null) {
             Log.w(TAG, "WallpaperService not running");
             throw new RuntimeException(new DeadSystemException());
@@ -1695,6 +1693,7 @@
         }
     }
 
+    // TODO(b/181083333): add multiple root display area support on this API.
     /**
      * For use only by the current home application, to specify the size of
      * wallpaper it would like to use.  This allows such applications to have
@@ -1714,7 +1713,7 @@
      * @param minimumHeight Desired minimum height
      */
     public void suggestDesiredDimensions(int minimumWidth, int minimumHeight) {
-        assertUiContext("suggestDesiredDimensions");
+        StrictMode.assertUiContext(mContext, "suggestDesiredDimensions");
         try {
             /**
              * The framework makes no attempt to limit the window size
@@ -1757,6 +1756,7 @@
         }
     }
 
+    // TODO(b/181083333): add multiple root display area support on this API.
     /**
      * Specify extra padding that the wallpaper should have outside of the display.
      * That is, the given padding supplies additional pixels the wallpaper should extend
@@ -1770,7 +1770,7 @@
      */
     @RequiresPermission(android.Manifest.permission.SET_WALLPAPER_HINTS)
     public void setDisplayPadding(Rect padding) {
-        assertUiContext("setDisplayPadding");
+        StrictMode.assertUiContext(mContext, "setDisplayPadding");
         try {
             if (sGlobals.mService == null) {
                 Log.w(TAG, "WallpaperService not running");
@@ -2023,7 +2023,6 @@
      */
     @RequiresPermission(android.Manifest.permission.SET_WALLPAPER)
     public void clear() throws IOException {
-        assertUiContext("clear");
         setStream(openDefaultWallpaper(mContext, FLAG_SYSTEM), null, false);
     }
 
@@ -2176,10 +2175,6 @@
         return mCmProxy;
     }
 
-    private void assertUiContext(final String methodName) {
-        StrictMode.assertUiContext(mContext, methodName);
-    }
-
     /**
      * A hidden class to help {@link Globals#getCurrentWallpaperLocked} handle color management.
      * @hide
diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java
index 53aaae0..16413e1 100644
--- a/core/java/android/bluetooth/BluetoothA2dp.java
+++ b/core/java/android/bluetooth/BluetoothA2dp.java
@@ -139,7 +139,7 @@
      * @hide
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+    @UnsupportedAppUsage(trackingBug = 181103983)
     public static final String ACTION_CODEC_CONFIG_CHANGED =
             "android.bluetooth.a2dp.profile.action.CODEC_CONFIG_CHANGED";
 
@@ -684,7 +684,7 @@
      * @return the current codec status
      * @hide
      */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+    @UnsupportedAppUsage(trackingBug = 181103983)
     @Nullable
     @RequiresPermission(Manifest.permission.BLUETOOTH)
     public BluetoothCodecStatus getCodecStatus(@NonNull BluetoothDevice device) {
@@ -713,7 +713,7 @@
      * @param codecConfig the codec configuration preference
      * @hide
      */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+    @UnsupportedAppUsage(trackingBug = 181103983)
     @RequiresPermission(Manifest.permission.BLUETOOTH)
     public void setCodecConfigPreference(@NonNull BluetoothDevice device,
                                          @NonNull BluetoothCodecConfig codecConfig) {
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 230c985..8ea417f 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -769,7 +769,7 @@
     // Always log queries which take 500ms+; shorter queries are
     // sampled accordingly.
     private static final boolean ENABLE_CONTENT_SAMPLE = false;
-    private static final int SLOW_THRESHOLD_MILLIS = 500;
+    private static final int SLOW_THRESHOLD_MILLIS = 500 * Build.HW_TIMEOUT_MULTIPLIER;
     private final Random mRandom = new Random();  // guarded by itself
 
     /** @hide */
@@ -783,7 +783,8 @@
      * before we decide it must be hung.
      * @hide
      */
-    public static final int CONTENT_PROVIDER_PUBLISH_TIMEOUT_MILLIS = 10 * 1000;
+    public static final int CONTENT_PROVIDER_PUBLISH_TIMEOUT_MILLIS =
+            10 * 1000 * Build.HW_TIMEOUT_MULTIPLIER;
 
     /**
      * How long we wait for an provider to be published. Should be longer than
@@ -791,10 +792,11 @@
      * @hide
      */
     public static final int CONTENT_PROVIDER_READY_TIMEOUT_MILLIS =
-            CONTENT_PROVIDER_PUBLISH_TIMEOUT_MILLIS + 10 * 1000;
+            CONTENT_PROVIDER_PUBLISH_TIMEOUT_MILLIS + 10 * 1000 * Build.HW_TIMEOUT_MULTIPLIER;
 
     // Timeout given a ContentProvider that has already been started and connected to.
-    private static final int CONTENT_PROVIDER_TIMEOUT_MILLIS = 3 * 1000;
+    private static final int CONTENT_PROVIDER_TIMEOUT_MILLIS =
+            3 * 1000 * Build.HW_TIMEOUT_MULTIPLIER;
 
     // Should be >= {@link #CONTENT_PROVIDER_WAIT_TIMEOUT_MILLIS}, because that's how
     // long ActivityManagerService is giving a content provider to get published if a new process
diff --git a/core/java/android/content/ContextParams.java b/core/java/android/content/ContextParams.java
index 17ec2a8..fad905b 100644
--- a/core/java/android/content/ContextParams.java
+++ b/core/java/android/content/ContextParams.java
@@ -120,14 +120,45 @@
         private Set<String> mRenouncedPermissions;
 
         /**
+         * Create a new builder.
+         * <p>
+         * This is valuable when you are interested in having explicit control
+         * over every sub-parameter, and don't want to inherit any values from
+         * an existing Context.
+         * <p>
+         * Developers should strongly consider using
+         * {@link #Builder(ContextParams)} instead of this constructor, since
+         * that will will automatically inherit any new sub-parameters added in
+         * future platform releases.
+         */
+        public Builder() {
+        }
+
+        /**
+         * Create a new builder that inherits all sub-parameters by default.
+         * <p>
+         * This is valuable when you are only interested in overriding specific
+         * sub-parameters, and want to preserve all other parameters. Setting a
+         * specific sub-parameter on the returned builder will override any
+         * inherited value.
+         */
+        public Builder(@NonNull ContextParams params) {
+            Objects.requireNonNull(params);
+            mAttributionTag = params.mAttributionTag;
+            mReceiverPackage = params.mReceiverPackage;
+            mReceiverAttributionTag = params.mReceiverAttributionTag;
+            mRenouncedPermissions = params.mRenouncedPermissions;
+        }
+
+        /**
          * Sets an attribution tag against which to track permission accesses.
          *
          * @param attributionTag The attribution tag.
          * @return This builder.
          */
         @NonNull
-        public Builder setAttributionTag(@NonNull String attributionTag) {
-            mAttributionTag = Objects.requireNonNull(attributionTag);
+        public Builder setAttributionTag(@Nullable String attributionTag) {
+            mAttributionTag = attributionTag;
             return this;
         }
 
@@ -140,9 +171,9 @@
          * @return This builder.
          */
         @NonNull
-        public Builder setReceiverPackage(@NonNull String packageName,
+        public Builder setReceiverPackage(@Nullable String packageName,
                 @Nullable String attributionTag) {
-            mReceiverPackage = Objects.requireNonNull(packageName);
+            mReceiverPackage = packageName;
             mReceiverAttributionTag = attributionTag;
             return this;
         }
@@ -169,8 +200,13 @@
          */
         @SystemApi
         @RequiresPermission(android.Manifest.permission.RENOUNCE_PERMISSIONS)
-        public @NonNull Builder setRenouncedPermissions(@NonNull Set<String> renouncedPermissions) {
-            mRenouncedPermissions = Collections.unmodifiableSet(renouncedPermissions);
+        public @NonNull Builder setRenouncedPermissions(
+                @Nullable Set<String> renouncedPermissions) {
+            if (renouncedPermissions != null) {
+                mRenouncedPermissions = Collections.unmodifiableSet(renouncedPermissions);
+            } else {
+                mRenouncedPermissions = null;
+            }
             return this;
         }
 
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index d352b27..de17fda 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -6761,6 +6761,12 @@
      * #putExtras(Bundle)} when the provided Bundle has not been unparceled.
      */
     private static final int LOCAL_FLAG_UNFILTERED_EXTRAS = 1 << 3;
+
+    /**
+     * Local flag indicating this instance was created from a {@link Uri}.
+     */
+    private static final int LOCAL_FLAG_FROM_URI = 1 << 4;
+
     // ---------------------------------------------------------------------
     // ---------------------------------------------------------------------
     // toUri() and parseUri() options.
@@ -7173,6 +7179,16 @@
      * @see #toUri
      */
     public static Intent parseUri(String uri, @UriFlags int flags) throws URISyntaxException {
+        Intent intent = parseUriInternal(uri, flags);
+        intent.mLocalFlags |= LOCAL_FLAG_FROM_URI;
+        return intent;
+    }
+
+    /**
+     * @see #parseUri(String, int)
+     */
+    private static Intent parseUriInternal(String uri, @UriFlags int flags)
+            throws URISyntaxException {
         int i = 0;
         try {
             final boolean androidApp = uri.startsWith("android-app:");
@@ -7392,7 +7408,9 @@
     }
 
     public static Intent getIntentOld(String uri) throws URISyntaxException {
-        return getIntentOld(uri, 0);
+        Intent intent = getIntentOld(uri, 0);
+        intent.mLocalFlags |= LOCAL_FLAG_FROM_URI;
+        return intent;
     }
 
     private static Intent getIntentOld(String uri, int flags) throws URISyntaxException {
@@ -11353,6 +11371,13 @@
                 StrictMode.onUnsafeIntentLaunch(this);
             } else if ((mLocalFlags & LOCAL_FLAG_UNFILTERED_EXTRAS) != 0) {
                 StrictMode.onUnsafeIntentLaunch(this);
+            } else if ((mLocalFlags & LOCAL_FLAG_FROM_URI) != 0
+                    && !(mCategories != null && mCategories.contains(CATEGORY_BROWSABLE)
+                        && mComponent == null)) {
+                // Since the docs for #URI_ALLOW_UNSAFE recommend setting the category to browsable
+                // for an implicit Intent parsed from a URI a violation should be reported if these
+                // conditions are not met.
+                StrictMode.onUnsafeIntentLaunch(this);
             }
         }
     }
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index b1ca12cd..1660c9d 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -74,12 +74,28 @@
      */
     public static final int LAUNCH_SINGLE_INSTANCE = 3;
     /**
-     * The launch mode style requested by the activity.  From the
-     * {@link android.R.attr#launchMode} attribute, one of
-     * {@link #LAUNCH_MULTIPLE},
-     * {@link #LAUNCH_SINGLE_TOP}, {@link #LAUNCH_SINGLE_TASK}, or
-     * {@link #LAUNCH_SINGLE_INSTANCE}.
+     * Constant corresponding to <code>singleInstancePerTask</code> in
+     * the {@link android.R.attr#launchMode} attribute.
      */
+    public static final int LAUNCH_SINGLE_INSTANCE_PER_TASK = 4;
+
+    /** @hide */
+    @IntDef(prefix = "LAUNCH_", value = {
+            LAUNCH_MULTIPLE,
+            LAUNCH_SINGLE_TOP,
+            LAUNCH_SINGLE_TASK,
+            LAUNCH_SINGLE_INSTANCE,
+            LAUNCH_SINGLE_INSTANCE_PER_TASK
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface LaunchMode {
+    }
+
+    /**
+     * The launch mode style requested by the activity.  From the
+     * {@link android.R.attr#launchMode} attribute.
+     */
+    @LaunchMode
     public int launchMode;
 
     /**
diff --git a/core/java/android/content/pm/DataLoaderParams.java b/core/java/android/content/pm/DataLoaderParams.java
index a791026..93db1e1 100644
--- a/core/java/android/content/pm/DataLoaderParams.java
+++ b/core/java/android/content/pm/DataLoaderParams.java
@@ -17,17 +17,11 @@
 package android.content.pm;
 
 import android.annotation.NonNull;
-import android.annotation.SystemApi;
 import android.content.ComponentName;
 
 /**
  * This class represents the parameters used to configure a Data Loader.
- *
- * WARNING: This is a system API to aid internal development.
- * Use at your own risk. It will change or be removed without warning.
- * @hide
  */
-@SystemApi
 public class DataLoaderParams {
     @NonNull
     private final DataLoaderParamsParcel mData;
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 42cbe35..5afec06 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -235,9 +235,7 @@
      * See the individual types documentation for details.
      *
      * @see Intent#getIntExtra(String, int)
-     * {@hide}
      */
-    @SystemApi
     public static final String EXTRA_DATA_LOADER_TYPE = "android.content.pm.extra.DATA_LOADER_TYPE";
 
     /**
@@ -245,7 +243,6 @@
      * Caller should make sure DataLoader is able to prepare image and reinitiate the operation.
      *
      * @see #EXTRA_SESSION_ID
-     * {@hide}
      */
     public static final int STATUS_PENDING_STREAMING = -2;
 
@@ -348,44 +345,33 @@
      * Default value, non-streaming installation session.
      *
      * @see #EXTRA_DATA_LOADER_TYPE
-     * {@hide}
      */
-    @SystemApi
     public static final int DATA_LOADER_TYPE_NONE = DataLoaderType.NONE;
 
     /**
      * Streaming installation using data loader.
      *
      * @see #EXTRA_DATA_LOADER_TYPE
-     * {@hide}
      */
-    @SystemApi
     public static final int DATA_LOADER_TYPE_STREAMING = DataLoaderType.STREAMING;
 
     /**
      * Streaming installation using Incremental FileSystem.
      *
      * @see #EXTRA_DATA_LOADER_TYPE
-     * {@hide}
      */
-    @SystemApi
     public static final int DATA_LOADER_TYPE_INCREMENTAL = DataLoaderType.INCREMENTAL;
 
     /**
      * Target location for the file in installation session is /data/app/<packageName>-<id>.
      * This is the intended location for APKs.
-     * Requires permission to install packages.
-     * {@hide}
      */
-    @SystemApi
     public static final int LOCATION_DATA_APP = InstallationFileLocation.DATA_APP;
 
     /**
      * Target location for the file in installation session is
      * /data/media/<userid>/Android/obb/<packageName>. This is the intended location for OBBs.
-     * {@hide}
      */
-    @SystemApi
     public static final int LOCATION_MEDIA_OBB = InstallationFileLocation.MEDIA_OBB;
 
     /**
@@ -393,9 +379,7 @@
      * /data/media/<userid>/Android/data/<packageName>.
      * This is the intended location for application data.
      * Can only be used by an app itself running under specific user.
-     * {@hide}
      */
-    @SystemApi
     public static final int LOCATION_MEDIA_DATA = InstallationFileLocation.MEDIA_DATA;
 
     /** @hide */
@@ -1167,12 +1151,7 @@
 
         /**
          * @return data loader params or null if the session is not using one.
-         *
-         * WARNING: This is a system API to aid internal development.
-         * Use at your own risk. It will change or be removed without warning.
-         * {@hide}
          */
-        @SystemApi
         public @Nullable DataLoaderParams getDataLoaderParams() {
             try {
                 DataLoaderParamsParcel data = mSession.getDataLoaderParams();
@@ -1206,12 +1185,7 @@
          * @throws SecurityException if called after the session has been
          *             sealed or abandoned
          * @throws IllegalStateException if called for non-callback session
-         *
-         * WARNING: This is a system API to aid internal development.
-         * Use at your own risk. It will change or be removed without warning.
-         * {@hide}
          */
-        @SystemApi
         public void addFile(@FileLocation int location, @NonNull String name, long lengthBytes,
                 @NonNull byte[] metadata, @Nullable byte[] signature) {
             try {
@@ -2041,13 +2015,7 @@
          * Set the data loader params for the session.
          * This also switches installation into data provider mode and disallow direct writes into
          * staging folder.
-         *
-         * WARNING: This is a system API to aid internal development.
-         * Use at your own risk. It will change or be removed without warning.
-         * {@hide}
          */
-        @SystemApi
-        @RequiresPermission(Manifest.permission.INSTALL_PACKAGES)
         public void setDataLoaderParams(@NonNull DataLoaderParams dataLoaderParams) {
             this.dataLoaderParams = dataLoaderParams;
         }
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index bf8d1f6..5e08399 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -214,6 +214,7 @@
     public static final String METADATA_SUPPORTS_SIZE_CHANGES = "android.supports_size_changes";
     public static final String METADATA_ACTIVITY_WINDOW_LAYOUT_AFFINITY =
             "android.activity_window_layout_affinity";
+    public static final String METADATA_ACTIVITY_LAUNCH_MODE = "android.activity.launch_mode";
 
     /**
      * Bit mask of all the valid bits that can be set in recreateOnConfigChanges.
diff --git a/core/java/android/content/pm/PermissionInfo.java b/core/java/android/content/pm/PermissionInfo.java
index 83baca6..691c69c 100644
--- a/core/java/android/content/pm/PermissionInfo.java
+++ b/core/java/android/content/pm/PermissionInfo.java
@@ -200,6 +200,8 @@
      * to the <code>wellbeing</code> value of
      * {@link android.R.attr#protectionLevel}.
      *
+     * @deprecated this protectionLevel is obsolete. Permissions previously granted through this
+     * protectionLevel have been migrated to use <code>role</code> instead
      * @hide
      */
     @SystemApi
@@ -307,7 +309,6 @@
             PROTECTION_FLAG_OEM,
             PROTECTION_FLAG_VENDOR_PRIVILEGED,
             PROTECTION_FLAG_SYSTEM_TEXT_CLASSIFIER,
-            PROTECTION_FLAG_WELLBEING,
             PROTECTION_FLAG_DOCUMENTER,
             PROTECTION_FLAG_CONFIGURATOR,
             PROTECTION_FLAG_INCIDENT_REPORT_APPROVER,
@@ -560,9 +561,6 @@
         if ((level & PermissionInfo.PROTECTION_FLAG_SYSTEM_TEXT_CLASSIFIER) != 0) {
             protLevel.append("|textClassifier");
         }
-        if ((level & PermissionInfo.PROTECTION_FLAG_WELLBEING) != 0) {
-            protLevel.append("|wellbeing");
-        }
         if ((level & PermissionInfo.PROTECTION_FLAG_DOCUMENTER) != 0) {
             protLevel.append("|documenter");
         }
diff --git a/core/java/android/content/pm/TEST_MAPPING b/core/java/android/content/pm/TEST_MAPPING
index 953400e..8bc3734 100644
--- a/core/java/android/content/pm/TEST_MAPPING
+++ b/core/java/android/content/pm/TEST_MAPPING
@@ -31,6 +31,14 @@
           "include-filter": "android.content.pm.cts"
         }
       ]
+    },
+    {
+      "name": "CtsIncrementalInstallHostTestCases",
+      "options": [
+        {
+          "include-filter": "android.incrementalinstall.cts.IncrementalFeatureTest"
+        }
+      ]
     }
   ],
   "postsubmit": [
diff --git a/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java b/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java
index f821e08..0f4aa06 100644
--- a/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java
+++ b/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java
@@ -16,6 +16,7 @@
 
 package android.content.pm.parsing.component;
 
+import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE_PER_TASK;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
 import static android.content.pm.parsing.component.ComponentParseUtils.flag;
 
@@ -23,6 +24,7 @@
 import android.app.ActivityTaskManager;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
+import android.content.pm.PackageParser;
 import android.content.pm.parsing.ParsingPackage;
 import android.content.pm.parsing.ParsingPackageUtils;
 import android.content.pm.parsing.ParsingUtils;
@@ -402,6 +404,16 @@
             }
         }
 
+        if (!isAlias && activity.launchMode != LAUNCH_SINGLE_INSTANCE_PER_TASK
+                && activity.metaData != null && activity.metaData.containsKey(
+                PackageParser.METADATA_ACTIVITY_LAUNCH_MODE)) {
+            final String launchMode = activity.metaData.getString(
+                    PackageParser.METADATA_ACTIVITY_LAUNCH_MODE);
+            if (launchMode != null && launchMode.equals("singleInstancePerTask")) {
+                activity.launchMode = LAUNCH_SINGLE_INSTANCE_PER_TASK;
+            }
+        }
+
         ParseResult<ActivityInfo.WindowLayout> layoutResult =
                 resolveActivityWindowLayout(activity, input);
         if (layoutResult.isError()) {
diff --git a/core/java/android/content/res/CompatibilityInfo.java b/core/java/android/content/res/CompatibilityInfo.java
index bbde8b1..d7225cc 100644
--- a/core/java/android/content/res/CompatibilityInfo.java
+++ b/core/java/android/content/res/CompatibilityInfo.java
@@ -110,6 +110,7 @@
     public final float applicationInvertedScale;
 
     @UnsupportedAppUsage
+    @Deprecated
     public CompatibilityInfo(ApplicationInfo appInfo, int screenLayout, int sw,
             boolean forceCompat) {
         this(appInfo, screenLayout, sw, forceCompat, 1f);
diff --git a/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
index 0a56171..1f5098f 100644
--- a/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
@@ -61,6 +61,7 @@
 import android.util.Size;
 import android.view.Surface;
 
+import java.io.Closeable;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -90,6 +91,8 @@
     private ImageReader mBurstCaptureImageReader = null;
     private ImageReader mStubCaptureImageReader = null;
     private ImageWriter mRepeatingRequestImageWriter = null;
+    private CameraOutputImageCallback mRepeatingRequestImageCallback = null;
+    private CameraOutputImageCallback mBurstCaptureImageCallback = null;
 
     private CameraExtensionJpegProcessor mImageJpegProcessor = null;
     private ICaptureProcessorImpl mImageProcessor = null;
@@ -400,8 +403,10 @@
                     PREVIEW_QUEUE_SIZE, repeatingSurfaceInfo.mUsage);
             mCameraRepeatingSurface = mRepeatingRequestImageReader.getSurface();
         }
+        mRepeatingRequestImageCallback = new CameraOutputImageCallback(
+                mRepeatingRequestImageReader);
         mRepeatingRequestImageReader
-                .setOnImageAvailableListener(new ImageLoopbackCallback(), mHandler);
+                .setOnImageAvailableListener(mRepeatingRequestImageCallback, mHandler);
     }
 
     private void initializeBurstCapturePipeline() throws RemoteException {
@@ -440,6 +445,9 @@
                         CameraExtensionCharacteristics.PROCESSING_INPUT_FORMAT);
             }
 
+            mBurstCaptureImageCallback = new CameraOutputImageCallback(mBurstCaptureImageReader);
+            mBurstCaptureImageReader.setOnImageAvailableListener(mBurstCaptureImageCallback,
+                    mHandler);
             mCameraBurstSurface = mBurstCaptureImageReader.getSurface();
             android.hardware.camera2.extension.Size sz =
                     new android.hardware.camera2.extension.Size();
@@ -534,7 +542,8 @@
             mInternalRepeatingRequestEnabled = false;
             try {
                 return setRepeatingRequest(mPreviewExtender.getCaptureStage(),
-                        new RepeatingRequestHandler(request, executor, listener));
+                        new RepeatingRequestHandler(request, executor, listener,
+                                mRepeatingRequestImageCallback));
             } catch (RemoteException e) {
                 Log.e(TAG, "Failed to set repeating request! Extension service does not "
                         + "respond");
@@ -648,7 +657,8 @@
         }
 
         return mCaptureSession.captureBurstRequests(burstRequest, new HandlerExecutor(mHandler),
-                new BurstRequestHandler(request, executor, listener, requestMap));
+                new BurstRequestHandler(request, executor, listener, requestMap,
+                        mBurstCaptureImageCallback));
     }
 
     @Override
@@ -689,7 +699,8 @@
                 if (!captureStageList.isEmpty()) {
                     CaptureRequest disableRequest = createRequest(mCameraDevice, captureStageList,
                             mCameraRepeatingSurface, CameraDevice.TEMPLATE_PREVIEW);
-                    mCaptureSession.capture(disableRequest, new CloseRequestHandler(), mHandler);
+                    mCaptureSession.capture(disableRequest,
+                            new CloseRequestHandler(mRepeatingRequestImageCallback), mHandler);
                 }
 
                 mCaptureSession.close();
@@ -735,11 +746,21 @@
                 CameraExtensionCharacteristics.unregisterClient(mExtensionClientId);
             }
 
+            if (mRepeatingRequestImageCallback != null) {
+                mRepeatingRequestImageCallback.close();
+                mRepeatingRequestImageCallback = null;
+            }
+
             if (mRepeatingRequestImageReader != null) {
                 mRepeatingRequestImageReader.close();
                 mRepeatingRequestImageReader = null;
             }
 
+            if (mBurstCaptureImageCallback != null) {
+                mBurstCaptureImageCallback.close();
+                mBurstCaptureImageCallback = null;
+            }
+
             if (mBurstCaptureImageReader != null) {
                 mBurstCaptureImageReader.close();
                 mBurstCaptureImageReader = null;
@@ -835,7 +856,8 @@
                 ArrayList<CaptureStageImpl> initialRequestList = compileInitialRequestList();
                 if (!initialRequestList.isEmpty()) {
                     try {
-                        setInitialCaptureRequest(initialRequestList, new InitialRequestHandler());
+                        setInitialCaptureRequest(initialRequestList,
+                                new InitialRequestHandler(mRepeatingRequestImageCallback));
                     } catch (CameraAccessException e) {
                         Log.e(TAG, "Failed to initialize the initial capture request!");
                         status = false;
@@ -843,7 +865,8 @@
                 } else {
                     try {
                         setRepeatingRequest(mPreviewExtender.getCaptureStage(),
-                                new RepeatingRequestHandler(null, null, null));
+                                new RepeatingRequestHandler(null, null, null,
+                                        mRepeatingRequestImageCallback));
                     } catch (CameraAccessException | RemoteException e) {
                         Log.e(TAG, "Failed to initialize internal repeating request!");
                         status = false;
@@ -863,6 +886,7 @@
         private final ExtensionCaptureCallback mCallbacks;
         private final CaptureRequest mClientRequest;
         private final HashMap<CaptureRequest, Integer> mCaptureRequestMap;
+        private final CameraOutputImageCallback mBurstImageCallback;
 
         private HashMap<Integer, Pair<Image, TotalCaptureResult>> mCaptureStageMap =
                 new HashMap<>();
@@ -873,12 +897,14 @@
         private boolean mCaptureFailed = false;
 
         public BurstRequestHandler(@NonNull CaptureRequest request, @NonNull Executor executor,
-                                   @NonNull ExtensionCaptureCallback callbacks,
-                                   @NonNull HashMap<CaptureRequest, Integer> requestMap) {
+                @NonNull ExtensionCaptureCallback callbacks,
+                @NonNull HashMap<CaptureRequest, Integer> requestMap,
+                @Nullable CameraOutputImageCallback imageCallback) {
             mClientRequest = request;
             mExecutor = executor;
             mCallbacks = callbacks;
             mCaptureRequestMap = requestMap;
+            mBurstImageCallback = imageCallback;
         }
 
         private void notifyCaptureFailed() {
@@ -893,6 +919,11 @@
                 } finally {
                     Binder.restoreCallingIdentity(ident);
                 }
+
+                for (Pair<Image, TotalCaptureResult> captureStage : mCaptureStageMap.values()) {
+                    captureStage.first.close();
+                }
+                mCaptureStageMap.clear();
             }
         }
 
@@ -905,8 +936,7 @@
             boolean initialCallback = false;
             synchronized (mInterfaceLock) {
                 if ((mImageProcessor != null) && (mImageCallback == null)) {
-                    mImageCallback = new ImageCallback(mBurstCaptureImageReader);
-                    mBurstCaptureImageReader.setOnImageAvailableListener(mImageCallback, mHandler);
+                    mImageCallback = new ImageCallback();
                     initialCallback = true;
                 } else if (mImageProcessor == null) {
                     // No burst expected in this case
@@ -924,6 +954,10 @@
                     Binder.restoreCallingIdentity(ident);
                 }
             }
+
+            if ((mBurstImageCallback != null) && (mImageCallback != null)) {
+                mBurstImageCallback.registerListener(timestamp, mImageCallback);
+            }
         }
 
         @Override
@@ -1062,70 +1096,62 @@
             }
         }
 
-        private class ImageCallback implements ImageReader.OnImageAvailableListener {
-            public ImageCallback(@NonNull ImageReader reader) {
-                //Check for any pending buffers
-                onImageAvailable(reader);
-            }
-
+        private class ImageCallback implements OnImageAvailableListener {
             @Override
-            public void onImageAvailable(ImageReader reader) {
-                Image img;
-                try {
-                    while ((!mCaptureRequestMap.isEmpty()) &&
-                            (img = reader.acquireNextImage()) != null) {
-                        long timestamp = img.getTimestamp();
-                        reader.detachImage(img);
-                        if (mCapturePendingMap.indexOfKey(timestamp) >= 0) {
-                            Integer stageId = mCapturePendingMap.get(timestamp).second;
-                            Pair<Image, TotalCaptureResult> captureStage =
-                                    mCaptureStageMap.get(stageId);
-                            if (captureStage != null) {
-                                mCaptureStageMap.put(stageId,
-                                        new Pair<>(img,
-                                                captureStage.second));
-                                checkAndFireBurstProcessing();
-                            } else {
-                                Log.e(TAG,
-                                        "Capture stage: " +
-                                                mCapturePendingMap.get(timestamp).second +
-                                                " is absent!");
-                            }
-                        } else {
-                            mCapturePendingMap.put(timestamp,
-                                    new Pair<>(img,
-                                            -1));
-                        }
+            public void onImageAvailable(ImageReader reader, Image img) {
+                if (mCaptureFailed) {
+                    img.close();
+                }
+
+                long timestamp = img.getTimestamp();
+                reader.detachImage(img);
+                if (mCapturePendingMap.indexOfKey(timestamp) >= 0) {
+                    Integer stageId = mCapturePendingMap.get(timestamp).second;
+                    Pair<Image, TotalCaptureResult> captureStage =
+                            mCaptureStageMap.get(stageId);
+                    if (captureStage != null) {
+                        mCaptureStageMap.put(stageId,
+                                new Pair<>(img,
+                                        captureStage.second));
+                        checkAndFireBurstProcessing();
+                    } else {
+                        Log.e(TAG,
+                                "Capture stage: " +
+                                        mCapturePendingMap.get(timestamp).second +
+                                        " is absent!");
                     }
-                } catch (IllegalStateException e) {
-                    // This is possible in case the maximum number of images is acquired.
+                } else {
+                    mCapturePendingMap.put(timestamp,
+                            new Pair<>(img,
+                                    -1));
                 }
             }
         }
     }
 
-    private class ImageLoopbackCallback implements ImageReader.OnImageAvailableListener {
-        @Override public void onImageAvailable(ImageReader reader) {
-            Image img;
-            try {
-                img = reader.acquireNextImage();
-            } catch (IllegalStateException e) {
-                Log.e(TAG, "Failed to acquire and loopback image!");
-                return;
-            }
-            if (img == null) {
-                Log.e(TAG,
-                        "Invalid image!");
-                return;
-            }
+    private class ImageLoopbackCallback implements OnImageAvailableListener {
+        @Override
+        public void onImageAvailable(ImageReader reader, Image img) {
             img.close();
         }
     }
 
     private class InitialRequestHandler extends CameraCaptureSession.CaptureCallback {
+        private final CameraOutputImageCallback mImageCallback;
+
+        public InitialRequestHandler(CameraOutputImageCallback imageCallback) {
+            mImageCallback = imageCallback;
+        }
+
+        @Override
+        public void onCaptureStarted(@NonNull CameraCaptureSession session,
+                @NonNull CaptureRequest request, long timestamp, long frameNumber) {
+            mImageCallback.registerListener(timestamp, new ImageLoopbackCallback());
+        }
+
         @Override
         public void onCaptureSequenceAborted(@NonNull CameraCaptureSession session,
-                                             int sequenceId) {
+                int sequenceId) {
             Log.e(TAG, "Initial capture request aborted!");
             notifyConfigurationFailure();
         }
@@ -1150,7 +1176,8 @@
                  */
                 try {
                     setRepeatingRequest(mPreviewExtender.getCaptureStage(),
-                            new RepeatingRequestHandler(null, null, null));
+                            new RepeatingRequestHandler(null, null, null,
+                                    mImageCallback));
                 } catch (CameraAccessException | RemoteException e) {
                     Log.e(TAG, "Failed to start the internal repeating request!");
                     status = false;
@@ -1164,16 +1191,92 @@
         }
     }
 
+    private interface OnImageAvailableListener {
+        public void onImageAvailable (ImageReader reader, Image img);
+    }
+
+    private class CameraOutputImageCallback implements ImageReader.OnImageAvailableListener,
+            Closeable {
+        private final ImageReader mImageReader;
+        // Map timestamp to specific images and listeners
+        private HashMap<Long, Pair<Image, OnImageAvailableListener>> mImageListenerMap =
+                new HashMap<>();
+        private boolean mOutOfBuffers = false;
+
+        CameraOutputImageCallback(ImageReader imageReader) {
+            mImageReader = imageReader;
+        }
+
+        @Override
+        public void onImageAvailable(ImageReader reader) {
+            Image img;
+            try {
+                img = reader.acquireNextImage();
+            } catch (IllegalStateException e) {
+                Log.e(TAG, "Failed to acquire image, too many images pending!");
+                mOutOfBuffers = true;
+                return;
+            }
+            if (img == null) {
+                Log.e(TAG, "Invalid image!");
+                return;
+            }
+
+            Long timestamp = img.getTimestamp();
+            if (mImageListenerMap.containsKey(timestamp)) {
+                Pair<Image, OnImageAvailableListener> entry = mImageListenerMap.remove(timestamp);
+                if (entry.second != null) {
+                    entry.second.onImageAvailable(reader, img);
+                } else {
+                    Log.w(TAG, "Invalid image listener, dropping frame!");
+                    img.close();
+                }
+            } else {
+                mImageListenerMap.put(img.getTimestamp(), new Pair<>(img, null));
+            }
+        }
+
+        public void registerListener(Long timestamp, OnImageAvailableListener listener) {
+            if (mImageListenerMap.containsKey(timestamp)) {
+                Pair<Image, OnImageAvailableListener> entry = mImageListenerMap.remove(timestamp);
+                if (entry.first != null) {
+                    listener.onImageAvailable(mImageReader, entry.first);
+                    if (mOutOfBuffers) {
+                        mOutOfBuffers = false;
+                        Log.w(TAG,"Out of buffers, retry!");
+                        onImageAvailable(mImageReader);
+                    }
+                } else {
+                    Log.w(TAG, "No valid image for listener with ts: " +
+                            timestamp.longValue());
+                }
+            } else {
+                mImageListenerMap.put(timestamp, new Pair<>(null, listener));
+            }
+        }
+
+        @Override
+        public void close() {
+            for (Pair<Image, OnImageAvailableListener> entry : mImageListenerMap.values()) {
+                if (entry.first != null) {
+                    entry.first.close();
+                }
+            }
+            mImageListenerMap.clear();
+        }
+    }
+
     private class CloseRequestHandler extends CameraCaptureSession.CaptureCallback {
+        private final CameraOutputImageCallback mImageCallback;
+
+        public CloseRequestHandler(CameraOutputImageCallback imageCallback) {
+            mImageCallback = imageCallback;
+        }
+
         @Override
         public void onCaptureStarted(@NonNull CameraCaptureSession session,
-                                     @NonNull CaptureRequest request,
-                                     long timestamp,
-                                     long frameNumber) {
-            synchronized (mInterfaceLock) {
-                mRepeatingRequestImageReader
-                        .setOnImageAvailableListener(new ImageLoopbackCallback(), mHandler);
-            }
+                @NonNull CaptureRequest request, long timestamp, long frameNumber) {
+            mImageCallback.registerListener(timestamp, new ImageLoopbackCallback());
         }
     }
 
@@ -1187,20 +1290,22 @@
         private final ExtensionCaptureCallback mCallbacks;
         private final CaptureRequest mClientRequest;
         private final boolean mClientNotificationsEnabled;
-        private ImageReader.OnImageAvailableListener mImageCallback = null;
+        private final CameraOutputImageCallback mRepeatingImageCallback;
+        private OnImageAvailableListener mImageCallback = null;
         private LongSparseArray<Pair<Image, TotalCaptureResult>> mPendingResultMap =
                 new LongSparseArray<>();
 
         private boolean mRequestUpdatedNeeded = false;
 
         public RepeatingRequestHandler(@Nullable CaptureRequest clientRequest,
-                                       @Nullable Executor executor,
-                                       @Nullable ExtensionCaptureCallback listener) {
+                @Nullable Executor executor, @Nullable ExtensionCaptureCallback listener,
+                @NonNull CameraOutputImageCallback imageCallback) {
             mClientRequest = clientRequest;
             mExecutor = executor;
             mCallbacks = listener;
             mClientNotificationsEnabled =
                     (mClientRequest != null) && (mExecutor != null) && (mCallbacks != null);
+            mRepeatingImageCallback = imageCallback;
         }
 
         @Override
@@ -1226,8 +1331,6 @@
                                 new ImageForwardCallback(mRepeatingRequestImageWriter) :
                                 new ImageLoopbackCallback();
                     }
-                    mRepeatingRequestImageReader
-                            .setOnImageAvailableListener(mImageCallback, mHandler);
                 }
             }
 
@@ -1241,6 +1344,8 @@
                     Binder.restoreCallingIdentity(ident);
                 }
             }
+
+            mRepeatingImageCallback.registerListener(timestamp, mImageCallback);
         }
 
         @Override
@@ -1248,8 +1353,6 @@
                                              int sequenceId) {
             synchronized (mInterfaceLock) {
                 if (mInternalRepeatingRequestEnabled) {
-                    mRepeatingRequestImageReader.setOnImageAvailableListener(
-                            new ImageLoopbackCallback(), mHandler);
                     resumeInternalRepeatingRequest(true);
                 }
             }
@@ -1280,12 +1383,7 @@
                     mRequestUpdatedNeeded = false;
                     resumeInternalRepeatingRequest(false);
                 } else if (mInternalRepeatingRequestEnabled) {
-                    mRepeatingRequestImageReader.setOnImageAvailableListener(
-                            new ImageLoopbackCallback(), mHandler);
                     resumeInternalRepeatingRequest(true);
-                } else {
-                    mRepeatingRequestImageReader.setOnImageAvailableListener(
-                            new ImageLoopbackCallback(), mHandler);
                 }
             }
 
@@ -1395,12 +1493,14 @@
                         try {
                             if (processStatus) {
                                 mExecutor.execute(() -> mCallbacks
-                                        .onCaptureProcessStarted(CameraExtensionSessionImpl.this,
+                                        .onCaptureProcessStarted(
+                                                CameraExtensionSessionImpl.this,
                                                 mClientRequest));
                             } else {
                                 mExecutor.execute(
                                         () -> mCallbacks
-                                                .onCaptureFailed(CameraExtensionSessionImpl.this,
+                                                .onCaptureFailed(
+                                                        CameraExtensionSessionImpl.this,
                                                         mClientRequest));
                             }
                         } finally {
@@ -1422,7 +1522,8 @@
             try {
                 if (internal) {
                     setRepeatingRequest(mPreviewExtender.getCaptureStage(),
-                            new RepeatingRequestHandler(null, null, null));
+                            new RepeatingRequestHandler(null, null, null,
+                                    mRepeatingImageCallback));
                 } else {
                     setRepeatingRequest(mPreviewExtender.getCaptureStage(), this);
                 }
@@ -1478,26 +1579,20 @@
             }
         }
 
-        private class ImageForwardCallback implements ImageReader.OnImageAvailableListener {
+        private class ImageForwardCallback implements OnImageAvailableListener {
             private final ImageWriter mOutputWriter;
 
             public ImageForwardCallback(@NonNull ImageWriter imageWriter) {
                 mOutputWriter = imageWriter;
             }
 
-            @Override public void onImageAvailable(ImageReader reader) {
-                Image img;
-                try {
-                    img = reader.acquireNextImage();
-                } catch (IllegalStateException e) {
-                    Log.e(TAG, "Failed to acquire and propagate repeating request image!");
-                    return;
-                }
+            @Override
+            public void onImageAvailable(ImageReader reader, Image img) {
                 if (img == null) {
-                    Log.e(TAG,
-                            "Invalid image!");
+                    Log.e(TAG, "Invalid image!");
                     return;
                 }
+
                 try {
                     mOutputWriter.queueInputImage(img);
                 } catch (IllegalStateException e) {
@@ -1509,13 +1604,11 @@
             }
         }
 
-        private class ImageProcessCallback implements ImageReader.OnImageAvailableListener {
+        private class ImageProcessCallback implements OnImageAvailableListener {
+
             @Override
-            public void onImageAvailable(ImageReader reader) {
-                Image img;
-                try {
-                    img = reader.acquireNextImage();
-                } catch (IllegalStateException e) {
+            public void onImageAvailable(ImageReader reader, Image img) {
+                if (mPendingResultMap.size() + 1 >= PREVIEW_QUEUE_SIZE) {
                     // We reached the maximum acquired images limit. This is possible in case we
                     // have capture failures that result in absent or missing capture results. In
                     // such scenario we can prune the oldest pending buffer.
@@ -1523,15 +1616,13 @@
                             mPendingResultMap
                                     .indexOfKey(calculatePruneThreshold(mPendingResultMap)),
                             mPendingResultMap, true);
-
-                    img = reader.acquireNextImage();
                 }
+
                 if (img == null) {
                     Log.e(TAG,
                             "Invalid preview buffer!");
                     return;
                 }
-
                 try {
                     reader.detachImage(img);
                 } catch (Exception e) {
diff --git a/core/java/android/hardware/devicestate/DeviceStateManagerGlobal.java b/core/java/android/hardware/devicestate/DeviceStateManagerGlobal.java
index 1b37fb9..904a54b 100644
--- a/core/java/android/hardware/devicestate/DeviceStateManagerGlobal.java
+++ b/core/java/android/hardware/devicestate/DeviceStateManagerGlobal.java
@@ -179,8 +179,6 @@
     @VisibleForTesting(visibility = Visibility.PACKAGE)
     public void registerDeviceStateCallback(@NonNull DeviceStateCallback callback,
             @NonNull Executor executor) {
-        DeviceStateCallbackWrapper wrapper;
-        DeviceStateInfo currentInfo;
         synchronized (mLock) {
             int index = findCallbackLocked(callback);
             if (index != -1) {
@@ -189,25 +187,22 @@
             }
 
             registerCallbackIfNeededLocked();
-            if (mLastReceivedInfo == null) {
-                // Initialize the last received info with the current info if this is the first
-                // callback being registered.
-                try {
-                    mLastReceivedInfo = mDeviceStateManager.getDeviceStateInfo();
-                } catch (RemoteException ex) {
-                    throw ex.rethrowFromSystemServer();
-                }
-            }
 
-            currentInfo = new DeviceStateInfo(mLastReceivedInfo);
-
-            wrapper = new DeviceStateCallbackWrapper(callback, executor);
+            // Add the callback wrapper to the mCallbacks array after registering the callback as
+            // the callback could be triggered immediately if the mDeviceStateManager IBinder is in
+            // the same process as this instance.
+            DeviceStateCallbackWrapper wrapper = new DeviceStateCallbackWrapper(callback, executor);
             mCallbacks.add(wrapper);
-        }
 
-        wrapper.notifySupportedStatesChanged(currentInfo.supportedStates);
-        wrapper.notifyBaseStateChanged(currentInfo.baseState);
-        wrapper.notifyStateChanged(currentInfo.currentState);
+            if (mLastReceivedInfo != null) {
+                // Copy the array to prevent the callback from modifying the internal state.
+                final int[] supportedStates = Arrays.copyOf(mLastReceivedInfo.supportedStates,
+                        mLastReceivedInfo.supportedStates.length);
+                wrapper.notifySupportedStatesChanged(supportedStates);
+                wrapper.notifyBaseStateChanged(mLastReceivedInfo.baseState);
+                wrapper.notifyStateChanged(mLastReceivedInfo.currentState);
+            }
+        }
     }
 
     /**
@@ -267,7 +262,7 @@
             callbacks = new ArrayList<>(mCallbacks);
         }
 
-        final int diff = oldInfo == null ? 1 : info.diff(oldInfo);
+        final int diff = oldInfo == null ? ~0 : info.diff(oldInfo);
         if ((diff & DeviceStateInfo.CHANGED_SUPPORTED_STATES) > 0) {
             for (int i = 0; i < callbacks.size(); i++) {
                 // Copy the array to prevent callbacks from modifying the internal state.
diff --git a/core/java/android/hardware/devicestate/IDeviceStateManagerCallback.aidl b/core/java/android/hardware/devicestate/IDeviceStateManagerCallback.aidl
index 593be86..efb9888 100644
--- a/core/java/android/hardware/devicestate/IDeviceStateManagerCallback.aidl
+++ b/core/java/android/hardware/devicestate/IDeviceStateManagerCallback.aidl
@@ -21,7 +21,8 @@
 /** @hide */
 interface IDeviceStateManagerCallback {
     /**
-     * Called in response to a change in {@link DeviceStateInfo}.
+     * Called in response to a change in {@link DeviceStateInfo}. Guaranteed to be called once
+     * after successful registration of the callback with the initial value.
      *
      * @param info the new device state info.
      *
diff --git a/core/java/android/hardware/fingerprint/IUdfpsOverlayController.aidl b/core/java/android/hardware/fingerprint/IUdfpsOverlayController.aidl
index 81c7d89..d2cb5bf 100644
--- a/core/java/android/hardware/fingerprint/IUdfpsOverlayController.aidl
+++ b/core/java/android/hardware/fingerprint/IUdfpsOverlayController.aidl
@@ -15,6 +15,8 @@
  */
 package android.hardware.fingerprint;
 
+import android.hardware.fingerprint.IUdfpsOverlayControllerCallback;
+
 /**
  * Interface for interacting with the under-display fingerprint sensor (UDFPS) overlay.
  * @hide
@@ -28,7 +30,7 @@
     const int REASON_AUTH_FPM_OTHER = 5; // Other FingerprintManager usage
 
     // Shows the overlay.
-    void showUdfpsOverlay(int sensorId, int reason);
+    void showUdfpsOverlay(int sensorId, int reason, IUdfpsOverlayControllerCallback callback);
 
     // Hides the overlay.
     void hideUdfpsOverlay(int sensorId);
diff --git a/core/java/android/view/translation/TranslationData.aidl b/core/java/android/hardware/fingerprint/IUdfpsOverlayControllerCallback.aidl
similarity index 66%
copy from core/java/android/view/translation/TranslationData.aidl
copy to core/java/android/hardware/fingerprint/IUdfpsOverlayControllerCallback.aidl
index 40f21a6..51ada29 100644
--- a/core/java/android/view/translation/TranslationData.aidl
+++ b/core/java/android/hardware/fingerprint/IUdfpsOverlayControllerCallback.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -13,7 +13,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package android.hardware.fingerprint;
 
-package android.view.translation;
-
-parcelable TranslationData;
+/**
+ * @hide
+ */
+oneway interface IUdfpsOverlayControllerCallback {
+    // Notify system_server if the user cancels a UDFPS-related operation (enroll, auth)
+    void onUserCanceled();
+}
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index e15d629..01fd396 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -17,6 +17,7 @@
 package android.hardware.input;
 
 import android.Manifest;
+import android.annotation.FloatRange;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -922,8 +923,11 @@
      * opacity of the windows above the touch-consuming window, per UID. Check documentation of
      * {@link LayoutParams#FLAG_NOT_TOUCHABLE} for more details.
      *
+     * <p>The value returned is between 0 (inclusive) and 1 (inclusive).
+     *
      * @see LayoutParams#FLAG_NOT_TOUCHABLE
      */
+    @FloatRange(from = 0, to = 1)
     public float getMaximumObscuringOpacityForTouch() {
         Context context = ActivityThread.currentApplication();
         return Settings.Global.getFloat(context.getContentResolver(),
@@ -934,11 +938,11 @@
     /**
      * Sets the maximum allowed obscuring opacity by UID to propagate touches.
      *
-     * For certain window types (eg. SAWs), the decision of honoring {@link LayoutParams
+     * <p>For certain window types (eg. SAWs), the decision of honoring {@link LayoutParams
      * #FLAG_NOT_TOUCHABLE} or not depends on the combined obscuring opacity of the windows
      * above the touch-consuming window.
      *
-     * For a certain UID:
+     * <p>For a certain UID:
      * <ul>
      *     <li>If it's the same as the UID of the touch-consuming window, allow it to propagate
      *     the touch.
@@ -949,7 +953,7 @@
      *     touch, allow the UID to propagate the touch.
      * </ul>
      *
-     * This value should be between 0 (inclusive) and 1 (inclusive).
+     * <p>This value should be between 0 (inclusive) and 1 (inclusive).
      *
      * @see #getMaximumObscuringOpacityForTouch()
      *
@@ -957,7 +961,7 @@
      */
     @TestApi
     @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
-    public void setMaximumObscuringOpacityForTouch(float opacity) {
+    public void setMaximumObscuringOpacityForTouch(@FloatRange(from = 0, to = 1) float opacity) {
         if (opacity < 0 || opacity > 1) {
             throw new IllegalArgumentException(
                     "Maximum obscuring opacity for touch should be >= 0 and <= 1");
diff --git a/core/java/android/net/EthernetNetworkSpecifier.java b/core/java/android/net/EthernetNetworkSpecifier.java
new file mode 100644
index 0000000..e168588
--- /dev/null
+++ b/core/java/android/net/EthernetNetworkSpecifier.java
@@ -0,0 +1,97 @@
+/*
+ * 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 android.text.TextUtils;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.Objects;
+
+/**
+ * A {@link NetworkSpecifier} used to identify ethernet interfaces.
+ *
+ * @see EthernetManager
+ * @hide
+ */
+@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+public final class EthernetNetworkSpecifier extends NetworkSpecifier implements Parcelable {
+
+    /**
+     * Name of the network interface.
+     */
+    @NonNull
+    private final String mInterfaceName;
+
+    public EthernetNetworkSpecifier(@NonNull String interfaceName) {
+        Preconditions.checkStringNotEmpty(interfaceName);
+        mInterfaceName = interfaceName;
+    }
+
+    // This may be null in the future to support specifiers based on data other than the interface
+    // name.
+    @Nullable
+    public String getInterfaceName() {
+        return mInterfaceName;
+    }
+
+    @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/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java
index a5ece7b..b037261 100644
--- a/core/java/android/net/NetworkIdentity.java
+++ b/core/java/android/net/NetworkIdentity.java
@@ -179,21 +179,6 @@
     }
 
     /**
-     * Build a {@link NetworkIdentity} from the given {@link NetworkState} and
-     * {@code subType}, assuming that any mobile networks are using the current IMSI.
-     * The subType if applicable, should be set as one of the TelephonyManager.NETWORK_TYPE_*
-     * constants, or {@link android.telephony.TelephonyManager#NETWORK_TYPE_UNKNOWN} if not.
-     */
-    // TODO: Delete this function after NetworkPolicyManagerService finishes the migration.
-    public static NetworkIdentity buildNetworkIdentity(Context context,
-            NetworkState state, boolean defaultNetwork, @NetworkType int subType) {
-        final NetworkStateSnapshot snapshot = new NetworkStateSnapshot(state.network,
-                state.networkCapabilities, state.linkProperties, state.subscriberId,
-                state.legacyNetworkType);
-        return buildNetworkIdentity(context, snapshot, defaultNetwork, subType);
-    }
-
-    /**
      * Build a {@link NetworkIdentity} from the given {@link NetworkStateSnapshot} and
      * {@code subType}, assuming that any mobile networks are using the current IMSI.
      * The subType if applicable, should be set as one of the TelephonyManager.NETWORK_TYPE_*
diff --git a/core/java/android/net/vcn/VcnControlPlaneIkeConfig.java b/core/java/android/net/vcn/VcnControlPlaneIkeConfig.java
index de086f6..22d7faf 100644
--- a/core/java/android/net/vcn/VcnControlPlaneIkeConfig.java
+++ b/core/java/android/net/vcn/VcnControlPlaneIkeConfig.java
@@ -19,11 +19,13 @@
 import static android.net.vcn.VcnControlPlaneConfig.CONFIG_TYPE_IKE;
 
 import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.net.ipsec.ike.IkeSessionParams;
 import android.net.ipsec.ike.TunnelModeChildSessionParams;
+import android.net.vcn.persistablebundleutils.IkeSessionParamsUtils;
+import android.net.vcn.persistablebundleutils.TunnelModeChildSessionParamsUtils;
 import android.os.PersistableBundle;
 import android.util.ArraySet;
+import android.util.Log;
 
 import java.util.Objects;
 
@@ -38,14 +40,11 @@
 public final class VcnControlPlaneIkeConfig extends VcnControlPlaneConfig {
     private static final String TAG = VcnControlPlaneIkeConfig.class.getSimpleName();
 
-    // STOPSHIP: b/163604823 Make mIkeParams and mChildParams @NonNull when it is supported to
-    // construct mIkeParams and mChildParams from PersistableBundles.
-
     private static final String IKE_PARAMS_KEY = "mIkeParams";
-    @Nullable private final IkeSessionParams mIkeParams;
+    @NonNull private final IkeSessionParams mIkeParams;
 
     private static final String CHILD_PARAMS_KEY = "mChildParams";
-    @Nullable private final TunnelModeChildSessionParams mChildParams;
+    @NonNull private final TunnelModeChildSessionParams mChildParams;
 
     private static final ArraySet<String> BUNDLE_KEY_SET = new ArraySet<>();
 
@@ -80,11 +79,19 @@
         final PersistableBundle ikeParamsBundle = in.getPersistableBundle(IKE_PARAMS_KEY);
         final PersistableBundle childParamsBundle = in.getPersistableBundle(CHILD_PARAMS_KEY);
 
-        // STOPSHIP: b/163604823 Support constructing mIkeParams and mChildParams from
-        // PersistableBundles.
+        Objects.requireNonNull(ikeParamsBundle, "IKE Session Params was null");
+        Objects.requireNonNull(childParamsBundle, "Child Session Params was null");
 
-        mIkeParams = null;
-        mChildParams = null;
+        mIkeParams = IkeSessionParamsUtils.fromPersistableBundle(ikeParamsBundle);
+        mChildParams = TunnelModeChildSessionParamsUtils.fromPersistableBundle(childParamsBundle);
+
+        for (String key : in.keySet()) {
+            if (!BUNDLE_KEY_SET.contains(key)) {
+                Log.w(TAG, "Found an unexpected key in the PersistableBundle: " + key);
+            }
+        }
+
+        validate();
     }
 
     private void validate() {
@@ -101,9 +108,11 @@
     @NonNull
     public PersistableBundle toPersistableBundle() {
         final PersistableBundle result = super.toPersistableBundle();
-
-        // STOPSHIP: b/163604823 Support converting mIkeParams and mChildParams to
-        // PersistableBundles.
+        result.putPersistableBundle(
+                IKE_PARAMS_KEY, IkeSessionParamsUtils.toPersistableBundle(mIkeParams));
+        result.putPersistableBundle(
+                CHILD_PARAMS_KEY,
+                TunnelModeChildSessionParamsUtils.toPersistableBundle(mChildParams));
         return result;
     }
 
@@ -134,10 +143,9 @@
 
         VcnControlPlaneIkeConfig other = (VcnControlPlaneIkeConfig) o;
 
-        // STOPSHIP: b/163604823 Also check mIkeParams and mChildParams when it is supported to
-        // construct mIkeParams and mChildParams from PersistableBundles. They are not checked
-        // now so that VcnGatewayConnectionConfigTest and VcnConfigTest can pass.
-        return super.equals(o);
+        return super.equals(o)
+                && Objects.equals(mIkeParams, other.mIkeParams)
+                && Objects.equals(mChildParams, other.mChildParams);
     }
 
     /** @hide */
diff --git a/core/java/android/net/vcn/persistablebundleutils/CertUtils.java b/core/java/android/net/vcn/persistablebundleutils/CertUtils.java
index b6036b4..35b3186 100644
--- a/core/java/android/net/vcn/persistablebundleutils/CertUtils.java
+++ b/core/java/android/net/vcn/persistablebundleutils/CertUtils.java
@@ -18,18 +18,24 @@
 
 import java.io.ByteArrayInputStream;
 import java.io.InputStream;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
 import java.security.cert.CertificateException;
 import java.security.cert.CertificateFactory;
 import java.security.cert.X509Certificate;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
 import java.util.Objects;
 
 /**
- * CertUtils provides utility methods for constructing Certificate.
+ * CertUtils provides utility methods for constructing Certificate and PrivateKey.
  *
  * @hide
  */
 public class CertUtils {
     private static final String CERT_TYPE_X509 = "X.509";
+    private static final String PRIVATE_KEY_TYPE_RSA = "RSA";
 
     /** Decodes an ASN.1 DER encoded Certificate */
     public static X509Certificate certificateFromByteArray(byte[] derEncoded) {
@@ -43,4 +49,18 @@
             throw new IllegalArgumentException("Fail to decode certificate", e);
         }
     }
+
+    /** Decodes a PKCS#8 encoded RSA private key */
+    public static RSAPrivateKey privateKeyFromByteArray(byte[] pkcs8Encoded) {
+        Objects.requireNonNull(pkcs8Encoded, "pkcs8Encoded was null");
+        PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(pkcs8Encoded);
+
+        try {
+            KeyFactory keyFactory = KeyFactory.getInstance(PRIVATE_KEY_TYPE_RSA);
+
+            return (RSAPrivateKey) keyFactory.generatePrivate(privateKeySpec);
+        } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
+            throw new IllegalArgumentException("Fail to decode PrivateKey", e);
+        }
+    }
 }
diff --git a/core/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java b/core/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java
new file mode 100644
index 0000000..9d3462c
--- /dev/null
+++ b/core/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java
@@ -0,0 +1,513 @@
+/*
+ * 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.vcn.persistablebundleutils;
+
+import static android.system.OsConstants.AF_INET;
+import static android.system.OsConstants.AF_INET6;
+
+import static com.android.internal.annotations.VisibleForTesting.Visibility;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.net.InetAddresses;
+import android.net.eap.EapSessionConfig;
+import android.net.ipsec.ike.IkeSaProposal;
+import android.net.ipsec.ike.IkeSessionParams;
+import android.net.ipsec.ike.IkeSessionParams.ConfigRequestIpv4PcscfServer;
+import android.net.ipsec.ike.IkeSessionParams.ConfigRequestIpv6PcscfServer;
+import android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig;
+import android.net.ipsec.ike.IkeSessionParams.IkeAuthDigitalSignLocalConfig;
+import android.net.ipsec.ike.IkeSessionParams.IkeAuthDigitalSignRemoteConfig;
+import android.net.ipsec.ike.IkeSessionParams.IkeAuthEapConfig;
+import android.net.ipsec.ike.IkeSessionParams.IkeAuthPskConfig;
+import android.net.ipsec.ike.IkeSessionParams.IkeConfigRequest;
+import android.os.PersistableBundle;
+import android.util.ArraySet;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.vcn.util.PersistableBundleUtils;
+
+import java.net.InetAddress;
+import java.security.PrivateKey;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * Abstract utility class to convert IkeSessionParams to/from PersistableBundle.
+ *
+ * @hide
+ */
+@VisibleForTesting(visibility = Visibility.PRIVATE)
+public final class IkeSessionParamsUtils {
+    private static final String SERVER_HOST_NAME_KEY = "SERVER_HOST_NAME_KEY";
+    private static final String SA_PROPOSALS_KEY = "SA_PROPOSALS_KEY";
+    private static final String LOCAL_ID_KEY = "LOCAL_ID_KEY";
+    private static final String REMOTE_ID_KEY = "REMOTE_ID_KEY";
+    private static final String LOCAL_AUTH_KEY = "LOCAL_AUTH_KEY";
+    private static final String REMOTE_AUTH_KEY = "REMOTE_AUTH_KEY";
+    private static final String CONFIG_REQUESTS_KEY = "CONFIG_REQUESTS_KEY";
+    private static final String RETRANS_TIMEOUTS_KEY = "RETRANS_TIMEOUTS_KEY";
+    private static final String HARD_LIFETIME_SEC_KEY = "HARD_LIFETIME_SEC_KEY";
+    private static final String SOFT_LIFETIME_SEC_KEY = "SOFT_LIFETIME_SEC_KEY";
+    private static final String DPD_DELAY_SEC_KEY = "DPD_DELAY_SEC_KEY";
+    private static final String NATT_KEEPALIVE_DELAY_SEC_KEY = "NATT_KEEPALIVE_DELAY_SEC_KEY";
+    private static final String IKE_OPTIONS_KEY = "IKE_OPTIONS_KEY";
+
+    private static final Set<Integer> IKE_OPTIONS = new ArraySet<>();
+
+    static {
+        IKE_OPTIONS.add(IkeSessionParams.IKE_OPTION_ACCEPT_ANY_REMOTE_ID);
+        IKE_OPTIONS.add(IkeSessionParams.IKE_OPTION_EAP_ONLY_AUTH);
+        IKE_OPTIONS.add(IkeSessionParams.IKE_OPTION_MOBIKE);
+    }
+
+    /** Serializes an IkeSessionParams to a PersistableBundle. */
+    @NonNull
+    public static PersistableBundle toPersistableBundle(@NonNull IkeSessionParams params) {
+        if (params.getConfiguredNetwork() != null || params.getIke3gppExtension() != null) {
+            throw new IllegalStateException(
+                    "Cannot convert a IkeSessionParams with a caller configured network or with"
+                            + " 3GPP extension enabled");
+        }
+
+        final PersistableBundle result = new PersistableBundle();
+
+        result.putString(SERVER_HOST_NAME_KEY, params.getServerHostname());
+
+        final PersistableBundle saProposalBundle =
+                PersistableBundleUtils.fromList(
+                        params.getSaProposals(), IkeSaProposalUtils::toPersistableBundle);
+        result.putPersistableBundle(SA_PROPOSALS_KEY, saProposalBundle);
+
+        result.putPersistableBundle(
+                LOCAL_ID_KEY,
+                IkeIdentificationUtils.toPersistableBundle(params.getLocalIdentification()));
+        result.putPersistableBundle(
+                REMOTE_ID_KEY,
+                IkeIdentificationUtils.toPersistableBundle(params.getRemoteIdentification()));
+
+        result.putPersistableBundle(
+                LOCAL_AUTH_KEY, AuthConfigUtils.toPersistableBundle(params.getLocalAuthConfig()));
+        result.putPersistableBundle(
+                REMOTE_AUTH_KEY, AuthConfigUtils.toPersistableBundle(params.getRemoteAuthConfig()));
+
+        final List<ConfigRequest> reqList = new ArrayList<>();
+        for (IkeConfigRequest req : params.getConfigurationRequests()) {
+            reqList.add(new ConfigRequest(req));
+        }
+        final PersistableBundle configReqListBundle =
+                PersistableBundleUtils.fromList(reqList, ConfigRequest::toPersistableBundle);
+        result.putPersistableBundle(CONFIG_REQUESTS_KEY, configReqListBundle);
+
+        result.putIntArray(RETRANS_TIMEOUTS_KEY, params.getRetransmissionTimeoutsMillis());
+        result.putInt(HARD_LIFETIME_SEC_KEY, params.getHardLifetimeSeconds());
+        result.putInt(SOFT_LIFETIME_SEC_KEY, params.getSoftLifetimeSeconds());
+        result.putInt(DPD_DELAY_SEC_KEY, params.getDpdDelaySeconds());
+        result.putInt(NATT_KEEPALIVE_DELAY_SEC_KEY, params.getNattKeepAliveDelaySeconds());
+
+        final List<Integer> enabledIkeOptions = new ArrayList<>();
+        for (int option : IKE_OPTIONS) {
+            if (params.hasIkeOption(option)) {
+                enabledIkeOptions.add(option);
+            }
+        }
+
+        final int[] optionArray = enabledIkeOptions.stream().mapToInt(i -> i).toArray();
+        result.putIntArray(IKE_OPTIONS_KEY, optionArray);
+
+        return result;
+    }
+
+    /** Constructs an IkeSessionParams by deserializing a PersistableBundle. */
+    @NonNull
+    public static IkeSessionParams fromPersistableBundle(@NonNull PersistableBundle in) {
+        Objects.requireNonNull(in, "PersistableBundle is null");
+
+        final IkeSessionParams.Builder builder = new IkeSessionParams.Builder();
+
+        builder.setServerHostname(in.getString(SERVER_HOST_NAME_KEY));
+
+        PersistableBundle proposalBundle = in.getPersistableBundle(SA_PROPOSALS_KEY);
+        Objects.requireNonNull(in, "SA Proposals was null");
+        List<IkeSaProposal> saProposals =
+                PersistableBundleUtils.toList(
+                        proposalBundle, IkeSaProposalUtils::fromPersistableBundle);
+        for (IkeSaProposal proposal : saProposals) {
+            builder.addSaProposal(proposal);
+        }
+
+        builder.setLocalIdentification(
+                IkeIdentificationUtils.fromPersistableBundle(
+                        in.getPersistableBundle(LOCAL_ID_KEY)));
+        builder.setRemoteIdentification(
+                IkeIdentificationUtils.fromPersistableBundle(
+                        in.getPersistableBundle(REMOTE_ID_KEY)));
+
+        AuthConfigUtils.setBuilderByReadingPersistableBundle(
+                in.getPersistableBundle(LOCAL_AUTH_KEY),
+                in.getPersistableBundle(REMOTE_AUTH_KEY),
+                builder);
+
+        builder.setRetransmissionTimeoutsMillis(in.getIntArray(RETRANS_TIMEOUTS_KEY));
+        builder.setLifetimeSeconds(
+                in.getInt(HARD_LIFETIME_SEC_KEY), in.getInt(SOFT_LIFETIME_SEC_KEY));
+        builder.setDpdDelaySeconds(in.getInt(DPD_DELAY_SEC_KEY));
+        builder.setNattKeepAliveDelaySeconds(in.getInt(NATT_KEEPALIVE_DELAY_SEC_KEY));
+
+        final PersistableBundle configReqListBundle = in.getPersistableBundle(CONFIG_REQUESTS_KEY);
+        Objects.requireNonNull(configReqListBundle, "Config request list was null");
+        final List<ConfigRequest> reqList =
+                PersistableBundleUtils.toList(configReqListBundle, ConfigRequest::new);
+        for (ConfigRequest req : reqList) {
+            switch (req.type) {
+                case ConfigRequest.IPV4_P_CSCF_ADDRESS:
+                    if (req.address == null) {
+                        builder.addPcscfServerRequest(AF_INET);
+                    } else {
+                        builder.addPcscfServerRequest(req.address);
+                    }
+                    break;
+                case ConfigRequest.IPV6_P_CSCF_ADDRESS:
+                    if (req.address == null) {
+                        builder.addPcscfServerRequest(AF_INET6);
+                    } else {
+                        builder.addPcscfServerRequest(req.address);
+                    }
+                    break;
+                default:
+                    throw new IllegalArgumentException(
+                            "Unrecognized config request type: " + req.type);
+            }
+        }
+
+        // Clear IKE Options that are by default enabled
+        for (int option : IKE_OPTIONS) {
+            builder.removeIkeOption(option);
+        }
+
+        final int[] optionArray = in.getIntArray(IKE_OPTIONS_KEY);
+        for (int option : optionArray) {
+            builder.addIkeOption(option);
+        }
+
+        return builder.build();
+    }
+
+    private static final class AuthConfigUtils {
+        private static final int IKE_AUTH_METHOD_PSK = 1;
+        private static final int IKE_AUTH_METHOD_PUB_KEY_SIGNATURE = 2;
+        private static final int IKE_AUTH_METHOD_EAP = 3;
+
+        private static final String AUTH_METHOD_KEY = "AUTH_METHOD_KEY";
+
+        @NonNull
+        public static PersistableBundle toPersistableBundle(@NonNull IkeAuthConfig authConfig) {
+            if (authConfig instanceof IkeAuthPskConfig) {
+                IkeAuthPskConfig config = (IkeAuthPskConfig) authConfig;
+                return IkeAuthPskConfigUtils.toPersistableBundle(
+                        config, createPersistableBundle(IKE_AUTH_METHOD_PSK));
+            } else if (authConfig instanceof IkeAuthDigitalSignLocalConfig) {
+                IkeAuthDigitalSignLocalConfig config = (IkeAuthDigitalSignLocalConfig) authConfig;
+                return IkeAuthDigitalSignConfigUtils.toPersistableBundle(
+                        config, createPersistableBundle(IKE_AUTH_METHOD_PUB_KEY_SIGNATURE));
+            } else if (authConfig instanceof IkeAuthDigitalSignRemoteConfig) {
+                IkeAuthDigitalSignRemoteConfig config = (IkeAuthDigitalSignRemoteConfig) authConfig;
+                return IkeAuthDigitalSignConfigUtils.toPersistableBundle(
+                        config, createPersistableBundle(IKE_AUTH_METHOD_PUB_KEY_SIGNATURE));
+            } else if (authConfig instanceof IkeAuthEapConfig) {
+                IkeAuthEapConfig config = (IkeAuthEapConfig) authConfig;
+                return IkeAuthEapConfigUtils.toPersistableBundle(
+                        config, createPersistableBundle(IKE_AUTH_METHOD_EAP));
+            } else {
+                throw new IllegalStateException("Invalid IkeAuthConfig subclass");
+            }
+        }
+
+        private static PersistableBundle createPersistableBundle(int type) {
+            final PersistableBundle result = new PersistableBundle();
+            result.putInt(AUTH_METHOD_KEY, type);
+            return result;
+        }
+
+        public static void setBuilderByReadingPersistableBundle(
+                @NonNull PersistableBundle localAuthBundle,
+                @NonNull PersistableBundle remoteAuthBundle,
+                @NonNull IkeSessionParams.Builder builder) {
+            Objects.requireNonNull(localAuthBundle, "localAuthBundle was null");
+            Objects.requireNonNull(remoteAuthBundle, "remoteAuthBundle was null");
+
+            final int localMethodType = localAuthBundle.getInt(AUTH_METHOD_KEY);
+            final int remoteMethodType = remoteAuthBundle.getInt(AUTH_METHOD_KEY);
+            switch (localMethodType) {
+                case IKE_AUTH_METHOD_PSK:
+                    if (remoteMethodType != IKE_AUTH_METHOD_PSK) {
+                        throw new IllegalArgumentException(
+                                "Expect remote auth method to be PSK based, but was "
+                                        + remoteMethodType);
+                    }
+                    IkeAuthPskConfigUtils.setBuilderByReadingPersistableBundle(
+                            localAuthBundle, remoteAuthBundle, builder);
+                    return;
+                case IKE_AUTH_METHOD_PUB_KEY_SIGNATURE:
+                    if (remoteMethodType != IKE_AUTH_METHOD_PUB_KEY_SIGNATURE) {
+                        throw new IllegalArgumentException(
+                                "Expect remote auth method to be digital signature based, but was "
+                                        + remoteMethodType);
+                    }
+                    IkeAuthDigitalSignConfigUtils.setBuilderByReadingPersistableBundle(
+                            localAuthBundle, remoteAuthBundle, builder);
+                    return;
+                case IKE_AUTH_METHOD_EAP:
+                    if (remoteMethodType != IKE_AUTH_METHOD_PUB_KEY_SIGNATURE) {
+                        throw new IllegalArgumentException(
+                                "When using EAP for local authentication, expect remote auth"
+                                        + " method to be digital signature based, but was "
+                                        + remoteMethodType);
+                    }
+                    IkeAuthEapConfigUtils.setBuilderByReadingPersistableBundle(
+                            localAuthBundle, remoteAuthBundle, builder);
+                    return;
+                default:
+                    throw new IllegalArgumentException(
+                            "Invalid EAP method type " + localMethodType);
+            }
+        }
+    }
+
+    private static final class IkeAuthPskConfigUtils {
+        private static final String PSK_KEY = "PSK_KEY";
+
+        @NonNull
+        public static PersistableBundle toPersistableBundle(
+                @NonNull IkeAuthPskConfig config, @NonNull PersistableBundle result) {
+            result.putPersistableBundle(
+                    PSK_KEY, PersistableBundleUtils.fromByteArray(config.getPsk()));
+            return result;
+        }
+
+        public static void setBuilderByReadingPersistableBundle(
+                @NonNull PersistableBundle localAuthBundle,
+                @NonNull PersistableBundle remoteAuthBundle,
+                @NonNull IkeSessionParams.Builder builder) {
+            Objects.requireNonNull(localAuthBundle, "localAuthBundle was null");
+            Objects.requireNonNull(remoteAuthBundle, "remoteAuthBundle was null");
+
+            final PersistableBundle localPskBundle = localAuthBundle.getPersistableBundle(PSK_KEY);
+            final PersistableBundle remotePskBundle =
+                    remoteAuthBundle.getPersistableBundle(PSK_KEY);
+            Objects.requireNonNull(localAuthBundle, "Local PSK was null");
+            Objects.requireNonNull(remoteAuthBundle, "Remote PSK was null");
+
+            final byte[] localPsk = PersistableBundleUtils.toByteArray(localPskBundle);
+            final byte[] remotePsk = PersistableBundleUtils.toByteArray(remotePskBundle);
+            if (!Arrays.equals(localPsk, remotePsk)) {
+                throw new IllegalArgumentException("Local PSK and remote PSK are different");
+            }
+            builder.setAuthPsk(localPsk);
+        }
+    }
+
+    private static class IkeAuthDigitalSignConfigUtils {
+        private static final String END_CERT_KEY = "END_CERT_KEY";
+        private static final String INTERMEDIATE_CERTS_KEY = "INTERMEDIATE_CERTS_KEY";
+        private static final String PRIVATE_KEY_KEY = "PRIVATE_KEY_KEY";
+        private static final String TRUST_CERT_KEY = "TRUST_CERT_KEY";
+
+        @NonNull
+        public static PersistableBundle toPersistableBundle(
+                @NonNull IkeAuthDigitalSignLocalConfig config, @NonNull PersistableBundle result) {
+            try {
+                result.putPersistableBundle(
+                        END_CERT_KEY,
+                        PersistableBundleUtils.fromByteArray(
+                                config.getClientEndCertificate().getEncoded()));
+
+                final List<X509Certificate> certList = config.getIntermediateCertificates();
+                final List<byte[]> encodedCertList = new ArrayList<>(certList.size());
+                for (X509Certificate cert : certList) {
+                    encodedCertList.add(cert.getEncoded());
+                }
+
+                final PersistableBundle certsBundle =
+                        PersistableBundleUtils.fromList(
+                                encodedCertList, PersistableBundleUtils::fromByteArray);
+                result.putPersistableBundle(INTERMEDIATE_CERTS_KEY, certsBundle);
+            } catch (CertificateEncodingException e) {
+                throw new IllegalArgumentException("Fail to encode certificate");
+            }
+
+            // TODO: b/170670506 Consider putting PrivateKey in Android KeyStore
+            result.putPersistableBundle(
+                    PRIVATE_KEY_KEY,
+                    PersistableBundleUtils.fromByteArray(config.getPrivateKey().getEncoded()));
+            return result;
+        }
+
+        @NonNull
+        public static PersistableBundle toPersistableBundle(
+                @NonNull IkeAuthDigitalSignRemoteConfig config, @NonNull PersistableBundle result) {
+            try {
+                X509Certificate caCert = config.getRemoteCaCert();
+                if (caCert != null) {
+                    result.putPersistableBundle(
+                            TRUST_CERT_KEY,
+                            PersistableBundleUtils.fromByteArray(caCert.getEncoded()));
+                }
+            } catch (CertificateEncodingException e) {
+                throw new IllegalArgumentException("Fail to encode the certificate");
+            }
+
+            return result;
+        }
+
+        public static void setBuilderByReadingPersistableBundle(
+                @NonNull PersistableBundle localAuthBundle,
+                @NonNull PersistableBundle remoteAuthBundle,
+                @NonNull IkeSessionParams.Builder builder) {
+            Objects.requireNonNull(localAuthBundle, "localAuthBundle was null");
+            Objects.requireNonNull(remoteAuthBundle, "remoteAuthBundle was null");
+
+            // Deserialize localAuth
+            final PersistableBundle endCertBundle =
+                    localAuthBundle.getPersistableBundle(END_CERT_KEY);
+            Objects.requireNonNull(endCertBundle, "End cert was null");
+            final byte[] encodedCert = PersistableBundleUtils.toByteArray(endCertBundle);
+            final X509Certificate endCert = CertUtils.certificateFromByteArray(encodedCert);
+
+            final PersistableBundle certsBundle =
+                    localAuthBundle.getPersistableBundle(INTERMEDIATE_CERTS_KEY);
+            Objects.requireNonNull(certsBundle, "Intermediate certs was null");
+            final List<byte[]> encodedCertList =
+                    PersistableBundleUtils.toList(certsBundle, PersistableBundleUtils::toByteArray);
+            final List<X509Certificate> certList = new ArrayList<>(encodedCertList.size());
+            for (byte[] encoded : encodedCertList) {
+                certList.add(CertUtils.certificateFromByteArray(encoded));
+            }
+
+            final PersistableBundle privateKeyBundle =
+                    localAuthBundle.getPersistableBundle(PRIVATE_KEY_KEY);
+            Objects.requireNonNull(privateKeyBundle, "PrivateKey bundle was null");
+            final PrivateKey privateKey =
+                    CertUtils.privateKeyFromByteArray(
+                            PersistableBundleUtils.toByteArray(privateKeyBundle));
+
+            // Deserialize remoteAuth
+            final PersistableBundle trustCertBundle =
+                    remoteAuthBundle.getPersistableBundle(TRUST_CERT_KEY);
+
+            X509Certificate caCert = null;
+            if (trustCertBundle != null) {
+                final byte[] encodedCaCert = PersistableBundleUtils.toByteArray(trustCertBundle);
+                caCert = CertUtils.certificateFromByteArray(encodedCaCert);
+            }
+
+            builder.setAuthDigitalSignature(caCert, endCert, certList, privateKey);
+        }
+    }
+
+    private static final class IkeAuthEapConfigUtils {
+        private static final String EAP_CONFIG_KEY = "EAP_CONFIG_KEY";
+
+        @NonNull
+        public static PersistableBundle toPersistableBundle(
+                @NonNull IkeAuthEapConfig config, @NonNull PersistableBundle result) {
+            result.putPersistableBundle(
+                    EAP_CONFIG_KEY,
+                    EapSessionConfigUtils.toPersistableBundle(config.getEapConfig()));
+            return result;
+        }
+
+        public static void setBuilderByReadingPersistableBundle(
+                @NonNull PersistableBundle localAuthBundle,
+                @NonNull PersistableBundle remoteAuthBundle,
+                @NonNull IkeSessionParams.Builder builder) {
+            // Deserialize localAuth
+            final PersistableBundle eapBundle =
+                    localAuthBundle.getPersistableBundle(EAP_CONFIG_KEY);
+            Objects.requireNonNull(eapBundle, "EAP Config was null");
+            final EapSessionConfig eapConfig =
+                    EapSessionConfigUtils.fromPersistableBundle(eapBundle);
+
+            // Deserialize remoteAuth
+            final PersistableBundle trustCertBundle =
+                    remoteAuthBundle.getPersistableBundle(
+                            IkeAuthDigitalSignConfigUtils.TRUST_CERT_KEY);
+
+            X509Certificate serverCaCert = null;
+            if (trustCertBundle != null) {
+                final byte[] encodedCaCert = PersistableBundleUtils.toByteArray(trustCertBundle);
+                serverCaCert = CertUtils.certificateFromByteArray(encodedCaCert);
+            }
+            builder.setAuthEap(serverCaCert, eapConfig);
+        }
+    }
+
+    private static final class ConfigRequest {
+        private static final int IPV4_P_CSCF_ADDRESS = 1;
+        private static final int IPV6_P_CSCF_ADDRESS = 2;
+
+        private static final String TYPE_KEY = "type";
+        private static final String ADDRESS_KEY = "address";
+
+        public final int type;
+
+        // Null when it is an empty request
+        @Nullable public final InetAddress address;
+
+        ConfigRequest(IkeConfigRequest config) {
+            if (config instanceof ConfigRequestIpv4PcscfServer) {
+                type = IPV4_P_CSCF_ADDRESS;
+                address = ((ConfigRequestIpv4PcscfServer) config).getAddress();
+            } else if (config instanceof ConfigRequestIpv6PcscfServer) {
+                type = IPV6_P_CSCF_ADDRESS;
+                address = ((ConfigRequestIpv6PcscfServer) config).getAddress();
+            } else {
+                throw new IllegalStateException("Unknown TunnelModeChildConfigRequest");
+            }
+        }
+
+        ConfigRequest(PersistableBundle in) {
+            Objects.requireNonNull(in, "PersistableBundle was null");
+
+            type = in.getInt(TYPE_KEY);
+
+            String addressStr = in.getString(ADDRESS_KEY);
+            if (addressStr == null) {
+                address = null;
+            } else {
+                address = InetAddresses.parseNumericAddress(addressStr);
+            }
+        }
+
+        @NonNull
+        public PersistableBundle toPersistableBundle() {
+            final PersistableBundle result = new PersistableBundle();
+
+            result.putInt(TYPE_KEY, type);
+            if (address != null) {
+                result.putString(ADDRESS_KEY, address.getHostAddress());
+            }
+
+            return result;
+        }
+    }
+}
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 6901df7..66f7bd9 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -986,26 +986,26 @@
         public abstract void getDeferredJobsLineLocked(StringBuilder sb, int which);
 
         /**
-         * Returns the measured energy in microjoules that the display consumed while the screen
-         * was on and uid active.
-         * Will return {@link #ENERGY_DATA_UNAVAILABLE} if data is unavailable
+         * Returns the battery consumption (in microcoulombs) of the screen while on and uid active,
+         * derived from on device power measurement data.
+         * Will return {@link #POWER_DATA_UNAVAILABLE} if data is unavailable.
          *
          * {@hide}
          */
-        public abstract long getScreenOnEnergy();
+        public abstract long getScreenOnMeasuredBatteryConsumptionUC();
 
         /**
-         * Returns the energies used by this uid for each
+         * Returns the battery consumption (in microcoulombs) used by this uid for each
          * {@link android.hardware.power.stats.EnergyConsumer.ordinal} of (custom) energy consumer
          * type {@link android.hardware.power.stats.EnergyConsumerType#OTHER}).
          *
-         * @return energies (in microjoules) used since boot for each (custom) energy consumer of
-         *         type OTHER, indexed by their ordinal. Returns null if no energy reporting is
-         *         supported.
+         * @return charge (in microcoulombs) consumed since last reset for each (custom) energy
+         *         consumer of type OTHER, indexed by their ordinal. Returns null if no energy
+         *         reporting is supported.
          *
          * {@hide}
          */
-        public abstract @Nullable long[] getCustomMeasuredEnergiesMicroJoules();
+        public abstract @Nullable long[] getCustomConsumerMeasuredBatteryConsumptionUC();
 
         public static abstract class Sensor {
 
@@ -2496,40 +2496,41 @@
     };
 
     /**
-     * Returned value if energy data is unavailable
+     * Returned value if power data is unavailable
      *
      * {@hide}
      */
-    public static final long ENERGY_DATA_UNAVAILABLE = -1;
+    public static final long POWER_DATA_UNAVAILABLE = -1;
 
     /**
-     * Returns the energy in microjoules that the screen consumed while on.
-     * Will return {@link #ENERGY_DATA_UNAVAILABLE} if data is unavailable
+     * Returns the battery consumption (in microcoulombs) of the screen while on, derived from on
+     * device power measurement data.
+     * Will return {@link #POWER_DATA_UNAVAILABLE} if data is unavailable.
      *
      * {@hide}
      */
-    public abstract long getScreenOnEnergy();
+    public abstract long getScreenOnMeasuredBatteryConsumptionUC();
 
     /**
-     * Returns the energy in microjoules that the screen consumed while in doze
-     * Will return {@link #ENERGY_DATA_UNAVAILABLE} if data is unavailable
+     * Returns the battery consumption (in microcoulombs) of the screen in doze, derived from on
+     * device power measurement data.
+     * Will return {@link #POWER_DATA_UNAVAILABLE} if data is unavailable.
      *
      * {@hide}
      */
-    public abstract long getScreenDozeEnergy();
+    public abstract long getScreenDozeMeasuredBatteryConsumptionUC();
 
     /**
-     * Returns the energies used for each
+     * Returns the battery consumption (in microcoulombs) that each
      * {@link android.hardware.power.stats.EnergyConsumer.ordinal} of (custom) energy consumer
-     * type {@link android.hardware.power.stats.EnergyConsumerType#OTHER}).
+     * type {@link android.hardware.power.stats.EnergyConsumerType#OTHER}) consumed.
      *
-     * @return energies (in microjoules) used since boot for each (custom) energy consumer of
-     *         type OTHER, indexed by their ordinal. Returns null if no energy reporting is
-     *         supported.
+     * @return charge (in microcoulombs) used by each (custom) energy consumer of type OTHER,
+     * indexed by their ordinal. Returns null if no energy reporting is supported.
      *
      * {@hide}
      */
-    public abstract @Nullable long[] getCustomMeasuredEnergiesMicroJoules();
+    public abstract @Nullable long[] getCustomConsumerMeasuredBatteryConsumptionUC();
 
     public static final BitDescription[] HISTORY_STATE_DESCRIPTIONS = new BitDescription[] {
         new BitDescription(HistoryItem.STATE_CPU_RUNNING_FLAG, "running", "r"),
diff --git a/core/java/android/os/BatteryStatsManager.java b/core/java/android/os/BatteryStatsManager.java
index 04e529e..1905d70 100644
--- a/core/java/android/os/BatteryStatsManager.java
+++ b/core/java/android/os/BatteryStatsManager.java
@@ -24,6 +24,7 @@
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.content.Context;
+import android.net.NetworkStack;
 import android.os.connectivity.CellularBatteryStats;
 import android.os.connectivity.WifiBatteryStats;
 import android.telephony.DataConnectionRealTimeInfo;
@@ -458,10 +459,31 @@
         }
     }
 
+    /**
+     * Notifies the battery stats of a new interface, and the transport types of the network that
+     * includes that interface.
+     *
+     * @param iface The interface of the network.
+     * @param transportTypes The transport type of the network {@link Transport}.
+     * @hide
+     */
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    @RequiresPermission(anyOf = {
+            NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
+            android.Manifest.permission.NETWORK_STACK})
+    public void reportNetworkInterfaceForTransports(@NonNull String iface,
+            @NonNull int[] transportTypes) throws RuntimeException {
+        try {
+            mBatteryStats.noteNetworkInterfaceForTransports(iface, transportTypes);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
     private static int getDataConnectionPowerState(boolean isActive) {
         // TODO: DataConnectionRealTimeInfo is under telephony package but the constants are used
-        // for both Wifi and mobile. It would make more sense to separate the constants to a generic
-        // class or move it to generic package.
+        // for both Wifi and mobile. It would make more sense to separate the constants to a
+        // generic class or move it to generic package.
         return isActive ? DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH
                 : DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
     }
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index a5b0e8d..83f78a5 100755
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -1117,6 +1117,18 @@
     }
 
     /**
+     * A multiplier for various timeouts on the system.
+     *
+     * The intent is that products targeting software emulators that are orders of magnitude slower
+     * than real hardware may set this to a large number. On real devices and hardware-accelerated
+     * virtualized devices this should not be set.
+     *
+     * @hide
+     */
+    public static final int HW_TIMEOUT_MULTIPLIER =
+        SystemProperties.getInt("ro.hw_timeout_multiplier", 1);
+
+    /**
      * True if Treble is enabled and required for this device.
      *
      * @hide
diff --git a/core/java/android/view/translation/TranslationData.aidl b/core/java/android/os/InputConstants.java
similarity index 64%
copy from core/java/android/view/translation/TranslationData.aidl
copy to core/java/android/os/InputConstants.java
index 40f21a6..c8fa065 100644
--- a/core/java/android/view/translation/TranslationData.aidl
+++ b/core/java/android/os/InputConstants.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -14,6 +14,11 @@
  * limitations under the License.
  */
 
-package android.view.translation;
+package android.os;
 
-parcelable TranslationData;
+/** @hide */
+public class InputConstants {
+    public static final int DEFAULT_DISPATCHING_TIMEOUT_MILLIS =
+            IInputConstants.UNMULTIPLIED_DEFAULT_DISPATCHING_TIMEOUT_MILLIS
+            * Build.HW_TIMEOUT_MULTIPLIER;
+}
diff --git a/core/java/android/os/OWNERS b/core/java/android/os/OWNERS
index a04047d..6e99b0d 100644
--- a/core/java/android/os/OWNERS
+++ b/core/java/android/os/OWNERS
@@ -58,7 +58,7 @@
 per-file IHwBinder.java = file:platform/system/libhwbinder:/OWNERS
 per-file IHwInterface.java = file:platform/system/libhwbinder:/OWNERS
 
-per-file GraphicsEnvironment.java = chrisforbes@google.com, cnorthrop@google.com, lpy@google.com, timvp@google.com, zzyiwei@google.com
+per-file GraphicsEnvironment.java = file:platform/frameworks/native:/opengl/OWNERS
 
 per-file *Network* = file:/services/core/java/com/android/server/net/OWNERS
 per-file *Power* = file:/services/core/java/com/android/server/power/OWNERS
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 136dc38..e75e224 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -397,6 +397,12 @@
     public static final int THREAD_PRIORITY_VIDEO = -10;
 
     /**
+     * Priority we boost main thread and RT of top app to.
+     * @hide
+     */
+    public static final int THREAD_PRIORITY_TOP_APP_BOOST = -10;
+
+    /**
      * Standard priority of audio threads.  Applications can not normally
      * change to this priority.
      * Use with {@link #setThreadPriority(int)} and
diff --git a/core/java/android/os/ShellCallback.java b/core/java/android/os/ShellCallback.java
index 632f6c8..be9fb89 100644
--- a/core/java/android/os/ShellCallback.java
+++ b/core/java/android/os/ShellCallback.java
@@ -102,6 +102,10 @@
         }
     }
 
+    public IBinder getShellCallbackBinder() {
+        return mShellCallback.asBinder();
+    }
+
     ShellCallback(Parcel in) {
         mLocal = false;
         mShellCallback = IShellCallback.Stub.asInterface(in.readStrongBinder());
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index 1189fdb..df24baa 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -2274,10 +2274,9 @@
      */
     public static void assertUiContext(@NonNull Context context, @NonNull String methodName) {
         if (vmIncorrectContextUseEnabled() && !context.isUiContext()) {
-            final String errorMessage = "Tried to access UI related API" + methodName
+            final String errorMessage = "Tried to access UI related API:" + methodName
                     + " from a non-UI Context:" + context;
-            final String message = "UI-related services, such as WindowManager, WallpaperService "
-                    + "or LayoutInflater should be accessed from Activity or other UI "
+            final String message = methodName + " should be accessed from Activity or other UI "
                     + "Contexts. Use an Activity or a Context created with "
                     + "Context#createWindowContext(int, Bundle), which are adjusted to "
                     + "the configuration and visual bounds of an area on screen.";
diff --git a/core/java/android/os/VibrationEffect.java b/core/java/android/os/VibrationEffect.java
index 03e5f1d..0199fad 100644
--- a/core/java/android/os/VibrationEffect.java
+++ b/core/java/android/os/VibrationEffect.java
@@ -1208,7 +1208,8 @@
          *
          * @param primitiveId The primitive to add
          * @param scale The scale to apply to the intensity of the primitive.
-         * @param delay The amount of time in milliseconds to wait before playing this primitive
+         * @param delay The amount of time in milliseconds to wait before playing this primitive,
+         *              starting at the time the previous element in this composition is finished.
          * @return The {@link Composition} object to enable adding multiple primitives in one chain.
          */
         @NonNull
diff --git a/core/java/android/os/incremental/IIncrementalService.aidl b/core/java/android/os/incremental/IIncrementalService.aidl
index 3fbc284..d7bb226 100644
--- a/core/java/android/os/incremental/IIncrementalService.aidl
+++ b/core/java/android/os/incremental/IIncrementalService.aidl
@@ -23,6 +23,7 @@
 import android.os.incremental.IStorageHealthListener;
 import android.os.incremental.PerUidReadTimeouts;
 import android.os.incremental.StorageHealthCheckParams;
+import android.os.PersistableBundle;
 
 /** @hide */
 interface IIncrementalService {
@@ -165,4 +166,13 @@
      * Register storage health status listener.
      */
     void unregisterStorageHealthListener(int storageId);
+
+    /**
+     * Metrics key for the duration in milliseconds between now and the oldest pending read. The value is a long.
+     */
+    const @utf8InCpp String METRICS_MILLIS_SINCE_OLDEST_PENDING_READ = "millisSinceOldestPendingRead";
+    /**
+     * Return a bundle containing the requested metrics keys and their values.
+     */
+    PersistableBundle getMetrics(int storageId);
 }
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 85cef84..4dfbb6f 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -825,6 +825,13 @@
             "android.settings.DISPLAY_SETTINGS";
 
     /**
+     * Activity Action: Show Auto Rotate configuration settings.
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_AUTO_ROTATE_SETTINGS =
+            "android.settings.AUTO_ROTATE_SETTINGS";
+
+    /**
      * Activity Action: Show settings to allow configuration of Night display.
      * <p>
      * In some cases, a matching Activity may not exist, so ensure you
diff --git a/core/java/android/service/autofill/FillRequest.java b/core/java/android/service/autofill/FillRequest.java
index 62becc5..af846b6 100644
--- a/core/java/android/service/autofill/FillRequest.java
+++ b/core/java/android/service/autofill/FillRequest.java
@@ -96,6 +96,8 @@
      */
     public static final @RequestFlags int FLAG_VIEW_NOT_FOCUSED = 0x10;
 
+    // The flag value 0x20 has been defined in AutofillManager.
+
     /** @hide */
     public static final int INVALID_REQUEST_ID = Integer.MIN_VALUE;
 
diff --git a/core/java/android/service/translation/ITranslationService.aidl b/core/java/android/service/translation/ITranslationService.aidl
index 6d6f278..8d798c3 100644
--- a/core/java/android/service/translation/ITranslationService.aidl
+++ b/core/java/android/service/translation/ITranslationService.aidl
@@ -16,8 +16,6 @@
 
 package android.service.translation;
 
-import android.service.translation.TranslationRequest;
-import android.service.translation.ITranslationCallback;
 import android.view.translation.TranslationSpec;
 import com.android.internal.os.IResultReceiver;
 
diff --git a/core/java/android/service/translation/TranslationRequest.aidl b/core/java/android/service/translation/TranslationRequest.aidl
deleted file mode 100644
index 9a2d415..0000000
--- a/core/java/android/service/translation/TranslationRequest.aidl
+++ /dev/null
@@ -1,19 +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.service.translation;
-
-parcelable TranslationRequest;
diff --git a/core/java/android/service/translation/TranslationRequest.java b/core/java/android/service/translation/TranslationRequest.java
deleted file mode 100644
index b8afd70..0000000
--- a/core/java/android/service/translation/TranslationRequest.java
+++ /dev/null
@@ -1,281 +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.service.translation;
-
-import android.annotation.NonNull;
-import android.annotation.SystemApi;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.view.translation.TranslationSpec;
-
-import com.android.internal.util.DataClass;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Internal translation request sent to the {@link android.service.translation.TranslationService}
- * which contains the text to be translated.
- *
- * @hide
- */
-@SystemApi
-@DataClass(genConstructor = true, genBuilder = true, genToString = true)
-public final class TranslationRequest implements Parcelable {
-
-    private final int mRequestId;
-    @NonNull
-    private final TranslationSpec mSourceSpec;
-    @NonNull
-    private final TranslationSpec mDestSpec;
-    @NonNull
-    private final List<android.view.translation.TranslationRequest> mTranslationRequests;
-
-
-
-    // Code below generated by codegen v1.0.22.
-    //
-    // DO NOT MODIFY!
-    // CHECKSTYLE:OFF Generated code
-    //
-    // To regenerate run:
-    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/service/translation/TranslationRequest.java
-    //
-    // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
-    //   Settings > Editor > Code Style > Formatter Control
-    //@formatter:off
-
-
-    @DataClass.Generated.Member
-    public TranslationRequest(
-            int requestId,
-            @NonNull TranslationSpec sourceSpec,
-            @NonNull TranslationSpec destSpec,
-            @NonNull List<android.view.translation.TranslationRequest> translationRequests) {
-        this.mRequestId = requestId;
-        this.mSourceSpec = sourceSpec;
-        com.android.internal.util.AnnotationValidations.validate(
-                NonNull.class, null, mSourceSpec);
-        this.mDestSpec = destSpec;
-        com.android.internal.util.AnnotationValidations.validate(
-                NonNull.class, null, mDestSpec);
-        this.mTranslationRequests = translationRequests;
-        com.android.internal.util.AnnotationValidations.validate(
-                NonNull.class, null, mTranslationRequests);
-
-        // onConstructed(); // You can define this method to get a callback
-    }
-
-    @DataClass.Generated.Member
-    public int getRequestId() {
-        return mRequestId;
-    }
-
-    @DataClass.Generated.Member
-    public @NonNull TranslationSpec getSourceSpec() {
-        return mSourceSpec;
-    }
-
-    @DataClass.Generated.Member
-    public @NonNull TranslationSpec getDestSpec() {
-        return mDestSpec;
-    }
-
-    @DataClass.Generated.Member
-    public @NonNull List<android.view.translation.TranslationRequest> getTranslationRequests() {
-        return mTranslationRequests;
-    }
-
-    @Override
-    @DataClass.Generated.Member
-    public String toString() {
-        // You can override field toString logic by defining methods like:
-        // String fieldNameToString() { ... }
-
-        return "TranslationRequest { " +
-                "requestId = " + mRequestId + ", " +
-                "sourceSpec = " + mSourceSpec + ", " +
-                "destSpec = " + mDestSpec + ", " +
-                "translationRequests = " + mTranslationRequests +
-        " }";
-    }
-
-    @Override
-    @DataClass.Generated.Member
-    public void writeToParcel(@NonNull Parcel dest, int flags) {
-        // You can override field parcelling by defining methods like:
-        // void parcelFieldName(Parcel dest, int flags) { ... }
-
-        dest.writeInt(mRequestId);
-        dest.writeTypedObject(mSourceSpec, flags);
-        dest.writeTypedObject(mDestSpec, flags);
-        dest.writeParcelableList(mTranslationRequests, flags);
-    }
-
-    @Override
-    @DataClass.Generated.Member
-    public int describeContents() { return 0; }
-
-    /** @hide */
-    @SuppressWarnings({"unchecked", "RedundantCast"})
-    @DataClass.Generated.Member
-    /* package-private */ TranslationRequest(@NonNull Parcel in) {
-        // You can override field unparcelling by defining methods like:
-        // static FieldType unparcelFieldName(Parcel in) { ... }
-
-        int requestId = in.readInt();
-        TranslationSpec sourceSpec = (TranslationSpec) in.readTypedObject(TranslationSpec.CREATOR);
-        TranslationSpec destSpec = (TranslationSpec) in.readTypedObject(TranslationSpec.CREATOR);
-        List<android.view.translation.TranslationRequest> translationRequests = new ArrayList<>();
-        in.readParcelableList(translationRequests, android.view.translation.TranslationRequest.class.getClassLoader());
-
-        this.mRequestId = requestId;
-        this.mSourceSpec = sourceSpec;
-        com.android.internal.util.AnnotationValidations.validate(
-                NonNull.class, null, mSourceSpec);
-        this.mDestSpec = destSpec;
-        com.android.internal.util.AnnotationValidations.validate(
-                NonNull.class, null, mDestSpec);
-        this.mTranslationRequests = translationRequests;
-        com.android.internal.util.AnnotationValidations.validate(
-                NonNull.class, null, mTranslationRequests);
-
-        // onConstructed(); // You can define this method to get a callback
-    }
-
-    @DataClass.Generated.Member
-    public static final @NonNull Parcelable.Creator<TranslationRequest> CREATOR
-            = new Parcelable.Creator<TranslationRequest>() {
-        @Override
-        public TranslationRequest[] newArray(int size) {
-            return new TranslationRequest[size];
-        }
-
-        @Override
-        public TranslationRequest createFromParcel(@NonNull Parcel in) {
-            return new TranslationRequest(in);
-        }
-    };
-
-    /**
-     * A builder for {@link TranslationRequest}
-     */
-    @SuppressWarnings("WeakerAccess")
-    @DataClass.Generated.Member
-    public static final class Builder {
-
-        private int mRequestId;
-        private @NonNull TranslationSpec mSourceSpec;
-        private @NonNull TranslationSpec mDestSpec;
-        private @NonNull List<android.view.translation.TranslationRequest> mTranslationRequests;
-
-        private long mBuilderFieldsSet = 0L;
-
-        public Builder(
-                int requestId,
-                @NonNull TranslationSpec sourceSpec,
-                @NonNull TranslationSpec destSpec,
-                @NonNull List<android.view.translation.TranslationRequest> translationRequests) {
-            mRequestId = requestId;
-            mSourceSpec = sourceSpec;
-            com.android.internal.util.AnnotationValidations.validate(
-                    NonNull.class, null, mSourceSpec);
-            mDestSpec = destSpec;
-            com.android.internal.util.AnnotationValidations.validate(
-                    NonNull.class, null, mDestSpec);
-            mTranslationRequests = translationRequests;
-            com.android.internal.util.AnnotationValidations.validate(
-                    NonNull.class, null, mTranslationRequests);
-        }
-
-        @DataClass.Generated.Member
-        public @NonNull Builder setRequestId(int value) {
-            checkNotUsed();
-            mBuilderFieldsSet |= 0x1;
-            mRequestId = value;
-            return this;
-        }
-
-        @DataClass.Generated.Member
-        public @NonNull Builder setSourceSpec(@NonNull TranslationSpec value) {
-            checkNotUsed();
-            mBuilderFieldsSet |= 0x2;
-            mSourceSpec = value;
-            return this;
-        }
-
-        @DataClass.Generated.Member
-        public @NonNull Builder setDestSpec(@NonNull TranslationSpec value) {
-            checkNotUsed();
-            mBuilderFieldsSet |= 0x4;
-            mDestSpec = value;
-            return this;
-        }
-
-        @DataClass.Generated.Member
-        public @NonNull Builder setTranslationRequests(@NonNull List<android.view.translation.TranslationRequest> value) {
-            checkNotUsed();
-            mBuilderFieldsSet |= 0x8;
-            mTranslationRequests = value;
-            return this;
-        }
-
-        /** @see #setTranslationRequests */
-        @DataClass.Generated.Member
-        public @NonNull Builder addTranslationRequests(@NonNull android.view.translation.TranslationRequest value) {
-            // You can refine this method's name by providing item's singular name, e.g.:
-            // @DataClass.PluralOf("item")) mItems = ...
-
-            if (mTranslationRequests == null) setTranslationRequests(new ArrayList<>());
-            mTranslationRequests.add(value);
-            return this;
-        }
-
-        /** Builds the instance. This builder should not be touched after calling this! */
-        public @NonNull TranslationRequest build() {
-            checkNotUsed();
-            mBuilderFieldsSet |= 0x10; // Mark builder used
-
-            TranslationRequest o = new TranslationRequest(
-                    mRequestId,
-                    mSourceSpec,
-                    mDestSpec,
-                    mTranslationRequests);
-            return o;
-        }
-
-        private void checkNotUsed() {
-            if ((mBuilderFieldsSet & 0x10) != 0) {
-                throw new IllegalStateException(
-                        "This Builder should not be reused. Use a new Builder instance instead");
-            }
-        }
-    }
-
-    @DataClass.Generated(
-            time = 1609966181888L,
-            codegenVersion = "1.0.22",
-            sourceFile = "frameworks/base/core/java/android/service/translation/TranslationRequest.java",
-            inputSignatures = "private final  int mRequestId\nprivate final @android.annotation.NonNull android.view.translation.TranslationSpec mSourceSpec\nprivate final @android.annotation.NonNull android.view.translation.TranslationSpec mDestSpec\nprivate final @android.annotation.NonNull java.util.List<android.view.translation.TranslationRequest> mTranslationRequests\nclass TranslationRequest extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=true, genBuilder=true, genToString=true)")
-    @Deprecated
-    private void __metadata() {}
-
-
-    //@formatter:on
-    // End of generated code
-
-}
diff --git a/core/java/android/service/translation/TranslationService.java b/core/java/android/service/translation/TranslationService.java
index b028807..d14a87f 100644
--- a/core/java/android/service/translation/TranslationService.java
+++ b/core/java/android/service/translation/TranslationService.java
@@ -37,6 +37,7 @@
 import android.util.Log;
 import android.view.translation.ITranslationDirectManager;
 import android.view.translation.TranslationManager;
+import android.view.translation.TranslationRequest;
 import android.view.translation.TranslationResponse;
 import android.view.translation.TranslationSpec;
 
diff --git a/core/java/android/text/method/TranslationTransformationMethod.java b/core/java/android/text/method/TranslationTransformationMethod.java
index cf66ac7..54c0ffc 100644
--- a/core/java/android/text/method/TranslationTransformationMethod.java
+++ b/core/java/android/text/method/TranslationTransformationMethod.java
@@ -21,7 +21,8 @@
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.View;
-import android.view.translation.TranslationRequest;
+import android.view.translation.TranslationResponseValue;
+import android.view.translation.ViewTranslationResponse;
 import android.widget.TextView;
 
 import java.util.regex.Pattern;
@@ -37,18 +38,18 @@
     private static final Pattern PATTERN_WHITESPACE = Pattern.compile("\\s+");
 
     @NonNull
-    private TranslationRequest mTranslationRequest;
+    private final ViewTranslationResponse mTranslationResponse;
     @Nullable
     private TransformationMethod mOriginalTranslationMethod;
     private boolean mAllowLengthChanges;
 
     /**
-     * @param request the translated result from translation service.
+     * @param response the translated result from translation service.
      * @param method the {@link TextView}'s original {@link TransformationMethod}
      */
-    public TranslationTransformationMethod(@NonNull TranslationRequest request,
+    public TranslationTransformationMethod(@NonNull ViewTranslationResponse response,
             @Nullable TransformationMethod method) {
-        mTranslationRequest = request;
+        mTranslationResponse = response;
         mOriginalTranslationMethod = method;
     }
 
@@ -66,7 +67,14 @@
             Log.w(TAG, "Caller did not enable length changes; not transforming to translated text");
             return source;
         }
-        CharSequence translatedText = mTranslationRequest.getTranslationText();
+        TranslationResponseValue value = mTranslationResponse.getValue("text");
+        CharSequence translatedText;
+        if (value.getStatusCode() == TranslationResponseValue.STATUS_SUCCESS) {
+            translatedText = value.getText();
+        } else {
+            translatedText = "";
+        }
+
         if (TextUtils.isEmpty(translatedText) || isWhitespace(translatedText.toString())) {
             return source;
         } else {
diff --git a/core/java/android/view/AccessibilityInteractionController.java b/core/java/android/view/AccessibilityInteractionController.java
index e5a137c..09452828 100644
--- a/core/java/android/view/AccessibilityInteractionController.java
+++ b/core/java/android/view/AccessibilityInteractionController.java
@@ -86,12 +86,6 @@
     // accessibility from hanging
     private static final long REQUEST_PREPARER_TIMEOUT_MS = 500;
 
-    // Callbacks should have the same configuration of the flags below to allow satisfying a pending
-    // node request on prefetch
-    private static final int FLAGS_AFFECTING_REPORTED_DATA =
-            AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS
-            | AccessibilityNodeInfo.FLAG_REPORT_VIEW_IDS;
-
     private final ArrayList<AccessibilityNodeInfo> mTempAccessibilityNodeInfoList =
         new ArrayList<AccessibilityNodeInfo>();
 
@@ -120,9 +114,6 @@
     private AddNodeInfosForViewId mAddNodeInfosForViewId;
 
     @GuardedBy("mLock")
-    private ArrayList<Message> mPendingFindNodeByIdMessages;
-
-    @GuardedBy("mLock")
     private int mNumActiveRequestPreparers;
     @GuardedBy("mLock")
     private List<MessageHolder> mMessagesWaitingForRequestPreparer;
@@ -137,7 +128,6 @@
         mViewRootImpl = viewRootImpl;
         mPrefetcher = new AccessibilityNodePrefetcher();
         mA11yManager = mViewRootImpl.mContext.getSystemService(AccessibilityManager.class);
-        mPendingFindNodeByIdMessages = new ArrayList<>();
     }
 
     private void scheduleMessage(Message message, int interrogatingPid, long interrogatingTid,
@@ -187,11 +177,7 @@
         args.arg4 = arguments;
         message.obj = args;
 
-        synchronized (mLock) {
-            mPendingFindNodeByIdMessages.add(message);
-            scheduleMessage(message, interrogatingPid, interrogatingTid,
-                    CONSIDER_REQUEST_PREPARERS);
-        }
+        scheduleMessage(message, interrogatingPid, interrogatingTid, CONSIDER_REQUEST_PREPARERS);
     }
 
     /**
@@ -329,9 +315,6 @@
     }
 
     private void findAccessibilityNodeInfoByAccessibilityIdUiThread(Message message) {
-        synchronized (mLock) {
-            mPendingFindNodeByIdMessages.remove(message);
-        }
         final int flags = message.arg1;
 
         SomeArgs args = (SomeArgs) message.obj;
@@ -346,58 +329,22 @@
 
         args.recycle();
 
-        View rootView = null;
-        AccessibilityNodeInfo rootNode = null;
+        List<AccessibilityNodeInfo> infos = mTempAccessibilityNodeInfoList;
+        infos.clear();
         try {
             if (mViewRootImpl.mView == null || mViewRootImpl.mAttachInfo == null) {
                 return;
             }
             mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = flags;
-            rootView = findViewByAccessibilityId(accessibilityViewId);
-            if (rootView != null && isShown(rootView)) {
-                rootNode = populateAccessibilityNodeInfoForView(
-                        rootView, arguments, virtualDescendantId);
+            final View root = findViewByAccessibilityId(accessibilityViewId);
+            if (root != null && isShown(root)) {
+                mPrefetcher.prefetchAccessibilityNodeInfos(
+                        root, virtualDescendantId, flags, infos, arguments);
             }
         } finally {
-            updateInfoForViewportAndReturnFindNodeResult(
-                    rootNode == null ? null : AccessibilityNodeInfo.obtain(rootNode),
-                    callback, interactionId, spec, interactiveRegion);
+            updateInfosForViewportAndReturnFindNodeResult(
+                    infos, callback, interactionId, spec, interactiveRegion);
         }
-        ArrayList<AccessibilityNodeInfo> infos = mTempAccessibilityNodeInfoList;
-        infos.clear();
-        mPrefetcher.prefetchAccessibilityNodeInfos(
-                rootView, rootNode == null ? null : AccessibilityNodeInfo.obtain(rootNode),
-                virtualDescendantId, flags, infos);
-        mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0;
-        updateInfosForViewPort(infos, spec, interactiveRegion);
-        returnPrefetchResult(interactionId, infos, callback);
-        returnPendingFindAccessibilityNodeInfosInPrefetch(rootNode, infos, flags);
-    }
-
-    private AccessibilityNodeInfo populateAccessibilityNodeInfoForView(
-            View view, Bundle arguments, int virtualViewId) {
-        AccessibilityNodeProvider provider = view.getAccessibilityNodeProvider();
-        // Determine if we'll be populating extra data
-        final String extraDataRequested = (arguments == null) ? null
-                : arguments.getString(EXTRA_DATA_REQUESTED_KEY);
-        AccessibilityNodeInfo root = null;
-        if (provider == null) {
-            root = view.createAccessibilityNodeInfo();
-            if (root != null) {
-                if (extraDataRequested != null) {
-                    view.addExtraDataToAccessibilityNodeInfo(root, extraDataRequested, arguments);
-                }
-            }
-        } else {
-            root = provider.createAccessibilityNodeInfo(virtualViewId);
-            if (root != null) {
-                if (extraDataRequested != null) {
-                    provider.addExtraDataToAccessibilityNodeInfo(
-                            virtualViewId, root, extraDataRequested, arguments);
-                }
-            }
-        }
-        return root;
     }
 
     public void findAccessibilityNodeInfosByViewIdClientThread(long accessibilityNodeId,
@@ -456,7 +403,6 @@
                 mAddNodeInfosForViewId.reset();
             }
         } finally {
-            mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0;
             updateInfosForViewportAndReturnFindNodeResult(
                     infos, callback, interactionId, spec, interactiveRegion);
         }
@@ -539,7 +485,6 @@
                 }
             }
         } finally {
-            mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0;
             updateInfosForViewportAndReturnFindNodeResult(
                     infos, callback, interactionId, spec, interactiveRegion);
         }
@@ -631,7 +576,6 @@
                 }
             }
         } finally {
-            mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0;
             updateInfoForViewportAndReturnFindNodeResult(
                     focused, callback, interactionId, spec, interactiveRegion);
         }
@@ -686,7 +630,6 @@
                 }
             }
         } finally {
-            mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0;
             updateInfoForViewportAndReturnFindNodeResult(
                     next, callback, interactionId, spec, interactiveRegion);
         }
@@ -843,6 +786,33 @@
         }
     }
 
+    private void applyAppScaleAndMagnificationSpecIfNeeded(List<AccessibilityNodeInfo> infos,
+            MagnificationSpec spec) {
+        if (infos == null) {
+            return;
+        }
+        final float applicationScale = mViewRootImpl.mAttachInfo.mApplicationScale;
+        if (shouldApplyAppScaleAndMagnificationSpec(applicationScale, spec)) {
+            final int infoCount = infos.size();
+            for (int i = 0; i < infoCount; i++) {
+                AccessibilityNodeInfo info = infos.get(i);
+                applyAppScaleAndMagnificationSpecIfNeeded(info, spec);
+            }
+        }
+    }
+
+    private void adjustIsVisibleToUserIfNeeded(List<AccessibilityNodeInfo> infos,
+            Region interactiveRegion) {
+        if (interactiveRegion == null || infos == null) {
+            return;
+        }
+        final int infoCount = infos.size();
+        for (int i = 0; i < infoCount; i++) {
+            AccessibilityNodeInfo info = infos.get(i);
+            adjustIsVisibleToUserIfNeeded(info, interactiveRegion);
+        }
+    }
+
     private void adjustIsVisibleToUserIfNeeded(AccessibilityNodeInfo info,
             Region interactiveRegion) {
         if (interactiveRegion == null || info == null) {
@@ -863,6 +833,17 @@
         return false;
     }
 
+    private void adjustBoundsInScreenIfNeeded(List<AccessibilityNodeInfo> infos) {
+        if (infos == null || shouldBypassAdjustBoundsInScreen()) {
+            return;
+        }
+        final int infoCount = infos.size();
+        for (int i = 0; i < infoCount; i++) {
+            final AccessibilityNodeInfo info = infos.get(i);
+            adjustBoundsInScreenIfNeeded(info);
+        }
+    }
+
     private void adjustBoundsInScreenIfNeeded(AccessibilityNodeInfo info) {
         if (info == null || shouldBypassAdjustBoundsInScreen()) {
             return;
@@ -910,6 +891,17 @@
         return screenMatrix == null || screenMatrix.isIdentity();
     }
 
+    private void associateLeashedParentIfNeeded(List<AccessibilityNodeInfo> infos) {
+        if (infos == null || shouldBypassAssociateLeashedParent()) {
+            return;
+        }
+        final int infoCount = infos.size();
+        for (int i = 0; i < infoCount; i++) {
+            final AccessibilityNodeInfo info = infos.get(i);
+            associateLeashedParentIfNeeded(info);
+        }
+    }
+
     private void associateLeashedParentIfNeeded(AccessibilityNodeInfo info) {
         if (info == null || shouldBypassAssociateLeashedParent()) {
             return;
@@ -983,46 +975,18 @@
         return (appScale != 1.0f || (spec != null && !spec.isNop()));
     }
 
-    private void updateInfosForViewPort(List<AccessibilityNodeInfo> infos, MagnificationSpec spec,
-                                        Region interactiveRegion) {
-        for (int i = 0; i < infos.size(); i++) {
-            updateInfoForViewPort(infos.get(i), spec, interactiveRegion);
-        }
-    }
-
-    private void updateInfoForViewPort(AccessibilityNodeInfo info, MagnificationSpec spec,
-                                       Region interactiveRegion) {
-        associateLeashedParentIfNeeded(info);
-        applyScreenMatrixIfNeeded(info);
-        adjustBoundsInScreenIfNeeded(info);
-        // To avoid applyAppScaleAndMagnificationSpecIfNeeded changing the bounds of node,
-        // then impact the visibility result, we need to adjust visibility before apply scale.
-        adjustIsVisibleToUserIfNeeded(info, interactiveRegion);
-        applyAppScaleAndMagnificationSpecIfNeeded(info, spec);
-    }
-
     private void updateInfosForViewportAndReturnFindNodeResult(List<AccessibilityNodeInfo> infos,
             IAccessibilityInteractionConnectionCallback callback, int interactionId,
             MagnificationSpec spec, Region interactiveRegion) {
-        if (infos != null) {
-            updateInfosForViewPort(infos, spec, interactiveRegion);
-        }
-        returnFindNodesResult(infos, callback, interactionId);
-    }
-
-    private void returnFindNodeResult(AccessibilityNodeInfo info,
-                                      IAccessibilityInteractionConnectionCallback callback,
-                                      int interactionId) {
         try {
-            callback.setFindAccessibilityNodeInfoResult(info, interactionId);
-        } catch (RemoteException re) {
-            /* ignore - the other side will time out */
-        }
-    }
-
-    private void returnFindNodesResult(List<AccessibilityNodeInfo> infos,
-            IAccessibilityInteractionConnectionCallback callback, int interactionId) {
-        try {
+            mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0;
+            associateLeashedParentIfNeeded(infos);
+            applyScreenMatrixIfNeeded(infos);
+            adjustBoundsInScreenIfNeeded(infos);
+            // To avoid applyAppScaleAndMagnificationSpecIfNeeded changing the bounds of node,
+            // then impact the visibility result, we need to adjust visibility before apply scale.
+            adjustIsVisibleToUserIfNeeded(infos, interactiveRegion);
+            applyAppScaleAndMagnificationSpecIfNeeded(infos, spec);
             callback.setFindAccessibilityNodeInfosResult(infos, interactionId);
             if (infos != null) {
                 infos.clear();
@@ -1032,80 +996,22 @@
         }
     }
 
-    private void returnPendingFindAccessibilityNodeInfosInPrefetch(AccessibilityNodeInfo rootNode,
-            List<AccessibilityNodeInfo> infos, int flags) {
-
-        AccessibilityNodeInfo satisfiedPendingRequestPrefetchedNode = null;
-        IAccessibilityInteractionConnectionCallback satisfiedPendingRequestCallback = null;
-        int satisfiedPendingRequestInteractionId = AccessibilityInteractionClient.NO_ID;
-
-        synchronized (mLock) {
-            for (int i = 0; i < mPendingFindNodeByIdMessages.size(); i++) {
-                final Message pendingMessage = mPendingFindNodeByIdMessages.get(i);
-                final int pendingFlags = pendingMessage.arg1;
-                if ((pendingFlags & FLAGS_AFFECTING_REPORTED_DATA)
-                        != (flags & FLAGS_AFFECTING_REPORTED_DATA)) {
-                    continue;
-                }
-                SomeArgs args = (SomeArgs) pendingMessage.obj;
-                final int accessibilityViewId = args.argi1;
-                final int virtualDescendantId = args.argi2;
-
-                satisfiedPendingRequestPrefetchedNode = nodeWithIdFromList(rootNode,
-                        infos, AccessibilityNodeInfo.makeNodeId(
-                                accessibilityViewId, virtualDescendantId));
-
-                if (satisfiedPendingRequestPrefetchedNode != null) {
-                    satisfiedPendingRequestCallback =
-                            (IAccessibilityInteractionConnectionCallback) args.arg1;
-                    satisfiedPendingRequestInteractionId = args.argi3;
-                    mHandler.removeMessages(
-                            PrivateHandler.MSG_FIND_ACCESSIBILITY_NODE_INFO_BY_ACCESSIBILITY_ID,
-                            pendingMessage.obj);
-                    args.recycle();
-                    break;
-                }
-            }
-            mPendingFindNodeByIdMessages.clear();
-        }
-
-        if (satisfiedPendingRequestPrefetchedNode != null) {
-            returnFindNodeResult(
-                    AccessibilityNodeInfo.obtain(satisfiedPendingRequestPrefetchedNode),
-                    satisfiedPendingRequestCallback, satisfiedPendingRequestInteractionId);
-        }
-    }
-
-    private AccessibilityNodeInfo nodeWithIdFromList(AccessibilityNodeInfo rootNode,
-            List<AccessibilityNodeInfo> infos, long nodeId) {
-        if (rootNode != null && rootNode.getSourceNodeId() == nodeId) {
-            return rootNode;
-        }
-        for (int j = 0; j < infos.size(); j++) {
-            AccessibilityNodeInfo info = infos.get(j);
-            if (info.getSourceNodeId() == nodeId) {
-                return info;
-            }
-        }
-        return null;
-    }
-
-    private void returnPrefetchResult(int interactionId, List<AccessibilityNodeInfo> infos,
-                                      IAccessibilityInteractionConnectionCallback callback) {
-        if (infos.size() > 0) {
-            try {
-                callback.setPrefetchAccessibilityNodeInfoResult(infos, interactionId);
-            } catch (RemoteException re) {
-                /* ignore - other side isn't too bothered if this doesn't arrive */
-            }
-        }
-    }
-
     private void updateInfoForViewportAndReturnFindNodeResult(AccessibilityNodeInfo info,
             IAccessibilityInteractionConnectionCallback callback, int interactionId,
             MagnificationSpec spec, Region interactiveRegion) {
-        updateInfoForViewPort(info, spec, interactiveRegion);
-        returnFindNodeResult(info, callback, interactionId);
+        try {
+            mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0;
+            associateLeashedParentIfNeeded(info);
+            applyScreenMatrixIfNeeded(info);
+            adjustBoundsInScreenIfNeeded(info);
+            // To avoid applyAppScaleAndMagnificationSpecIfNeeded changing the bounds of node,
+            // then impact the visibility result, we need to adjust visibility before apply scale.
+            adjustIsVisibleToUserIfNeeded(info, interactiveRegion);
+            applyAppScaleAndMagnificationSpecIfNeeded(info, spec);
+            callback.setFindAccessibilityNodeInfoResult(info, interactionId);
+        } catch (RemoteException re) {
+                /* ignore - the other side will time out */
+        }
     }
 
     private boolean handleClickableSpanActionUiThread(
@@ -1148,45 +1054,56 @@
 
         private final ArrayList<View> mTempViewList = new ArrayList<View>();
 
-        public void prefetchAccessibilityNodeInfos(View view, AccessibilityNodeInfo root,
-                int virtualViewId, int fetchFlags, List<AccessibilityNodeInfo> outInfos) {
-            if (root == null) {
-                return;
-            }
+        public void prefetchAccessibilityNodeInfos(View view, int virtualViewId, int fetchFlags,
+                List<AccessibilityNodeInfo> outInfos, Bundle arguments) {
             AccessibilityNodeProvider provider = view.getAccessibilityNodeProvider();
+            // Determine if we'll be populating extra data
+            final String extraDataRequested = (arguments == null) ? null
+                    : arguments.getString(EXTRA_DATA_REQUESTED_KEY);
             if (provider == null) {
-                if ((fetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_PREDECESSORS) != 0) {
-                    prefetchPredecessorsOfRealNode(view, outInfos);
-                }
-                if ((fetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_SIBLINGS) != 0) {
-                    prefetchSiblingsOfRealNode(view, outInfos);
-                }
-                if ((fetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS) != 0) {
-                    prefetchDescendantsOfRealNode(view, outInfos);
+                AccessibilityNodeInfo root = view.createAccessibilityNodeInfo();
+                if (root != null) {
+                    if (extraDataRequested != null) {
+                        view.addExtraDataToAccessibilityNodeInfo(
+                                root, extraDataRequested, arguments);
+                    }
+                    outInfos.add(root);
+                    if ((fetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_PREDECESSORS) != 0) {
+                        prefetchPredecessorsOfRealNode(view, outInfos);
+                    }
+                    if ((fetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_SIBLINGS) != 0) {
+                        prefetchSiblingsOfRealNode(view, outInfos);
+                    }
+                    if ((fetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS) != 0) {
+                        prefetchDescendantsOfRealNode(view, outInfos);
+                    }
                 }
             } else {
-                if ((fetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_PREDECESSORS) != 0) {
-                    prefetchPredecessorsOfVirtualNode(root, view, provider, outInfos);
-                }
-                if ((fetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_SIBLINGS) != 0) {
-                    prefetchSiblingsOfVirtualNode(root, view, provider, outInfos);
-                }
-                if ((fetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS) != 0) {
-                    prefetchDescendantsOfVirtualNode(root, provider, outInfos);
+                final AccessibilityNodeInfo root =
+                        provider.createAccessibilityNodeInfo(virtualViewId);
+                if (root != null) {
+                    if (extraDataRequested != null) {
+                        provider.addExtraDataToAccessibilityNodeInfo(
+                                virtualViewId, root, extraDataRequested, arguments);
+                    }
+                    outInfos.add(root);
+                    if ((fetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_PREDECESSORS) != 0) {
+                        prefetchPredecessorsOfVirtualNode(root, view, provider, outInfos);
+                    }
+                    if ((fetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_SIBLINGS) != 0) {
+                        prefetchSiblingsOfVirtualNode(root, view, provider, outInfos);
+                    }
+                    if ((fetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS) != 0) {
+                        prefetchDescendantsOfVirtualNode(root, provider, outInfos);
+                    }
                 }
             }
             if (ENFORCE_NODE_TREE_CONSISTENT) {
-                enforceNodeTreeConsistent(root, outInfos);
+                enforceNodeTreeConsistent(outInfos);
             }
         }
 
-        private boolean shouldStopPrefetching(List prefetchededInfos) {
-            return mHandler.hasUserInteractiveMessagesWaiting()
-                    || prefetchededInfos.size() >= MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE;
-        }
-
-        private void enforceNodeTreeConsistent(
-                AccessibilityNodeInfo root, List<AccessibilityNodeInfo> nodes) {
+        private void enforceNodeTreeConsistent(List<AccessibilityNodeInfo> nodes) {
             LongSparseArray<AccessibilityNodeInfo> nodeMap =
                     new LongSparseArray<AccessibilityNodeInfo>();
             final int nodeCount = nodes.size();
@@ -1197,6 +1114,7 @@
 
             // If the nodes are a tree it does not matter from
             // which node we start to search for the root.
+            AccessibilityNodeInfo root = nodeMap.valueAt(0);
             AccessibilityNodeInfo parent = root;
             while (parent != null) {
                 root = parent;
@@ -1263,11 +1181,9 @@
 
         private void prefetchPredecessorsOfRealNode(View view,
                 List<AccessibilityNodeInfo> outInfos) {
-            if (shouldStopPrefetching(outInfos)) {
-                return;
-            }
             ViewParent parent = view.getParentForAccessibility();
-            while (parent instanceof View && !shouldStopPrefetching(outInfos)) {
+            while (parent instanceof View
+                    && outInfos.size() < MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) {
                 View parentView = (View) parent;
                 AccessibilityNodeInfo info = parentView.createAccessibilityNodeInfo();
                 if (info != null) {
@@ -1279,9 +1195,6 @@
 
         private void prefetchSiblingsOfRealNode(View current,
                 List<AccessibilityNodeInfo> outInfos) {
-            if (shouldStopPrefetching(outInfos)) {
-                return;
-            }
             ViewParent parent = current.getParentForAccessibility();
             if (parent instanceof ViewGroup) {
                 ViewGroup parentGroup = (ViewGroup) parent;
@@ -1291,7 +1204,7 @@
                     parentGroup.addChildrenForAccessibility(children);
                     final int childCount = children.size();
                     for (int i = 0; i < childCount; i++) {
-                        if (shouldStopPrefetching(outInfos)) {
+                        if (outInfos.size() >= MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) {
                             return;
                         }
                         View child = children.get(i);
@@ -1319,7 +1232,7 @@
 
         private void prefetchDescendantsOfRealNode(View root,
                 List<AccessibilityNodeInfo> outInfos) {
-            if (shouldStopPrefetching(outInfos) || !(root instanceof ViewGroup)) {
+            if (!(root instanceof ViewGroup)) {
                 return;
             }
             HashMap<View, AccessibilityNodeInfo> addedChildren =
@@ -1330,7 +1243,7 @@
                 root.addChildrenForAccessibility(children);
                 final int childCount = children.size();
                 for (int i = 0; i < childCount; i++) {
-                    if (shouldStopPrefetching(outInfos)) {
+                    if (outInfos.size() >= MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) {
                         return;
                     }
                     View child = children.get(i);
@@ -1355,7 +1268,7 @@
             } finally {
                 children.clear();
             }
-            if (!shouldStopPrefetching(outInfos)) {
+            if (outInfos.size() < MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) {
                 for (Map.Entry<View, AccessibilityNodeInfo> entry : addedChildren.entrySet()) {
                     View addedChild = entry.getKey();
                     AccessibilityNodeInfo virtualRoot = entry.getValue();
@@ -1377,7 +1290,7 @@
             long parentNodeId = root.getParentNodeId();
             int accessibilityViewId = AccessibilityNodeInfo.getAccessibilityViewId(parentNodeId);
             while (accessibilityViewId != AccessibilityNodeInfo.UNDEFINED_ITEM_ID) {
-                if (shouldStopPrefetching(outInfos)) {
+                if (outInfos.size() >= MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) {
                     return;
                 }
                 final int virtualDescendantId =
@@ -1422,7 +1335,7 @@
                 if (parent != null) {
                     final int childCount = parent.getChildCount();
                     for (int i = 0; i < childCount; i++) {
-                        if (shouldStopPrefetching(outInfos)) {
+                        if (outInfos.size() >= MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) {
                             return;
                         }
                         final long childNodeId = parent.getChildId(i);
@@ -1447,7 +1360,7 @@
             final int initialOutInfosSize = outInfos.size();
             final int childCount = root.getChildCount();
             for (int i = 0; i < childCount; i++) {
-                if (shouldStopPrefetching(outInfos)) {
+                if (outInfos.size() >= MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) {
                     return;
                 }
                 final long childNodeId = root.getChildId(i);
@@ -1457,7 +1370,7 @@
                     outInfos.add(child);
                 }
             }
-            if (!shouldStopPrefetching(outInfos)) {
+            if (outInfos.size() < MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) {
                 final int addedChildCount = outInfos.size() - initialOutInfosSize;
                 for (int i = 0; i < addedChildCount; i++) {
                     AccessibilityNodeInfo child = outInfos.get(initialOutInfosSize + i);
@@ -1566,10 +1479,6 @@
         boolean hasAccessibilityCallback(Message message) {
             return message.what < FIRST_NO_ACCESSIBILITY_CALLBACK_MSG ? true : false;
         }
-
-        boolean hasUserInteractiveMessagesWaiting() {
-            return hasMessagesOrCallbacks();
-        }
     }
 
     private final class AddNodeInfosForViewId implements Predicate<View> {
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 8117c96..d138b4b 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -26,7 +26,6 @@
 import android.annotation.TestApi;
 import android.app.KeyguardManager;
 import android.compat.annotation.UnsupportedAppUsage;
-import android.content.Context;
 import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
 import android.content.res.Resources;
@@ -61,11 +60,12 @@
  * be smaller than the real display area because the system subtracts the space needed
  * for decor elements such as the status bar.  Use {@link WindowMetrics#getBounds()} to query the
  * application window bounds.</li>
- * <li>The real display area specifies the part of the display that contains content
- * including the system decorations.  Even so, the real display area may be smaller than the
- * physical size of the display if the window manager is emulating a smaller display
- * using (adb shell wm size).  Use the following methods to query the
- * real display area: {@link #getRealSize}, {@link #getRealMetrics}.</li>
+ * <li>The real display area specifies the part of the display that is accessible to an application
+ * in the current system state. The real display area may be smaller than the physical size of the
+ * display in a few scenarios. Use {@link WindowManager#getCurrentWindowMetrics()} to identify the
+ * current size of the activity window. UI-related work, such as choosing UI layouts, should rely
+ * upon {@link WindowMetrics#getBounds()}. See {@link #getRealSize} / {@link #getRealMetrics} for
+ * details.</li>
  * </ul>
  * </p><p>
  * A logical display does not necessarily represent a particular physical display device
@@ -1230,27 +1230,51 @@
     }
 
     /**
-     * Gets the real size of the display without subtracting any window decor or
-     * applying any compatibility scale factors.
+     * Gets the size of the largest region of the display accessible to an app in the current system
+     * state, without subtracting any window decor or applying scaling factors.
      * <p>
      * The size is adjusted based on the current rotation of the display.
+     * <p></p>
+     * The returned size will fall into one of these scenarios:
+     * <ol>
+     * <li>The device has no partitions on the display. The returned value is the largest region
+     * of the display accessible to an app in the current system state, regardless of windowing
+     * mode.</li>
+     * <li>The device divides a single display into multiple partitions. An application is
+     * restricted to a portion of the display. This is common in devices where the display changes
+     * size, such as foldables or large screens. The returned size will match the portion of
+     * the display the application is restricted to.</li>
+     * <li>The window manager is emulating a different display size, using {@code adb shell wm
+     * size}. The returned size will match the emulated display size.</li>
+     * </ol>
      * </p><p>
-     * The real size may be smaller than the physical size of the screen when the
-     * window manager is emulating a smaller display (using adb shell wm size).
-     * </p><p>
-     * In general, {@link #getRealSize(Point)} and {@link WindowManager#getMaximumWindowMetrics()}
-     * report the same bounds except that certain areas of the display may not be available to
-     * windows created in the {@link WindowManager}'s {@link Context}.
-     *
-     * For example, imagine a device which has a multi-task mode that limits windows to half of the
-     * screen. In this case, {@link WindowManager#getMaximumWindowMetrics()} reports the
-     * bounds of the screen half where the window is located, while {@link #getRealSize(Point)}
-     * still reports the bounds of the whole display.
+     * The returned value is <b>unsuitable to use when sizing and placing UI elements</b>, since it
+     * does not reflect the application window size in any of these scenarios.
+     * {@link WindowManager#getCurrentWindowMetrics()} is an alternative that returns the size
+     * of the current application window, even if the window is on a device with a partitioned
+     * display. This helps prevent UI bugs where UI elements are misaligned or placed beyond the
+     * bounds of the window.
+     * <p></p>
+     * Handling multi-window mode correctly is necessary since applications are not always
+     * fullscreen. A user on a large screen device, such as a tablet or Chrome OS devices, is more
+     * likely to use multi-window modes.
+     * <p></p>
+     * For example, consider a device with a display partitioned into two halves. The user may have
+     * a fullscreen application open on the first partition. They may have two applications open in
+     * split screen (an example of multi-window mode) on the second partition, with each application
+     * consuming half of the partition. In this case,
+     * {@link WindowManager#getCurrentWindowMetrics()} reports the fullscreen window is half of the
+     * screen in size, and each split screen window is a quarter of the screen in size. On the other
+     * hand, {@link #getRealSize} reports half of the screen size for all windows, since the
+     * application windows are all restricted to their respective partitions.
+     * </p>
      *
      * @param outSize Set to the real size of the display.
-     *
-     * @see WindowManager#getMaximumWindowMetrics()
+     * @deprecated Use {@link WindowManager#getCurrentWindowMetrics()} to identify the current size
+     * of the activity window. UI-related work, such as choosing UI layouts, should rely
+     * upon {@link WindowMetrics#getBounds()}.
      */
+    @Deprecated
     public void getRealSize(Point outSize) {
         synchronized (this) {
             updateDisplayInfoLocked();
@@ -1263,16 +1287,52 @@
     }
 
     /**
-     * Gets display metrics based on the real size of this display.
+     * Gets the size of the largest region of the display accessible to an app in the current system
+     * state, without subtracting any window decor or applying scaling factors.
      * <p>
      * The size is adjusted based on the current rotation of the display.
+     * <p></p>
+     * The returned size will fall into one of these scenarios:
+     * <ol>
+     * <li>The device has no partitions on the display. The returned value is the largest region
+     * of the display accessible to an app in the current system state, regardless of windowing
+     * mode.</li>
+     * <li>The device divides a single display into multiple partitions. An application is
+     * restricted to a portion of the display. This is common in devices where the display changes
+     * size, such as foldables or large screens. The returned size will match the portion of
+     * the display the application is restricted to.</li>
+     * <li>The window manager is emulating a different display size, using {@code adb shell wm
+     * size}. The returned size will match the emulated display size.</li>
+     * </ol>
      * </p><p>
-     * The real size may be smaller than the physical size of the screen when the
-     * window manager is emulating a smaller display (using adb shell wm size).
+     * The returned value is <b>unsuitable to use when sizing and placing UI elements</b>, since it
+     * does not reflect the application window size in any of these scenarios.
+     * {@link WindowManager#getCurrentWindowMetrics()} is an alternative that returns the size
+     * of the current application window, even if the window is on a device with a partitioned
+     * display. This helps prevent UI bugs where UI elements are misaligned or placed beyond the
+     * bounds of the window.
+     * <p></p>
+     * Handling multi-window mode correctly is necessary since applications are not always
+     * fullscreen. A user on a large screen device, such as a tablet or Chrome OS devices, is more
+     * likely to use multi-window modes.
+     * <p></p>
+     * For example, consider a device with a display partitioned into two halves. The user may have
+     * a fullscreen application open on the first partition. They may have two applications open in
+     * split screen (an example of multi-window mode) on the second partition, with each application
+     * consuming half of the partition. In this case,
+     * {@link WindowManager#getCurrentWindowMetrics()} reports the fullscreen window is half of the
+     * screen in size, and each split screen window is a quarter of the screen in size. On the other
+     * hand, {@link #getRealMetrics} reports half of the screen size for all windows, since the
+     * application windows are all restricted to their respective partitions.
      * </p>
      *
      * @param outMetrics A {@link DisplayMetrics} object to receive the metrics.
+     * @deprecated Use {@link WindowManager#getCurrentWindowMetrics()} to identify the current size
+     * of the activity window. UI-related work, such as choosing UI layouts, should rely
+     * upon {@link WindowMetrics#getBounds()}. Use {@link Configuration#densityDpi} to
+     * get the current density.
      */
+    @Deprecated
     public void getRealMetrics(DisplayMetrics outMetrics) {
         synchronized (this) {
             updateDisplayInfoLocked();
diff --git a/core/java/android/view/FrameMetricsObserver.java b/core/java/android/view/FrameMetricsObserver.java
index 41bc9a7..35d95be 100644
--- a/core/java/android/view/FrameMetricsObserver.java
+++ b/core/java/android/view/FrameMetricsObserver.java
@@ -45,7 +45,8 @@
         mWindow = new WeakReference<>(window);
         mListener = listener;
         mFrameMetrics = new FrameMetrics();
-        mObserver = new HardwareRendererObserver(this,  mFrameMetrics.mTimingData, handler);
+        mObserver = new HardwareRendererObserver(this,  mFrameMetrics.mTimingData, handler,
+                false /*waitForPresentTime*/);
     }
 
     /**
diff --git a/core/java/android/view/InputEventReceiver.java b/core/java/android/view/InputEventReceiver.java
index 7d1adc36..79d8c14 100644
--- a/core/java/android/view/InputEventReceiver.java
+++ b/core/java/android/view/InputEventReceiver.java
@@ -21,6 +21,7 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.MessageQueue;
+import android.os.Trace;
 import android.util.Log;
 import android.util.SparseIntArray;
 
@@ -198,6 +199,15 @@
     }
 
     /**
+     * Report the latency information for a specific input event.
+     */
+    public final void reportLatencyInfo(int inputEventId, long gpuCompletedTime, long presentTime) {
+        Trace.traceBegin(Trace.TRACE_TAG_INPUT, "reportLatencyInfo");
+        // TODO(b/169866723) : send this data to InputDispatcher via InputChannel
+        Trace.traceEnd(Trace.TRACE_TAG_INPUT);
+    }
+
+    /**
      * Consumes all pending batched input events.
      * Must be called on the same Looper thread to which the receiver is attached.
      *
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index ab7732b..35d5d8e 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -150,7 +150,8 @@
 import android.view.inspector.InspectableProperty;
 import android.view.inspector.InspectableProperty.EnumEntry;
 import android.view.inspector.InspectableProperty.FlagEntry;
-import android.view.translation.TranslationRequest;
+import android.view.translation.ViewTranslationRequest;
+import android.view.translation.ViewTranslationResponse;
 import android.widget.Checkable;
 import android.widget.FrameLayout;
 import android.widget.ScrollBarDrawable;
@@ -30683,18 +30684,18 @@
     }
 
     /**
-     * Returns a {@link TranslationRequest} to the {@link onStartUiTranslation} which represents
+     * Returns a {@link ViewTranslationRequest} to the {@link onStartUiTranslation} which represents
      * the content to be translated.
      *
      * <p>The default implementation does nothing and return null.</p>
      *
      * @hide
      *
-     * @return the {@link TranslationRequest} which contains the information to be translated.
+     * @return the {@link ViewTranslationRequest} which contains the information to be translated.
      */
     @Nullable
     //TODO(b/178046780): initial version for demo. Will mark public when the design is reviewed.
-    public TranslationRequest onCreateTranslationRequest() {
+    public ViewTranslationRequest onCreateTranslationRequest() {
         return null;
     }
 
@@ -30743,10 +30744,10 @@
      *
      * <p> The default implementation does nothing.</p>
      *
-     * @param request the translated information which can be shown in the view.
+     * @param response the translated information which can be shown in the view.
      */
     //TODO(b/178046780): initial version for demo. Will mark public when the design is reviewed.
-    public void onTranslationComplete(@NonNull TranslationRequest request) {
+    public void onTranslationComplete(@NonNull ViewTranslationResponse response) {
         // no-op
     }
 
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 390e3ae..9fc415d 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -16,6 +16,7 @@
 
 package android.view;
 
+import static android.os.IInputConstants.INVALID_INPUT_EVENT_ID;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.INVALID_DISPLAY;
 import static android.view.InputDevice.SOURCE_CLASS_NONE;
@@ -105,6 +106,7 @@
 import android.graphics.FrameInfo;
 import android.graphics.HardwareRenderer;
 import android.graphics.HardwareRenderer.FrameDrawingCallback;
+import android.graphics.HardwareRendererObserver;
 import android.graphics.Insets;
 import android.graphics.Matrix;
 import android.graphics.PixelFormat;
@@ -1191,6 +1193,14 @@
                     }
                     mInputEventReceiver = new WindowInputEventReceiver(inputChannel,
                             Looper.myLooper());
+
+                    if (mAttachInfo.mThreadedRenderer != null) {
+                        InputMetricsListener listener =
+                                new InputMetricsListener(mInputEventReceiver);
+                        mHardwareRendererObserver = new HardwareRendererObserver(
+                                listener, listener.data, mHandler, true /*waitForPresentTime*/);
+                        mAttachInfo.mThreadedRenderer.addObserver(mHardwareRendererObserver);
+                    }
                 }
 
                 view.assignParent(this);
@@ -8569,6 +8579,34 @@
     }
     WindowInputEventReceiver mInputEventReceiver;
 
+    final class InputMetricsListener
+            implements HardwareRendererObserver.OnFrameMetricsAvailableListener {
+        public long[] data = new long[FrameMetrics.Index.FRAME_STATS_COUNT];
+
+        private InputEventReceiver mReceiver;
+
+        InputMetricsListener(InputEventReceiver receiver) {
+            mReceiver = receiver;
+        }
+
+        @Override
+        public void onFrameMetricsAvailable(int dropCountSinceLastInvocation) {
+            final int inputEventId = (int) data[FrameMetrics.Index.INPUT_EVENT_ID];
+            if (inputEventId == INVALID_INPUT_EVENT_ID) {
+                return;
+            }
+            final long presentTime = data[FrameMetrics.Index.DISPLAY_PRESENT_TIME];
+            if (presentTime <= 0) {
+                // Present time is not available for this frame. If the present time is not
+                // available, we cannot compute end-to-end input latency metrics.
+                return;
+            }
+            final long gpuCompletedTime = data[FrameMetrics.Index.GPU_COMPLETED];
+            mReceiver.reportLatencyInfo(inputEventId, gpuCompletedTime, presentTime);
+        }
+    }
+    HardwareRendererObserver mHardwareRendererObserver;
+
     final class ConsumeBatchedInputRunnable implements Runnable {
         @Override
         public void run() {
diff --git a/core/java/android/view/accessibility/AccessibilityInteractionClient.java b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
index 8d1271d..f63749b 100644
--- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java
+++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
@@ -23,9 +23,7 @@
 import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
-import android.os.Handler;
 import android.os.IBinder;
-import android.os.Looper;
 import android.os.Message;
 import android.os.Process;
 import android.os.RemoteException;
@@ -115,8 +113,6 @@
 
     private final Object mInstanceLock = new Object();
 
-    private Handler mMainHandler;
-
     private volatile int mInteractionId = -1;
 
     private AccessibilityNodeInfo mFindAccessibilityNodeInfoResult;
@@ -127,11 +123,6 @@
 
     private Message mSameThreadMessage;
 
-    private int mInteractionIdWaitingForPrefetchResult;
-    private int mConnectionIdWaitingForPrefetchResult;
-    private String[] mPackageNamesForNextPrefetchResult;
-    private Runnable mPrefetchResultRunnable;
-
     /**
      * @return The client for the current thread.
      */
@@ -206,10 +197,6 @@
 
     private AccessibilityInteractionClient() {
         /* reducing constructor visibility */
-        Looper mainLooper = Looper.getMainLooper();
-        if (mainLooper != null) {
-            mMainHandler = new Handler(mainLooper);
-        }
     }
 
     /**
@@ -464,16 +451,16 @@
                     Binder.restoreCallingIdentity(identityToken);
                 }
                 if (packageNames != null) {
-                    AccessibilityNodeInfo info =
-                            getFindAccessibilityNodeInfoResultAndClear(interactionId);
-                    if ((prefetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_MASK) != 0
-                            && info != null) {
-                        setInteractionWaitingForPrefetchResult(interactionId, connectionId,
-                                packageNames);
-                    }
-                    finalizeAndCacheAccessibilityNodeInfo(info, connectionId,
+                    List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear(
+                            interactionId);
+                    finalizeAndCacheAccessibilityNodeInfos(infos, connectionId,
                             bypassCache, packageNames);
-                    return info;
+                    if (infos != null && !infos.isEmpty()) {
+                        for (int i = 1; i < infos.size(); i++) {
+                            infos.get(i).recycle();
+                        }
+                        return infos.get(0);
+                    }
                 }
             } else {
                 if (DEBUG) {
@@ -487,15 +474,6 @@
         return null;
     }
 
-    private void setInteractionWaitingForPrefetchResult(int interactionId, int connectionId,
-            String[] packageNames) {
-        synchronized (mInstanceLock) {
-            mInteractionIdWaitingForPrefetchResult = interactionId;
-            mConnectionIdWaitingForPrefetchResult = connectionId;
-            mPackageNamesForNextPrefetchResult = packageNames;
-        }
-    }
-
     private static String idToString(int accessibilityWindowId, long accessibilityNodeId) {
         return accessibilityWindowId + "/"
                 + AccessibilityNodeInfo.idToString(accessibilityNodeId);
@@ -851,59 +829,6 @@
     }
 
     /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void setPrefetchAccessibilityNodeInfoResult(@NonNull List<AccessibilityNodeInfo> infos,
-                                                       int interactionId) {
-        List<AccessibilityNodeInfo> infosCopy = null;
-        int mConnectionIdWaitingForPrefetchResultCopy = -1;
-        String[] mPackageNamesForNextPrefetchResultCopy = null;
-
-        synchronized (mInstanceLock) {
-            if (!infos.isEmpty() && mInteractionIdWaitingForPrefetchResult == interactionId) {
-                if (mMainHandler != null) {
-                    if (mPrefetchResultRunnable != null) {
-                        mMainHandler.removeCallbacks(mPrefetchResultRunnable);
-                        mPrefetchResultRunnable = null;
-                    }
-                    /**
-                     * TODO(b/180957109): AccessibilityCache is prone to deadlocks
-                     * We post caching the prefetched nodes in the main thread. Using the binder
-                     * thread results in "Long monitor contention with owner main" logs where
-                     * service response times may exceed 5 seconds. This is due to the cache calling
-                     * out to the system when refreshing nodes with the lock held.
-                     */
-                    mPrefetchResultRunnable = () -> finalizeAndCacheAccessibilityNodeInfos(
-                            infos, mConnectionIdWaitingForPrefetchResult, false,
-                            mPackageNamesForNextPrefetchResult);
-                    mMainHandler.post(mPrefetchResultRunnable);
-
-                } else {
-                    for (AccessibilityNodeInfo info : infos) {
-                        infosCopy.add(new AccessibilityNodeInfo(info));
-                    }
-                    mConnectionIdWaitingForPrefetchResultCopy =
-                            mConnectionIdWaitingForPrefetchResult;
-                    mPackageNamesForNextPrefetchResultCopy =
-                            new String[mPackageNamesForNextPrefetchResult.length];
-                    for (int i = 0; i < mPackageNamesForNextPrefetchResult.length; i++) {
-                        mPackageNamesForNextPrefetchResultCopy[i] =
-                                mPackageNamesForNextPrefetchResult[i];
-                    }
-                }
-            }
-
-        }
-
-        if (infosCopy != null) {
-            finalizeAndCacheAccessibilityNodeInfos(
-                    infosCopy, mConnectionIdWaitingForPrefetchResultCopy, false,
-                    mPackageNamesForNextPrefetchResultCopy);
-        }
-    }
-
-    /**
      * Gets the result of a request to perform an accessibility action.
      *
      * @param interactionId The interaction id to match the result with the request.
diff --git a/core/java/android/view/accessibility/IAccessibilityInteractionConnectionCallback.aidl b/core/java/android/view/accessibility/IAccessibilityInteractionConnectionCallback.aidl
index 231e75a..049bb31 100644
--- a/core/java/android/view/accessibility/IAccessibilityInteractionConnectionCallback.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityInteractionConnectionCallback.aidl
@@ -47,15 +47,6 @@
         int interactionId);
 
     /**
-     * Sets the result of a prefetch request that returns {@link AccessibilityNodeInfo}s.
-     *
-     * @param root The {@link AccessibilityNodeInfo} for which the prefetching is based off of.
-     * @param infos The result {@link AccessibilityNodeInfo}s.
-     */
-    void setPrefetchAccessibilityNodeInfoResult(
-        in List<AccessibilityNodeInfo> infos, int interactionId);
-
-    /**
      * Sets the result of a request to perform an accessibility action.
      *
      * @param Whether the action was performed.
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 208cd96..b0b9d24 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -25,6 +25,7 @@
 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;
@@ -45,16 +46,21 @@
 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.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;
@@ -74,6 +80,7 @@
 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;
@@ -99,6 +106,7 @@
 import java.util.List;
 import java.util.Objects;
 import java.util.Set;
+import java.util.concurrent.Executor;
 
 import sun.misc.Cleaner;
 
@@ -167,6 +175,12 @@
  * 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.
@@ -292,6 +306,7 @@
     /** @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;
@@ -592,6 +607,11 @@
     @GuardedBy("mLock")
     private boolean mEnabledForAugmentedAutofillOnly;
 
+    @GuardedBy("mLock")
+    @Nullable private AutofillRequestCallback mAutofillRequestCallback;
+    @GuardedBy("mLock")
+    @Nullable private Executor mRequestCallbackExecutor;
+
     /** @hide */
     public interface AutofillClient {
         /**
@@ -1836,6 +1856,32 @@
         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) {
@@ -1896,6 +1942,13 @@
                 }
             }
 
+            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, componentName,
@@ -2245,6 +2298,28 @@
         }
     }
 
+    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 */
@@ -3624,6 +3699,23 @@
                 afm.post(() -> afm.requestShowSoftInput(id));
             }
         }
+
+        @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));
+            }
+        }
     }
 
     private static final class AugmentedAutofillManagerClient
diff --git a/core/java/android/view/autofill/AutofillRequestCallback.java b/core/java/android/view/autofill/AutofillRequestCallback.java
new file mode 100644
index 0000000..e632a58
--- /dev/null
+++ b/core/java/android/view/autofill/AutofillRequestCallback.java
@@ -0,0 +1,72 @@
+/*
+ * 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 1f833f6..64507aa 100644
--- a/core/java/android/view/autofill/IAutoFillManagerClient.aidl
+++ b/core/java/android/view/autofill/IAutoFillManagerClient.aidl
@@ -24,9 +24,11 @@
 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;
@@ -140,4 +142,10 @@
     * Requests to show the soft input method if the focus is on the given id.
     */
    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);
 }
diff --git a/core/java/android/view/textclassifier/TextClassificationConstants.java b/core/java/android/view/textclassifier/TextClassificationConstants.java
index d0959f9..5f3159c 100644
--- a/core/java/android/view/textclassifier/TextClassificationConstants.java
+++ b/core/java/android/view/textclassifier/TextClassificationConstants.java
@@ -91,8 +91,9 @@
             "system_textclassifier_api_timeout_in_second";
 
     /**
-     * The max amount of characters before and after the selected text that are passed to the
-     * TextClassifier for the smart selection.
+     * The maximum amount of characters before and after the selected text that is passed to the
+     * TextClassifier for the smart selection. e.g. If this value is 100, then 100 characters before
+     * the selection and 100 characters after the selection will be passed to the TextClassifier.
      */
     private static final String SMART_SELECTION_TRIM_DELTA = "smart_selection_trim_delta";
 
diff --git a/core/java/android/view/textservice/TextServicesManager.java b/core/java/android/view/textservice/TextServicesManager.java
index 5980cb6..996757d 100644
--- a/core/java/android/view/textservice/TextServicesManager.java
+++ b/core/java/android/view/textservice/TextServicesManager.java
@@ -257,9 +257,11 @@
     }
 
     /**
+     * Deprecated. Use {@link #getEnabledSpellCheckerInfos()} instead.
      * @hide
      */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553,
+            publicAlternatives = "Use {@link #getEnabledSpellCheckerInfos()} instead.")
     public SpellCheckerInfo[] getEnabledSpellCheckers() {
         try {
             final SpellCheckerInfo[] retval = mService.getEnabledSpellCheckers(mUserId);
@@ -279,7 +281,7 @@
      */
     @Nullable
     @SuppressLint("NullableCollection")
-    public List<SpellCheckerInfo> getEnabledSpellCheckersList() {
+    public List<SpellCheckerInfo> getEnabledSpellCheckerInfos() {
         final SpellCheckerInfo[] enabledSpellCheckers = getEnabledSpellCheckers();
         return enabledSpellCheckers != null ? Arrays.asList(enabledSpellCheckers) : null;
     }
@@ -290,7 +292,7 @@
      * @return The current active spell checker info.
      */
     @Nullable
-    public SpellCheckerInfo getCurrentSpellChecker() {
+    public SpellCheckerInfo getCurrentSpellCheckerInfo() {
         try {
             // Passing null as a locale for ICS
             return mService.getCurrentSpellChecker(mUserId, null);
@@ -300,12 +302,26 @@
     }
 
     /**
+     * Deprecated. Use {@link #getCurrentSpellCheckerInfo()} instead.
+     * @hide
+     */
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R,
+            publicAlternatives = "Use {@link #getCurrentSpellCheckerInfo()} instead.")
+    @Nullable
+    public SpellCheckerInfo getCurrentSpellChecker() {
+        return getCurrentSpellCheckerInfo();
+    }
+
+    /**
      * Retrieve the selected subtype of the selected spell checker, or null if there is none.
      *
      * @param allowImplicitlySelectedSubtype {@code true} to return the default language matching
      * system locale if there's no subtype selected explicitly, otherwise, returns null.
      * @return The meta information of the selected subtype of the selected spell checker.
+     *
+     * @hide
      */
+    @UnsupportedAppUsage
     @Nullable
     public SpellCheckerSubtype getCurrentSpellCheckerSubtype(
             boolean allowImplicitlySelectedSubtype) {
diff --git a/core/java/android/view/translation/ITranslationDirectManager.aidl b/core/java/android/view/translation/ITranslationDirectManager.aidl
index 358f99a..46475b7 100644
--- a/core/java/android/view/translation/ITranslationDirectManager.aidl
+++ b/core/java/android/view/translation/ITranslationDirectManager.aidl
@@ -16,7 +16,7 @@
 
 package android.view.translation;
 
-import android.service.translation.TranslationRequest;
+import android.view.translation.TranslationRequest;
 import android.service.translation.ITranslationCallback;
 import com.android.internal.os.IResultReceiver;
 
diff --git a/core/java/android/view/translation/ITranslationManager.aidl b/core/java/android/view/translation/ITranslationManager.aidl
index 872e15e..7f6c4b4 100644
--- a/core/java/android/view/translation/ITranslationManager.aidl
+++ b/core/java/android/view/translation/ITranslationManager.aidl
@@ -16,9 +16,7 @@
 
 package android.view.translation;
 
-import android.content.ComponentName;
 import android.os.IBinder;
-import android.service.translation.TranslationRequest;
 import android.view.autofill.AutofillId;
 import android.view.translation.TranslationSpec;
 import com.android.internal.os.IResultReceiver;
diff --git a/core/java/android/view/translation/TranslationRequest.java b/core/java/android/view/translation/TranslationRequest.java
index a5e3f75..1dc711b 100644
--- a/core/java/android/view/translation/TranslationRequest.java
+++ b/core/java/android/view/translation/TranslationRequest.java
@@ -17,35 +17,85 @@
 package android.view.translation;
 
 import android.annotation.NonNull;
-import android.annotation.Nullable;
+import android.os.Parcel;
 import android.os.Parcelable;
-import android.view.autofill.AutofillId;
 
 import com.android.internal.util.DataClass;
 
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
 /**
- * Wrapper class for data to be translated by {@link android.service.translation.TranslationService}
+ * Translation request sent to the {@link android.service.translation.TranslationService} by the
+ * {@link android.view.translation.Translator} which contains the text to be translated.
  */
-@DataClass(genToString = true, genBuilder = true)
+@DataClass(genToString = true, genHiddenConstDefs = true, genBuilder = true)
 public final class TranslationRequest implements Parcelable {
 
-    @Nullable
-    private final AutofillId mAutofillId;
+    /**
+     * Indicates this request wants to receive the standard translation result.
+     */
+    public static final @RequestFlags int FLAG_TRANSLATION_RESULT = 0x1;
+    /**
+     * Indicates this request wants to receive the dictionary result.
+     * TODO: describe the structure of the result.
+     */
+    public static final @RequestFlags int FLAG_DICTIONARY_RESULT = 0x2;
+    /**
+     * Indicates this request wants to receive the transliteration result.
+     * TODO: describe the structure of the result.
+     */
+    public static final @RequestFlags int FLAG_TRANSLITERATION_RESULT = 0x4;
+    /**
+     * Indicates this request is willing to accept partial responses.
+     *
+     * <p>The partial responses can be accessed by
+     * {@link TranslationResponse#getTranslationResponseValues()} or
+     * {@link TranslationResponse#getViewTranslationResponses()}. These responses will each contain
+     * only a subset of the corresponding translated values.
+     *
+     * <p>The are no guarantees to the number of translated values or the order in which these
+     * values are returned in the {@link TranslationResponse}.
+     *
+     * <p>This flag denotes the client can expect multiple partial responses, but there may not
+     * necessarily be multiple responses.</p>
+     */
+    public static final @RequestFlags int FLAG_PARTIAL_RESPONSES = 0x8;
 
-    @Nullable
-    private final CharSequence mTranslationText;
+    /**
+     * Request flags. {@link #FLAG_TRANSLATION_RESULT} by default.
+     */
+    private final @RequestFlags int mFlags;
 
-    public TranslationRequest(@Nullable CharSequence text) {
-        mAutofillId = null;
-        mTranslationText = text;
+    /**
+     * List of {@link TranslationRequestValue}s to be translated. The index of entries in this list
+     * will be their respective key in the {@link android.util.SparseArray} returned by calling
+     * {@link TranslationResponse#getTranslationResponseValues()}.
+     */
+    @NonNull
+    @DataClass.PluralOf("translationRequestValue")
+    private final List<TranslationRequestValue> mTranslationRequestValues;
+
+    /**
+     * List of {@link ViewTranslationRequest}s to be translated. The index of entries in this list
+     * will be their respective key in the {@link android.util.SparseArray} returned by calling
+     * {@link TranslationResponse#getViewTranslationResponses()}.
+     */
+    @NonNull
+    @DataClass.PluralOf("viewTranslationRequest")
+    private final List<ViewTranslationRequest> mViewTranslationRequests;
+
+    private static int defaultFlags() {
+        return FLAG_TRANSLATION_RESULT;
     }
 
-    private static CharSequence defaultTranslationText() {
-        return null;
+    private static List<TranslationRequestValue> defaultTranslationRequestValues() {
+        return Collections.emptyList();
     }
 
-    private static AutofillId defaultAutofillId() {
-        return null;
+    private static List<ViewTranslationRequest> defaultViewTranslationRequests() {
+        return Collections.emptyList();
     }
 
 
@@ -63,24 +113,88 @@
     //@formatter:off
 
 
+    /** @hide */
+    @android.annotation.IntDef(flag = true, prefix = "FLAG_", value = {
+        FLAG_TRANSLATION_RESULT,
+        FLAG_DICTIONARY_RESULT,
+        FLAG_TRANSLITERATION_RESULT,
+        FLAG_PARTIAL_RESPONSES
+    })
+    @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE)
+    @DataClass.Generated.Member
+    public @interface RequestFlags {}
+
+    /** @hide */
+    @DataClass.Generated.Member
+    public static String requestFlagsToString(@RequestFlags int value) {
+        return com.android.internal.util.BitUtils.flagsToString(
+                value, TranslationRequest::singleRequestFlagsToString);
+    }
+
+    @DataClass.Generated.Member
+    static String singleRequestFlagsToString(@RequestFlags int value) {
+        switch (value) {
+            case FLAG_TRANSLATION_RESULT:
+                    return "FLAG_TRANSLATION_RESULT";
+            case FLAG_DICTIONARY_RESULT:
+                    return "FLAG_DICTIONARY_RESULT";
+            case FLAG_TRANSLITERATION_RESULT:
+                    return "FLAG_TRANSLITERATION_RESULT";
+            case FLAG_PARTIAL_RESPONSES:
+                    return "FLAG_PARTIAL_RESPONSES";
+            default: return Integer.toHexString(value);
+        }
+    }
+
     @DataClass.Generated.Member
     /* package-private */ TranslationRequest(
-            @Nullable AutofillId autofillId,
-            @Nullable CharSequence translationText) {
-        this.mAutofillId = autofillId;
-        this.mTranslationText = translationText;
+            @RequestFlags int flags,
+            @NonNull List<TranslationRequestValue> translationRequestValues,
+            @NonNull List<ViewTranslationRequest> viewTranslationRequests) {
+        this.mFlags = flags;
+
+        com.android.internal.util.Preconditions.checkFlagsArgument(
+                mFlags,
+                FLAG_TRANSLATION_RESULT
+                        | FLAG_DICTIONARY_RESULT
+                        | FLAG_TRANSLITERATION_RESULT
+                        | FLAG_PARTIAL_RESPONSES);
+        this.mTranslationRequestValues = translationRequestValues;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mTranslationRequestValues);
+        this.mViewTranslationRequests = viewTranslationRequests;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mViewTranslationRequests);
 
         // onConstructed(); // You can define this method to get a callback
     }
 
+    /**
+     * Request flags. {@link #FLAG_TRANSLATION_RESULT} by default.
+     */
     @DataClass.Generated.Member
-    public @Nullable AutofillId getAutofillId() {
-        return mAutofillId;
+    public @RequestFlags int getFlags() {
+        return mFlags;
     }
 
+    /**
+     * List of {@link TranslationRequestValue}s to be translated. The index of entries in this list
+     * will be their respective key in the {@link android.util.SparseArray} returned by calling
+     * {@link TranslationResponse#getTranslationResponseValues()}.
+     */
     @DataClass.Generated.Member
-    public @Nullable CharSequence getTranslationText() {
-        return mTranslationText;
+    public @NonNull List<TranslationRequestValue> getTranslationRequestValues() {
+        return mTranslationRequestValues;
+    }
+
+    /**
+     * List of {@link ViewTranslationRequest}s to be translated. The index of entries in this list
+     * will be their respective key in the {@link android.util.SparseArray} returned by calling
+     * {@link TranslationResponse#getViewTranslationResponses()}.
+     */
+    @DataClass.Generated.Member
+    public @NonNull List<ViewTranslationRequest> getViewTranslationRequests() {
+        return mViewTranslationRequests;
     }
 
     @Override
@@ -90,23 +204,21 @@
         // String fieldNameToString() { ... }
 
         return "TranslationRequest { " +
-                "autofillId = " + mAutofillId + ", " +
-                "translationText = " + mTranslationText +
+                "flags = " + requestFlagsToString(mFlags) + ", " +
+                "translationRequestValues = " + mTranslationRequestValues + ", " +
+                "viewTranslationRequests = " + mViewTranslationRequests +
         " }";
     }
 
     @Override
     @DataClass.Generated.Member
-    public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
         // You can override field parcelling by defining methods like:
         // void parcelFieldName(Parcel dest, int flags) { ... }
 
-        byte flg = 0;
-        if (mAutofillId != null) flg |= 0x1;
-        if (mTranslationText != null) flg |= 0x2;
-        dest.writeByte(flg);
-        if (mAutofillId != null) dest.writeTypedObject(mAutofillId, flags);
-        if (mTranslationText != null) dest.writeCharSequence(mTranslationText);
+        dest.writeInt(mFlags);
+        dest.writeParcelableList(mTranslationRequestValues, flags);
+        dest.writeParcelableList(mViewTranslationRequests, flags);
     }
 
     @Override
@@ -116,16 +228,30 @@
     /** @hide */
     @SuppressWarnings({"unchecked", "RedundantCast"})
     @DataClass.Generated.Member
-    /* package-private */ TranslationRequest(@NonNull android.os.Parcel in) {
+    /* package-private */ TranslationRequest(@NonNull Parcel in) {
         // You can override field unparcelling by defining methods like:
         // static FieldType unparcelFieldName(Parcel in) { ... }
 
-        byte flg = in.readByte();
-        AutofillId autofillId = (flg & 0x1) == 0 ? null : (AutofillId) in.readTypedObject(AutofillId.CREATOR);
-        CharSequence translationText = (flg & 0x2) == 0 ? null : (CharSequence) in.readCharSequence();
+        int flags = in.readInt();
+        List<TranslationRequestValue> translationRequestValues = new ArrayList<>();
+        in.readParcelableList(translationRequestValues, TranslationRequestValue.class.getClassLoader());
+        List<ViewTranslationRequest> viewTranslationRequests = new ArrayList<>();
+        in.readParcelableList(viewTranslationRequests, ViewTranslationRequest.class.getClassLoader());
 
-        this.mAutofillId = autofillId;
-        this.mTranslationText = translationText;
+        this.mFlags = flags;
+
+        com.android.internal.util.Preconditions.checkFlagsArgument(
+                mFlags,
+                FLAG_TRANSLATION_RESULT
+                        | FLAG_DICTIONARY_RESULT
+                        | FLAG_TRANSLITERATION_RESULT
+                        | FLAG_PARTIAL_RESPONSES);
+        this.mTranslationRequestValues = translationRequestValues;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mTranslationRequestValues);
+        this.mViewTranslationRequests = viewTranslationRequests;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mViewTranslationRequests);
 
         // onConstructed(); // You can define this method to get a callback
     }
@@ -139,7 +265,7 @@
         }
 
         @Override
-        public TranslationRequest createFromParcel(@NonNull android.os.Parcel in) {
+        public TranslationRequest createFromParcel(@NonNull Parcel in) {
             return new TranslationRequest(in);
         }
     };
@@ -151,49 +277,91 @@
     @DataClass.Generated.Member
     public static final class Builder {
 
-        private @Nullable AutofillId mAutofillId;
-        private @Nullable CharSequence mTranslationText;
+        private @RequestFlags int mFlags;
+        private @NonNull List<TranslationRequestValue> mTranslationRequestValues;
+        private @NonNull List<ViewTranslationRequest> mViewTranslationRequests;
 
         private long mBuilderFieldsSet = 0L;
 
         public Builder() {
         }
 
+        /**
+         * Request flags. {@link #FLAG_TRANSLATION_RESULT} by default.
+         */
         @DataClass.Generated.Member
-        public @NonNull Builder setAutofillId(@NonNull AutofillId value) {
+        public @NonNull Builder setFlags(@RequestFlags int value) {
             checkNotUsed();
             mBuilderFieldsSet |= 0x1;
-            mAutofillId = value;
+            mFlags = value;
             return this;
         }
 
+        /**
+         * List of {@link TranslationRequestValue}s to be translated. The index of entries in this list
+         * will be their respective key in the {@link android.util.SparseArray} returned by calling
+         * {@link TranslationResponse#getTranslationResponseValues()}.
+         */
         @DataClass.Generated.Member
-        public @NonNull Builder setTranslationText(@NonNull CharSequence value) {
+        public @NonNull Builder setTranslationRequestValues(@NonNull List<TranslationRequestValue> value) {
             checkNotUsed();
             mBuilderFieldsSet |= 0x2;
-            mTranslationText = value;
+            mTranslationRequestValues = value;
+            return this;
+        }
+
+        /** @see #setTranslationRequestValues */
+        @DataClass.Generated.Member
+        public @NonNull Builder addTranslationRequestValue(@NonNull TranslationRequestValue value) {
+            if (mTranslationRequestValues == null) setTranslationRequestValues(new ArrayList<>());
+            mTranslationRequestValues.add(value);
+            return this;
+        }
+
+        /**
+         * List of {@link ViewTranslationRequest}s to be translated. The index of entries in this list
+         * will be their respective key in the {@link android.util.SparseArray} returned by calling
+         * {@link TranslationResponse#getViewTranslationResponses()}.
+         */
+        @DataClass.Generated.Member
+        public @NonNull Builder setViewTranslationRequests(@NonNull List<ViewTranslationRequest> value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x4;
+            mViewTranslationRequests = value;
+            return this;
+        }
+
+        /** @see #setViewTranslationRequests */
+        @DataClass.Generated.Member
+        public @NonNull Builder addViewTranslationRequest(@NonNull ViewTranslationRequest value) {
+            if (mViewTranslationRequests == null) setViewTranslationRequests(new ArrayList<>());
+            mViewTranslationRequests.add(value);
             return this;
         }
 
         /** Builds the instance. This builder should not be touched after calling this! */
         public @NonNull TranslationRequest build() {
             checkNotUsed();
-            mBuilderFieldsSet |= 0x4; // Mark builder used
+            mBuilderFieldsSet |= 0x8; // Mark builder used
 
             if ((mBuilderFieldsSet & 0x1) == 0) {
-                mAutofillId = defaultAutofillId();
+                mFlags = defaultFlags();
             }
             if ((mBuilderFieldsSet & 0x2) == 0) {
-                mTranslationText = defaultTranslationText();
+                mTranslationRequestValues = defaultTranslationRequestValues();
+            }
+            if ((mBuilderFieldsSet & 0x4) == 0) {
+                mViewTranslationRequests = defaultViewTranslationRequests();
             }
             TranslationRequest o = new TranslationRequest(
-                    mAutofillId,
-                    mTranslationText);
+                    mFlags,
+                    mTranslationRequestValues,
+                    mViewTranslationRequests);
             return o;
         }
 
         private void checkNotUsed() {
-            if ((mBuilderFieldsSet & 0x4) != 0) {
+            if ((mBuilderFieldsSet & 0x8) != 0) {
                 throw new IllegalStateException(
                         "This Builder should not be reused. Use a new Builder instance instead");
             }
@@ -201,10 +369,10 @@
     }
 
     @DataClass.Generated(
-            time = 1610060189421L,
+            time = 1614132376448L,
             codegenVersion = "1.0.22",
             sourceFile = "frameworks/base/core/java/android/view/translation/TranslationRequest.java",
-            inputSignatures = "private final @android.annotation.Nullable android.view.autofill.AutofillId mAutofillId\nprivate final @android.annotation.Nullable java.lang.CharSequence mTranslationText\nprivate static  java.lang.CharSequence defaultTranslationText()\nprivate static  android.view.autofill.AutofillId defaultAutofillId()\nclass TranslationRequest extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genBuilder=true)")
+            inputSignatures = "public static final @android.view.translation.TranslationRequest.RequestFlags int FLAG_TRANSLATION_RESULT\npublic static final @android.view.translation.TranslationRequest.RequestFlags int FLAG_DICTIONARY_RESULT\npublic static final @android.view.translation.TranslationRequest.RequestFlags int FLAG_TRANSLITERATION_RESULT\npublic static final @android.view.translation.TranslationRequest.RequestFlags int FLAG_PARTIAL_RESPONSES\nprivate final @android.view.translation.TranslationRequest.RequestFlags int mFlags\nprivate final @android.annotation.NonNull @com.android.internal.util.DataClass.PluralOf(\"translationRequestValue\") java.util.List<android.view.translation.TranslationRequestValue> mTranslationRequestValues\nprivate final @android.annotation.NonNull @com.android.internal.util.DataClass.PluralOf(\"viewTranslationRequest\") java.util.List<android.view.translation.ViewTranslationRequest> mViewTranslationRequests\nprivate static  int defaultFlags()\nprivate static  java.util.List<android.view.translation.TranslationRequestValue> defaultTranslationRequestValues()\nprivate static  java.util.List<android.view.translation.ViewTranslationRequest> defaultViewTranslationRequests()\nclass TranslationRequest extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstDefs=true, genBuilder=true)")
     @Deprecated
     private void __metadata() {}
 
diff --git a/core/java/android/view/translation/TranslationData.aidl b/core/java/android/view/translation/TranslationRequestValue.aidl
similarity index 86%
copy from core/java/android/view/translation/TranslationData.aidl
copy to core/java/android/view/translation/TranslationRequestValue.aidl
index 40f21a6..92526b6 100644
--- a/core/java/android/view/translation/TranslationData.aidl
+++ b/core/java/android/view/translation/TranslationRequestValue.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -16,4 +16,4 @@
 
 package android.view.translation;
 
-parcelable TranslationData;
+parcelable TranslationRequestValue;
diff --git a/core/java/android/view/translation/TranslationRequestValue.java b/core/java/android/view/translation/TranslationRequestValue.java
new file mode 100644
index 0000000..0619618
--- /dev/null
+++ b/core/java/android/view/translation/TranslationRequestValue.java
@@ -0,0 +1,185 @@
+/*
+ * 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.view.translation;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.DataClass;
+
+import java.util.Objects;
+
+/**
+ * A value to be translated via {@link android.view.translation.Translator}.
+ */
+@DataClass(genHiddenConstructor = true, genToString = true, genEqualsHashCode = true)
+public final class TranslationRequestValue implements Parcelable {
+
+    @Nullable
+    private final CharSequence mText;
+
+    /**
+     * Creates a {@link TranslationRequestValue} with a {@link CharSequence} value;
+     *
+     * @param text the text to be translated.
+     */
+    @NonNull
+    public static TranslationRequestValue forText(@NonNull CharSequence text) {
+        Objects.requireNonNull(text, "text should not be null");
+        return new TranslationRequestValue(text);
+    }
+
+    /**
+     * @return the text value as a {@link CharSequence}.
+     *
+     * @throws IllegalStateException if the format of this {@link TranslationRequestValue} is not a
+     * text value.
+     */
+    @NonNull
+    public CharSequence getText() {
+        if (mText == null) {
+            throw new IllegalStateException("Value is not of type text");
+        }
+        return mText;
+    }
+
+
+
+    // Code below generated by codegen v1.0.22.
+    //
+    // DO NOT MODIFY!
+    // CHECKSTYLE:OFF Generated code
+    //
+    // To regenerate run:
+    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/view/translation/TranslationRequestValue.java
+    //
+    // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+    //   Settings > Editor > Code Style > Formatter Control
+    //@formatter:off
+
+
+    /**
+     * Creates a new TranslationRequestValue.
+     *
+     * @hide
+     */
+    @DataClass.Generated.Member
+    public TranslationRequestValue(
+            @Nullable CharSequence text) {
+        this.mText = text;
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public String toString() {
+        // You can override field toString logic by defining methods like:
+        // String fieldNameToString() { ... }
+
+        return "TranslationRequestValue { " +
+                "text = " + mText +
+        " }";
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public boolean equals(@Nullable Object o) {
+        // You can override field equality logic by defining either of the methods like:
+        // boolean fieldNameEquals(TranslationRequestValue other) { ... }
+        // boolean fieldNameEquals(FieldType otherValue) { ... }
+
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        @SuppressWarnings("unchecked")
+        TranslationRequestValue that = (TranslationRequestValue) o;
+        //noinspection PointlessBooleanExpression
+        return true
+                && java.util.Objects.equals(mText, that.mText);
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int hashCode() {
+        // You can override field hashCode logic by defining methods like:
+        // int fieldNameHashCode() { ... }
+
+        int _hash = 1;
+        _hash = 31 * _hash + java.util.Objects.hashCode(mText);
+        return _hash;
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        // You can override field parcelling by defining methods like:
+        // void parcelFieldName(Parcel dest, int flags) { ... }
+
+        byte flg = 0;
+        if (mText != null) flg |= 0x1;
+        dest.writeByte(flg);
+        if (mText != null) dest.writeCharSequence(mText);
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int describeContents() { return 0; }
+
+    /** @hide */
+    @SuppressWarnings({"unchecked", "RedundantCast"})
+    @DataClass.Generated.Member
+    /* package-private */ TranslationRequestValue(@NonNull Parcel in) {
+        // You can override field unparcelling by defining methods like:
+        // static FieldType unparcelFieldName(Parcel in) { ... }
+
+        byte flg = in.readByte();
+        CharSequence text = (flg & 0x1) == 0 ? null : (CharSequence) in.readCharSequence();
+
+        this.mText = text;
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    @DataClass.Generated.Member
+    public static final @NonNull Parcelable.Creator<TranslationRequestValue> CREATOR
+            = new Parcelable.Creator<TranslationRequestValue>() {
+        @Override
+        public TranslationRequestValue[] newArray(int size) {
+            return new TranslationRequestValue[size];
+        }
+
+        @Override
+        public TranslationRequestValue createFromParcel(@NonNull Parcel in) {
+            return new TranslationRequestValue(in);
+        }
+    };
+
+    @DataClass.Generated(
+            time = 1613687761635L,
+            codegenVersion = "1.0.22",
+            sourceFile = "frameworks/base/core/java/android/view/translation/TranslationRequestValue.java",
+            inputSignatures = "private final @android.annotation.Nullable java.lang.CharSequence mText\npublic static @android.annotation.NonNull android.view.translation.TranslationRequestValue forText(java.lang.CharSequence)\npublic @android.annotation.NonNull java.lang.CharSequence getText()\nclass TranslationRequestValue extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genHiddenConstructor=true, genToString=true, genEqualsHashCode=true)")
+    @Deprecated
+    private void __metadata() {}
+
+
+    //@formatter:on
+    // End of generated code
+
+}
diff --git a/core/java/android/view/translation/TranslationResponse.java b/core/java/android/view/translation/TranslationResponse.java
index d29063f..03731e1 100644
--- a/core/java/android/view/translation/TranslationResponse.java
+++ b/core/java/android/view/translation/TranslationResponse.java
@@ -21,13 +21,13 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.service.translation.TranslationService;
+import android.util.SparseArray;
 
 import com.android.internal.util.DataClass;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.Objects;
 
 /**
  * Response from the {@link TranslationService}, which contains the translated result.
@@ -44,19 +44,83 @@
      */
     public static final int TRANSLATION_STATUS_UNKNOWN_ERROR = 1;
     /**
-     * The language of the request is not available to be translated.
+     * The languages of the request is not available to be translated.
      */
-    public static final int TRANSLATION_STATUS_LANGUAGE_UNAVAILABLE = 2;
+    public static final int TRANSLATION_STATUS_CONTEXT_UNSUPPORTED = 2;
 
     /**
      * The translation result status code.
      */
     private final @TranslationStatus int mTranslationStatus;
+
     /**
-     * The translation results. If there is no translation result, set it with an empty list.
+     * List of translated {@link TranslationResponseValue}s. The key of entries in this list
+     * will be their respective index in {@link TranslationRequest#getTranslationRequestValues()}.
      */
     @NonNull
-    private List<TranslationRequest> mTranslations = new ArrayList();
+    private final SparseArray<TranslationResponseValue> mTranslationResponseValues;
+
+    /**
+     * List of translated {@link ViewTranslationResponse}s. The key of entries in this list
+     * will be their respective index in {@link TranslationRequest#getViewTranslationRequests()}.
+     */
+    @NonNull
+    private final SparseArray<ViewTranslationResponse> mViewTranslationResponses;
+
+    abstract static class BaseBuilder {
+
+        /**
+         * Adds {@link TranslationResponseValue} to be translated. The input
+         * TranslationResponseValue format should match those provided by the
+         * {@link android.view.translation.Translator}'s destSpec.
+         *
+         * @param value the translated value.
+         * @return this Builder.
+         */
+        @NonNull
+        @SuppressWarnings("MissingGetterMatchingBuilder")
+        public Builder setTranslationResponseValue(int index,
+                @NonNull TranslationResponseValue value) {
+            Objects.requireNonNull(value, "value should not be null");
+            final Builder builder = (Builder) this;
+
+            if (builder.mTranslationResponseValues == null) {
+                builder.setTranslationResponseValues(new SparseArray<>());
+            }
+            builder.mTranslationResponseValues.put(index, value);
+            return builder;
+        }
+
+        /**
+         * Sets the list of {@link ViewTranslationResponse} to be translated. The input
+         * ViewTranslationResponse contains {@link TranslationResponseValue}s whose  format should
+         * match those provided by the {@link android.view.translation.Translator}'s destSpec.
+         *
+         * @param response the translated response.
+         * @return this Builder.
+         */
+        @NonNull
+        @SuppressWarnings("MissingGetterMatchingBuilder")
+        public Builder setViewTranslationResponse(int index,
+                @NonNull ViewTranslationResponse response) {
+            Objects.requireNonNull(response, "value should not be null");
+            final Builder builder = (Builder) this;
+
+            if (builder.mViewTranslationResponses == null) {
+                builder.setViewTranslationResponses(new SparseArray<>());
+            }
+            builder.mViewTranslationResponses.put(index, response);
+            return builder;
+        }
+    }
+
+    private static SparseArray<TranslationResponseValue> defaultTranslationResponseValues() {
+        return new SparseArray<>();
+    }
+
+    private static SparseArray<ViewTranslationResponse> defaultViewTranslationResponses() {
+        return new SparseArray<>();
+    }
 
 
 
@@ -78,7 +142,7 @@
     @IntDef(prefix = "TRANSLATION_STATUS_", value = {
         TRANSLATION_STATUS_SUCCESS,
         TRANSLATION_STATUS_UNKNOWN_ERROR,
-        TRANSLATION_STATUS_LANGUAGE_UNAVAILABLE
+        TRANSLATION_STATUS_CONTEXT_UNSUPPORTED
     })
     @Retention(RetentionPolicy.SOURCE)
     @DataClass.Generated.Member
@@ -92,8 +156,8 @@
                     return "TRANSLATION_STATUS_SUCCESS";
             case TRANSLATION_STATUS_UNKNOWN_ERROR:
                     return "TRANSLATION_STATUS_UNKNOWN_ERROR";
-            case TRANSLATION_STATUS_LANGUAGE_UNAVAILABLE:
-                    return "TRANSLATION_STATUS_LANGUAGE_UNAVAILABLE";
+            case TRANSLATION_STATUS_CONTEXT_UNSUPPORTED:
+                    return "TRANSLATION_STATUS_CONTEXT_UNSUPPORTED";
             default: return Integer.toHexString(value);
         }
     }
@@ -101,22 +165,26 @@
     @DataClass.Generated.Member
     /* package-private */ TranslationResponse(
             @TranslationStatus int translationStatus,
-            @NonNull List<TranslationRequest> translations) {
+            @NonNull SparseArray<TranslationResponseValue> translationResponseValues,
+            @NonNull SparseArray<ViewTranslationResponse> viewTranslationResponses) {
         this.mTranslationStatus = translationStatus;
 
         if (!(mTranslationStatus == TRANSLATION_STATUS_SUCCESS)
                 && !(mTranslationStatus == TRANSLATION_STATUS_UNKNOWN_ERROR)
-                && !(mTranslationStatus == TRANSLATION_STATUS_LANGUAGE_UNAVAILABLE)) {
+                && !(mTranslationStatus == TRANSLATION_STATUS_CONTEXT_UNSUPPORTED)) {
             throw new java.lang.IllegalArgumentException(
                     "translationStatus was " + mTranslationStatus + " but must be one of: "
                             + "TRANSLATION_STATUS_SUCCESS(" + TRANSLATION_STATUS_SUCCESS + "), "
                             + "TRANSLATION_STATUS_UNKNOWN_ERROR(" + TRANSLATION_STATUS_UNKNOWN_ERROR + "), "
-                            + "TRANSLATION_STATUS_LANGUAGE_UNAVAILABLE(" + TRANSLATION_STATUS_LANGUAGE_UNAVAILABLE + ")");
+                            + "TRANSLATION_STATUS_CONTEXT_UNSUPPORTED(" + TRANSLATION_STATUS_CONTEXT_UNSUPPORTED + ")");
         }
 
-        this.mTranslations = translations;
+        this.mTranslationResponseValues = translationResponseValues;
         com.android.internal.util.AnnotationValidations.validate(
-                NonNull.class, null, mTranslations);
+                NonNull.class, null, mTranslationResponseValues);
+        this.mViewTranslationResponses = viewTranslationResponses;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mViewTranslationResponses);
 
         // onConstructed(); // You can define this method to get a callback
     }
@@ -130,11 +198,21 @@
     }
 
     /**
-     * The translation results. If there is no translation result, set it with an empty list.
+     * List of translated {@link TranslationResponseValue}s. The key of entries in this list
+     * will be their respective index in {@link TranslationRequest#getTranslationRequestValues()}.
      */
     @DataClass.Generated.Member
-    public @NonNull List<TranslationRequest> getTranslations() {
-        return mTranslations;
+    public @NonNull SparseArray<TranslationResponseValue> getTranslationResponseValues() {
+        return mTranslationResponseValues;
+    }
+
+    /**
+     * List of translated {@link ViewTranslationResponse}s. The key of entries in this list
+     * will be their respective index in {@link TranslationRequest#getViewTranslationRequests()}.
+     */
+    @DataClass.Generated.Member
+    public @NonNull SparseArray<ViewTranslationResponse> getViewTranslationResponses() {
+        return mViewTranslationResponses;
     }
 
     @Override
@@ -145,7 +223,8 @@
 
         return "TranslationResponse { " +
                 "translationStatus = " + translationStatusToString(mTranslationStatus) + ", " +
-                "translations = " + mTranslations +
+                "translationResponseValues = " + mTranslationResponseValues + ", " +
+                "viewTranslationResponses = " + mViewTranslationResponses +
         " }";
     }
 
@@ -156,7 +235,8 @@
         // void parcelFieldName(Parcel dest, int flags) { ... }
 
         dest.writeInt(mTranslationStatus);
-        dest.writeParcelableList(mTranslations, flags);
+        dest.writeSparseArray(mTranslationResponseValues);
+        dest.writeSparseArray(mViewTranslationResponses);
     }
 
     @Override
@@ -171,24 +251,27 @@
         // static FieldType unparcelFieldName(Parcel in) { ... }
 
         int translationStatus = in.readInt();
-        List<TranslationRequest> translations = new ArrayList<>();
-        in.readParcelableList(translations, TranslationRequest.class.getClassLoader());
+        SparseArray<TranslationResponseValue> translationResponseValues = (SparseArray) in.readSparseArray(TranslationResponseValue.class.getClassLoader());
+        SparseArray<ViewTranslationResponse> viewTranslationResponses = (SparseArray) in.readSparseArray(ViewTranslationResponse.class.getClassLoader());
 
         this.mTranslationStatus = translationStatus;
 
         if (!(mTranslationStatus == TRANSLATION_STATUS_SUCCESS)
                 && !(mTranslationStatus == TRANSLATION_STATUS_UNKNOWN_ERROR)
-                && !(mTranslationStatus == TRANSLATION_STATUS_LANGUAGE_UNAVAILABLE)) {
+                && !(mTranslationStatus == TRANSLATION_STATUS_CONTEXT_UNSUPPORTED)) {
             throw new java.lang.IllegalArgumentException(
                     "translationStatus was " + mTranslationStatus + " but must be one of: "
                             + "TRANSLATION_STATUS_SUCCESS(" + TRANSLATION_STATUS_SUCCESS + "), "
                             + "TRANSLATION_STATUS_UNKNOWN_ERROR(" + TRANSLATION_STATUS_UNKNOWN_ERROR + "), "
-                            + "TRANSLATION_STATUS_LANGUAGE_UNAVAILABLE(" + TRANSLATION_STATUS_LANGUAGE_UNAVAILABLE + ")");
+                            + "TRANSLATION_STATUS_CONTEXT_UNSUPPORTED(" + TRANSLATION_STATUS_CONTEXT_UNSUPPORTED + ")");
         }
 
-        this.mTranslations = translations;
+        this.mTranslationResponseValues = translationResponseValues;
         com.android.internal.util.AnnotationValidations.validate(
-                NonNull.class, null, mTranslations);
+                NonNull.class, null, mTranslationResponseValues);
+        this.mViewTranslationResponses = viewTranslationResponses;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mViewTranslationResponses);
 
         // onConstructed(); // You can define this method to get a callback
     }
@@ -212,10 +295,11 @@
      */
     @SuppressWarnings("WeakerAccess")
     @DataClass.Generated.Member
-    public static final class Builder {
+    public static final class Builder extends BaseBuilder {
 
         private @TranslationStatus int mTranslationStatus;
-        private @NonNull List<TranslationRequest> mTranslations;
+        private @NonNull SparseArray<TranslationResponseValue> mTranslationResponseValues;
+        private @NonNull SparseArray<ViewTranslationResponse> mViewTranslationResponses;
 
         private long mBuilderFieldsSet = 0L;
 
@@ -231,12 +315,12 @@
 
             if (!(mTranslationStatus == TRANSLATION_STATUS_SUCCESS)
                     && !(mTranslationStatus == TRANSLATION_STATUS_UNKNOWN_ERROR)
-                    && !(mTranslationStatus == TRANSLATION_STATUS_LANGUAGE_UNAVAILABLE)) {
+                    && !(mTranslationStatus == TRANSLATION_STATUS_CONTEXT_UNSUPPORTED)) {
                 throw new java.lang.IllegalArgumentException(
                         "translationStatus was " + mTranslationStatus + " but must be one of: "
                                 + "TRANSLATION_STATUS_SUCCESS(" + TRANSLATION_STATUS_SUCCESS + "), "
                                 + "TRANSLATION_STATUS_UNKNOWN_ERROR(" + TRANSLATION_STATUS_UNKNOWN_ERROR + "), "
-                                + "TRANSLATION_STATUS_LANGUAGE_UNAVAILABLE(" + TRANSLATION_STATUS_LANGUAGE_UNAVAILABLE + ")");
+                                + "TRANSLATION_STATUS_CONTEXT_UNSUPPORTED(" + TRANSLATION_STATUS_CONTEXT_UNSUPPORTED + ")");
             }
 
         }
@@ -253,43 +337,49 @@
         }
 
         /**
-         * The translation results. If there is no translation result, set it with an empty list.
+         * List of translated {@link TranslationResponseValue}s. The key of entries in this list
+         * will be their respective index in {@link TranslationRequest#getTranslationRequestValues()}.
          */
         @DataClass.Generated.Member
-        public @NonNull Builder setTranslations(@NonNull List<TranslationRequest> value) {
+        public @NonNull Builder setTranslationResponseValues(@NonNull SparseArray<TranslationResponseValue> value) {
             checkNotUsed();
             mBuilderFieldsSet |= 0x2;
-            mTranslations = value;
+            mTranslationResponseValues = value;
             return this;
         }
 
-        /** @see #setTranslations */
+        /**
+         * List of translated {@link ViewTranslationResponse}s. The key of entries in this list
+         * will be their respective index in {@link TranslationRequest#getViewTranslationRequests()}.
+         */
         @DataClass.Generated.Member
-        public @NonNull Builder addTranslations(@NonNull TranslationRequest value) {
-            // You can refine this method's name by providing item's singular name, e.g.:
-            // @DataClass.PluralOf("item")) mItems = ...
-
-            if (mTranslations == null) setTranslations(new ArrayList<>());
-            mTranslations.add(value);
+        public @NonNull Builder setViewTranslationResponses(@NonNull SparseArray<ViewTranslationResponse> value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x4;
+            mViewTranslationResponses = value;
             return this;
         }
 
         /** Builds the instance. This builder should not be touched after calling this! */
         public @NonNull TranslationResponse build() {
             checkNotUsed();
-            mBuilderFieldsSet |= 0x4; // Mark builder used
+            mBuilderFieldsSet |= 0x8; // Mark builder used
 
             if ((mBuilderFieldsSet & 0x2) == 0) {
-                mTranslations = new ArrayList();
+                mTranslationResponseValues = defaultTranslationResponseValues();
+            }
+            if ((mBuilderFieldsSet & 0x4) == 0) {
+                mViewTranslationResponses = defaultViewTranslationResponses();
             }
             TranslationResponse o = new TranslationResponse(
                     mTranslationStatus,
-                    mTranslations);
+                    mTranslationResponseValues,
+                    mViewTranslationResponses);
             return o;
         }
 
         private void checkNotUsed() {
-            if ((mBuilderFieldsSet & 0x4) != 0) {
+            if ((mBuilderFieldsSet & 0x8) != 0) {
                 throw new IllegalStateException(
                         "This Builder should not be reused. Use a new Builder instance instead");
             }
@@ -297,10 +387,10 @@
     }
 
     @DataClass.Generated(
-            time = 1609973911361L,
+            time = 1614211889478L,
             codegenVersion = "1.0.22",
             sourceFile = "frameworks/base/core/java/android/view/translation/TranslationResponse.java",
-            inputSignatures = "public static final  int TRANSLATION_STATUS_SUCCESS\npublic static final  int TRANSLATION_STATUS_UNKNOWN_ERROR\npublic static final  int TRANSLATION_STATUS_LANGUAGE_UNAVAILABLE\nprivate final @android.view.translation.TranslationResponse.TranslationStatus int mTranslationStatus\nprivate @android.annotation.NonNull java.util.List<android.view.translation.TranslationRequest> mTranslations\nclass TranslationResponse extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genToString=true, genHiddenConstDefs=true)")
+            inputSignatures = "public static final  int TRANSLATION_STATUS_SUCCESS\npublic static final  int TRANSLATION_STATUS_UNKNOWN_ERROR\npublic static final  int TRANSLATION_STATUS_CONTEXT_UNSUPPORTED\nprivate final @android.view.translation.TranslationResponse.TranslationStatus int mTranslationStatus\nprivate final @android.annotation.NonNull android.util.SparseArray<android.view.translation.TranslationResponseValue> mTranslationResponseValues\nprivate final @android.annotation.NonNull android.util.SparseArray<android.view.translation.ViewTranslationResponse> mViewTranslationResponses\nprivate static  android.util.SparseArray<android.view.translation.TranslationResponseValue> defaultTranslationResponseValues()\nprivate static  android.util.SparseArray<android.view.translation.ViewTranslationResponse> defaultViewTranslationResponses()\nclass TranslationResponse extends java.lang.Object implements [android.os.Parcelable]\npublic @android.annotation.NonNull @java.lang.SuppressWarnings android.view.translation.TranslationResponse.Builder setTranslationResponseValue(int,android.view.translation.TranslationResponseValue)\npublic @android.annotation.NonNull @java.lang.SuppressWarnings android.view.translation.TranslationResponse.Builder setViewTranslationResponse(int,android.view.translation.ViewTranslationResponse)\nclass BaseBuilder extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genBuilder=true, genToString=true, genHiddenConstDefs=true)\npublic @android.annotation.NonNull @java.lang.SuppressWarnings android.view.translation.TranslationResponse.Builder setTranslationResponseValue(int,android.view.translation.TranslationResponseValue)\npublic @android.annotation.NonNull @java.lang.SuppressWarnings android.view.translation.TranslationResponse.Builder setViewTranslationResponse(int,android.view.translation.ViewTranslationResponse)\nclass BaseBuilder extends java.lang.Object implements []")
     @Deprecated
     private void __metadata() {}
 
diff --git a/core/java/android/view/translation/TranslationData.aidl b/core/java/android/view/translation/TranslationResponseValue.aidl
similarity index 86%
copy from core/java/android/view/translation/TranslationData.aidl
copy to core/java/android/view/translation/TranslationResponseValue.aidl
index 40f21a6..6fb6a5c 100644
--- a/core/java/android/view/translation/TranslationData.aidl
+++ b/core/java/android/view/translation/TranslationResponseValue.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -16,4 +16,4 @@
 
 package android.view.translation;
 
-parcelable TranslationData;
+parcelable TranslationResponseValue;
diff --git a/core/java/android/view/translation/TranslationResponseValue.java b/core/java/android/view/translation/TranslationResponseValue.java
new file mode 100644
index 0000000..e8e9868
--- /dev/null
+++ b/core/java/android/view/translation/TranslationResponseValue.java
@@ -0,0 +1,419 @@
+/*
+ * 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.view.translation;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.DataClass;
+
+import java.util.Objects;
+
+/**
+ * A translated response value from {@link android.service.translation.TranslationService}.
+ */
+@DataClass(genBuilder = true, genToString = true, genEqualsHashCode = true,
+        genHiddenConstDefs = true)
+public final class TranslationResponseValue implements Parcelable {
+
+    /**
+     * This value was successfully translated.
+     */
+    public static final int STATUS_SUCCESS = 0;
+    /**
+     * This value was not successfully translated. No value can be obtained with {@link #getText()}.
+     */
+    public static final int STATUS_ERROR = 1;
+
+    /**
+     * The status code of this {@link TranslationResponseValue}.
+     *
+     * <p>If the status code is {@link #STATUS_ERROR}, no values are attached, and all getters will
+     * return {@code null}.
+     */
+    private final @Status int mStatusCode;
+
+    /**
+     * The translated text result.
+     */
+    @Nullable
+    private final CharSequence mText;
+
+    /**
+     * The dictionary description of the translated text.
+     * TODO: Describe the result structure.
+     */
+    @Nullable
+    private final CharSequence mDictionaryDescription;
+
+    /**
+     * The transliteration result of the translated text.
+     * TODO: Describe the result structure.
+     */
+    @Nullable
+    private final CharSequence mTransliteration;
+
+    /**
+     * Creates a {@link TranslationResponseValue} with the {@link #STATUS_ERROR} result;
+     */
+    @NonNull
+    public static TranslationResponseValue forError() {
+        return new TranslationResponseValue(STATUS_ERROR, null, null, null);
+    }
+
+    private static CharSequence defaultText() {
+        return null;
+    }
+
+    private static CharSequence defaultDictionaryDescription() {
+        return null;
+    }
+
+    private static CharSequence defaultTransliteration() {
+        return null;
+    }
+
+    @DataClass.Suppress("setStatusCode")
+    abstract static class BaseBuilder {
+
+    }
+
+
+
+    // Code below generated by codegen v1.0.22.
+    //
+    // DO NOT MODIFY!
+    // CHECKSTYLE:OFF Generated code
+    //
+    // To regenerate run:
+    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/view/translation/TranslationResponseValue.java
+    //
+    // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+    //   Settings > Editor > Code Style > Formatter Control
+    //@formatter:off
+
+
+    /** @hide */
+    @android.annotation.IntDef(prefix = "STATUS_", value = {
+        STATUS_SUCCESS,
+        STATUS_ERROR
+    })
+    @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE)
+    @DataClass.Generated.Member
+    public @interface Status {}
+
+    /** @hide */
+    @DataClass.Generated.Member
+    public static String statusToString(@Status int value) {
+        switch (value) {
+            case STATUS_SUCCESS:
+                    return "STATUS_SUCCESS";
+            case STATUS_ERROR:
+                    return "STATUS_ERROR";
+            default: return Integer.toHexString(value);
+        }
+    }
+
+    @DataClass.Generated.Member
+    /* package-private */ TranslationResponseValue(
+            @Status int statusCode,
+            @Nullable CharSequence text,
+            @Nullable CharSequence dictionaryDescription,
+            @Nullable CharSequence transliteration) {
+        this.mStatusCode = statusCode;
+
+        if (!(mStatusCode == STATUS_SUCCESS)
+                && !(mStatusCode == STATUS_ERROR)) {
+            throw new java.lang.IllegalArgumentException(
+                    "statusCode was " + mStatusCode + " but must be one of: "
+                            + "STATUS_SUCCESS(" + STATUS_SUCCESS + "), "
+                            + "STATUS_ERROR(" + STATUS_ERROR + ")");
+        }
+
+        this.mText = text;
+        this.mDictionaryDescription = dictionaryDescription;
+        this.mTransliteration = transliteration;
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    /**
+     * The status code of this {@link TranslationResponseValue}.
+     *
+     * <p>If the status code is {@link #STATUS_ERROR}, no values are attached, and all getters will
+     * return {@code null}.
+     */
+    @DataClass.Generated.Member
+    public @Status int getStatusCode() {
+        return mStatusCode;
+    }
+
+    /**
+     * The translated text result.
+     */
+    @DataClass.Generated.Member
+    public @Nullable CharSequence getText() {
+        return mText;
+    }
+
+    /**
+     * The dictionary description of the translated text.
+     * TODO: Describe the result structure.
+     */
+    @DataClass.Generated.Member
+    public @Nullable CharSequence getDictionaryDescription() {
+        return mDictionaryDescription;
+    }
+
+    /**
+     * The transliteration result of the translated text.
+     * TODO: Describe the result structure.
+     */
+    @DataClass.Generated.Member
+    public @Nullable CharSequence getTransliteration() {
+        return mTransliteration;
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public String toString() {
+        // You can override field toString logic by defining methods like:
+        // String fieldNameToString() { ... }
+
+        return "TranslationResponseValue { " +
+                "statusCode = " + statusToString(mStatusCode) + ", " +
+                "text = " + mText + ", " +
+                "dictionaryDescription = " + mDictionaryDescription + ", " +
+                "transliteration = " + mTransliteration +
+        " }";
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public boolean equals(@Nullable Object o) {
+        // You can override field equality logic by defining either of the methods like:
+        // boolean fieldNameEquals(TranslationResponseValue other) { ... }
+        // boolean fieldNameEquals(FieldType otherValue) { ... }
+
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        @SuppressWarnings("unchecked")
+        TranslationResponseValue that = (TranslationResponseValue) o;
+        //noinspection PointlessBooleanExpression
+        return true
+                && mStatusCode == that.mStatusCode
+                && Objects.equals(mText, that.mText)
+                && Objects.equals(mDictionaryDescription, that.mDictionaryDescription)
+                && Objects.equals(mTransliteration, that.mTransliteration);
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int hashCode() {
+        // You can override field hashCode logic by defining methods like:
+        // int fieldNameHashCode() { ... }
+
+        int _hash = 1;
+        _hash = 31 * _hash + mStatusCode;
+        _hash = 31 * _hash + Objects.hashCode(mText);
+        _hash = 31 * _hash + Objects.hashCode(mDictionaryDescription);
+        _hash = 31 * _hash + Objects.hashCode(mTransliteration);
+        return _hash;
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        // You can override field parcelling by defining methods like:
+        // void parcelFieldName(Parcel dest, int flags) { ... }
+
+        byte flg = 0;
+        if (mText != null) flg |= 0x2;
+        if (mDictionaryDescription != null) flg |= 0x4;
+        if (mTransliteration != null) flg |= 0x8;
+        dest.writeByte(flg);
+        dest.writeInt(mStatusCode);
+        if (mText != null) dest.writeCharSequence(mText);
+        if (mDictionaryDescription != null) dest.writeCharSequence(mDictionaryDescription);
+        if (mTransliteration != null) dest.writeCharSequence(mTransliteration);
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int describeContents() { return 0; }
+
+    /** @hide */
+    @SuppressWarnings({"unchecked", "RedundantCast"})
+    @DataClass.Generated.Member
+    /* package-private */ TranslationResponseValue(@NonNull Parcel in) {
+        // You can override field unparcelling by defining methods like:
+        // static FieldType unparcelFieldName(Parcel in) { ... }
+
+        byte flg = in.readByte();
+        int statusCode = in.readInt();
+        CharSequence text = (flg & 0x2) == 0 ? null : (CharSequence) in.readCharSequence();
+        CharSequence dictionaryDescription = (flg & 0x4) == 0 ? null : (CharSequence) in.readCharSequence();
+        CharSequence transliteration = (flg & 0x8) == 0 ? null : (CharSequence) in.readCharSequence();
+
+        this.mStatusCode = statusCode;
+
+        if (!(mStatusCode == STATUS_SUCCESS)
+                && !(mStatusCode == STATUS_ERROR)) {
+            throw new java.lang.IllegalArgumentException(
+                    "statusCode was " + mStatusCode + " but must be one of: "
+                            + "STATUS_SUCCESS(" + STATUS_SUCCESS + "), "
+                            + "STATUS_ERROR(" + STATUS_ERROR + ")");
+        }
+
+        this.mText = text;
+        this.mDictionaryDescription = dictionaryDescription;
+        this.mTransliteration = transliteration;
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    @DataClass.Generated.Member
+    public static final @NonNull Parcelable.Creator<TranslationResponseValue> CREATOR
+            = new Parcelable.Creator<TranslationResponseValue>() {
+        @Override
+        public TranslationResponseValue[] newArray(int size) {
+            return new TranslationResponseValue[size];
+        }
+
+        @Override
+        public TranslationResponseValue createFromParcel(@NonNull Parcel in) {
+            return new TranslationResponseValue(in);
+        }
+    };
+
+    /**
+     * A builder for {@link TranslationResponseValue}
+     */
+    @SuppressWarnings("WeakerAccess")
+    @DataClass.Generated.Member
+    public static final class Builder extends BaseBuilder {
+
+        private @Status int mStatusCode;
+        private @Nullable CharSequence mText;
+        private @Nullable CharSequence mDictionaryDescription;
+        private @Nullable CharSequence mTransliteration;
+
+        private long mBuilderFieldsSet = 0L;
+
+        /**
+         * Creates a new Builder.
+         *
+         * @param statusCode
+         *   The status code of this {@link TranslationResponseValue}.
+         *
+         *   <p>If the status code is {@link #STATUS_ERROR}, no values are attached, and all getters will
+         *   return {@code null}.
+         */
+        public Builder(
+                @Status int statusCode) {
+            mStatusCode = statusCode;
+
+            if (!(mStatusCode == STATUS_SUCCESS)
+                    && !(mStatusCode == STATUS_ERROR)) {
+                throw new java.lang.IllegalArgumentException(
+                        "statusCode was " + mStatusCode + " but must be one of: "
+                                + "STATUS_SUCCESS(" + STATUS_SUCCESS + "), "
+                                + "STATUS_ERROR(" + STATUS_ERROR + ")");
+            }
+
+        }
+
+        /**
+         * The translated text result.
+         */
+        @DataClass.Generated.Member
+        public @NonNull Builder setText(@NonNull CharSequence value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x2;
+            mText = value;
+            return this;
+        }
+
+        /**
+         * The dictionary description of the translated text.
+         * TODO: Describe the result structure.
+         */
+        @DataClass.Generated.Member
+        public @NonNull Builder setDictionaryDescription(@NonNull CharSequence value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x4;
+            mDictionaryDescription = value;
+            return this;
+        }
+
+        /**
+         * The transliteration result of the translated text.
+         * TODO: Describe the result structure.
+         */
+        @DataClass.Generated.Member
+        public @NonNull Builder setTransliteration(@NonNull CharSequence value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x8;
+            mTransliteration = value;
+            return this;
+        }
+
+        /** Builds the instance. This builder should not be touched after calling this! */
+        public @NonNull TranslationResponseValue build() {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x10; // Mark builder used
+
+            if ((mBuilderFieldsSet & 0x2) == 0) {
+                mText = defaultText();
+            }
+            if ((mBuilderFieldsSet & 0x4) == 0) {
+                mDictionaryDescription = defaultDictionaryDescription();
+            }
+            if ((mBuilderFieldsSet & 0x8) == 0) {
+                mTransliteration = defaultTransliteration();
+            }
+            TranslationResponseValue o = new TranslationResponseValue(
+                    mStatusCode,
+                    mText,
+                    mDictionaryDescription,
+                    mTransliteration);
+            return o;
+        }
+
+        private void checkNotUsed() {
+            if ((mBuilderFieldsSet & 0x10) != 0) {
+                throw new IllegalStateException(
+                        "This Builder should not be reused. Use a new Builder instance instead");
+            }
+        }
+    }
+
+    @DataClass.Generated(
+            time = 1614983829716L,
+            codegenVersion = "1.0.22",
+            sourceFile = "frameworks/base/core/java/android/view/translation/TranslationResponseValue.java",
+            inputSignatures = "public static final  int STATUS_SUCCESS\npublic static final  int STATUS_ERROR\nprivate final @android.view.translation.TranslationResponseValue.Status int mStatusCode\nprivate final @android.annotation.Nullable java.lang.CharSequence mText\nprivate final @android.annotation.Nullable java.lang.CharSequence mDictionaryDescription\nprivate final @android.annotation.Nullable java.lang.CharSequence mTransliteration\npublic static @android.annotation.NonNull android.view.translation.TranslationResponseValue forError()\nprivate static  java.lang.CharSequence defaultText()\nprivate static  java.lang.CharSequence defaultDictionaryDescription()\nprivate static  java.lang.CharSequence defaultTransliteration()\nclass TranslationResponseValue extends java.lang.Object implements [android.os.Parcelable]\nclass BaseBuilder extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genBuilder=true, genToString=true, genEqualsHashCode=true, genHiddenConstDefs=true)\nclass BaseBuilder extends java.lang.Object implements []")
+    @Deprecated
+    private void __metadata() {}
+
+
+    //@formatter:on
+    // End of generated code
+
+}
diff --git a/core/java/android/view/translation/Translator.java b/core/java/android/view/translation/Translator.java
index 163f832..3e1e6db 100644
--- a/core/java/android/view/translation/Translator.java
+++ b/core/java/android/view/translation/Translator.java
@@ -37,8 +37,6 @@
 
 import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.List;
 import java.util.Objects;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
@@ -234,7 +232,7 @@
      *
      * <p><strong>NOTE: </strong>Call on a worker thread.
      *
-     * @param request {@link TranslationRequest} request to be translated.
+     * @param request {@link TranslationRequest} request to be translate.
      *
      * @return {@link TranslationRequest} containing translated request,
      *         or null if translation could not be done.
@@ -250,17 +248,11 @@
             throw new IllegalStateException(
                     "This translator has been destroyed");
         }
-        final ArrayList<TranslationRequest> requests = new ArrayList<>();
-        requests.add(request);
-        final android.service.translation.TranslationRequest internalRequest =
-                new android.service.translation.TranslationRequest
-                        .Builder(getNextRequestId(), mSourceSpec, mDestSpec, requests)
-                        .build();
 
         TranslationResponse response = null;
         try {
             final SyncResultReceiver receiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS);
-            mDirectServiceBinder.onTranslationRequest(internalRequest, mId, null, receiver);
+            mDirectServiceBinder.onTranslationRequest(request, mId, null, receiver);
 
             response = receiver.getParcelableResult();
         } catch (RemoteException e) {
@@ -306,16 +298,12 @@
 
     // TODO: add methods for UI-toolkit case.
     /** @hide */
-    public void requestUiTranslate(@NonNull List<TranslationRequest> requests,
+    public void requestUiTranslate(@NonNull TranslationRequest request,
             @NonNull Consumer<TranslationResponse> responseCallback) {
         if (mDirectServiceBinder == null) {
             Log.wtf(TAG, "Translator created without proper initialization.");
             return;
         }
-        final android.service.translation.TranslationRequest request =
-                new android.service.translation.TranslationRequest
-                        .Builder(getNextRequestId(), mSourceSpec, mDestSpec, requests)
-                        .build();
         final ITranslationCallback callback =
                 new TranslationResponseCallbackImpl(responseCallback);
         try {
diff --git a/core/java/android/view/translation/UiTranslationController.java b/core/java/android/view/translation/UiTranslationController.java
index 8100612..cf3358b 100644
--- a/core/java/android/view/translation/UiTranslationController.java
+++ b/core/java/android/view/translation/UiTranslationController.java
@@ -31,6 +31,7 @@
 import android.util.ArrayMap;
 import android.util.Log;
 import android.util.Pair;
+import android.util.SparseArray;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewRootImpl;
@@ -160,19 +161,20 @@
             Log.w(TAG, "Fail result from TranslationService, response: " + response);
             return;
         }
-        final List<TranslationRequest> translatedResult = response.getTranslations();
+        final SparseArray<ViewTranslationResponse> translatedResult =
+                response.getViewTranslationResponses();
         onTranslationCompleted(translatedResult);
     }
 
-    private void onTranslationCompleted(List<TranslationRequest> translatedResult) {
+    private void onTranslationCompleted(SparseArray<ViewTranslationResponse> translatedResult) {
         if (!mActivity.isResumed()) {
             return;
         }
         final int resultCount = translatedResult.size();
         synchronized (mLock) {
             for (int i = 0; i < resultCount; i++) {
-                final TranslationRequest request = translatedResult.get(i);
-                final AutofillId autofillId = request.getAutofillId();
+                final ViewTranslationResponse response = translatedResult.get(i);
+                final AutofillId autofillId = response.getAutofillId();
                 if (autofillId == null) {
                     continue;
                 }
@@ -182,7 +184,7 @@
                             + " may be gone.");
                     continue;
                 }
-                mActivity.runOnUiThread(() -> view.onTranslationComplete(request));
+                mActivity.runOnUiThread(() -> view.onTranslationComplete(response));
             }
         }
     }
@@ -205,8 +207,11 @@
 
     @WorkerThread
     private void sendTranslationRequest(Translator translator,
-            ArrayList<TranslationRequest> requests) {
-        translator.requestUiTranslate(requests, this::onTranslationCompleted);
+            List<ViewTranslationRequest> requests) {
+        final TranslationRequest request = new TranslationRequest.Builder()
+                .setViewTranslationRequests(requests)
+                .build();
+        translator.requestUiTranslate(request, this::onTranslationCompleted);
     }
 
     /**
@@ -215,17 +220,17 @@
     private void onUiTranslationStarted(Translator translator, List<AutofillId> views) {
         synchronized (mLock) {
             // Find Views collect the translation data
-            final ArrayList<TranslationRequest> requests = new ArrayList<>();
+            final ArrayList<ViewTranslationRequest> requests = new ArrayList<>();
             final ArrayList<View> foundViews = new ArrayList<>();
             findViewsTraversalByAutofillIds(views, foundViews);
             for (int i = 0; i < foundViews.size(); i++) {
                 final View view = foundViews.get(i);
                 final int currentCount = i;
                 mActivity.runOnUiThread(() -> {
-                    final TranslationRequest translationRequest = view.onCreateTranslationRequest();
-                    if (translationRequest != null
-                            && translationRequest.getTranslationText().length() > 0) {
-                        requests.add(translationRequest);
+                    final ViewTranslationRequest request = view.onCreateTranslationRequest();
+                    if (request != null
+                            && request.getKeys().size() > 0) {
+                        requests.add(request);
                     }
                     if (currentCount == (foundViews.size() - 1)) {
                         Log.v(TAG, "onUiTranslationStarted: send " + requests.size() + " request.");
diff --git a/core/java/android/view/translation/TranslationData.aidl b/core/java/android/view/translation/ViewTranslationRequest.aidl
similarity index 86%
rename from core/java/android/view/translation/TranslationData.aidl
rename to core/java/android/view/translation/ViewTranslationRequest.aidl
index 40f21a6..b50acd6 100644
--- a/core/java/android/view/translation/TranslationData.aidl
+++ b/core/java/android/view/translation/ViewTranslationRequest.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -16,4 +16,4 @@
 
 package android.view.translation;
 
-parcelable TranslationData;
+parcelable ViewTranslationRequest;
diff --git a/core/java/android/view/translation/ViewTranslationRequest.java b/core/java/android/view/translation/ViewTranslationRequest.java
new file mode 100644
index 0000000..180b1c2
--- /dev/null
+++ b/core/java/android/view/translation/ViewTranslationRequest.java
@@ -0,0 +1,305 @@
+/*
+ * 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.view.translation;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.ArrayMap;
+import android.view.autofill.AutofillId;
+
+import com.android.internal.util.DataClass;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * Wrapper class representing a translation request associated with a {@link android.view.View} to
+ * be used by {@link android.service.translation.TranslationService}.
+ */
+@DataClass(genBuilder = true, genToString = true, genEqualsHashCode = true, genGetters = false)
+public final class ViewTranslationRequest implements Parcelable {
+
+    /**
+     * Constant id for the default view text to be translated. This is used by
+     * {@link Builder#setValue(String, TranslationRequestValue)}.
+     */
+    public static final String ID_TEXT = "text";
+
+    /**
+     * The {@link AutofillId} of the view associated with this request.
+     */
+    @NonNull
+    private final AutofillId mAutofillId;
+
+    @NonNull
+    @DataClass.PluralOf("translationRequestValue")
+    private final Map<String, TranslationRequestValue> mTranslationRequestValues;
+
+    /**
+     * Gets the corresponding {@link TranslationRequestValue} of the provided key.
+     * @param key String id of the translation request value to be translated.
+     * @return the {@link TranslationRequestValue}.
+     * @throws IllegalArgumentException if the key does not exist.
+     */
+    @NonNull
+    public TranslationRequestValue getValue(@NonNull String key) {
+        Objects.requireNonNull(key, "key should not be null");
+        if (!mTranslationRequestValues.containsKey(key)) {
+            throw new IllegalArgumentException("Request does not contain value for key=" + key);
+        }
+        return mTranslationRequestValues.get(key);
+    }
+
+    /**
+     * Returns all keys in this request as a {@link Set} of Strings. The keys are used by
+     * {@link #getValue(String)} to get the {@link TranslationRequestValue}s.
+     */
+    @NonNull
+    public Set<String> getKeys() {
+        return mTranslationRequestValues.keySet();
+    }
+
+
+    /**
+     * Returns the associated {@link AutofillId} of this request.
+     */
+    @NonNull
+    public AutofillId getAutofillId() {
+        return mAutofillId;
+    }
+
+    private static Map<String, TranslationRequestValue> defaultTranslationRequestValues() {
+        return Collections.emptyMap();
+    }
+
+    @DataClass.Suppress({"addTranslationRequestValue", "setAutofillId"})
+    abstract static class BaseBuilder {
+
+        abstract Builder setTranslationRequestValues(Map<String, TranslationRequestValue> value);
+
+        /**
+         * Sets the corresponding {@link TranslationRequestValue} for the provided key.
+         *
+         * @param key The key for this translation request value.
+         * @param value the translation request value holding the content to be translated.
+         * @return this builder.
+         */
+        @SuppressLint("MissingGetterMatchingBuilder")
+        public Builder setValue(String key,
+                TranslationRequestValue value) {
+            final Builder builder = (Builder) this;
+            if (builder.mTranslationRequestValues == null) {
+                setTranslationRequestValues(new ArrayMap<>());
+            }
+            builder.mTranslationRequestValues.put(key, value);
+            return builder;
+        }
+    }
+
+
+
+    // Code below generated by codegen v1.0.22.
+    //
+    // DO NOT MODIFY!
+    // CHECKSTYLE:OFF Generated code
+    //
+    // To regenerate run:
+    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/view/translation/ViewTranslationRequest.java
+    //
+    // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+    //   Settings > Editor > Code Style > Formatter Control
+    //@formatter:off
+
+
+    @DataClass.Generated.Member
+    /* package-private */ ViewTranslationRequest(
+            @NonNull AutofillId autofillId,
+            @NonNull Map<String,TranslationRequestValue> translationRequestValues) {
+        this.mAutofillId = autofillId;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mAutofillId);
+        this.mTranslationRequestValues = translationRequestValues;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mTranslationRequestValues);
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public String toString() {
+        // You can override field toString logic by defining methods like:
+        // String fieldNameToString() { ... }
+
+        return "ViewTranslationRequest { " +
+                "autofillId = " + mAutofillId + ", " +
+                "translationRequestValues = " + mTranslationRequestValues +
+        " }";
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public boolean equals(@Nullable Object o) {
+        // You can override field equality logic by defining either of the methods like:
+        // boolean fieldNameEquals(ViewTranslationRequest other) { ... }
+        // boolean fieldNameEquals(FieldType otherValue) { ... }
+
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        @SuppressWarnings("unchecked")
+        ViewTranslationRequest that = (ViewTranslationRequest) o;
+        //noinspection PointlessBooleanExpression
+        return true
+                && Objects.equals(mAutofillId, that.mAutofillId)
+                && Objects.equals(mTranslationRequestValues, that.mTranslationRequestValues);
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int hashCode() {
+        // You can override field hashCode logic by defining methods like:
+        // int fieldNameHashCode() { ... }
+
+        int _hash = 1;
+        _hash = 31 * _hash + Objects.hashCode(mAutofillId);
+        _hash = 31 * _hash + Objects.hashCode(mTranslationRequestValues);
+        return _hash;
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        // You can override field parcelling by defining methods like:
+        // void parcelFieldName(Parcel dest, int flags) { ... }
+
+        dest.writeTypedObject(mAutofillId, flags);
+        dest.writeMap(mTranslationRequestValues);
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int describeContents() { return 0; }
+
+    /** @hide */
+    @SuppressWarnings({"unchecked", "RedundantCast"})
+    @DataClass.Generated.Member
+    /* package-private */ ViewTranslationRequest(@NonNull Parcel in) {
+        // You can override field unparcelling by defining methods like:
+        // static FieldType unparcelFieldName(Parcel in) { ... }
+
+        AutofillId autofillId = (AutofillId) in.readTypedObject(AutofillId.CREATOR);
+        Map<String,TranslationRequestValue> translationRequestValues = new java.util.LinkedHashMap<>();
+        in.readMap(translationRequestValues, TranslationRequestValue.class.getClassLoader());
+
+        this.mAutofillId = autofillId;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mAutofillId);
+        this.mTranslationRequestValues = translationRequestValues;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mTranslationRequestValues);
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    @DataClass.Generated.Member
+    public static final @NonNull Parcelable.Creator<ViewTranslationRequest> CREATOR
+            = new Parcelable.Creator<ViewTranslationRequest>() {
+        @Override
+        public ViewTranslationRequest[] newArray(int size) {
+            return new ViewTranslationRequest[size];
+        }
+
+        @Override
+        public ViewTranslationRequest createFromParcel(@NonNull Parcel in) {
+            return new ViewTranslationRequest(in);
+        }
+    };
+
+    /**
+     * A builder for {@link ViewTranslationRequest}
+     */
+    @SuppressWarnings("WeakerAccess")
+    @DataClass.Generated.Member
+    public static final class Builder extends BaseBuilder {
+
+        private @NonNull AutofillId mAutofillId;
+        private @NonNull Map<String,TranslationRequestValue> mTranslationRequestValues;
+
+        private long mBuilderFieldsSet = 0L;
+
+        /**
+         * Creates a new Builder.
+         *
+         * @param autofillId
+         *   The {@link AutofillId} of the view associated with this request.
+         */
+        public Builder(
+                @NonNull AutofillId autofillId) {
+            mAutofillId = autofillId;
+            com.android.internal.util.AnnotationValidations.validate(
+                    NonNull.class, null, mAutofillId);
+        }
+
+        @DataClass.Generated.Member
+        @Override
+        @NonNull Builder setTranslationRequestValues(@NonNull Map<String,TranslationRequestValue> value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x2;
+            mTranslationRequestValues = value;
+            return this;
+        }
+
+        /** Builds the instance. This builder should not be touched after calling this! */
+        public @NonNull ViewTranslationRequest build() {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x4; // Mark builder used
+
+            if ((mBuilderFieldsSet & 0x2) == 0) {
+                mTranslationRequestValues = defaultTranslationRequestValues();
+            }
+            ViewTranslationRequest o = new ViewTranslationRequest(
+                    mAutofillId,
+                    mTranslationRequestValues);
+            return o;
+        }
+
+        private void checkNotUsed() {
+            if ((mBuilderFieldsSet & 0x4) != 0) {
+                throw new IllegalStateException(
+                        "This Builder should not be reused. Use a new Builder instance instead");
+            }
+        }
+    }
+
+    @DataClass.Generated(
+            time = 1614992269658L,
+            codegenVersion = "1.0.22",
+            sourceFile = "frameworks/base/core/java/android/view/translation/ViewTranslationRequest.java",
+            inputSignatures = "public static final  java.lang.String ID_TEXT\nprivate final @android.annotation.NonNull android.view.autofill.AutofillId mAutofillId\nprivate final @android.annotation.NonNull @com.android.internal.util.DataClass.PluralOf(\"translationRequestValue\") java.util.Map<java.lang.String,android.view.translation.TranslationRequestValue> mTranslationRequestValues\npublic @android.annotation.NonNull android.view.translation.TranslationRequestValue getValue(java.lang.String)\npublic @android.annotation.NonNull java.util.Set<java.lang.String> getKeys()\npublic @android.annotation.NonNull android.view.autofill.AutofillId getAutofillId()\nprivate static  java.util.Map<java.lang.String,android.view.translation.TranslationRequestValue> defaultTranslationRequestValues()\nclass ViewTranslationRequest extends java.lang.Object implements [android.os.Parcelable]\nabstract  android.view.translation.ViewTranslationRequest.Builder setTranslationRequestValues(java.util.Map<java.lang.String,android.view.translation.TranslationRequestValue>)\npublic @android.annotation.SuppressLint android.view.translation.ViewTranslationRequest.Builder setValue(java.lang.String,android.view.translation.TranslationRequestValue)\nclass BaseBuilder extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genBuilder=true, genToString=true, genEqualsHashCode=true, genGetters=false)\nabstract  android.view.translation.ViewTranslationRequest.Builder setTranslationRequestValues(java.util.Map<java.lang.String,android.view.translation.TranslationRequestValue>)\npublic @android.annotation.SuppressLint android.view.translation.ViewTranslationRequest.Builder setValue(java.lang.String,android.view.translation.TranslationRequestValue)\nclass BaseBuilder extends java.lang.Object implements []")
+    @Deprecated
+    private void __metadata() {}
+
+
+    //@formatter:on
+    // End of generated code
+
+}
diff --git a/core/java/android/view/translation/TranslationData.aidl b/core/java/android/view/translation/ViewTranslationResponse.aidl
similarity index 86%
copy from core/java/android/view/translation/TranslationData.aidl
copy to core/java/android/view/translation/ViewTranslationResponse.aidl
index 40f21a6..b906b13 100644
--- a/core/java/android/view/translation/TranslationData.aidl
+++ b/core/java/android/view/translation/ViewTranslationResponse.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -16,4 +16,4 @@
 
 package android.view.translation;
 
-parcelable TranslationData;
+parcelable ViewTranslationResponse;
diff --git a/core/java/android/view/translation/ViewTranslationResponse.java b/core/java/android/view/translation/ViewTranslationResponse.java
new file mode 100644
index 0000000..d993114
--- /dev/null
+++ b/core/java/android/view/translation/ViewTranslationResponse.java
@@ -0,0 +1,299 @@
+/*
+ * 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.view.translation;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.ArrayMap;
+import android.view.autofill.AutofillId;
+
+import com.android.internal.util.DataClass;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * Wrapper class representing a translation response associated with a {@link android.view.View} to
+ * be used by {@link android.service.translation.TranslationService}.
+ */
+@DataClass(genBuilder = true, genToString = true, genEqualsHashCode = true, genGetters = false)
+public final class ViewTranslationResponse implements Parcelable {
+
+    /**
+     * The {@link AutofillId} of the view associated with this response.
+     */
+    @NonNull
+    private final AutofillId mAutofillId;
+
+    @NonNull
+    @DataClass.PluralOf("translationResponseValue")
+    private final Map<String, TranslationResponseValue> mTranslationResponseValues;
+
+    /**
+     * Gets the {@link TranslationResponseValue} of the corresponding key.
+     * @param key String id of the translated translation response value.
+     * @return the {@link TranslationResponseValue}.
+     * @throws IllegalArgumentException if the key does not exist.
+     */
+    @NonNull
+    public TranslationResponseValue getValue(@NonNull String key) {
+        Objects.requireNonNull(key);
+        if (!mTranslationResponseValues.containsKey(key)) {
+            throw new IllegalArgumentException("Request does not contain value for key=" + key);
+        }
+        return mTranslationResponseValues.get(key);
+    }
+
+    /**
+     * Returns all keys in this response as a {@link Set} of Strings. The keys are used by
+     * {@link #getValue(String)} to get the {@link TranslationResponseValue}s.
+     */
+    @NonNull
+    public Set<String> getKeys() {
+        return mTranslationResponseValues.keySet();
+    }
+
+
+    /**
+     * Returns the associated {@link AutofillId} of this response.
+     */
+    @NonNull
+    public AutofillId getAutofillId() {
+        return mAutofillId;
+    }
+
+    private static Map<String, TranslationResponseValue> defaultTranslationResponseValues() {
+        return Collections.emptyMap();
+    }
+
+    @DataClass.Suppress({"addTranslationResponseValue", "setAutofillId"})
+    abstract static class BaseBuilder {
+
+        abstract Builder setTranslationResponseValues(Map<String, TranslationResponseValue> value);
+
+        /**
+         * Sets the corresponding {@link TranslationResponseValue} for the provided key.
+         *
+         * @param key The key for this translation response value.
+         * @param value the translation response value holding the translated content.
+         * @return this builder.
+         */
+        @SuppressLint("MissingGetterMatchingBuilder")
+        public Builder setValue(String key,
+                TranslationResponseValue value) {
+            final Builder builder = (Builder) this;
+            if (builder.mTranslationResponseValues == null) {
+                setTranslationResponseValues(new ArrayMap<>());
+            }
+            builder.mTranslationResponseValues.put(key, value);
+            return builder;
+        }
+    }
+
+
+
+    // Code below generated by codegen v1.0.22.
+    //
+    // DO NOT MODIFY!
+    // CHECKSTYLE:OFF Generated code
+    //
+    // To regenerate run:
+    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/view/translation/ViewTranslationResponse.java
+    //
+    // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+    //   Settings > Editor > Code Style > Formatter Control
+    //@formatter:off
+
+
+    @DataClass.Generated.Member
+    /* package-private */ ViewTranslationResponse(
+            @NonNull AutofillId autofillId,
+            @NonNull Map<String,TranslationResponseValue> translationResponseValues) {
+        this.mAutofillId = autofillId;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mAutofillId);
+        this.mTranslationResponseValues = translationResponseValues;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mTranslationResponseValues);
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public String toString() {
+        // You can override field toString logic by defining methods like:
+        // String fieldNameToString() { ... }
+
+        return "ViewTranslationResponse { " +
+                "autofillId = " + mAutofillId + ", " +
+                "translationResponseValues = " + mTranslationResponseValues +
+        " }";
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public boolean equals(@Nullable Object o) {
+        // You can override field equality logic by defining either of the methods like:
+        // boolean fieldNameEquals(ViewTranslationResponse other) { ... }
+        // boolean fieldNameEquals(FieldType otherValue) { ... }
+
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        @SuppressWarnings("unchecked")
+        ViewTranslationResponse that = (ViewTranslationResponse) o;
+        //noinspection PointlessBooleanExpression
+        return true
+                && Objects.equals(mAutofillId, that.mAutofillId)
+                && Objects.equals(mTranslationResponseValues, that.mTranslationResponseValues);
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int hashCode() {
+        // You can override field hashCode logic by defining methods like:
+        // int fieldNameHashCode() { ... }
+
+        int _hash = 1;
+        _hash = 31 * _hash + Objects.hashCode(mAutofillId);
+        _hash = 31 * _hash + Objects.hashCode(mTranslationResponseValues);
+        return _hash;
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        // You can override field parcelling by defining methods like:
+        // void parcelFieldName(Parcel dest, int flags) { ... }
+
+        dest.writeTypedObject(mAutofillId, flags);
+        dest.writeMap(mTranslationResponseValues);
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int describeContents() { return 0; }
+
+    /** @hide */
+    @SuppressWarnings({"unchecked", "RedundantCast"})
+    @DataClass.Generated.Member
+    /* package-private */ ViewTranslationResponse(@NonNull Parcel in) {
+        // You can override field unparcelling by defining methods like:
+        // static FieldType unparcelFieldName(Parcel in) { ... }
+
+        AutofillId autofillId = (AutofillId) in.readTypedObject(AutofillId.CREATOR);
+        Map<String,TranslationResponseValue> translationResponseValues = new java.util.LinkedHashMap<>();
+        in.readMap(translationResponseValues, TranslationResponseValue.class.getClassLoader());
+
+        this.mAutofillId = autofillId;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mAutofillId);
+        this.mTranslationResponseValues = translationResponseValues;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mTranslationResponseValues);
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    @DataClass.Generated.Member
+    public static final @NonNull Parcelable.Creator<ViewTranslationResponse> CREATOR
+            = new Parcelable.Creator<ViewTranslationResponse>() {
+        @Override
+        public ViewTranslationResponse[] newArray(int size) {
+            return new ViewTranslationResponse[size];
+        }
+
+        @Override
+        public ViewTranslationResponse createFromParcel(@NonNull Parcel in) {
+            return new ViewTranslationResponse(in);
+        }
+    };
+
+    /**
+     * A builder for {@link ViewTranslationResponse}
+     */
+    @SuppressWarnings("WeakerAccess")
+    @DataClass.Generated.Member
+    public static final class Builder extends BaseBuilder {
+
+        private @NonNull AutofillId mAutofillId;
+        private @NonNull Map<String,TranslationResponseValue> mTranslationResponseValues;
+
+        private long mBuilderFieldsSet = 0L;
+
+        /**
+         * Creates a new Builder.
+         *
+         * @param autofillId
+         *   The {@link AutofillId} of the view associated with this response.
+         */
+        public Builder(
+                @NonNull AutofillId autofillId) {
+            mAutofillId = autofillId;
+            com.android.internal.util.AnnotationValidations.validate(
+                    NonNull.class, null, mAutofillId);
+        }
+
+        @DataClass.Generated.Member
+        @Override
+        @NonNull Builder setTranslationResponseValues(@NonNull Map<String,TranslationResponseValue> value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x2;
+            mTranslationResponseValues = value;
+            return this;
+        }
+
+        /** Builds the instance. This builder should not be touched after calling this! */
+        public @NonNull ViewTranslationResponse build() {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x4; // Mark builder used
+
+            if ((mBuilderFieldsSet & 0x2) == 0) {
+                mTranslationResponseValues = defaultTranslationResponseValues();
+            }
+            ViewTranslationResponse o = new ViewTranslationResponse(
+                    mAutofillId,
+                    mTranslationResponseValues);
+            return o;
+        }
+
+        private void checkNotUsed() {
+            if ((mBuilderFieldsSet & 0x4) != 0) {
+                throw new IllegalStateException(
+                        "This Builder should not be reused. Use a new Builder instance instead");
+            }
+        }
+    }
+
+    @DataClass.Generated(
+            time = 1614992272865L,
+            codegenVersion = "1.0.22",
+            sourceFile = "frameworks/base/core/java/android/view/translation/ViewTranslationResponse.java",
+            inputSignatures = "private final @android.annotation.NonNull android.view.autofill.AutofillId mAutofillId\nprivate final @android.annotation.NonNull @com.android.internal.util.DataClass.PluralOf(\"translationResponseValue\") java.util.Map<java.lang.String,android.view.translation.TranslationResponseValue> mTranslationResponseValues\npublic @android.annotation.NonNull android.view.translation.TranslationResponseValue getValue(java.lang.String)\npublic @android.annotation.NonNull java.util.Set<java.lang.String> getKeys()\npublic @android.annotation.NonNull android.view.autofill.AutofillId getAutofillId()\nprivate static  java.util.Map<java.lang.String,android.view.translation.TranslationResponseValue> defaultTranslationResponseValues()\nclass ViewTranslationResponse extends java.lang.Object implements [android.os.Parcelable]\nabstract  android.view.translation.ViewTranslationResponse.Builder setTranslationResponseValues(java.util.Map<java.lang.String,android.view.translation.TranslationResponseValue>)\npublic @android.annotation.SuppressLint android.view.translation.ViewTranslationResponse.Builder setValue(java.lang.String,android.view.translation.TranslationResponseValue)\nclass BaseBuilder extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genBuilder=true, genToString=true, genEqualsHashCode=true, genGetters=false)\nabstract  android.view.translation.ViewTranslationResponse.Builder setTranslationResponseValues(java.util.Map<java.lang.String,android.view.translation.TranslationResponseValue>)\npublic @android.annotation.SuppressLint android.view.translation.ViewTranslationResponse.Builder setValue(java.lang.String,android.view.translation.TranslationResponseValue)\nclass BaseBuilder extends java.lang.Object implements []")
+    @Deprecated
+    private void __metadata() {}
+
+
+    //@formatter:on
+    // End of generated code
+
+}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index ca0747f..fdc66fc 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -194,7 +194,9 @@
 import android.view.textclassifier.TextLinks;
 import android.view.textservice.SpellCheckerSubtype;
 import android.view.textservice.TextServicesManager;
-import android.view.translation.TranslationRequest;
+import android.view.translation.TranslationRequestValue;
+import android.view.translation.ViewTranslationRequest;
+import android.view.translation.ViewTranslationResponse;
 import android.widget.RemoteViews.RemoteView;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -13817,7 +13819,7 @@
     }
 
     /**
-     * Provides a {@link TranslationRequest} that represents the content to be translated via
+     * Provides a {@link ViewTranslationRequest} that represents the content to be translated via
      * translation service.
      *
      * <p>NOTE: When overriding the method, it should not translate the password. We also suggest
@@ -13831,7 +13833,7 @@
      */
     @Nullable
     @Override
-    public TranslationRequest onCreateTranslationRequest() {
+    public ViewTranslationRequest onCreateTranslationRequest() {
         if (mText == null || mText.length() == 0) {
             return null;
         }
@@ -13843,11 +13845,12 @@
             return null;
         }
         // TODO(b/176488462): apply the view's important for translation property
-        // TODO(b/174283799): remove the spans from the mText and save the spans informatopn
-        TranslationRequest request =
-                new TranslationRequest.Builder()
-                        .setAutofillId(getAutofillId())
-                        .setTranslationText(mText)
+        // TODO(b/174283799): remove the spans from the mText and save the spans information
+        // TODO: use fixed ids for request texts.
+        ViewTranslationRequest request =
+                new ViewTranslationRequest.Builder(getAutofillId())
+                        .setValue(ViewTranslationRequest.ID_TEXT,
+                                TranslationRequestValue.forText(mText))
                         .build();
         return request;
     }
@@ -13923,12 +13926,12 @@
      * @hide
      */
     @Override
-    public void onTranslationComplete(@NonNull TranslationRequest data) {
+    public void onTranslationComplete(@NonNull ViewTranslationResponse response) {
         // Show the translated text.
         TransformationMethod originalTranslationMethod = mTranslationTransformation != null
                 ? mTranslationTransformation.getOriginalTransformationMethod() : mTransformation;
         mTranslationTransformation =
-                new TranslationTransformationMethod(data, originalTranslationMethod);
+                new TranslationTransformationMethod(response, originalTranslationMethod);
         // TODO(b/178353965): well-handle setTransformationMethod.
         setTransformationMethod(mTranslationTransformation);
     }
diff --git a/core/java/android/window/TaskOrganizer.java b/core/java/android/window/TaskOrganizer.java
index 217ade8..04020ec 100644
--- a/core/java/android/window/TaskOrganizer.java
+++ b/core/java/android/window/TaskOrganizer.java
@@ -52,7 +52,7 @@
     /** @hide */
     @VisibleForTesting
     public TaskOrganizer(ITaskOrganizerController taskOrganizerController, Executor executor) {
-        mExecutor = executor != null ? executor : command -> command.run();
+        mExecutor = executor != null ? executor : Runnable::run;
         mTaskOrganizerController = taskOrganizerController != null
                 ? taskOrganizerController : getController();
     }
diff --git a/core/java/com/android/internal/jank/FrameTracker.java b/core/java/com/android/internal/jank/FrameTracker.java
index db0b48e..5829047 100644
--- a/core/java/com/android/internal/jank/FrameTracker.java
+++ b/core/java/com/android/internal/jank/FrameTracker.java
@@ -16,7 +16,6 @@
 
 package com.android.internal.jank;
 
-import static android.view.SurfaceControl.JankData.BUFFER_STUFFING;
 import static android.view.SurfaceControl.JankData.DISPLAY_HAL;
 import static android.view.SurfaceControl.JankData.JANK_APP_DEADLINE_MISSED;
 import static android.view.SurfaceControl.JankData.JANK_NONE;
@@ -42,6 +41,7 @@
 import android.view.ThreadedRenderer;
 import android.view.ViewRootImpl;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.jank.InteractionJankMonitor.Session;
 import com.android.internal.util.FrameworkStatsLog;
 
@@ -121,7 +121,8 @@
         mChoreographer = choreographer;
         mSurfaceControlWrapper = surfaceControlWrapper;
         mHandler = handler;
-        mObserver = new HardwareRendererObserver(this, mMetricsWrapper.getTiming(), handler);
+        mObserver = new HardwareRendererObserver(
+                this, mMetricsWrapper.getTiming(), handler, false /*waitForPresentTime*/);
         mTraceThresholdMissedFrames = traceThresholdMissedFrames;
         mTraceThresholdFrameTimeMillis = traceThresholdFrameTimeMillis;
         mListener = listener;
@@ -162,6 +163,8 @@
                 }, 50);
             }
         };
+
+        // This callback has a reference to FrameTracker, remember to remove it to avoid leakage.
         viewRootWrapper.addSurfaceChangedCallback(mSurfaceChangedCallback);
     }
 
@@ -186,9 +189,13 @@
      */
     public synchronized void end() {
         mEndVsyncId = mChoreographer.getVsyncId();
-        Trace.endAsyncSection(mSession.getName(), (int) mBeginVsyncId);
-        if (mEndVsyncId == mBeginVsyncId) {
+        // Cancel the session if:
+        // 1. The session begins and ends at the same vsync id.
+        // 2. The session never begun.
+        if (mEndVsyncId == mBeginVsyncId || mBeginVsyncId == INVALID_ID) {
             cancel();
+        } else {
+            Trace.endAsyncSection(mSession.getName(), (int) mBeginVsyncId);
         }
         // We don't remove observer here,
         // will remove it when all the frame metrics in this duration are called back.
@@ -199,11 +206,19 @@
      * Cancel the trace session of the CUJ.
      */
     public synchronized void cancel() {
-        if (mBeginVsyncId == INVALID_ID || mEndVsyncId != INVALID_ID) return;
-        Trace.endAsyncSection(mSession.getName(), (int) mBeginVsyncId);
+        // The session is ongoing, end the trace session.
+        // That means the cancel call is from external invocation, not from end().
+        if (mBeginVsyncId != INVALID_ID && mEndVsyncId == INVALID_ID) {
+            Trace.endAsyncSection(mSession.getName(), (int) mBeginVsyncId);
+        }
         mCancelled = true;
+
+        // Always remove the observers in cancel call to avoid leakage.
         removeObservers();
-        if (mListener != null) {
+
+        // Notify the listener the session has been cancelled.
+        // We don't notify the listeners if the session never begun.
+        if (mListener != null && mBeginVsyncId != INVALID_ID) {
             mListener.onNotifyCujEvents(mSession, InteractionJankMonitor.ACTION_SESSION_CANCEL);
         }
     }
@@ -392,7 +407,11 @@
         }
     }
 
-    private void removeObservers() {
+    /**
+     * Remove all the registered listeners, observers and callbacks.
+     */
+    @VisibleForTesting
+    public void removeObservers() {
         mRendererWrapper.removeObserver(mObserver);
         mSurfaceControlWrapper.removeJankStatsListener(this);
         if (mSurfaceChangedCallback != null) {
diff --git a/core/java/com/android/internal/os/AmbientDisplayPowerCalculator.java b/core/java/com/android/internal/os/AmbientDisplayPowerCalculator.java
index e153eb2..586607e 100644
--- a/core/java/com/android/internal/os/AmbientDisplayPowerCalculator.java
+++ b/core/java/com/android/internal/os/AmbientDisplayPowerCalculator.java
@@ -46,7 +46,8 @@
             long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) {
         final long durationMs = calculateDuration(batteryStats, rawRealtimeUs,
                 BatteryStats.STATS_SINCE_CHARGED);
-        final double powerMah = getMeasuredOrEstimatedPower(batteryStats.getScreenDozeEnergy(),
+        final double powerMah = getMeasuredOrEstimatedPower(
+                batteryStats.getScreenDozeMeasuredBatteryConsumptionUC(),
                 mPowerEstimator, durationMs, query.shouldForceUsePowerProfileModel());
         builder.getOrCreateSystemBatteryConsumerBuilder(
                         SystemBatteryConsumer.DRAIN_TYPE_AMBIENT_DISPLAY)
@@ -64,7 +65,8 @@
     public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats,
             long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) {
         final long durationMs = calculateDuration(batteryStats, rawRealtimeUs, statsType);
-        final double powerMah = getMeasuredOrEstimatedPower(batteryStats.getScreenDozeEnergy(),
+        final double powerMah = getMeasuredOrEstimatedPower(
+                batteryStats.getScreenDozeMeasuredBatteryConsumptionUC(),
                 mPowerEstimator, durationMs, false);
         if (powerMah > 0) {
             BatterySipper bs = new BatterySipper(BatterySipper.DrainType.AMBIENT_DISPLAY, null, 0);
@@ -78,5 +80,4 @@
     private long calculateDuration(BatteryStats batteryStats, long rawRealtimeUs, int statsType) {
         return batteryStats.getScreenDozeTime(rawRealtimeUs, statsType) / 1000;
     }
-
 }
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 73527d4..9ecb0ad 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -105,7 +105,7 @@
 import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidUserSysTimeReader;
 import com.android.internal.os.SystemServerCpuThreadReader.SystemServiceCpuThreadTimes;
 import com.android.internal.power.MeasuredEnergyStats;
-import com.android.internal.power.MeasuredEnergyStats.StandardEnergyBucket;
+import com.android.internal.power.MeasuredEnergyStats.StandardPowerBucket;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FrameworkStatsLog;
 import com.android.internal.util.XmlUtils;
@@ -169,7 +169,7 @@
     private static final int MAGIC = 0xBA757475; // 'BATSTATS'
 
     // Current on-disk Parcel version
-    static final int VERSION = 193;
+    static final int VERSION = 194;
 
     // The maximum number of names wakelocks we will keep track of
     // per uid; once the limit is reached, we batch the remaining wakelocks
@@ -996,9 +996,9 @@
     int mWifiRadioPowerState = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
 
     /**
-     * Accumulated global (generally, device-wide total) energy consumption of various consumers
+     * Accumulated global (generally, device-wide total) charge consumption of various consumers
      * while on battery.
-     * Its '<b>custom</b> energy buckets' correspond to the
+     * Its '<b>custom</b> power buckets' correspond to the
      * {@link android.hardware.power.stats.EnergyConsumer.ordinal}s of (custom) energy consumer
      * type {@link android.hardware.power.stats.EnergyConsumerType#OTHER}).
      *
@@ -1009,6 +1009,8 @@
     protected @Nullable MeasuredEnergyStats mGlobalMeasuredEnergyStats;
     /** Last known screen state. Needed for apportioning display energy. */
     int mScreenStateAtLastEnergyMeasurement = Display.STATE_UNKNOWN;
+    /** Cpu Power calculator for attributing measured cpu charge consumption to uids */
+    @Nullable CpuPowerCalculator mCpuPowerCalculator = null;
 
     /**
      * These provide time bases that discount the time the device is plugged
@@ -6965,35 +6967,35 @@
     }
 
     @Override
-    public long getScreenOnEnergy() {
-        return getMeasuredEnergyMicroJoules(MeasuredEnergyStats.ENERGY_BUCKET_SCREEN_ON);
+    public long getScreenOnMeasuredBatteryConsumptionUC() {
+        return getPowerBucketConsumptionUC(MeasuredEnergyStats.POWER_BUCKET_SCREEN_ON);
     }
 
     @Override
-    public long getScreenDozeEnergy() {
-        return getMeasuredEnergyMicroJoules(MeasuredEnergyStats.ENERGY_BUCKET_SCREEN_DOZE);
+    public long getScreenDozeMeasuredBatteryConsumptionUC() {
+        return getPowerBucketConsumptionUC(MeasuredEnergyStats.POWER_BUCKET_SCREEN_DOZE);
     }
 
     /**
-     * Returns the energy in microjoules that the given standard energy bucket consumed.
-     * Will return {@link #ENERGY_DATA_UNAVAILABLE} if data is unavailable
+     * Returns the consumption (in microcoulombs) that the given standard power bucket consumed.
+     * Will return {@link #POWER_DATA_UNAVAILABLE} if data is unavailable
      *
-     * @param bucket standard energy bucket of interest
-     * @return energy (in microjoules) used for this energy bucket
+     * @param bucket standard power bucket of interest
+     * @return charge (in microcoulombs) used for this power bucket
      */
-    private long getMeasuredEnergyMicroJoules(@StandardEnergyBucket int bucket) {
+    private long getPowerBucketConsumptionUC(@StandardPowerBucket int bucket) {
         if (mGlobalMeasuredEnergyStats == null) {
-            return ENERGY_DATA_UNAVAILABLE;
+            return POWER_DATA_UNAVAILABLE;
         }
-        return mGlobalMeasuredEnergyStats.getAccumulatedStandardBucketEnergy(bucket);
+        return mGlobalMeasuredEnergyStats.getAccumulatedStandardBucketCharge(bucket);
     }
 
     @Override
-    public @Nullable long[] getCustomMeasuredEnergiesMicroJoules() {
+    public @Nullable long[] getCustomConsumerMeasuredBatteryConsumptionUC() {
         if (mGlobalMeasuredEnergyStats == null) {
             return null;
         }
-        return mGlobalMeasuredEnergyStats.getAccumulatedCustomBucketEnergies();
+        return mGlobalMeasuredEnergyStats.getAccumulatedCustomBucketCharges();
     }
 
     @Override public long getStartClockTime() {
@@ -7347,8 +7349,8 @@
         private final ArraySet<BinderCallStats> mBinderCallStats = new ArraySet<>();
 
         /**
-         * Measured energies attributed to this uid while on battery.
-         * Its '<b>custom</b> energy buckets' correspond to the
+         * Measured charge consumption by this uid while on battery.
+         * Its '<b>custom</b> power buckets' correspond to the
          * {@link android.hardware.power.stats.EnergyConsumer.ordinal}s of (custom) energy consumer
          * type {@link android.hardware.power.stats.EnergyConsumerType#OTHER}).
          *
@@ -7768,44 +7770,44 @@
             return mUidMeasuredEnergyStats;
         }
 
-        /** Adds the given energy to the given standard energy bucket for this uid. */
-        private void addEnergyToStandardBucketLocked(long energyDeltaUJ,
-                @StandardEnergyBucket int energyBucket) {
-            getOrCreateMeasuredEnergyStatsLocked()
-                    .updateStandardBucket(energyBucket, energyDeltaUJ);
+        /** Adds the given charge to the given standard power bucket for this uid. */
+        private void addChargeToStandardBucketLocked(long chargeDeltaUC,
+                @StandardPowerBucket int powerBucket) {
+            getOrCreateMeasuredEnergyStatsLocked().updateStandardBucket(powerBucket, chargeDeltaUC);
         }
 
-        /** Adds the given energy to the given custom energy bucket for this uid. */
-        private void addEnergyToCustomBucketLocked(long energyDeltaUJ, int energyBucket) {
-            getOrCreateMeasuredEnergyStatsLocked().updateCustomBucket(energyBucket, energyDeltaUJ);
+        /** Adds the given charge to the given custom power bucket for this uid. */
+        private void addChargeToCustomBucketLocked(long chargeDeltaUC, int powerBucket) {
+            getOrCreateMeasuredEnergyStatsLocked().updateCustomBucket(powerBucket, chargeDeltaUC);
         }
 
         /**
-         * Returns the energy used by this uid for a standard energy bucket of interest.
-         * @param bucket standard energy bucket of interest
-         * @return energy (in microjoules) used by this uid for this energy bucket
+         * Returns the battery consumption (in microcoulomb) of this uid for a standard power bucket
+         * of interest.
+         * @param bucket standard power bucket of interest
+         * @return consumption (in microcolombs) used by this uid for this power bucket
          */
-        public long getMeasuredEnergyMicroJoules(@StandardEnergyBucket int bucket) {
+        public long getMeasuredBatteryConsumptionUC(@StandardPowerBucket int bucket) {
             if (mBsi.mGlobalMeasuredEnergyStats == null
                     || !mBsi.mGlobalMeasuredEnergyStats.isStandardBucketSupported(bucket)) {
-                return ENERGY_DATA_UNAVAILABLE;
+                return POWER_DATA_UNAVAILABLE;
             }
             if (mUidMeasuredEnergyStats == null) {
                 return 0L; // It is supported, but was never filled, so it must be 0
             }
-            return mUidMeasuredEnergyStats.getAccumulatedStandardBucketEnergy(bucket);
+            return mUidMeasuredEnergyStats.getAccumulatedStandardBucketCharge(bucket);
         }
 
         @Override
-        public long[] getCustomMeasuredEnergiesMicroJoules() {
+        public long[] getCustomConsumerMeasuredBatteryConsumptionUC() {
             if (mBsi.mGlobalMeasuredEnergyStats == null) {
                 return null;
             }
             if (mUidMeasuredEnergyStats == null) {
                 // Custom buckets may exist. But all values for this uid are 0 so we report all 0s.
-                return new long[mBsi.mGlobalMeasuredEnergyStats.getNumberCustomEnergyBuckets()];
+                return new long[mBsi.mGlobalMeasuredEnergyStats.getNumberCustomPowerBuckets()];
             }
-            return mUidMeasuredEnergyStats.getAccumulatedCustomBucketEnergies();
+            return mUidMeasuredEnergyStats.getAccumulatedCustomBucketCharges();
         }
 
         /**
@@ -8476,8 +8478,8 @@
         }
 
         @Override
-        public long getScreenOnEnergy() {
-            return getMeasuredEnergyMicroJoules(MeasuredEnergyStats.ENERGY_BUCKET_SCREEN_ON);
+        public long getScreenOnMeasuredBatteryConsumptionUC() {
+            return getMeasuredBatteryConsumptionUC(MeasuredEnergyStats.POWER_BUCKET_SCREEN_ON);
         }
 
         void initNetworkActivityLocked() {
@@ -12170,27 +12172,108 @@
     }
 
     /**
-     * Accumulate Display energy and distribute it to the correct state and the apps.
+     * Accumulate Cpu charge consumption and distribute it to the correct state and the apps.
+     * Only call if device is on battery.
+     *
+     * @param clusterChargeUC amount of charge (microcoulombs) consumed by each Cpu Cluster
+     * @param accumulator collection of calculated uid cpu power consumption to smear
+     *                    clusterChargeUC against.
+     */
+    @GuardedBy("this")
+    private void updateCpuMeasuredEnergyStatsLocked(@NonNull long[] clusterChargeUC,
+            @NonNull CpuDeltaPowerAccumulator accumulator) {
+        if (DEBUG_ENERGY) {
+            Slog.d(TAG,
+                    "Updating cpu cluster stats: " + clusterChargeUC.toString());
+        }
+        if (mGlobalMeasuredEnergyStats == null) {
+            return;
+        }
+
+        final int numClusters = clusterChargeUC.length;
+        long totalCpuChargeUC = 0;
+        for (int i = 0; i < numClusters; i++) {
+            totalCpuChargeUC += clusterChargeUC[i];
+        }
+        if (totalCpuChargeUC <= 0) return;
+
+        mGlobalMeasuredEnergyStats.updateStandardBucket(MeasuredEnergyStats.POWER_BUCKET_CPU,
+                totalCpuChargeUC);
+
+        // Calculate the measured microcoulombs/calculated milliamp-hour charge ratio for each
+        // cluster to normalize  each uid's estimated power usage against actual power usage for
+        // a given cluster.
+        final double[] clusterChargeRatio = new double[numClusters];
+        for (int cluster = 0; cluster < numClusters; cluster++) {
+
+            final double totalClusterChargeMah = accumulator.totalClusterChargesMah[cluster];
+            if (totalClusterChargeMah <= 0.0) {
+                // This cluster did not have any work on it, since last update.
+                // Avoid dividing by zero.
+                clusterChargeRatio[cluster] = 0.0;
+            } else {
+                clusterChargeRatio[cluster] =
+                        clusterChargeUC[cluster] / accumulator.totalClusterChargesMah[cluster];
+            }
+        }
+
+        // Assign and distribute power usage to apps based on their calculated cpu cluster charge.
+        final long uidChargeArraySize = accumulator.perUidCpuClusterChargesMah.size();
+        for (int i = 0; i < uidChargeArraySize; i++) {
+            final Uid uid = accumulator.perUidCpuClusterChargesMah.keyAt(i);
+            final double[] uidClusterChargesMah = accumulator.perUidCpuClusterChargesMah.valueAt(i);
+
+            // Iterate each cpu cluster and sum the proportional measured cpu cluster charge to
+            // get the total cpu charge consumed by a uid.
+            long uidCpuChargeUC = 0;
+            for (int cluster = 0; cluster < numClusters; cluster++) {
+                final double uidClusterChargeMah = uidClusterChargesMah[cluster];
+
+                // Proportionally allocate the measured cpu cluster charge to a uid using the
+                // measured charge/calculated charge ratio. Add 0.5 to round the proportional
+                // charge double to the nearest long value.
+                final long uidClusterChargeUC =
+                        (long) (uidClusterChargeMah * clusterChargeRatio[cluster]
+                                + 0.5);
+
+                uidCpuChargeUC += uidClusterChargeUC;
+            }
+
+            if (uidCpuChargeUC < 0) {
+                Slog.wtf(TAG,
+                        "Unexpected proportional measured charge (" + uidCpuChargeUC + ") for uid "
+                                + uid.mUid);
+                continue;
+            }
+
+            uid.addChargeToStandardBucketLocked(uidCpuChargeUC,
+                    MeasuredEnergyStats.POWER_BUCKET_CPU);
+        }
+    }
+
+    /**
+     * Accumulate Display charge consumption and distribute it to the correct state and the apps.
      *
      * NOTE: The algorithm used makes the strong assumption that app foreground activity time
      * is always 0 when the screen is not "ON" and whenever the rail energy is 0 (if supported).
      * To the extent that those assumptions are violated, the algorithm will err.
      *
-     * @param energyUJ amount of energy (microjoules) used by Display since this was last called.
+     * @param chargeUC amount of charge (microcoulombs) used by Display since this was last called.
      * @param screenState screen state at the time this data collection was scheduled
      */
     @GuardedBy("this")
-    public void updateDisplayEnergyLocked(long energyUJ, int screenState, long elapsedRealtimeMs) {
-        if (DEBUG_ENERGY) Slog.d(TAG, "Updating display stats: " + energyUJ);
+    public void updateDisplayMeasuredEnergyStatsLocked(long chargeUC, int screenState,
+            long elapsedRealtimeMs) {
+        if (DEBUG_ENERGY) Slog.d(TAG, "Updating display stats: " + chargeUC);
         if (mGlobalMeasuredEnergyStats == null) {
             return;
         }
 
-        final @StandardEnergyBucket int energyBucket =
-                MeasuredEnergyStats.getDisplayEnergyBucket(mScreenStateAtLastEnergyMeasurement);
+        final @StandardPowerBucket int powerBucket =
+                MeasuredEnergyStats.getDisplayPowerBucket(mScreenStateAtLastEnergyMeasurement);
         mScreenStateAtLastEnergyMeasurement = screenState;
 
-        if (!mOnBatteryInternal || energyUJ <= 0) {
+        if (!mOnBatteryInternal || chargeUC <= 0) {
             // There's nothing further to update.
             return;
         }
@@ -12205,13 +12288,13 @@
             return;
         }
 
-        mGlobalMeasuredEnergyStats.updateStandardBucket(energyBucket, energyUJ);
+        mGlobalMeasuredEnergyStats.updateStandardBucket(powerBucket, chargeUC);
 
         // Now we blame individual apps, but only if the display was ON.
-        if (energyBucket != MeasuredEnergyStats.ENERGY_BUCKET_SCREEN_ON) {
+        if (powerBucket != MeasuredEnergyStats.POWER_BUCKET_SCREEN_ON) {
             return;
         }
-        // TODO(b/175726779): Consider unifying the code with the non-rail display energy blaming.
+        // TODO(b/175726779): Consider unifying the code with the non-rail display power blaming.
 
         // NOTE: fg time is NOT pooled. If two uids are both somehow in fg, then that time is
         // 'double counted' and will simply exceed the realtime that elapsed.
@@ -12230,7 +12313,7 @@
             fgTimeMsArray.put(uid, fgTimeMs);
             totalFgTimeMs += fgTimeMs;
         }
-        long totalDisplayEnergyMJ = energyUJ / 1000; // not final
+        long totalDisplayChargeMC = chargeUC / 1000; // not final
 
         // Actually assign and distribute power usage to apps based on their fg time since mark.
         // TODO(b/175726326): Decide on 'energy' units and make sure algorithm won't overflow.
@@ -12240,47 +12323,47 @@
             final long fgTimeMs = fgTimeMsArray.valueAt(i);
 
             // Using long division: "appEnergy = totalEnergy * appFg/totalFg + 0.5" with rounding
-            final long appDisplayEnergyMJ =
-                    (totalDisplayEnergyMJ * fgTimeMs + (totalFgTimeMs / 2))
+            final long appDisplayChargeMC =
+                    (totalDisplayChargeMC * fgTimeMs + (totalFgTimeMs / 2))
                     / totalFgTimeMs;
-            uid.addEnergyToStandardBucketLocked(appDisplayEnergyMJ * 1000, energyBucket);
+            uid.addChargeToStandardBucketLocked(appDisplayChargeMC * 1000, powerBucket);
 
             // To mitigate round-off errors, remove this app from numerator & denominator totals
-            totalDisplayEnergyMJ -= appDisplayEnergyMJ;
+            totalDisplayChargeMC -= appDisplayChargeMC;
             totalFgTimeMs -= fgTimeMs;
         }
     }
 
     /**
-     * Accumulate Custom energy bucket energy, globally and for each app.
+     * Accumulate Custom power bucket charge, globally and for each app.
      *
-     * @param totalEnergyUJ energy (microjoules) used for this bucket since this was last called.
-     * @param uidEnergies map of uid->energy (microjoules) for this bucket since last called.
-     *                    Data inside uidEnergies will not be modified (treated immutable).
+     * @param totalChargeUC charge (microcoulombs) used for this bucket since this was last called.
+     * @param uidCharges map of uid->charge (microcoulombs) for this bucket since last called.
+     *                    Data inside uidCharges will not be modified (treated immutable).
      *                    Uids not already known to BatteryStats will be ignored.
      */
-    public void updateCustomMeasuredEnergyDataLocked(int customEnergyBucket,
-            long totalEnergyUJ, @Nullable SparseLongArray uidEnergies) {
+    public void updateCustomMeasuredEnergyStatsLocked(int customPowerBucket,
+            long totalChargeUC, @Nullable SparseLongArray uidCharges) {
         if (DEBUG_ENERGY) {
-            Slog.d(TAG, "Updating attributed measured energy stats for custom bucket "
-                    + customEnergyBucket
-                    + " with total energy " + totalEnergyUJ
-                    + " and uid energies " + String.valueOf(uidEnergies));
+            Slog.d(TAG, "Updating attributed measured charge stats for custom bucket "
+                    + customPowerBucket
+                    + " with total charge " + totalChargeUC
+                    + " and uid charges " + String.valueOf(uidCharges));
         }
         if (mGlobalMeasuredEnergyStats == null) return;
-        if (!mOnBatteryInternal || mIgnoreNextExternalStats || totalEnergyUJ <= 0) return;
+        if (!mOnBatteryInternal || mIgnoreNextExternalStats || totalChargeUC <= 0) return;
 
-        mGlobalMeasuredEnergyStats.updateCustomBucket(customEnergyBucket, totalEnergyUJ);
+        mGlobalMeasuredEnergyStats.updateCustomBucket(customPowerBucket, totalChargeUC);
 
-        if (uidEnergies == null) return;
-        final int numUids = uidEnergies.size();
+        if (uidCharges == null) return;
+        final int numUids = uidCharges.size();
         for (int i = 0; i < numUids; i++) {
-            final int uidInt = mapUid(uidEnergies.keyAt(i));
-            final long uidEnergyUJ = uidEnergies.valueAt(i);
-            if (uidEnergyUJ == 0) continue;
+            final int uidInt = mapUid(uidCharges.keyAt(i));
+            final long uidChargeUC = uidCharges.valueAt(i);
+            if (uidChargeUC == 0) continue;
             final Uid uidObj = getAvailableUidStatsLocked(uidInt);
             if (uidObj != null) {
-                uidObj.addEnergyToCustomBucketLocked(uidEnergyUJ, customEnergyBucket);
+                uidObj.addChargeToCustomBucketLocked(uidChargeUC, customPowerBucket);
             } else {
                 // Ignore any uid not already known to BatteryStats, rather than creating a new Uid.
                 // Otherwise we could end up reviving dead Uids. Note that the CPU data is updated
@@ -12288,8 +12371,8 @@
                 // Recently removed uids (especially common for isolated uids) can reach this path
                 // and are ignored.
                 if (!Process.isIsolated(uidInt)) {
-                    Slog.w(TAG, "Received measured energy " + totalEnergyUJ + " for custom bucket "
-                        + customEnergyBucket + " for non-existent uid " + uidInt);
+                    Slog.w(TAG, "Received measured charge " + totalChargeUC + " for custom bucket "
+                            + customPowerBucket + " for non-existent uid " + uidInt);
                 }
             }
         }
@@ -12416,6 +12499,64 @@
     }
 
     /**
+     * Object for calculating and accumulating the estimated cpu power used while reading the
+     * various cpu kernel files.
+     */
+    @VisibleForTesting
+    public static class CpuDeltaPowerAccumulator {
+        // Keeps track of total charge used per cluster.
+        public final double[] totalClusterChargesMah;
+        // Keeps track of charge used per cluster per uid.
+        public final ArrayMap<Uid, double[]> perUidCpuClusterChargesMah;
+
+        private final CpuPowerCalculator mCalculator;
+        private Uid mCachedUid = null;
+        private double[] mUidClusterCache = null;
+
+        CpuDeltaPowerAccumulator(CpuPowerCalculator calculator, int nClusters) {
+            mCalculator = calculator;
+            totalClusterChargesMah = new double[nClusters];
+            perUidCpuClusterChargesMah = new ArrayMap<>();
+        }
+
+        /** Add per cpu cluster durations to the currently cached uid. */
+        public void addCpuClusterDurationsMs(Uid uid, long[] durationsMs) {
+            final double[] uidChargesMah = getOrCreateUidCpuClusterCharges(uid);
+            for (int cluster = 0; cluster < durationsMs.length; cluster++) {
+                final double estimatedDeltaMah = mCalculator.calculatePerCpuClusterPowerMah(cluster,
+                        durationsMs[cluster]);
+                uidChargesMah[cluster] += estimatedDeltaMah;
+                totalClusterChargesMah[cluster] += estimatedDeltaMah;
+            }
+        }
+
+        /** Add per speed per cpu cluster durations to the currently cached uid. */
+        public void addCpuClusterSpeedDurationsMs(Uid uid, int cluster, int speed,
+                long durationsMs) {
+            final double[] uidChargesMah = getOrCreateUidCpuClusterCharges(uid);
+            final double estimatedDeltaMah = mCalculator.calculatePerCpuFreqPowerMah(cluster, speed,
+                    durationsMs);
+            uidChargesMah[cluster] += estimatedDeltaMah;
+            totalClusterChargesMah[cluster] += estimatedDeltaMah;
+        }
+
+        private double[] getOrCreateUidCpuClusterCharges(Uid uid) {
+            // Repeated additions on the same uid is very likely.
+            // Skip a lookup if getting the same uid as the last get.
+            if (uid == mCachedUid) return mUidClusterCache;
+
+            double[] uidChargesMah = perUidCpuClusterChargesMah.get(uid);
+            if (uidChargesMah == null) {
+                uidChargesMah = new double[totalClusterChargesMah.length];
+                perUidCpuClusterChargesMah.put(uid, uidChargesMah);
+            }
+            mCachedUid = uid;
+            mUidClusterCache = uidChargesMah;
+            return uidChargesMah;
+        }
+    }
+
+    /**
      * Read and distribute CPU usage across apps. If their are partial wakelocks being held
      * and we are on battery with screen off, we give more of the cpu time to those apps holding
      * wakelocks. If the screen is on, we just assign the actual cpu time an app used.
@@ -12424,7 +12565,8 @@
      * buckets.
      */
     @GuardedBy("this")
-    public void updateCpuTimeLocked(boolean onBattery, boolean onBatteryScreenOff) {
+    public void updateCpuTimeLocked(boolean onBattery, boolean onBatteryScreenOff,
+            long[] measuredCpuClusterChargeUC) {
         if (mPowerProfile == null) {
             return;
         }
@@ -12478,21 +12620,48 @@
         mUserInfoProvider.refreshUserIds();
         final SparseLongArray updatedUids = mCpuUidFreqTimeReader.perClusterTimesAvailable()
                 ? null : new SparseLongArray();
+
+        final CpuDeltaPowerAccumulator powerAccumulator;
+        if (mGlobalMeasuredEnergyStats != null
+                && mGlobalMeasuredEnergyStats.isStandardBucketSupported(
+                MeasuredEnergyStats.POWER_BUCKET_CPU) && mCpuPowerCalculator != null) {
+            if (measuredCpuClusterChargeUC == null) {
+                Slog.wtf(TAG,
+                        "POWER_BUCKET_CPU supported but no measured Cpu Cluster charge reported "
+                                + "on updateCpuTimeLocked!");
+                powerAccumulator = null;
+            } else {
+                // Cpu Measured Energy is supported, create an object to accumulate the estimated
+                // charge consumption since the last cpu update
+                final int numClusters = mPowerProfile.getNumCpuClusters();
+                powerAccumulator = new CpuDeltaPowerAccumulator(mCpuPowerCalculator, numClusters);
+            }
+        } else {
+            powerAccumulator = null;
+        }
+
         readKernelUidCpuTimesLocked(partialTimersToConsider, updatedUids, onBattery);
         // updatedUids=null means /proc/uid_time_in_state provides snapshots of per-cluster cpu
         // freqs, so no need to approximate these values.
         if (updatedUids != null) {
-            updateClusterSpeedTimes(updatedUids, onBattery);
+            updateClusterSpeedTimes(updatedUids, onBattery, powerAccumulator);
         }
-        readKernelUidCpuFreqTimesLocked(partialTimersToConsider, onBattery, onBatteryScreenOff);
+        readKernelUidCpuFreqTimesLocked(partialTimersToConsider, onBattery, onBatteryScreenOff,
+                powerAccumulator);
         mNumAllUidCpuTimeReads += 2;
         if (mConstants.TRACK_CPU_ACTIVE_CLUSTER_TIME) {
+            // Cpu Active times do not get any info ony how to attribute measured Cpu Cluster
+            // charge, so not need to provide the powerAccumulator
             readKernelUidCpuActiveTimesLocked(onBattery);
-            readKernelUidCpuClusterTimesLocked(onBattery);
+            readKernelUidCpuClusterTimesLocked(onBattery, powerAccumulator);
             mNumAllUidCpuTimeReads += 2;
         }
 
         updateSystemServerThreadStats();
+
+        if (powerAccumulator != null) {
+            updateCpuMeasuredEnergyStatsLocked(measuredCpuClusterChargeUC, powerAccumulator);
+        }
     }
 
     /**
@@ -12579,12 +12748,16 @@
 
     /**
      * Take snapshot of cpu times (aggregated over all uids) at different frequencies and
-     * calculate cpu times spent by each uid at different frequencies.
+     * calculate cpu times spent by each uid at different frequencies. Will also add estimated
+     * power consumptions, if powerAccumulator data structure is provided.
      *
-     * @param updatedUids The uids for which times spent at different frequencies are calculated.
+     * @param updatedUids  The uids for which times spent at different frequencies are calculated.
+     * @param onBattery whether or not this is onBattery
+     * @param powerAccumulator object to accumulate the estimated cluster charge consumption.
      */
     @VisibleForTesting
-    public void updateClusterSpeedTimes(@NonNull SparseLongArray updatedUids, boolean onBattery) {
+    public void updateClusterSpeedTimes(@NonNull SparseLongArray updatedUids, boolean onBattery,
+            @Nullable CpuDeltaPowerAccumulator powerAccumulator) {
         long totalCpuClustersTimeMs = 0;
         // Read the time spent for each cluster at various cpu frequencies.
         final long[][] clusterSpeedTimesMs = new long[mKernelCpuSpeedReaders.length][];
@@ -12626,9 +12799,15 @@
                         if (cpuSpeeds[speed] == null) {
                             cpuSpeeds[speed] = new LongSamplingCounter(mOnBatteryTimeBase);
                         }
-                        cpuSpeeds[speed].addCountLocked(appCpuTimeUs
+                        final long deltaSpeedCount = appCpuTimeUs
                                 * clusterSpeedTimesMs[cluster][speed]
-                                / totalCpuClustersTimeMs, onBattery);
+                                / totalCpuClustersTimeMs;
+                        cpuSpeeds[speed].addCountLocked(deltaSpeedCount, onBattery);
+
+                        if (powerAccumulator != null) {
+                            powerAccumulator.addCpuClusterSpeedDurationsMs(u, cluster,
+                                    speed, deltaSpeedCount);
+                        }
                     }
                 }
             }
@@ -12750,13 +12929,18 @@
 
     /**
      * Take a snapshot of the cpu times spent by each uid in each freq and update the
-     * corresponding counters.
+     * corresponding counters.  Will also add estimated power consumptions, if powerAccumulator
+     * data structure is provided.
      *
      * @param partialTimers The wakelock holders among which the cpu freq times will be distributed.
+     * @param onBattery whether or not this is onBattery
+     * @param onBatteryScreenOff whether or not this is onBattery with the screen off.
+     * @param powerAccumulator object to accumulate the estimated cluster charge consumption.
      */
     @VisibleForTesting
     public void readKernelUidCpuFreqTimesLocked(@Nullable ArrayList<StopwatchTimer> partialTimers,
-            boolean onBattery, boolean onBatteryScreenOff) {
+            boolean onBattery, boolean onBatteryScreenOff,
+            @Nullable CpuDeltaPowerAccumulator powerAccumulator) {
         final boolean perClusterTimesAvailable =
                 mCpuUidFreqTimeReader.perClusterTimesAvailable();
         final int numWakelocks = partialTimers == null ? 0 : partialTimers.size();
@@ -12765,7 +12949,9 @@
         final long startTimeMs = mClocks.uptimeMillis();
         final long elapsedRealtimeMs = mClocks.elapsedRealtime();
         final List<Integer> uidsToRemove = new ArrayList<>();
-        mCpuUidFreqTimeReader.readDelta(false, (uid, cpuFreqTimeMs) -> {
+        // If power is being accumulated for attribution, data needs to be read immediately.
+        final boolean forceRead = powerAccumulator != null;
+        mCpuUidFreqTimeReader.readDelta(forceRead, (uid, cpuFreqTimeMs) -> {
             uid = mapUid(uid);
             if (Process.isIsolated(uid)) {
                 uidsToRemove.add(uid);
@@ -12828,6 +13014,11 @@
                             appAllocationUs = cpuFreqTimeMs[freqIndex] * 1000;
                         }
                         cpuTimesUs[speed].addCountLocked(appAllocationUs, onBattery);
+
+                        if (powerAccumulator != null) {
+                            powerAccumulator.addCpuClusterSpeedDurationsMs(u, cluster,
+                                    speed, appAllocationUs / 1000);
+                        }
                         freqIndex++;
                     }
                 }
@@ -12868,6 +13059,11 @@
                                 mWakeLockAllocationsUs[cluster][speed] / (numWakelocks - i);
                         cpuTimeUs[speed].addCountLocked(allocationUs, onBattery);
                         mWakeLockAllocationsUs[cluster][speed] -= allocationUs;
+
+                        if (powerAccumulator != null) {
+                            powerAccumulator.addCpuClusterSpeedDurationsMs(u, cluster,
+                                    speed, allocationUs / 1000);
+                        }
                     }
                 }
             }
@@ -12910,14 +13106,21 @@
 
     /**
      * Take a snapshot of the cpu cluster times spent by each uid and update the corresponding
-     * counters.
+     * counters. Will also add estimated power consumptions, if powerAccumulator data structure
+     * is provided.
+     *
+     * @param onBattery whether or not this is onBattery
+     * @param powerAccumulator object to accumulate the estimated cluster charge consumption.
      */
     @VisibleForTesting
-    public void readKernelUidCpuClusterTimesLocked(boolean onBattery) {
+    public void readKernelUidCpuClusterTimesLocked(boolean onBattery,
+            @Nullable CpuDeltaPowerAccumulator powerAccumulator) {
         final long startTimeMs = mClocks.uptimeMillis();
         final long elapsedRealtimeMs = mClocks.elapsedRealtime();
         final List<Integer> uidsToRemove = new ArrayList<>();
-        mCpuUidClusterTimeReader.readDelta(false, (uid, cpuClusterTimesMs) -> {
+        // If power is being accumulated for attribution, data needs to be read immediately.
+        final boolean forceRead = powerAccumulator != null;
+        mCpuUidClusterTimeReader.readDelta(forceRead, (uid, cpuClusterTimesMs) -> {
             uid = mapUid(uid);
             if (Process.isIsolated(uid)) {
                 uidsToRemove.add(uid);
@@ -12931,6 +13134,10 @@
             }
             final Uid u = getUidStatsLocked(uid, elapsedRealtimeMs, startTimeMs);
             u.mCpuClusterTimesMs.addCountLocked(cpuClusterTimesMs, onBattery);
+
+            if (powerAccumulator != null) {
+                powerAccumulator.addCpuClusterDurationsMs(u, cpuClusterTimesMs);
+            }
         });
         for (int uid : uidsToRemove) {
             mCpuUidClusterTimeReader.removeUid(uid);
@@ -13197,8 +13404,9 @@
             }
         }
 
+        mBatteryVoltageMv = voltageMv;
+
         if (ENABLE_FOREGROUND_STATS_COLLECTION) {
-            mBatteryVoltageMv = voltageMv;
             if (onBattery) {
                 final long energyNwh = (voltageMv * (long) chargeUah);
                 final long energyDelta = mLastBatteryEnergyCapacityNwh - energyNwh;
@@ -13982,9 +14190,9 @@
         registerUsbStateReceiver(context);
     }
     /**
-     * Initialize the measured energy stats data structures.
+     * Initialize the measured charge stats data structures.
      *
-     * @param supportedStandardBuckets boolean array indicating which {@link StandardEnergyBucket}s
+     * @param supportedStandardBuckets boolean array indicating which {@link StandardPowerBucket}s
      *                                 are currently supported.
      *                                 If null, none are supported (regardless of numCustomBuckets).
      * @param numCustomBuckets number of custom (OTHER) EnergyConsumers on this device
@@ -13997,27 +14205,39 @@
 
         if (supportedStandardBuckets == null) {
             if (mGlobalMeasuredEnergyStats != null) {
-                // Measured energy buckets no longer supported, wipe out the existing data.
+                // Measured energy no longer supported, wipe out the existing data.
                 supportedBucketMismatch = true;
             }
-        } else if (mGlobalMeasuredEnergyStats == null) {
-            mGlobalMeasuredEnergyStats
-                    = new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
-            return;
         } else {
-            supportedBucketMismatch = !mGlobalMeasuredEnergyStats.isSupportEqualTo(
-                    supportedStandardBuckets, numCustomBuckets);
+            if (mGlobalMeasuredEnergyStats == null) {
+                mGlobalMeasuredEnergyStats =
+                        new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
+                return;
+            } else {
+                supportedBucketMismatch = !mGlobalMeasuredEnergyStats.isSupportEqualTo(
+                        supportedStandardBuckets, numCustomBuckets);
+            }
+
+            if (supportedStandardBuckets[MeasuredEnergyStats.POWER_BUCKET_CPU]) {
+                mCpuPowerCalculator = new CpuPowerCalculator(mPowerProfile);
+            }
         }
 
         if (supportedBucketMismatch) {
-            mGlobalMeasuredEnergyStats = supportedStandardBuckets == null ?
-                    null : new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
-            // Supported energy buckets changed since last boot.
+            mGlobalMeasuredEnergyStats = supportedStandardBuckets == null
+                    ? null : new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
+            // Supported power buckets changed since last boot.
             // Existing data is no longer reliable.
             resetAllStatsLocked(SystemClock.uptimeMillis(), SystemClock.elapsedRealtime());
         }
     }
 
+    /** Get the last known Battery voltage (in millivolts), returns -1 if unknown */
+    @GuardedBy("this")
+    public int getBatteryVoltageMvLocked() {
+        return mBatteryVoltageMv;
+    }
+
     @VisibleForTesting
     public final class Constants extends ContentObserver {
         public static final String KEY_TRACK_CPU_TIMES_BY_PROC_STATE
@@ -14293,11 +14513,11 @@
     }
 
     /**
-     * Dump measured energy stats
+     * Dump measured charge stats
      */
     @GuardedBy("this")
     public void dumpMeasuredEnergyStatsLocked(PrintWriter pw) {
-        pw.printf("On battery measured energy stats (microjoules) \n");
+        pw.printf("On battery measured charge stats (microcoulombs) \n");
         if (mGlobalMeasuredEnergyStats == null) {
             pw.printf("    Not supported on this device.\n");
             return;
@@ -14314,7 +14534,7 @@
         }
     }
 
-    /** Dump measured energy stats for the given uid */
+    /** Dump measured charge stats for the given uid */
     @GuardedBy("this")
     private void dumpMeasuredEnergyStatsLocked(PrintWriter pw, String name,
             MeasuredEnergyStats stats) {
diff --git a/core/java/com/android/internal/os/BatteryUsageStatsProvider.java b/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
index 619cd8e..6dd612e 100644
--- a/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
+++ b/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
@@ -123,10 +123,10 @@
         final long realtimeUs = mStats.mClocks.elapsedRealtime() * 1000;
         final long uptimeUs = mStats.mClocks.uptimeMillis() * 1000;
 
-        final long[] customMeasuredEnergiesMicroJoules =
-                mStats.getCustomMeasuredEnergiesMicroJoules();
-        final int customPowerComponentCount = customMeasuredEnergiesMicroJoules != null
-                ? customMeasuredEnergiesMicroJoules.length
+        final long[] customMeasuredChargesUC =
+                mStats.getCustomConsumerMeasuredBatteryConsumptionUC();
+        final int customPowerComponentCount = customMeasuredChargesUC != null
+                ? customMeasuredChargesUC.length
                 : 0;
 
         // TODO(b/174186358): read extra time component number from configuration
diff --git a/core/java/com/android/internal/os/BinderCallsStats.java b/core/java/com/android/internal/os/BinderCallsStats.java
index b3e8db2..14b8705 100644
--- a/core/java/com/android/internal/os/BinderCallsStats.java
+++ b/core/java/com/android/internal/os/BinderCallsStats.java
@@ -120,8 +120,13 @@
                     UidEntry uidEntry = mUidEntries.get(mSendUidsToObserver.valueAt(i));
                     if (uidEntry != null) {
                         ArrayMap<CallStatKey, CallStat> callStats = uidEntry.mCallStats;
+                        final int csize = callStats.size();
+                        final ArrayList<CallStat> tmpCallStats = new ArrayList<>(csize);
+                        for (int j = 0; j < csize; j++) {
+                            tmpCallStats.add(callStats.valueAt(j).clone());
+                        }
                         mCallStatsObserver.noteCallStats(uidEntry.workSourceUid,
-                                uidEntry.incrementalCallCount, callStats.values()
+                                uidEntry.incrementalCallCount, tmpCallStats
                         );
                         uidEntry.incrementalCallCount = 0;
                         for (int j = callStats.size() - 1; j >= 0; j--) {
@@ -830,6 +835,23 @@
         }
 
         @Override
+        public CallStat clone() {
+            CallStat clone = new CallStat(callingUid, binderClass, transactionCode,
+                    screenInteractive);
+            clone.recordedCallCount = recordedCallCount;
+            clone.callCount = callCount;
+            clone.cpuTimeMicros = cpuTimeMicros;
+            clone.maxCpuTimeMicros = maxCpuTimeMicros;
+            clone.latencyMicros = latencyMicros;
+            clone.maxLatencyMicros = maxLatencyMicros;
+            clone.maxRequestSizeBytes = maxRequestSizeBytes;
+            clone.maxReplySizeBytes = maxReplySizeBytes;
+            clone.exceptionCount = exceptionCount;
+            clone.incrementalCallCount = incrementalCallCount;
+            return clone;
+        }
+
+        @Override
         public String toString() {
             // This is expensive, but CallStat.toString() is only used for debugging.
             String methodName = new BinderTransactionNameResolver().getMethodName(binderClass,
diff --git a/core/java/com/android/internal/os/CustomMeasuredPowerCalculator.java b/core/java/com/android/internal/os/CustomMeasuredPowerCalculator.java
index 2606d80..9941e30 100644
--- a/core/java/com/android/internal/os/CustomMeasuredPowerCalculator.java
+++ b/core/java/com/android/internal/os/CustomMeasuredPowerCalculator.java
@@ -35,7 +35,7 @@
             long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) {
         super.calculate(builder, batteryStats, rawRealtimeUs, rawUptimeUs, query);
         final double[] customMeasuredPowerMah = calculateMeasuredEnergiesMah(
-                batteryStats.getCustomMeasuredEnergiesMicroJoules());
+                batteryStats.getCustomConsumerMeasuredBatteryConsumptionUC());
         if (customMeasuredPowerMah != null) {
             final SystemBatteryConsumer.Builder systemBatteryConsumerBuilder =
                     builder.getOrCreateSystemBatteryConsumerBuilder(
@@ -52,7 +52,7 @@
     protected void calculateApp(UidBatteryConsumer.Builder app, BatteryStats.Uid u,
             long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) {
         final double[] customMeasuredPowerMah = calculateMeasuredEnergiesMah(
-                u.getCustomMeasuredEnergiesMicroJoules());
+                u.getCustomConsumerMeasuredBatteryConsumptionUC());
         if (customMeasuredPowerMah != null) {
             for (int i = 0; i < customMeasuredPowerMah.length; i++) {
                 app.setConsumedPowerForCustomComponent(
@@ -65,20 +65,20 @@
     @Override
     protected void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
             long rawUptimeUs, int statsType) {
-        updateCustomMeasuredPowerMah(app, u.getCustomMeasuredEnergiesMicroJoules());
+        updateCustomMeasuredPowerMah(app, u.getCustomConsumerMeasuredBatteryConsumptionUC());
     }
 
-    private void updateCustomMeasuredPowerMah(BatterySipper sipper, long[] measuredEnergiesUJ) {
-        sipper.customMeasuredPowerMah = calculateMeasuredEnergiesMah(measuredEnergiesUJ);
+    private void updateCustomMeasuredPowerMah(BatterySipper sipper, long[] measuredChargeUC) {
+        sipper.customMeasuredPowerMah = calculateMeasuredEnergiesMah(measuredChargeUC);
     }
 
-    private double[] calculateMeasuredEnergiesMah(long[] measuredEnergiesUJ) {
-        if (measuredEnergiesUJ == null) {
+    private double[] calculateMeasuredEnergiesMah(long[] measuredChargeUC) {
+        if (measuredChargeUC == null) {
             return null;
         }
-        final double[] measuredEnergiesMah = new double[measuredEnergiesUJ.length];
-        for (int i = 0; i < measuredEnergiesUJ.length; i++) {
-            measuredEnergiesMah[i] = uJtoMah(measuredEnergiesUJ[i]);
+        final double[] measuredEnergiesMah = new double[measuredChargeUC.length];
+        for (int i = 0; i < measuredChargeUC.length; i++) {
+            measuredEnergiesMah[i] = uCtoMah(measuredChargeUC[i]);
         }
         return measuredEnergiesMah;
     }
diff --git a/core/java/com/android/internal/os/PowerCalculator.java b/core/java/com/android/internal/os/PowerCalculator.java
index fe4fb7a..72385e2 100644
--- a/core/java/com/android/internal/os/PowerCalculator.java
+++ b/core/java/com/android/internal/os/PowerCalculator.java
@@ -30,6 +30,8 @@
  */
 public abstract class PowerCalculator {
 
+    protected static final double MILLIAMPHOUR_PER_MICROCOULOMB = 1.0 / 1000.0 / 60.0 / 60.0;
+
     /**
      * Attributes the total amount of power used by this subsystem to various consumers such
      * as apps.
@@ -115,12 +117,12 @@
     /**
      * Returns either the measured energy converted to mAh or a usage-based estimate.
      */
-    protected static double getMeasuredOrEstimatedPower(long measuredEnergyUj,
+    protected static double getMeasuredOrEstimatedPower(long measuredEnergyUC,
             UsageBasedPowerEstimator powerEstimator, long durationMs,
             boolean forceUsePowerProfileModel) {
-        if (measuredEnergyUj != BatteryStats.ENERGY_DATA_UNAVAILABLE
+        if (measuredEnergyUC != BatteryStats.POWER_DATA_UNAVAILABLE
                 && !forceUsePowerProfileModel) {
-            return uJtoMah(measuredEnergyUj);
+            return uCtoMah(measuredEnergyUC);
         }
         return powerEstimator.calculatePower(durationMs);
     }
@@ -156,13 +158,7 @@
         return String.format(Locale.ENGLISH, format, power);
     }
 
-    static double uJtoMah(long energyUJ) {
-        if (energyUJ == 0) {
-            return 0;
-        }
-
-        // TODO(b/173765509): Convert properly. This is mJ / V * (h/3600s) = mAh with V = 3.7 fixed.
-        //                    Leaving for later since desired units of energy have yet to be decided
-        return energyUJ / 1000.0 / 3.7  / 3600;
+    static double uCtoMah(long chargeUC) {
+        return chargeUC * MILLIAMPHOUR_PER_MICROCOULOMB;
     }
 }
diff --git a/core/java/com/android/internal/os/ScreenPowerCalculator.java b/core/java/com/android/internal/os/ScreenPowerCalculator.java
index 5dca8d5..d94bb31 100644
--- a/core/java/com/android/internal/os/ScreenPowerCalculator.java
+++ b/core/java/com/android/internal/os/ScreenPowerCalculator.java
@@ -141,9 +141,9 @@
                 statsType);
 
         if (!forceUsePowerProfileModel) {
-            final long energyUJ = batteryStats.getScreenOnEnergy();
-            if (energyUJ != BatteryStats.ENERGY_DATA_UNAVAILABLE) {
-                totalPowerAndDuration.powerMah = uJtoMah(energyUJ);
+            final long chargeUC = batteryStats.getScreenOnMeasuredBatteryConsumptionUC();
+            if (chargeUC != BatteryStats.POWER_DATA_UNAVAILABLE) {
+                totalPowerAndDuration.powerMah = uCtoMah(chargeUC);
                 return true;
             }
         }
@@ -157,14 +157,14 @@
             BatteryStats.Uid u, long rawRealtimeUs) {
         appPowerAndDuration.durationMs = getProcessForegroundTimeMs(u, rawRealtimeUs);
 
-        final long energyUJ = u.getScreenOnEnergy();
-        if (energyUJ < 0) {
+        final long chargeUC = u.getScreenOnMeasuredBatteryConsumptionUC();
+        if (chargeUC < 0) {
             Slog.wtf(TAG, "Screen energy not supported, so calculateApp shouldn't de called");
             appPowerAndDuration.powerMah = 0;
             return;
         }
 
-        appPowerAndDuration.powerMah = uJtoMah(energyUJ);
+        appPowerAndDuration.powerMah = uCtoMah(chargeUC);
     }
 
     private long calculateDuration(BatteryStats batteryStats, long rawRealtimeUs, int statsType) {
diff --git a/core/java/com/android/internal/os/SystemServicePowerCalculator.java b/core/java/com/android/internal/os/SystemServicePowerCalculator.java
index 5c0eeb2..b4d5f97 100644
--- a/core/java/com/android/internal/os/SystemServicePowerCalculator.java
+++ b/core/java/com/android/internal/os/SystemServicePowerCalculator.java
@@ -134,7 +134,8 @@
         // TODO(179210707): additionally account for CPU active and per cluster battery use
 
         double powerMah = 0;
-        for (int i = 0; i < mPowerEstimators.length; i++) {
+        final int size = Math.min(mPowerEstimators.length, systemServiceTimeAtCpuSpeeds.length);
+        for (int i = 0; i < size; i++) {
             powerMah += mPowerEstimators[i].calculatePower(systemServiceTimeAtCpuSpeeds[i]);
         }
 
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index d5b778e..47b0f8c 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -651,8 +651,6 @@
      */
     private static void performSystemServerDexOpt(String classPath) {
         final String[] classPathElements = classPath.split(":");
-        final IInstalld installd = IInstalld.Stub
-                .asInterface(ServiceManager.getService("installd"));
         final String instructionSet = VMRuntime.getRuntime().vmInstructionSet();
 
         String classPathForElement = "";
@@ -689,6 +687,10 @@
                 final String uuid = StorageManager.UUID_PRIVATE_INTERNAL;
                 final String seInfo = null;
                 final int targetSdkVersion = 0;  // SystemServer targets the system's SDK version
+                // Wait for installd to be made available
+                IInstalld installd = IInstalld.Stub.asInterface(
+                        ServiceManager.waitForService("installd"));
+
                 try {
                     installd.dexopt(classPathElement, Process.SYSTEM_UID, packageName,
                             instructionSet, dexoptNeeded, outputPath, dexFlags, systemServerFilter,
diff --git a/core/java/com/android/internal/power/MeasuredEnergyStats.java b/core/java/com/android/internal/power/MeasuredEnergyStats.java
index d49203c..e3d5464 100644
--- a/core/java/com/android/internal/power/MeasuredEnergyStats.java
+++ b/core/java/com/android/internal/power/MeasuredEnergyStats.java
@@ -17,7 +17,7 @@
 package com.android.internal.power;
 
 
-import static android.os.BatteryStats.ENERGY_DATA_UNAVAILABLE;
+import static android.os.BatteryStats.POWER_DATA_UNAVAILABLE;
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
@@ -34,8 +34,8 @@
 import java.lang.annotation.RetentionPolicy;
 
 /**
- * Tracks the measured energy usage of various subsystems according to their
- * {@link StandardEnergyBucket} or custom energy bucket (which is tied to
+ * Tracks the measured charge consumption of various subsystems according to their
+ * {@link StandardPowerBucket} or custom power bucket (which is tied to
  * {@link android.hardware.power.stats.EnergyConsumer.ordinal}).
  *
  * This class doesn't use a TimeBase, and instead requires manually decisions about when to
@@ -46,51 +46,53 @@
     private static final String TAG = "MeasuredEnergyStats";
 
     // Note: {@link com.android.internal.os.BatteryStatsImpl#VERSION} MUST be updated if standard
-    // energy bucket integers are modified/added/removed.
-    public static final int ENERGY_BUCKET_UNKNOWN = -1;
-    public static final int ENERGY_BUCKET_SCREEN_ON = 0;
-    public static final int ENERGY_BUCKET_SCREEN_DOZE = 1;
-    public static final int ENERGY_BUCKET_SCREEN_OTHER = 2;
-    public static final int NUMBER_STANDARD_ENERGY_BUCKETS = 3; // Buckets above this are custom.
+    // power bucket integers are modified/added/removed.
+    public static final int POWER_BUCKET_UNKNOWN = -1;
+    public static final int POWER_BUCKET_SCREEN_ON = 0;
+    public static final int POWER_BUCKET_SCREEN_DOZE = 1;
+    public static final int POWER_BUCKET_SCREEN_OTHER = 2;
+    public static final int POWER_BUCKET_CPU = 3;
+    public static final int NUMBER_STANDARD_POWER_BUCKETS = 4; // Buckets above this are custom.
 
-    @IntDef(prefix = {"ENERGY_BUCKET_"}, value = {
-            ENERGY_BUCKET_UNKNOWN,
-            ENERGY_BUCKET_SCREEN_ON,
-            ENERGY_BUCKET_SCREEN_DOZE,
-            ENERGY_BUCKET_SCREEN_OTHER,
+    @IntDef(prefix = {"POWER_BUCKET_"}, value = {
+            POWER_BUCKET_UNKNOWN,
+            POWER_BUCKET_SCREEN_ON,
+            POWER_BUCKET_SCREEN_DOZE,
+            POWER_BUCKET_SCREEN_OTHER,
+            POWER_BUCKET_CPU,
     })
     @Retention(RetentionPolicy.SOURCE)
-    public @interface StandardEnergyBucket {
+    public @interface StandardPowerBucket {
     }
 
     /**
-     * Total energy (in microjoules) that an energy bucket (including both
-     * {@link StandardEnergyBucket} and custom buckets) has accumulated since the last reset.
-     * Values MUST be non-zero or ENERGY_DATA_UNAVAILABLE. Accumulation only occurs
+     * Total charge (in microcoulombs) that a power bucket (including both
+     * {@link StandardPowerBucket} and custom buckets) has accumulated since the last reset.
+     * Values MUST be non-zero or POWER_DATA_UNAVAILABLE. Accumulation only occurs
      * while the necessary conditions are satisfied (e.g. on battery).
      *
-     * Energy for both {@link StandardEnergyBucket}s and custom energy buckets are stored in this
+     * Charge for both {@link StandardPowerBucket}s and custom power buckets are stored in this
      * array, and may internally both referred to as 'buckets'. This is an implementation detail;
      * externally, we differentiate between these two data sources.
      *
      * Warning: Long array is used for access speed. If the number of supported subsystems
      * becomes large, consider using an alternate data structure such as a SparseLongArray.
      */
-    private final long[] mAccumulatedEnergiesMicroJoules;
+    private final long[] mAccumulatedChargeMicroCoulomb;
 
     /**
-     * Creates a MeasuredEnergyStats set to support the provided energy buckets.
-     * supportedStandardBuckets must be of size {@link #NUMBER_STANDARD_ENERGY_BUCKETS}.
-     * numCustomBuckets >= 0 is the number of (non-standard) custom energy buckets on the device.
+     * Creates a MeasuredEnergyStats set to support the provided power buckets.
+     * supportedStandardBuckets must be of size {@link #NUMBER_STANDARD_POWER_BUCKETS}.
+     * numCustomBuckets >= 0 is the number of (non-standard) custom power buckets on the device.
      */
     public MeasuredEnergyStats(boolean[] supportedStandardBuckets, int numCustomBuckets) {
-        final int numTotalBuckets = NUMBER_STANDARD_ENERGY_BUCKETS + numCustomBuckets;
-        mAccumulatedEnergiesMicroJoules = new long[numTotalBuckets];
-        // Initialize to all zeros where supported, otherwise ENERGY_DATA_UNAVAILABLE.
+        final int numTotalBuckets = NUMBER_STANDARD_POWER_BUCKETS + numCustomBuckets;
+        mAccumulatedChargeMicroCoulomb = new long[numTotalBuckets];
+        // Initialize to all zeros where supported, otherwise POWER_DATA_UNAVAILABLE.
         // All custom buckets are, by definition, supported, so their values stay at 0.
-        for (int stdBucket = 0; stdBucket < NUMBER_STANDARD_ENERGY_BUCKETS; stdBucket++) {
+        for (int stdBucket = 0; stdBucket < NUMBER_STANDARD_POWER_BUCKETS; stdBucket++) {
             if (!supportedStandardBuckets[stdBucket]) {
-                mAccumulatedEnergiesMicroJoules[stdBucket] = ENERGY_DATA_UNAVAILABLE;
+                mAccumulatedChargeMicroCoulomb[stdBucket] = POWER_DATA_UNAVAILABLE;
             }
         }
     }
@@ -101,12 +103,12 @@
      */
     private MeasuredEnergyStats(MeasuredEnergyStats template) {
         final int numIndices = template.getNumberOfIndices();
-        mAccumulatedEnergiesMicroJoules = new long[numIndices];
-        // Initialize to all zeros where supported, otherwise ENERGY_DATA_UNAVAILABLE.
+        mAccumulatedChargeMicroCoulomb = new long[numIndices];
+        // Initialize to all zeros where supported, otherwise POWER_DATA_UNAVAILABLE.
         // All custom buckets are, by definition, supported, so their values stay at 0.
-        for (int stdBucket = 0; stdBucket < NUMBER_STANDARD_ENERGY_BUCKETS; stdBucket++) {
+        for (int stdBucket = 0; stdBucket < NUMBER_STANDARD_POWER_BUCKETS; stdBucket++) {
             if (!template.isIndexSupported(stdBucket)) {
-                mAccumulatedEnergiesMicroJoules[stdBucket] = ENERGY_DATA_UNAVAILABLE;
+                mAccumulatedChargeMicroCoulomb[stdBucket] = POWER_DATA_UNAVAILABLE;
             }
         }
     }
@@ -124,20 +126,20 @@
      * See {@link #createAndReadSummaryFromParcel(Parcel, MeasuredEnergyStats)}.
      */
     private MeasuredEnergyStats(int numIndices) {
-        mAccumulatedEnergiesMicroJoules = new long[numIndices];
+        mAccumulatedChargeMicroCoulomb = new long[numIndices];
     }
 
     /** Construct from parcel. */
     public MeasuredEnergyStats(Parcel in) {
         final int size = in.readInt();
-        mAccumulatedEnergiesMicroJoules = new long[size];
-        in.readLongArray(mAccumulatedEnergiesMicroJoules);
+        mAccumulatedChargeMicroCoulomb = new long[size];
+        in.readLongArray(mAccumulatedChargeMicroCoulomb);
     }
 
     /** Write to parcel */
     public void writeToParcel(Parcel out) {
-        out.writeInt(mAccumulatedEnergiesMicroJoules.length);
-        out.writeLongArray(mAccumulatedEnergiesMicroJoules);
+        out.writeInt(mAccumulatedChargeMicroCoulomb.length);
+        out.writeLongArray(mAccumulatedChargeMicroCoulomb);
     }
 
     /**
@@ -153,11 +155,11 @@
         final int numWrittenEntries = in.readInt();
         for (int entry = 0; entry < numWrittenEntries; entry++) {
             final int index = in.readInt();
-            final long energyUJ = in.readLong();
+            final long chargeUC = in.readLong();
             if (overwriteAvailability) {
-                mAccumulatedEnergiesMicroJoules[index] = energyUJ;
+                mAccumulatedChargeMicroCoulomb[index] = chargeUC;
             } else {
-                setValueIfSupported(index, energyUJ);
+                setValueIfSupported(index, chargeUC);
             }
         }
     }
@@ -172,14 +174,14 @@
         final int posOfNumWrittenEntries = out.dataPosition();
         out.writeInt(0);
         int numWrittenEntries = 0;
-        // Write only the supported buckets (with non-zero energy, if applicable).
-        for (int index = 0; index < mAccumulatedEnergiesMicroJoules.length; index++) {
-            final long energy = mAccumulatedEnergiesMicroJoules[index];
-            if (energy < 0) continue;
-            if (energy == 0 && skipZero) continue;
+        // Write only the supported buckets (with non-zero charge, if applicable).
+        for (int index = 0; index < mAccumulatedChargeMicroCoulomb.length; index++) {
+            final long charge = mAccumulatedChargeMicroCoulomb[index];
+            if (charge < 0) continue;
+            if (charge == 0 && skipZero) continue;
 
             out.writeInt(index);
-            out.writeLong(mAccumulatedEnergiesMicroJoules[index]);
+            out.writeLong(charge);
             numWrittenEntries++;
         }
         final int currPos = out.dataPosition();
@@ -190,80 +192,82 @@
 
     /** Get number of possible buckets, including both standard and custom ones. */
     private int getNumberOfIndices() {
-        return mAccumulatedEnergiesMicroJoules.length;
+        return mAccumulatedChargeMicroCoulomb.length;
     }
 
-    /** Updates the given standard energy bucket with the given energy if accumulate is true. */
-    public void updateStandardBucket(@StandardEnergyBucket int bucket, long energyDeltaUJ) {
+
+    /** Updates the given standard power bucket with the given charge if accumulate is true. */
+    public void updateStandardBucket(@StandardPowerBucket int bucket, long chargeDeltaUC) {
         checkValidStandardBucket(bucket);
-        updateEntry(bucket, energyDeltaUJ);
+        updateEntry(bucket, chargeDeltaUC);
     }
 
-    /** Updates the given custom energy bucket with the given energy if accumulate is true. */
-    public void updateCustomBucket(int customBucket, long energyDeltaUJ) {
+    /** Updates the given custom power bucket with the given charge if accumulate is true. */
+    public void updateCustomBucket(int customBucket, long chargeDeltaUC) {
         if (!isValidCustomBucket(customBucket)) {
             Slog.e(TAG, "Attempted to update invalid custom bucket " + customBucket);
             return;
         }
         final int index = customBucketToIndex(customBucket);
-        updateEntry(index, energyDeltaUJ);
+        updateEntry(index, chargeDeltaUC);
     }
 
-    /** Updates the given index with the given energy if accumulate is true. */
-    private void updateEntry(int index, long energyDeltaUJ) {
-        if (mAccumulatedEnergiesMicroJoules[index] >= 0L) {
-            mAccumulatedEnergiesMicroJoules[index] += energyDeltaUJ;
+    /** Updates the given index with the given charge if accumulate is true. */
+    private void updateEntry(int index, long chargeDeltaUC) {
+        if (mAccumulatedChargeMicroCoulomb[index] >= 0L) {
+            mAccumulatedChargeMicroCoulomb[index] += chargeDeltaUC;
         } else {
-            Slog.wtf(TAG, "Attempting to add " + energyDeltaUJ + " to unavailable bucket "
+            Slog.wtf(TAG, "Attempting to add " + chargeDeltaUC + " to unavailable bucket "
                     + getBucketName(index) + " whose value was "
-                    + mAccumulatedEnergiesMicroJoules[index]);
+                    + mAccumulatedChargeMicroCoulomb[index]);
         }
     }
 
     /**
-     * Return accumulated energy (in microjoules) for a standard energy bucket since last reset.
-     * Returns {@link android.os.BatteryStats#ENERGY_DATA_UNAVAILABLE} if this data is unavailable.
-     * @throws IllegalArgumentException if no such {@link StandardEnergyBucket}.
+     * Return accumulated charge (in microcouloumb) for a standard power bucket since last reset.
+     * Returns {@link android.os.BatteryStats#POWER_DATA_UNAVAILABLE} if this data is unavailable.
+     * @throws IllegalArgumentException if no such {@link StandardPowerBucket}.
      */
-    public long getAccumulatedStandardBucketEnergy(@StandardEnergyBucket int bucket) {
+    public long getAccumulatedStandardBucketCharge(@StandardPowerBucket int bucket) {
         checkValidStandardBucket(bucket);
-        return mAccumulatedEnergiesMicroJoules[bucket];
+        return mAccumulatedChargeMicroCoulomb[bucket];
     }
 
     /**
-     * Return accumulated energy (in microjoules) for the a custom energy bucket since last reset.
-     * Returns {@link android.os.BatteryStats#ENERGY_DATA_UNAVAILABLE} if this data is unavailable.
+     * Return accumulated charge (in microcoulomb) for the a custom power bucket since last
+     * reset.
+     * Returns {@link android.os.BatteryStats#POWER_DATA_UNAVAILABLE} if this data is unavailable.
      */
     @VisibleForTesting
-    public long getAccumulatedCustomBucketEnergy(int customBucket) {
+    public long getAccumulatedCustomBucketCharge(int customBucket) {
         if (!isValidCustomBucket(customBucket)) {
-            return ENERGY_DATA_UNAVAILABLE;
+            return POWER_DATA_UNAVAILABLE;
         }
-        return mAccumulatedEnergiesMicroJoules[customBucketToIndex(customBucket)];
+        return mAccumulatedChargeMicroCoulomb[customBucketToIndex(customBucket)];
     }
 
     /**
-     * Return accumulated energies (in microjoules) for all custom energy buckets since last reset.
+     * Return accumulated charge (in microcoulomb) for all custom power buckets since last reset.
      */
-    public @NonNull long[] getAccumulatedCustomBucketEnergies() {
-        final long[] energies = new long[getNumberCustomEnergyBuckets()];
-        for (int bucket = 0; bucket < energies.length; bucket++) {
-            energies[bucket] = mAccumulatedEnergiesMicroJoules[customBucketToIndex(bucket)];
+    public @NonNull long[] getAccumulatedCustomBucketCharges() {
+        final long[] charges = new long[getNumberCustomPowerBuckets()];
+        for (int bucket = 0; bucket < charges.length; bucket++) {
+            charges[bucket] = mAccumulatedChargeMicroCoulomb[customBucketToIndex(bucket)];
         }
-        return energies;
+        return charges;
     }
 
     /**
-     * Map {@link android.view.Display} STATE_ to corresponding {@link StandardEnergyBucket}.
+     * Map {@link android.view.Display} STATE_ to corresponding {@link StandardPowerBucket}.
      */
-    public static @StandardEnergyBucket int getDisplayEnergyBucket(int screenState) {
+    public static @StandardPowerBucket int getDisplayPowerBucket(int screenState) {
         if (Display.isOnState(screenState)) {
-            return ENERGY_BUCKET_SCREEN_ON;
+            return POWER_BUCKET_SCREEN_ON;
         }
         if (Display.isDozeState(screenState)) {
-            return ENERGY_BUCKET_SCREEN_DOZE;
+            return POWER_BUCKET_SCREEN_DOZE;
         }
-        return ENERGY_BUCKET_SCREEN_OTHER;
+        return POWER_BUCKET_SCREEN_OTHER;
     }
 
     /**
@@ -280,9 +284,9 @@
         // Check if any MeasuredEnergyStats exists on the parcel
         if (arraySize == 0) return null;
 
-        final int numCustomBuckets = arraySize - NUMBER_STANDARD_ENERGY_BUCKETS;
+        final int numCustomBuckets = arraySize - NUMBER_STANDARD_POWER_BUCKETS;
         final MeasuredEnergyStats stats = new MeasuredEnergyStats(
-                new boolean[NUMBER_STANDARD_ENERGY_BUCKETS], numCustomBuckets);
+                new boolean[NUMBER_STANDARD_POWER_BUCKETS], numCustomBuckets);
         stats.readSummaryFromParcel(in, true);
         return stats;
     }
@@ -337,8 +341,8 @@
 
     /** Returns true iff any of the buckets are supported and non-zero. */
     private boolean containsInterestingData() {
-        for (int index = 0; index < mAccumulatedEnergiesMicroJoules.length; index++) {
-            if (mAccumulatedEnergiesMicroJoules[index] > 0) return true;
+        for (int index = 0; index < mAccumulatedChargeMicroCoulomb.length; index++) {
+            if (mAccumulatedChargeMicroCoulomb[index] > 0) return true;
         }
         return false;
     }
@@ -359,7 +363,7 @@
         stats.writeSummaryToParcel(dest, skipZero);
     }
 
-    /** Reset accumulated energy. */
+    /** Reset accumulated charges. */
     private void reset() {
         final int numIndices = getNumberOfIndices();
         for (int index = 0; index < numIndices; index++) {
@@ -367,42 +371,42 @@
         }
     }
 
-    /** Reset accumulated energy of the given stats. */
+    /** Reset accumulated charges of the given stats. */
     public static void resetIfNotNull(@Nullable MeasuredEnergyStats stats) {
         if (stats != null) stats.reset();
     }
 
     /** If the index is AVAILABLE, overwrite its value; otherwise leave it as UNAVAILABLE. */
     private void setValueIfSupported(int index, long value) {
-        if (mAccumulatedEnergiesMicroJoules[index] != ENERGY_DATA_UNAVAILABLE) {
-            mAccumulatedEnergiesMicroJoules[index] = value;
+        if (mAccumulatedChargeMicroCoulomb[index] != POWER_DATA_UNAVAILABLE) {
+            mAccumulatedChargeMicroCoulomb[index] = value;
         }
     }
 
     /**
-     * Check if measuring the energy of the given bucket is supported by this device.
-     * @throws IllegalArgumentException if not a valid {@link StandardEnergyBucket}.
+     * Check if measuring the charge consumption of the given bucket is supported by this device.
+     * @throws IllegalArgumentException if not a valid {@link StandardPowerBucket}.
      */
-    public boolean isStandardBucketSupported(@StandardEnergyBucket int bucket) {
+    public boolean isStandardBucketSupported(@StandardPowerBucket int bucket) {
         checkValidStandardBucket(bucket);
         return isIndexSupported(bucket);
     }
 
     private boolean isIndexSupported(int index) {
-        return mAccumulatedEnergiesMicroJoules[index] != ENERGY_DATA_UNAVAILABLE;
+        return mAccumulatedChargeMicroCoulomb[index] != POWER_DATA_UNAVAILABLE;
     }
 
-    /** Check if the supported energy buckets are precisely those given. */
+    /** Check if the supported power buckets are precisely those given. */
     public boolean isSupportEqualTo(
             @NonNull boolean[] queriedStandardBuckets, int numCustomBuckets) {
 
         final int numBuckets = getNumberOfIndices();
         // TODO(b/178504428): Detect whether custom buckets have changed qualitatively, not just
         //                    quantitatively, and treat as mismatch if so.
-        if (numBuckets != NUMBER_STANDARD_ENERGY_BUCKETS + numCustomBuckets) {
+        if (numBuckets != NUMBER_STANDARD_POWER_BUCKETS + numCustomBuckets) {
             return false;
         }
-        for (int stdBucket = 0; stdBucket < NUMBER_STANDARD_ENERGY_BUCKETS; stdBucket++) {
+        for (int stdBucket = 0; stdBucket < NUMBER_STANDARD_POWER_BUCKETS; stdBucket++) {
             if (isStandardBucketSupported(stdBucket) != queriedStandardBuckets[stdBucket]) {
                 return false;
             }
@@ -413,14 +417,14 @@
     /** Dump debug data. */
     public void dump(PrintWriter pw) {
         pw.print("   ");
-        for (int index = 0; index < mAccumulatedEnergiesMicroJoules.length; index++) {
+        for (int index = 0; index < mAccumulatedChargeMicroCoulomb.length; index++) {
             pw.print(getBucketName(index));
             pw.print(" : ");
-            pw.print(mAccumulatedEnergiesMicroJoules[index]);
+            pw.print(mAccumulatedChargeMicroCoulomb[index]);
             if (!isIndexSupported(index)) {
                 pw.print(" (unsupported)");
             }
-            if (index != mAccumulatedEnergiesMicroJoules.length - 1) {
+            if (index != mAccumulatedChargeMicroCoulomb.length - 1) {
                 pw.print(", ");
             }
         }
@@ -433,38 +437,38 @@
      */
     private static String getBucketName(int index) {
         if (isValidStandardBucket(index)) {
-            return DebugUtils.valueToString(MeasuredEnergyStats.class, "ENERGY_BUCKET_", index);
+            return DebugUtils.valueToString(MeasuredEnergyStats.class, "POWER_BUCKET_", index);
         }
         return "CUSTOM_" + indexToCustomBucket(index);
     }
 
-    /** Get the number of custom energy buckets on this device. */
-    public int getNumberCustomEnergyBuckets() {
-        return mAccumulatedEnergiesMicroJoules.length - NUMBER_STANDARD_ENERGY_BUCKETS;
+    /** Get the number of custom power buckets on this device. */
+    public int getNumberCustomPowerBuckets() {
+        return mAccumulatedChargeMicroCoulomb.length - NUMBER_STANDARD_POWER_BUCKETS;
     }
 
     private static int customBucketToIndex(int customBucket) {
-        return customBucket + NUMBER_STANDARD_ENERGY_BUCKETS;
+        return customBucket + NUMBER_STANDARD_POWER_BUCKETS;
     }
 
     private static int indexToCustomBucket(int index) {
-        return index - NUMBER_STANDARD_ENERGY_BUCKETS;
+        return index - NUMBER_STANDARD_POWER_BUCKETS;
     }
 
-    private static void checkValidStandardBucket(@StandardEnergyBucket int bucket) {
+    private static void checkValidStandardBucket(@StandardPowerBucket int bucket) {
         if (!isValidStandardBucket(bucket)) {
-            throw new IllegalArgumentException("Illegal StandardEnergyBucket " + bucket);
+            throw new IllegalArgumentException("Illegal StandardPowerBucket " + bucket);
         }
     }
 
-    private static boolean isValidStandardBucket(@StandardEnergyBucket int bucket) {
-        return bucket >= 0 && bucket < NUMBER_STANDARD_ENERGY_BUCKETS;
+    private static boolean isValidStandardBucket(@StandardPowerBucket int bucket) {
+        return bucket >= 0 && bucket < NUMBER_STANDARD_POWER_BUCKETS;
     }
 
     /** Returns whether the given custom bucket is valid (exists) on this device. */
     @VisibleForTesting
     public boolean isValidCustomBucket(int customBucket) {
         return customBucket >= 0
-                && customBucketToIndex(customBucket) < mAccumulatedEnergiesMicroJoules.length;
+                && customBucketToIndex(customBucket) < mAccumulatedChargeMicroCoulomb.length;
     }
 }
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index fde48e8..2e25ea3 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -79,7 +79,7 @@
             in int notificationLocation, boolean modifiedBeforeSending);
     void onNotificationSettingsViewed(String key);
     void onNotificationBubbleChanged(String key, boolean isBubble, int flags);
-    void onBubbleNotificationSuppressionChanged(String key, boolean isSuppressed);
+    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);
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index 8dcb210..de65b89 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -905,7 +905,7 @@
             continue;
         }
 
-        if (!AppendDmaBufInfo(pid, &dmabufs, false)) {
+        if (!ReadDmaBufMapRefs(pid, &dmabufs)) {
             LOG(ERROR) << "Failed to read maps for pid " << pid;
         }
     }
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 19f1f03..f7eb364 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1915,7 +1915,7 @@
          @hide
     -->
     <permission android:name="android.permission.SUSPEND_APPS"
-        android:protectionLevel="signature|wellbeing" />
+        android:protectionLevel="signature|role" />
 
     <!-- Allows applications to discover and pair bluetooth devices.
          <p>Protection level: normal
@@ -2706,9 +2706,10 @@
     <permission android:name="android.permission.START_ACTIVITIES_FROM_BACKGROUND"
         android:protectionLevel="signature|privileged|vendorPrivileged|oem|verifier" />
 
-    <!-- @SystemApi @hide Allows an application to start foreground services from background -->
+    <!-- Allows an application to start foreground services from background, can only be granted to
+         privileged apps or app that is SMS/EMERGENCY/SYSTEM GALLERY roles. -->
     <permission android:name="android.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND"
-                android:protectionLevel="signature|privileged|vendorPrivileged|oem|verifier" />
+                android:protectionLevel="signature|privileged|vendorPrivileged|oem|verifier|role"/>
 
     <!-- @SystemApi Must be required by activities that handle the intent action
          {@link Intent#ACTION_SEND_SHOW_SUSPENDED_APP_DETAILS}. This is for use by apps that
@@ -2789,7 +2790,7 @@
 
          <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.SYSTEM_APPLICATION_OVERLAY"
-                android:protectionLevel="signature|recents|wellbeing"/>
+                android:protectionLevel="signature|recents|role"/>
 
     <!-- @deprecated Use {@link android.Manifest.permission#REQUEST_COMPANION_RUN_IN_BACKGROUND}
          @hide
@@ -5138,7 +5139,7 @@
     <!-- @SystemApi Allows the holder to access and manage instant applications on the device.
          @hide -->
     <permission android:name="android.permission.ACCESS_INSTANT_APPS"
-            android:protectionLevel="signature|installer|verifier|wellbeing" />
+            android:protectionLevel="signature|installer|verifier|role" />
     <uses-permission android:name="android.permission.ACCESS_INSTANT_APPS"/>
 
     <!-- Allows the holder to view the instant applications on the device.
@@ -5318,7 +5319,7 @@
     <!-- @SystemApi Allows an application to turn on / off quiet mode.
          @hide -->
     <permission android:name="android.permission.MODIFY_QUIET_MODE"
-                android:protectionLevel="signature|privileged|wellbeing|development" />
+                android:protectionLevel="signature|privileged|development" />
 
     <!-- Allows internal management of the camera framework
          @hide -->
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index efc8fe9..e0a116b 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3853,6 +3853,15 @@
         <!-- Attribute whether the accessibility service wants to be able to take screenshot. -->
         <attr name="canTakeScreenshot" format="boolean" />
 
+        <!-- Attribute indicating whether the accessibility service is used to assist users with
+             disabilities. This criteria might be defined by the installer. The default is false.
+             <p>
+             Note: If this flag is false, system will show a notification after a duration to
+             inform the user about the privacy implications of the service.
+             </p>
+        -->
+        <attr name="isAccessibilityTool" format="boolean" />
+
         <!-- Animated image of the accessibility service purpose or behavior, to help users
              understand how the service can help them.-->
         <attr name="animatedImageDrawable" format="reference"/>
@@ -8633,6 +8642,9 @@
          Described here are the attributes that can be included in that tag. -->
     <declare-styleable name="RecognitionService">
         <attr name="settingsActivity" />
+        <!-- Flag indicating whether a recognition service can be selected as default. The default
+             value of this flag is true. -->
+        <attr name="selectableAsDefault" format="boolean" />
     </declare-styleable>
 
     <!-- Use <code>voice-interaction-service</code> as the root tag of the XML resource that
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index bed5c31..cc52655ad7 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -285,9 +285,6 @@
         <!-- Additional flag from base permission type: this permission can be automatically
             granted to the system default text classifier -->
         <flag name="textClassifier" value="0x10000" />
-        <!-- Additional flag from base permission type: this permission will be granted to the
-             wellbeing app, as defined by the OEM. -->
-        <flag name="wellbeing" value="0x20000" />
         <!-- Additional flag from base permission type: this permission can be automatically
             granted to the document manager -->
         <flag name="documenter" value="0x40000" />
@@ -825,6 +822,12 @@
             <a href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">Tasks and Back
             Stack</a> document for more details about tasks.-->
         <enum name="singleInstance" value="3" />
+        <!-- The activity can only be running as the root activity of the task, the first activity
+            that created the task, and therefore there will only be one instance of this activity
+            in a task. In constrast to the {@code singleTask} launch mode, this activity can be
+            started in multiple instances in different tasks if the
+            {@code FLAG_ACTIVITY_MULTIPLE_TASK} is set.-->
+        <enum name="singleInstancePerTask" value="4" />
     </attr>
 
     <!-- Specify the orientation an activity should be run in.  If not
@@ -1370,7 +1373,7 @@
          <p>The default value of this attribute is <code>false</code>. -->
     <attr name="resumeWhilePausing" format="boolean" />
 
-    <!-- Indicates that it is okay for this activity to be put in multi-window mode. Intended for a
+    <!-- Hint to platform that the activity works well in multi-window mode. Intended for a
          multi-window device where there can be multiple activities of various sizes on the screen
          at the same time.
 
@@ -1390,7 +1393,7 @@
          resizeable.
 
          <p>NOTE: The value of {@link android.R.attr#screenOrientation} is ignored for
-         resizeable activities when in multi-window mode. -->
+         resizeable activities when in multi-window mode before Android 12. -->
     <attr name="resizeableActivity" format="boolean" />
 
     <!-- Indicates that the activity specifically supports the picture-in-picture form of
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index c00581f..22467e4 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -171,7 +171,7 @@
     <color name="accessibility_focus_highlight_color">#bf39b500</color>
     <color name="autofilled_highlight">#4dffeb3b</color>
 
-    <color name="system_notification_accent_color">#ff607D8B</color>
+    <color name="system_notification_accent_color">#00000000</color>
 
     <!-- Default user icon colors -->
     <color name="user_icon_1">#ff00bcd4</color><!-- cyan 500 -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 247ca16..8bc3a52 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1959,6 +1959,8 @@
     <string name="config_systemSpeechRecognizer" translatable="false"></string>
     <!-- The name of the package that will hold the system Wi-Fi coex manager role. -->
     <string name="config_systemWifiCoexManager" translateable="false"></string>
+    <!-- The name of the package that will hold the wellbeing role. -->
+    <string name="config_systemWellbeing" translatable="false"></string>
 
     <!-- The name of the package that will be allowed to change its components' label/icon. -->
     <string name="config_overrideComponentUiPackage" translatable="false"></string>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 7702ee4..293018d 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3086,6 +3086,8 @@
     <public name="hand_secondTintMode"/>
     <public name="dataExtractionRules"/>
     <public name="passwordsActivity"/>
+    <public name="selectableAsDefault"/>
+    <public name="isAccessibilityTool"/>
   </public-group>
 
   <public-group type="drawable" first-id="0x010800b5">
@@ -3171,6 +3173,8 @@
     <public name="config_systemSpeechRecognizer" />
     <!-- @hide @SystemApi -->
     <public name="config_systemWifiCoexManager" />
+    <!-- @hide @SystemApi -->
+    <public name="config_systemWellbeing" />
   </public-group>
 
   <public-group type="id" first-id="0x01020055">
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 9e6827c..78569bd 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
@@ -38,14 +38,9 @@
     private static final String[] PACKAGES_SYSTEM = {PACKAGE_MEDIA_PROVIDER,
             PACKAGE_CALENDAR_PROVIDER, PACKAGE_SYSTEMUI};
 
-    // Temporary placeholder voltage for converting energy to charge
-    // TODO: remove this when b/173765509 is resolved
-    private static final double MOCK_NOMINAL_VOLTAGE = 3.7;
-
     // Unit conversion:
-    //   mAh = uWs * (1/1000)(milli/micro) * (1/Voltage) * (1/3600)(hours/second)
-    private static final double UJ_2_MAH =
-            (1.0 / 1000) * (1.0 / MOCK_NOMINAL_VOLTAGE) * (1.0 / 3600);
+    //   mAh = uC * (1/1000)(milli/micro) * (1/3600)(hours/second)
+    private static final double UC_2_MAH = (1.0 / 1000)  * (1.0 / 3600);
 
     enum EntryType {
         POWER,
@@ -178,8 +173,10 @@
 
         mBatteryConsumerInfo = BatteryConsumerInfoHelper.makeBatteryConsumerInfo(
                 context.getPackageManager(), requestedBatterySipper);
-        long totalScreenMeasuredEnergyUJ = batteryStats.getScreenOnEnergy();
-        long uidScreenMeasuredEnergyUJ = requestedBatterySipper.uidObj.getScreenOnEnergy();
+        long totalScreenMeasuredChargeUC =
+                batteryStats.getScreenOnMeasuredBatteryConsumptionUC();
+        long uidScreenMeasuredChargeUC =
+                requestedBatterySipper.uidObj.getScreenOnMeasuredBatteryConsumptionUC();
 
         addEntry("Total power", EntryType.POWER,
                 requestedBatterySipper.totalSmearedPowerMah, totalSmearedPowerMah);
@@ -189,10 +186,10 @@
                 requestedBatterySipper.totalSmearedPowerMah, totalPowerExcludeSystemMah);
         addEntry("Screen, smeared", EntryType.POWER,
                 requestedBatterySipper.screenPowerMah, totalScreenPower);
-        if (uidScreenMeasuredEnergyUJ != BatteryStats.ENERGY_DATA_UNAVAILABLE
-                && totalScreenMeasuredEnergyUJ != BatteryStats.ENERGY_DATA_UNAVAILABLE) {
-            final double measuredCharge = UJ_2_MAH * uidScreenMeasuredEnergyUJ;
-            final double totalMeasuredCharge = UJ_2_MAH * totalScreenMeasuredEnergyUJ;
+        if (uidScreenMeasuredChargeUC != BatteryStats.POWER_DATA_UNAVAILABLE
+                && totalScreenMeasuredChargeUC != BatteryStats.POWER_DATA_UNAVAILABLE) {
+            final double measuredCharge = UC_2_MAH * uidScreenMeasuredChargeUC;
+            final double totalMeasuredCharge = UC_2_MAH * totalScreenMeasuredChargeUC;
             addEntry("Screen, measured", EntryType.POWER,
                     measuredCharge, totalMeasuredCharge);
         }
@@ -297,17 +294,19 @@
             BatteryStats batteryStats) {
         switch (drainType) {
             case AMBIENT_DISPLAY:
-                final long totalDozeMeasuredEnergyUJ = batteryStats.getScreenDozeEnergy();
-                if (totalDozeMeasuredEnergyUJ != BatteryStats.ENERGY_DATA_UNAVAILABLE) {
-                    final double measuredCharge = UJ_2_MAH * totalDozeMeasuredEnergyUJ;
+                final long totalDozeMeasuredChargeUC =
+                        batteryStats.getScreenDozeMeasuredBatteryConsumptionUC();
+                if (totalDozeMeasuredChargeUC != BatteryStats.POWER_DATA_UNAVAILABLE) {
+                    final double measuredCharge = UC_2_MAH * totalDozeMeasuredChargeUC;
                     addEntry("Measured ambient display power", EntryType.POWER, measuredCharge,
                             measuredCharge);
                 }
                 break;
             case SCREEN:
-                final long totalScreenMeasuredEnergyUJ = batteryStats.getScreenOnEnergy();
-                if (totalScreenMeasuredEnergyUJ != BatteryStats.ENERGY_DATA_UNAVAILABLE) {
-                    final double measuredCharge = UJ_2_MAH * totalScreenMeasuredEnergyUJ;
+                final long totalScreenMeasuredChargeUC =
+                        batteryStats.getScreenOnMeasuredBatteryConsumptionUC();
+                if (totalScreenMeasuredChargeUC != BatteryStats.POWER_DATA_UNAVAILABLE) {
+                    final double measuredCharge = UC_2_MAH * totalScreenMeasuredChargeUC;
                     addEntry("Measured screen power", EntryType.POWER, measuredCharge,
                             measuredCharge);
                 }
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityInteractionClientTest.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityInteractionClientTest.java
index 7e1e7f4..ab24f89 100644
--- a/core/tests/coretests/src/android/view/accessibility/AccessibilityInteractionClientTest.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityInteractionClientTest.java
@@ -33,6 +33,9 @@
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 
+import java.util.Arrays;
+import java.util.List;
+
 /**
  * Tests for AccessibilityInteractionClient
  */
@@ -62,7 +65,7 @@
         final long accessibilityNodeId = 0x4321L;
         AccessibilityNodeInfo nodeFromConnection = AccessibilityNodeInfo.obtain();
         nodeFromConnection.setSourceNodeId(accessibilityNodeId, windowId);
-        mMockConnection.mInfoToReturn = nodeFromConnection;
+        mMockConnection.mInfosToReturn = Arrays.asList(nodeFromConnection);
         AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
         AccessibilityNodeInfo node = client.findAccessibilityNodeInfoByAccessibilityId(
                 MOCK_CONNECTION_ID, windowId, accessibilityNodeId, true, 0, null);
@@ -72,7 +75,7 @@
     }
 
     private static class MockConnection extends AccessibilityServiceConnectionImpl {
-        AccessibilityNodeInfo mInfoToReturn;
+        List<AccessibilityNodeInfo> mInfosToReturn;
 
         @Override
         public String[] findAccessibilityNodeInfoByAccessibilityId(int accessibilityWindowId,
@@ -80,7 +83,7 @@
                 IAccessibilityInteractionConnectionCallback callback, int flags, long threadId,
                 Bundle arguments) {
             try {
-                callback.setFindAccessibilityNodeInfoResult(mInfoToReturn, interactionId);
+                callback.setFindAccessibilityNodeInfosResult(mInfosToReturn, interactionId);
             } catch (RemoteException e) {
                 throw new RuntimeException(e);
             }
diff --git a/core/tests/coretests/src/com/android/internal/jank/FrameTrackerTest.java b/core/tests/coretests/src/com/android/internal/jank/FrameTrackerTest.java
index 9cb7876..64bcc1c 100644
--- a/core/tests/coretests/src/com/android/internal/jank/FrameTrackerTest.java
+++ b/core/tests/coretests/src/com/android/internal/jank/FrameTrackerTest.java
@@ -98,9 +98,10 @@
         mListenerCapture = ArgumentCaptor.forClass(OnJankDataListener.class);
         doNothing().when(mSurfaceControlWrapper).addJankStatsListener(
                 mListenerCapture.capture(), any());
+        doNothing().when(mSurfaceControlWrapper).removeJankStatsListener(
+                mListenerCapture.capture());
         mChoreographer = mock(ChoreographerWrapper.class);
 
-
         Session session = new Session(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE);
         mTracker = Mockito.spy(
                 new FrameTracker(session, handler, mRenderer, mViewRootWrapper,
@@ -127,11 +128,12 @@
         sendFirstWindowFrame(5, JANK_NONE, 101L);
 
         // end the trace session, the last janky frame is after the end() so is discarded.
-        when(mChoreographer.getVsyncId()).thenReturn(101L);
+        when(mChoreographer.getVsyncId()).thenReturn(102L);
         mTracker.end();
-        sendFrame(500, JANK_APP_DEADLINE_MISSED, 102L);
+        sendFrame(5, JANK_NONE, 102L);
+        sendFrame(500, JANK_APP_DEADLINE_MISSED, 103L);
 
-        verify(mRenderer).removeObserver(any());
+        verify(mTracker).removeObservers();
         verify(mTracker, never()).triggerPerfetto();
     }
 
@@ -148,11 +150,11 @@
         sendFrame(40, JANK_SURFACEFLINGER_DEADLINE_MISSED, 101L);
 
         // end the trace session
-        when(mChoreographer.getVsyncId()).thenReturn(101L);
+        when(mChoreographer.getVsyncId()).thenReturn(102L);
         mTracker.end();
         sendFrame(4, JANK_NONE, 102L);
 
-        verify(mRenderer).removeObserver(any());
+        verify(mTracker).removeObservers();
 
         // We detected a janky frame - trigger Perfetto
         verify(mTracker).triggerPerfetto();
@@ -171,11 +173,11 @@
         sendFrame(4, JANK_NONE, 101L);
 
         // end the trace session
-        when(mChoreographer.getVsyncId()).thenReturn(101L);
+        when(mChoreographer.getVsyncId()).thenReturn(102L);
         mTracker.end();
         sendFrame(4, JANK_NONE, 102L);
 
-        verify(mRenderer).removeObserver(any());
+        verify(mTracker).removeObservers();
 
         // We detected a janky frame - trigger Perfetto
         verify(mTracker, never()).triggerPerfetto();
@@ -194,11 +196,11 @@
         sendFrame(40, JANK_APP_DEADLINE_MISSED, 101L);
 
         // end the trace session
-        when(mChoreographer.getVsyncId()).thenReturn(101L);
+        when(mChoreographer.getVsyncId()).thenReturn(102L);
         mTracker.end();
         sendFrame(4, JANK_NONE, 102L);
 
-        verify(mRenderer).removeObserver(any());
+        verify(mTracker).removeObservers();
 
         // We detected a janky frame - trigger Perfetto
         verify(mTracker).triggerPerfetto();
@@ -224,7 +226,7 @@
         // One more callback with VSYNC after the end() vsync id.
         sendFrame(4, JANK_NONE, 103L);
 
-        verify(mRenderer).removeObserver(any());
+        verify(mTracker).removeObservers();
 
         // We detected a janky frame - trigger Perfetto
         verify(mTracker).triggerPerfetto();
@@ -246,11 +248,50 @@
         sendFrame(50, JANK_APP_DEADLINE_MISSED, 102L);
 
         mTracker.cancel();
-        verify(mRenderer).removeObserver(any());
+        verify(mTracker).removeObservers();
         // Since the tracker has been cancelled, shouldn't trigger perfetto.
         verify(mTracker, never()).triggerPerfetto();
     }
 
+    @Test
+    public void testRemoveObserversWhenCancelledInEnd() {
+        when(mChoreographer.getVsyncId()).thenReturn(100L);
+        mTracker.begin();
+        verify(mRenderer, only()).addObserver(any());
+
+        // send first frame - not janky
+        sendFrame(4, JANK_NONE, 100L);
+
+        // send another frame - should be considered janky
+        sendFrame(40, JANK_APP_DEADLINE_MISSED, 101L);
+
+        // end the trace session
+        when(mChoreographer.getVsyncId()).thenReturn(101L);
+        mTracker.end();
+        sendFrame(4, JANK_NONE, 102L);
+
+        // Since the begin vsync id (101) equals to the end vsync id (101), will be treat as cancel.
+        verify(mTracker).cancel();
+
+        // Observers should be removed in this case, or FrameTracker object will be leaked.
+        verify(mTracker).removeObservers();
+
+        // Should never trigger Perfetto since it is a cancel.
+        verify(mTracker, never()).triggerPerfetto();
+    }
+
+    @Test
+    public void testCancelWhenSessionNeverBegun() {
+        mTracker.cancel();
+        verify(mTracker).removeObservers();
+    }
+
+    @Test
+    public void testEndWhenSessionNeverBegun() {
+        mTracker.end();
+        verify(mTracker).removeObservers();
+    }
+
     private void sendFirstWindowFrame(long durationMillis,
             @JankType int jankType, long vsyncId) {
         sendFrame(durationMillis, jankType, vsyncId, true /* firstWindowFrame */);
diff --git a/core/tests/coretests/src/com/android/internal/os/AmbientDisplayPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/AmbientDisplayPowerCalculatorTest.java
index add0469..c67f901 100644
--- a/core/tests/coretests/src/com/android/internal/os/AmbientDisplayPowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/AmbientDisplayPowerCalculatorTest.java
@@ -44,18 +44,18 @@
     public void testMeasuredEnergyBasedModel() {
         BatteryStatsImpl stats = mStatsRule.getBatteryStats();
 
-        stats.updateDisplayEnergyLocked(300_000_000, Display.STATE_ON, 0);
+        stats.updateDisplayMeasuredEnergyStatsLocked(300_000_000, Display.STATE_ON, 0);
 
         stats.noteScreenStateLocked(Display.STATE_DOZE, 30 * MINUTE_IN_MS, 30 * MINUTE_IN_MS,
                 30 * MINUTE_IN_MS);
 
-        stats.updateDisplayEnergyLocked(200_000_000, Display.STATE_DOZE,
+        stats.updateDisplayMeasuredEnergyStatsLocked(200_000_000, Display.STATE_DOZE,
                 30 * MINUTE_IN_MS);
 
         stats.noteScreenStateLocked(Display.STATE_OFF, 120 * MINUTE_IN_MS, 120 * MINUTE_IN_MS,
                 120 * MINUTE_IN_MS);
 
-        stats.updateDisplayEnergyLocked(100_000_000, Display.STATE_OFF,
+        stats.updateDisplayMeasuredEnergyStatsLocked(100_000_000, Display.STATE_OFF,
                 120 * MINUTE_IN_MS);
 
         AmbientDisplayPowerCalculator calculator =
@@ -68,8 +68,9 @@
                         SystemBatteryConsumer.DRAIN_TYPE_AMBIENT_DISPLAY);
         assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_USAGE))
                 .isEqualTo(90 * MINUTE_IN_MS);
+        // 100,000,00 uC / 1000 (micro-/milli-) / 360 (seconds/hour) = 27.777778 mAh
         assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE))
-                .isWithin(PRECISION).of(7.5075075);
+                .isWithin(PRECISION).of(27.777778);
     }
 
     @Test
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsCpuTimesTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsCpuTimesTest.java
index ff728d6..4319740 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsCpuTimesTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsCpuTimesTest.java
@@ -121,7 +121,7 @@
         when(mCpuUidFreqTimeReader.readFreqs(mPowerProfile)).thenReturn(freqs);
 
         // RUN
-        mBatteryStatsImpl.updateCpuTimeLocked(false, false);
+        mBatteryStatsImpl.updateCpuTimeLocked(false, false, null);
 
         // VERIFY
         assertArrayEquals("Unexpected cpu freqs", freqs, mBatteryStatsImpl.getCpuFreqs());
@@ -141,7 +141,7 @@
         mBatteryStatsImpl.setOnBatteryInternal(true);
 
         // RUN
-        mBatteryStatsImpl.updateCpuTimeLocked(true, false);
+        mBatteryStatsImpl.updateCpuTimeLocked(true, false, null);
 
         // VERIFY
         verify(mUserInfoProvider).refreshUserIds();
@@ -221,7 +221,7 @@
         }
 
         // RUN
-        mBatteryStatsImpl.updateClusterSpeedTimes(updatedUids, true);
+        mBatteryStatsImpl.updateClusterSpeedTimes(updatedUids, true, null);
 
         // VERIFY
         int totalClustersTimeMs = 0;
@@ -563,7 +563,7 @@
                 any(KernelCpuUidFreqTimeReader.Callback.class));
 
         // RUN
-        mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, false);
+        mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, false, null);
 
         // VERIFY
         for (int i = 0; i < testUids.length; ++i) {
@@ -596,7 +596,7 @@
                 any(KernelCpuUidFreqTimeReader.Callback.class));
 
         // RUN
-        mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, true);
+        mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, true, null);
 
         // VERIFY
         for (int i = 0; i < testUids.length; ++i) {
@@ -647,7 +647,7 @@
         when(mCpuUidFreqTimeReader.perClusterTimesAvailable()).thenReturn(true);
 
         // RUN
-        mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, false);
+        mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, false, null);
 
         // VERIFY
         for (int i = 0; i < testUids.length; ++i) {
@@ -690,7 +690,7 @@
                 any(KernelCpuUidFreqTimeReader.Callback.class));
 
         // RUN
-        mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, true);
+        mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, true, null);
 
         // VERIFY
         for (int i = 0; i < testUids.length; ++i) {
@@ -757,7 +757,7 @@
         when(mCpuUidFreqTimeReader.perClusterTimesAvailable()).thenReturn(true);
 
         // RUN
-        mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(partialTimers, true, false);
+        mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(partialTimers, true, false, null);
 
         // VERIFY
         final long[][] expectedWakeLockUidTimesUs = new long[clusterFreqs.length][];
@@ -846,7 +846,7 @@
                 any(KernelCpuUidFreqTimeReader.Callback.class));
 
         // RUN
-        mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, false);
+        mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, false, null);
 
         // VERIFY
         for (int i = 0; i < testUids.length; ++i) {
@@ -879,7 +879,7 @@
                 any(KernelCpuUidFreqTimeReader.Callback.class));
 
         // RUN
-        mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, true);
+        mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, true, null);
 
         // VERIFY
         for (int i = 0; i < testUids.length; ++i) {
@@ -923,7 +923,7 @@
                 any(KernelCpuUidFreqTimeReader.Callback.class));
 
         // RUN
-        mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, false);
+        mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, false, null);
 
         // VERIFY
         for (int i = 0; i < testUids.length; ++i) {
@@ -963,7 +963,7 @@
                 any(KernelCpuUidFreqTimeReader.Callback.class));
 
         // RUN
-        mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, false);
+        mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, false, null);
 
         // VERIFY
         for (int i = 0; i < testUids.length; ++i) {
@@ -1020,7 +1020,7 @@
                 any(KernelCpuUidFreqTimeReader.Callback.class));
 
         // RUN
-        mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, false);
+        mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, false, null);
 
         // VERIFY
         for (int i = 0; i < testUids.length; ++i) {
@@ -1169,7 +1169,7 @@
                 any(KernelCpuUidClusterTimeReader.Callback.class));
 
         // RUN
-        mBatteryStatsImpl.readKernelUidCpuClusterTimesLocked(true);
+        mBatteryStatsImpl.readKernelUidCpuClusterTimesLocked(true, null);
 
         // VERIFY
         for (int i = 0; i < testUids.length; ++i) {
@@ -1199,7 +1199,7 @@
                 any(KernelCpuUidClusterTimeReader.Callback.class));
 
         // RUN
-        mBatteryStatsImpl.readKernelUidCpuClusterTimesLocked(true);
+        mBatteryStatsImpl.readKernelUidCpuClusterTimesLocked(true, null);
 
         // VERIFY
         for (int i = 0; i < testUids.length; ++i) {
@@ -1244,7 +1244,7 @@
                 any(KernelCpuUidClusterTimeReader.Callback.class));
 
         // RUN
-        mBatteryStatsImpl.readKernelUidCpuClusterTimesLocked(true);
+        mBatteryStatsImpl.readKernelUidCpuClusterTimesLocked(true, null);
 
         // VERIFY
         for (int i = 0; i < testUids.length; ++i) {
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 931611e..f168b3c 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
@@ -503,7 +503,7 @@
     }
 
     @SmallTest
-    public void testUpdateDisplayEnergyLocked() {
+    public void testUpdateDisplayMeasuredEnergyStatsLocked() {
         final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms
         final MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
 
@@ -520,8 +520,8 @@
         // Case A: uid1 off, uid2 off, battery off, screen off
         bi.updateTimeBasesLocked(battery, screen, clocks.realtime*1000, 0);
         bi.setOnBatteryInternal(battery);
-        bi.updateDisplayEnergyLocked(500_000, screen, clocks.realtime);
-        checkMeasuredEnergy("A", uid1, blame1, uid2, blame2, globalDoze, bi);
+        bi.updateDisplayMeasuredEnergyStatsLocked(500_000, screen, clocks.realtime);
+        checkMeasuredCharge("A", uid1, blame1, uid2, blame2, globalDoze, bi);
 
         // Case B: uid1 off, uid2 off, battery ON,  screen off
         clocks.realtime += 17;
@@ -529,65 +529,65 @@
         bi.updateTimeBasesLocked(battery, screen, clocks.realtime*1000, 0);
         bi.setOnBatteryInternal(battery);
         clocks.realtime += 19;
-        bi.updateDisplayEnergyLocked(510_000, screen, clocks.realtime);
-        checkMeasuredEnergy("B", uid1, blame1, uid2, blame2, globalDoze, bi);
+        bi.updateDisplayMeasuredEnergyStatsLocked(510_000, screen, clocks.realtime);
+        checkMeasuredCharge("B", uid1, blame1, uid2, blame2, globalDoze, bi);
 
         // Case C: uid1 ON,  uid2 off, battery on,  screen off
         clocks.realtime += 18;
         setFgState(uid1, true, bi);
         clocks.realtime += 18;
-        bi.updateDisplayEnergyLocked(520_000, screen, clocks.realtime);
-        checkMeasuredEnergy("C", uid1, blame1, uid2, blame2, globalDoze, bi);
+        bi.updateDisplayMeasuredEnergyStatsLocked(520_000, screen, clocks.realtime);
+        checkMeasuredCharge("C", uid1, blame1, uid2, blame2, globalDoze, bi);
 
         // Case D: uid1 on,  uid2 off, battery on,  screen ON
         clocks.realtime += 17;
         screen = Display.STATE_ON;
-        bi.updateDisplayEnergyLocked(521_000, screen, clocks.realtime);
+        bi.updateDisplayMeasuredEnergyStatsLocked(521_000, screen, clocks.realtime);
         blame1 += 0; // Screen had been off during the measurement period
-        checkMeasuredEnergy("D.1", uid1, blame1, uid2, blame2, globalDoze, bi);
+        checkMeasuredCharge("D.1", uid1, blame1, uid2, blame2, globalDoze, bi);
         clocks.realtime += 101;
-        bi.updateDisplayEnergyLocked(530_000, screen, clocks.realtime);
+        bi.updateDisplayMeasuredEnergyStatsLocked(530_000, screen, clocks.realtime);
         blame1 += 530_000;
-        checkMeasuredEnergy("D.2", uid1, blame1, uid2, blame2, globalDoze, bi);
+        checkMeasuredCharge("D.2", uid1, blame1, uid2, blame2, globalDoze, bi);
 
         // Case E: uid1 on,  uid2 ON,  battery on,  screen on
         clocks.realtime += 20;
         setFgState(uid2, true, bi);
         clocks.realtime += 40;
-        bi.updateDisplayEnergyLocked(540_000, screen, clocks.realtime);
+        bi.updateDisplayMeasuredEnergyStatsLocked(540_000, screen, clocks.realtime);
         // In the past 60ms, sum of fg is 20+40+40=100ms. uid1 is blamed for 60/100; uid2 for 40/100
         blame1 += 540_000 * (20 + 40) / (20 + 40 + 40);
         blame2 += 540_000 * ( 0 + 40) / (20 + 40 + 40);
-        checkMeasuredEnergy("E", uid1, blame1, uid2, blame2, globalDoze, bi);
+        checkMeasuredCharge("E", uid1, blame1, uid2, blame2, globalDoze, bi);
 
         // Case F: uid1 on,  uid2 OFF, battery on,  screen on
         clocks.realtime += 40;
         setFgState(uid2, false, bi);
         clocks.realtime += 120;
-        bi.updateDisplayEnergyLocked(550_000, screen, clocks.realtime);
+        bi.updateDisplayMeasuredEnergyStatsLocked(550_000, screen, clocks.realtime);
         // In the past 160ms, sum f fg is 200ms. uid1 is blamed for 40+120 of it; uid2 for 40 of it.
         blame1 += 550_000 * (40 + 120) / (40 + 40 + 120);
         blame2 += 550_000 * (40 + 0  ) / (40 + 40 + 120);
-        checkMeasuredEnergy("F", uid1, blame1, uid2, blame2, globalDoze, bi);
+        checkMeasuredCharge("F", uid1, blame1, uid2, blame2, globalDoze, bi);
 
         // Case G: uid1 on,  uid2 off,  battery on, screen DOZE
         clocks.realtime += 5;
         screen = Display.STATE_DOZE;
-        bi.updateDisplayEnergyLocked(570_000, screen, clocks.realtime);
+        bi.updateDisplayMeasuredEnergyStatsLocked(570_000, screen, clocks.realtime);
         blame1 += 570_000; // All of this pre-doze time is blamed on uid1.
-        checkMeasuredEnergy("G", uid1, blame1, uid2, blame2, globalDoze, bi);
+        checkMeasuredCharge("G", uid1, blame1, uid2, blame2, globalDoze, bi);
 
         // Case H: uid1 on,  uid2 off,  battery on, screen ON
         clocks.realtime += 6;
         screen = Display.STATE_ON;
-        bi.updateDisplayEnergyLocked(580_000, screen, clocks.realtime);
+        bi.updateDisplayMeasuredEnergyStatsLocked(580_000, screen, clocks.realtime);
         blame1 += 0; // The screen had been doze during the energy period
         globalDoze += 580_000;
-        checkMeasuredEnergy("H", uid1, blame1, uid2, blame2, globalDoze, bi);
+        checkMeasuredCharge("H", uid1, blame1, uid2, blame2, globalDoze, bi);
     }
 
     @SmallTest
-    public void testUpdateCustomMeasuredEnergyDataLocked_neverCalled() {
+    public void testUpdateCustomMeasuredEnergyStatsLocked_neverCalled() {
         final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms
         final MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
         bi.setOnBatteryInternal(true);
@@ -595,20 +595,20 @@
         final int uid1 = 11500;
         final int uid2 = 11501;
 
-        // Initially, all custom buckets report energy of 0.
-        checkCustomMeasuredEnergy("0", 0, 0, uid1, 0, 0, uid2, 0, 0, bi);
+        // Initially, all custom buckets report charge of 0.
+        checkCustomBatteryConsumption("0", 0, 0, uid1, 0, 0, uid2, 0, 0, bi);
     }
 
     @SmallTest
-    public void testUpdateCustomMeasuredEnergyDataLocked() {
+    public void testUpdateCustomMeasuredEnergyStatsLocked() {
         final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms
         final MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
 
         final int bucketA = 0; // Custom bucket 0
         final int bucketB = 1; // Custom bucket 1
 
-        long totalBlameA = 0; // Total energy consumption for bucketA (may exceed sum of uids)
-        long totalBlameB = 0; // Total energy consumption for bucketB (may exceed sum of uids)
+        long totalBlameA = 0; // Total charge consumption for bucketA (may exceed sum of uids)
+        long totalBlameB = 0; // Total charge consumption for bucketB (may exceed sum of uids)
 
         final int uid1 = 10500;
         long blame1A = 0; // Blame for uid1 in bucketA
@@ -618,60 +618,60 @@
         long blame2A = 0; // Blame for uid2 in bucketA
         long blame2B = 0; // Blame for uid2 in bucketB
 
-        final SparseLongArray newEnergiesA = new SparseLongArray(2);
-        final SparseLongArray newEnergiesB = new SparseLongArray(2);
+        final SparseLongArray newChargesA = new SparseLongArray(2);
+        final SparseLongArray newChargesB = new SparseLongArray(2);
 
 
         // ----- Case A: battery off (so blame does not increase)
         bi.setOnBatteryInternal(false);
 
-        newEnergiesA.put(uid1, 20_000);
-        // Implicit newEnergiesA.put(uid2, 0);
-        bi.updateCustomMeasuredEnergyDataLocked(bucketA, 500_000, newEnergiesA);
+        newChargesA.put(uid1, 20_000);
+        // Implicit newChargesA.put(uid2, 0);
+        bi.updateCustomMeasuredEnergyStatsLocked(bucketA, 500_000, newChargesA);
 
-        newEnergiesB.put(uid1, 60_000);
-        // Implicit newEnergiesB.put(uid2, 0);
-        bi.updateCustomMeasuredEnergyDataLocked(bucketB, 700_000, newEnergiesB);
+        newChargesB.put(uid1, 60_000);
+        // Implicit newChargesB.put(uid2, 0);
+        bi.updateCustomMeasuredEnergyStatsLocked(bucketB, 700_000, newChargesB);
 
-        checkCustomMeasuredEnergy(
+        checkCustomBatteryConsumption(
                 "A", totalBlameA, totalBlameB, uid1, blame1A, blame1B, uid2, blame2A, blame2B, bi);
 
 
         // ----- Case B: battery on
         bi.setOnBatteryInternal(true);
 
-        newEnergiesA.put(uid1, 7_000); blame1A += 7_000;
-        // Implicit newEnergiesA.put(uid2, 0); blame2A += 0;
-        bi.updateCustomMeasuredEnergyDataLocked(bucketA, 310_000, newEnergiesA);
+        newChargesA.put(uid1, 7_000); blame1A += 7_000;
+        // Implicit newChargesA.put(uid2, 0); blame2A += 0;
+        bi.updateCustomMeasuredEnergyStatsLocked(bucketA, 310_000, newChargesA);
         totalBlameA += 310_000;
 
-        newEnergiesB.put(uid1, 63_000); blame1B += 63_000;
-        newEnergiesB.put(uid2, 15_000); blame2B += 15_000;
-        bi.updateCustomMeasuredEnergyDataLocked(bucketB, 790_000, newEnergiesB);
+        newChargesB.put(uid1, 63_000); blame1B += 63_000;
+        newChargesB.put(uid2, 15_000); blame2B += 15_000;
+        bi.updateCustomMeasuredEnergyStatsLocked(bucketB, 790_000, newChargesB);
         totalBlameB += 790_000;
 
-        checkCustomMeasuredEnergy(
+        checkCustomBatteryConsumption(
                 "B", totalBlameA, totalBlameB, uid1, blame1A, blame1B, uid2, blame2A, blame2B, bi);
 
 
         // ----- Case C: battery still on
-        newEnergiesA.delete(uid1); blame1A += 0;
-        newEnergiesA.put(uid2, 16_000); blame2A += 16_000;
-        bi.updateCustomMeasuredEnergyDataLocked(bucketA, 560_000, newEnergiesA);
+        newChargesA.delete(uid1); blame1A += 0;
+        newChargesA.put(uid2, 16_000); blame2A += 16_000;
+        bi.updateCustomMeasuredEnergyStatsLocked(bucketA, 560_000, newChargesA);
         totalBlameA += 560_000;
 
-        bi.updateCustomMeasuredEnergyDataLocked(bucketB, 10_000, null);
+        bi.updateCustomMeasuredEnergyStatsLocked(bucketB, 10_000, null);
         totalBlameB += 10_000;
 
-        checkCustomMeasuredEnergy(
+        checkCustomBatteryConsumption(
                 "C", totalBlameA, totalBlameB, uid1, blame1A, blame1B, uid2, blame2A, blame2B, bi);
 
 
         // ----- Case D: battery still on
-        bi.updateCustomMeasuredEnergyDataLocked(bucketA, 0, newEnergiesA);
-        bi.updateCustomMeasuredEnergyDataLocked(bucketB, 15_000, new SparseLongArray(1));
+        bi.updateCustomMeasuredEnergyStatsLocked(bucketA, 0, newChargesA);
+        bi.updateCustomMeasuredEnergyStatsLocked(bucketB, 15_000, new SparseLongArray(1));
         totalBlameB += 15_000;
-        checkCustomMeasuredEnergy(
+        checkCustomBatteryConsumption(
                 "D", totalBlameA, totalBlameB, uid1, blame1A, blame1B, uid2, blame2A, blame2B, bi);
     }
 
@@ -686,32 +686,34 @@
         }
     }
 
-    private void checkMeasuredEnergy(String caseName, int uid1, long blame1, int uid2, long blame2,
+    private void checkMeasuredCharge(String caseName, int uid1, long blame1, int uid2, long blame2,
             long globalDoze, MockBatteryStatsImpl bi) {
-        final int bucket = MeasuredEnergyStats.ENERGY_BUCKET_SCREEN_ON;
+        final int bucket = MeasuredEnergyStats.POWER_BUCKET_SCREEN_ON;
 
         assertEquals("Wrong uid1 blame for Case " + caseName, blame1,
-                bi.getUidStatsLocked(uid1).getMeasuredEnergyMicroJoules(bucket));
+                bi.getUidStatsLocked(uid1).getMeasuredBatteryConsumptionUC(bucket));
 
         assertEquals("Wrong uid2 blame for Case " + caseName, blame2,
-                bi.getUidStatsLocked(uid2).getMeasuredEnergyMicroJoules(bucket));
+                bi.getUidStatsLocked(uid2).getMeasuredBatteryConsumptionUC(bucket));
 
         assertEquals("Wrong total blame for Case " + caseName, blame1 + blame2,
-                bi.getScreenOnEnergy());
+                bi.getScreenOnMeasuredBatteryConsumptionUC());
 
         assertEquals("Wrong doze for Case " + caseName, globalDoze,
-                bi.getScreenDozeEnergy());
+                bi.getScreenDozeMeasuredBatteryConsumptionUC());
     }
 
-    private void checkCustomMeasuredEnergy(String caseName,
+    private void checkCustomBatteryConsumption(String caseName,
             long totalBlameA, long totalBlameB,
             int uid1, long blame1A, long blame1B,
             int uid2, long blame2A, long blame2B,
             MockBatteryStatsImpl bi) {
 
-        final long[] actualTotal = bi.getCustomMeasuredEnergiesMicroJoules();
-        final long[] actualUid1 = bi.getUidStatsLocked(uid1).getCustomMeasuredEnergiesMicroJoules();
-        final long[] actualUid2 = bi.getUidStatsLocked(uid2).getCustomMeasuredEnergiesMicroJoules();
+        final long[] actualTotal = bi.getCustomConsumerMeasuredBatteryConsumptionUC();
+        final long[] actualUid1 =
+                bi.getUidStatsLocked(uid1).getCustomConsumerMeasuredBatteryConsumptionUC();
+        final long[] actualUid2 =
+                bi.getUidStatsLocked(uid2).getCustomConsumerMeasuredBatteryConsumptionUC();
 
         assertNotNull(actualTotal);
         assertNotNull(actualUid1);
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java
index 1679942..8aeb761 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java
@@ -147,7 +147,7 @@
 
     BatteryUsageStats apply(BatteryUsageStatsQuery query, PowerCalculator... calculators) {
         final long[] customMeasuredEnergiesMicroJoules =
-                mBatteryStats.getCustomMeasuredEnergiesMicroJoules();
+                mBatteryStats.getCustomConsumerMeasuredBatteryConsumptionUC();
         final int customMeasuredEnergiesCount = customMeasuredEnergiesMicroJoules != null
                 ? customMeasuredEnergiesMicroJoules.length
                 : 0;
diff --git a/core/tests/coretests/src/com/android/internal/os/CpuPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/CpuPowerCalculatorTest.java
index e691beb..7088890 100644
--- a/core/tests/coretests/src/com/android/internal/os/CpuPowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/CpuPowerCalculatorTest.java
@@ -126,7 +126,7 @@
             return null;
         }).when(mMockKernelCpuUidClusterTimeReader).readDelta(any());
 
-        mStatsRule.getBatteryStats().updateCpuTimeLocked(true, true);
+        mStatsRule.getBatteryStats().updateCpuTimeLocked(true, true, null);
 
         mStatsRule.getUidStats(APP_UID1).getProcessStatsLocked("foo").addCpuTimeLocked(4321, 1234);
         mStatsRule.getUidStats(APP_UID1).getProcessStatsLocked("bar").addCpuTimeLocked(5432, 2345);
diff --git a/core/tests/coretests/src/com/android/internal/os/CustomMeasuredPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/CustomMeasuredPowerCalculatorTest.java
index f298f59..0c91b29 100644
--- a/core/tests/coretests/src/com/android/internal/os/CustomMeasuredPowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/CustomMeasuredPowerCalculatorTest.java
@@ -47,10 +47,10 @@
         final BatteryStatsImpl batteryStats = mStatsRule.getBatteryStats();
         SparseLongArray uidEnergies = new SparseLongArray();
         uidEnergies.put(APP_UID, 30_000_000);
-        batteryStats.updateCustomMeasuredEnergyDataLocked(0, 100_000_000, uidEnergies);
+        batteryStats.updateCustomMeasuredEnergyStatsLocked(0, 100_000_000, uidEnergies);
 
         uidEnergies.put(APP_UID, 120_000_000);
-        batteryStats.updateCustomMeasuredEnergyDataLocked(1, 200_000_000, uidEnergies);
+        batteryStats.updateCustomMeasuredEnergyStatsLocked(1, 200_000_000, uidEnergies);
 
         CustomMeasuredPowerCalculator calculator =
                 new CustomMeasuredPowerCalculator(mStatsRule.getPowerProfile());
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 1687a78..a47c4d8 100644
--- a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
+++ b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
@@ -47,8 +47,8 @@
 
         setExternalStatsSyncLocked(new DummyExternalStatsSync());
 
-        final boolean[] supportedStandardBuckets
-                = new boolean[MeasuredEnergyStats.NUMBER_STANDARD_ENERGY_BUCKETS];
+        final boolean[] supportedStandardBuckets =
+                new boolean[MeasuredEnergyStats.NUMBER_STANDARD_POWER_BUCKETS];
         Arrays.fill(supportedStandardBuckets, true);
         mGlobalMeasuredEnergyStats = new MeasuredEnergyStats(supportedStandardBuckets, 2);
 
diff --git a/core/tests/coretests/src/com/android/internal/os/ScreenPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/ScreenPowerCalculatorTest.java
index 86e615c..f3cf81c 100644
--- a/core/tests/coretests/src/com/android/internal/os/ScreenPowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/ScreenPowerCalculatorTest.java
@@ -52,19 +52,19 @@
         BatteryStatsImpl batteryStats = mStatsRule.getBatteryStats();
 
         batteryStats.noteScreenStateLocked(Display.STATE_ON, 0, 0, 0);
-        batteryStats.updateDisplayEnergyLocked(0, Display.STATE_ON, 2 * MINUTE_IN_MS);
+        batteryStats.updateDisplayMeasuredEnergyStatsLocked(0, Display.STATE_ON, 2 * MINUTE_IN_MS);
 
         setFgState(APP_UID1, true, 2 * MINUTE_IN_MS, 2 * MINUTE_IN_MS);
         setFgState(APP_UID1, false, 20 * MINUTE_IN_MS, 20 * MINUTE_IN_MS);
         setFgState(APP_UID2, true, 30 * MINUTE_IN_MS, 30 * MINUTE_IN_MS);
 
-        batteryStats.updateDisplayEnergyLocked(300_000_000, Display.STATE_ON,
+        batteryStats.updateDisplayMeasuredEnergyStatsLocked(300_000_000, Display.STATE_ON,
                 60 * MINUTE_IN_MS);
 
         batteryStats.noteScreenStateLocked(Display.STATE_OFF,
                 80 * MINUTE_IN_MS, 80 * MINUTE_IN_MS, 80 * MINUTE_IN_MS);
 
-        batteryStats.updateDisplayEnergyLocked(100_000_000, Display.STATE_DOZE,
+        batteryStats.updateDisplayMeasuredEnergyStatsLocked(100_000_000, Display.STATE_DOZE,
                 120 * MINUTE_IN_MS);
 
         mStatsRule.setTime(120 * MINUTE_IN_US, 120 * MINUTE_IN_US);
@@ -78,20 +78,29 @@
                 mStatsRule.getSystemBatteryConsumer(SystemBatteryConsumer.DRAIN_TYPE_SCREEN);
         assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_USAGE))
                 .isEqualTo(80 * MINUTE_IN_MS);
+
+        // 400000000 uAs * (1 mA / 1000 uA) * (1 h / 3600 s)  = 111.11111 mAh
         assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE))
-                .isWithin(PRECISION).of(30.03003);
+                .isWithin(PRECISION).of(111.11111);
 
         UidBatteryConsumer uid1 = mStatsRule.getUidBatteryConsumer(APP_UID1);
         assertThat(uid1.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_SCREEN))
                 .isEqualTo(18 * MINUTE_IN_MS);
+
+        // Uid1 ran for 18 minutes out of the total 48 min of foreground time during the first
+        // Display update. Uid1 charge = 18 / 48 * 300000000 uAs = 31.25 mAh
         assertThat(uid1.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN))
-                .isWithin(PRECISION).of(8.44594);
+                .isWithin(PRECISION).of(31.25);
 
         UidBatteryConsumer uid2 = mStatsRule.getUidBatteryConsumer(APP_UID2);
         assertThat(uid2.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_SCREEN))
                 .isEqualTo(90 * MINUTE_IN_MS);
+
+        // Uid2 ran for 30 minutes out of the total 48 min of foreground time during the first
+        // Display update and then took all of the time during the second Display update.
+        // Uid1 charge = 30 / 48 * 300000000 + 100000000 mAs = 79.86111 mAh
         assertThat(uid2.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN))
-                .isWithin(PRECISION).of(21.58408);
+                .isWithin(PRECISION).of(79.86111);
     }
 
     @Test
diff --git a/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java
index b5282e9..6edbbb0 100644
--- a/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java
@@ -91,7 +91,7 @@
                 new long[] {10000, 20000, 30000, 40000}
         );
 
-        mMockBatteryStats.readKernelUidCpuFreqTimesLocked(null, true, false);
+        mMockBatteryStats.readKernelUidCpuFreqTimesLocked(null, true, false, null);
 
         int workSourceUid1 = 100;
         int workSourceUid2 = 200;
diff --git a/core/tests/coretests/src/com/android/internal/power/MeasuredEnergyStatsTest.java b/core/tests/coretests/src/com/android/internal/power/MeasuredEnergyStatsTest.java
index d217bce..ed6e27b 100644
--- a/core/tests/coretests/src/com/android/internal/power/MeasuredEnergyStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/power/MeasuredEnergyStatsTest.java
@@ -16,12 +16,12 @@
 
 package com.android.internal.power;
 
-import static android.os.BatteryStats.ENERGY_DATA_UNAVAILABLE;
+import static android.os.BatteryStats.POWER_DATA_UNAVAILABLE;
 
-import static com.android.internal.power.MeasuredEnergyStats.ENERGY_BUCKET_SCREEN_DOZE;
-import static com.android.internal.power.MeasuredEnergyStats.ENERGY_BUCKET_SCREEN_ON;
-import static com.android.internal.power.MeasuredEnergyStats.ENERGY_BUCKET_SCREEN_OTHER;
-import static com.android.internal.power.MeasuredEnergyStats.NUMBER_STANDARD_ENERGY_BUCKETS;
+import static com.android.internal.power.MeasuredEnergyStats.NUMBER_STANDARD_POWER_BUCKETS;
+import static com.android.internal.power.MeasuredEnergyStats.POWER_BUCKET_SCREEN_DOZE;
+import static com.android.internal.power.MeasuredEnergyStats.POWER_BUCKET_SCREEN_ON;
+import static com.android.internal.power.MeasuredEnergyStats.POWER_BUCKET_SCREEN_OTHER;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -48,75 +48,75 @@
 
     @Test
     public void testConstruction() {
-        final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_ENERGY_BUCKETS];
+        final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_POWER_BUCKETS];
         final int numCustomBuckets = 2;
-        supportedStandardBuckets[ENERGY_BUCKET_SCREEN_ON] = true;
-        supportedStandardBuckets[ENERGY_BUCKET_SCREEN_DOZE] = false;
-        supportedStandardBuckets[ENERGY_BUCKET_SCREEN_OTHER] = true;
+        supportedStandardBuckets[POWER_BUCKET_SCREEN_ON] = true;
+        supportedStandardBuckets[POWER_BUCKET_SCREEN_DOZE] = false;
+        supportedStandardBuckets[POWER_BUCKET_SCREEN_OTHER] = true;
 
-        final MeasuredEnergyStats stats
-                = new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
+        final MeasuredEnergyStats stats =
+                new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
 
-        for (int i = 0; i < NUMBER_STANDARD_ENERGY_BUCKETS; i++) {
+        for (int i = 0; i < NUMBER_STANDARD_POWER_BUCKETS; i++) {
             if (supportedStandardBuckets[i]) {
                 assertTrue(stats.isStandardBucketSupported(i));
-                assertEquals(0L, stats.getAccumulatedStandardBucketEnergy(i));
+                assertEquals(0L, stats.getAccumulatedStandardBucketCharge(i));
             } else {
                 assertFalse(stats.isStandardBucketSupported(i));
-                assertEquals(ENERGY_DATA_UNAVAILABLE, stats.getAccumulatedStandardBucketEnergy(i));
+                assertEquals(POWER_DATA_UNAVAILABLE, stats.getAccumulatedStandardBucketCharge(i));
             }
         }
         for (int i = 0; i < numCustomBuckets; i++) {
-            assertEquals(0L, stats.getAccumulatedCustomBucketEnergy(i));
+            assertEquals(0L, stats.getAccumulatedCustomBucketCharge(i));
         }
     }
 
     @Test
     public void testCreateFromTemplate() {
-        final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_ENERGY_BUCKETS];
+        final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_POWER_BUCKETS];
         final int numCustomBuckets = 2;
-        supportedStandardBuckets[ENERGY_BUCKET_SCREEN_ON] = true;
-        supportedStandardBuckets[ENERGY_BUCKET_SCREEN_DOZE] = false;
-        supportedStandardBuckets[ENERGY_BUCKET_SCREEN_OTHER] = true;
+        supportedStandardBuckets[POWER_BUCKET_SCREEN_ON] = true;
+        supportedStandardBuckets[POWER_BUCKET_SCREEN_DOZE] = false;
+        supportedStandardBuckets[POWER_BUCKET_SCREEN_OTHER] = true;
 
-        final MeasuredEnergyStats stats
-                = new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
-        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 10);
-        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 5);
-        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_OTHER, 40);
+        final MeasuredEnergyStats stats =
+                new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
+        stats.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 10);
+        stats.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 5);
+        stats.updateStandardBucket(POWER_BUCKET_SCREEN_OTHER, 40);
         stats.updateCustomBucket(0, 50);
         stats.updateCustomBucket(1, 60);
 
         final MeasuredEnergyStats newStats = MeasuredEnergyStats.createFromTemplate(stats);
 
-        for (int i = 0; i < NUMBER_STANDARD_ENERGY_BUCKETS; i++) {
+        for (int i = 0; i < NUMBER_STANDARD_POWER_BUCKETS; i++) {
             if (supportedStandardBuckets[i]) {
                 assertTrue(newStats.isStandardBucketSupported(i));
-                assertEquals(0L, newStats.getAccumulatedStandardBucketEnergy(i));
+                assertEquals(0L, newStats.getAccumulatedStandardBucketCharge(i));
             } else {
                 assertFalse(newStats.isStandardBucketSupported(i));
-                assertEquals(ENERGY_DATA_UNAVAILABLE,
-                        newStats.getAccumulatedStandardBucketEnergy(i));
+                assertEquals(POWER_DATA_UNAVAILABLE,
+                        newStats.getAccumulatedStandardBucketCharge(i));
             }
         }
         for (int i = 0; i < numCustomBuckets; i++) {
-            assertEquals(0L, newStats.getAccumulatedCustomBucketEnergy(i));
+            assertEquals(0L, newStats.getAccumulatedCustomBucketCharge(i));
         }
     }
 
     @Test
     public void testReadWriteParcel() {
-        final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_ENERGY_BUCKETS];
+        final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_POWER_BUCKETS];
         final int numCustomBuckets = 2;
-        supportedStandardBuckets[ENERGY_BUCKET_SCREEN_ON] = true;
-        supportedStandardBuckets[ENERGY_BUCKET_SCREEN_DOZE] = false;
-        supportedStandardBuckets[ENERGY_BUCKET_SCREEN_OTHER] = true;
+        supportedStandardBuckets[POWER_BUCKET_SCREEN_ON] = true;
+        supportedStandardBuckets[POWER_BUCKET_SCREEN_DOZE] = false;
+        supportedStandardBuckets[POWER_BUCKET_SCREEN_OTHER] = true;
 
-        final MeasuredEnergyStats stats
-                = new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
-        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 10);
-        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 5);
-        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_OTHER, 40);
+        final MeasuredEnergyStats stats =
+                new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
+        stats.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 10);
+        stats.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 5);
+        stats.updateStandardBucket(POWER_BUCKET_SCREEN_OTHER, 40);
         stats.updateCustomBucket(0, 50);
         stats.updateCustomBucket(1, 60);
 
@@ -126,32 +126,32 @@
         parcel.setDataPosition(0);
         MeasuredEnergyStats newStats = new MeasuredEnergyStats(parcel);
 
-        for (int i = 0; i < NUMBER_STANDARD_ENERGY_BUCKETS; i++) {
-            assertEquals(stats.getAccumulatedStandardBucketEnergy(i),
-                    newStats.getAccumulatedStandardBucketEnergy(i));
+        for (int i = 0; i < NUMBER_STANDARD_POWER_BUCKETS; i++) {
+            assertEquals(stats.getAccumulatedStandardBucketCharge(i),
+                    newStats.getAccumulatedStandardBucketCharge(i));
         }
         for (int i = 0; i < numCustomBuckets; i++) {
-            assertEquals(stats.getAccumulatedCustomBucketEnergy(i),
-                    newStats.getAccumulatedCustomBucketEnergy(i));
+            assertEquals(stats.getAccumulatedCustomBucketCharge(i),
+                    newStats.getAccumulatedCustomBucketCharge(i));
         }
-        assertEquals(ENERGY_DATA_UNAVAILABLE,
-                newStats.getAccumulatedCustomBucketEnergy(numCustomBuckets + 1));
+        assertEquals(POWER_DATA_UNAVAILABLE,
+                newStats.getAccumulatedCustomBucketCharge(numCustomBuckets + 1));
         parcel.recycle();
     }
 
     @Test
     public void testCreateAndReadSummaryFromParcel() {
-        final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_ENERGY_BUCKETS];
+        final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_POWER_BUCKETS];
         final int numCustomBuckets = 2;
-        supportedStandardBuckets[ENERGY_BUCKET_SCREEN_ON] = true;
-        supportedStandardBuckets[ENERGY_BUCKET_SCREEN_DOZE] = false;
-        supportedStandardBuckets[ENERGY_BUCKET_SCREEN_OTHER] = true;
+        supportedStandardBuckets[POWER_BUCKET_SCREEN_ON] = true;
+        supportedStandardBuckets[POWER_BUCKET_SCREEN_DOZE] = false;
+        supportedStandardBuckets[POWER_BUCKET_SCREEN_OTHER] = true;
 
-        final MeasuredEnergyStats stats
-                = new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
-        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 10);
-        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 5);
-        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_OTHER, 40);
+        final MeasuredEnergyStats stats =
+                new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
+        stats.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 10);
+        stats.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 5);
+        stats.updateStandardBucket(POWER_BUCKET_SCREEN_OTHER, 40);
         stats.updateCustomBucket(0, 50);
         stats.updateCustomBucket(1, 60);
 
@@ -160,90 +160,90 @@
         parcel.setDataPosition(0);
         MeasuredEnergyStats newStats = MeasuredEnergyStats.createAndReadSummaryFromParcel(parcel);
 
-        for (int i = 0; i < NUMBER_STANDARD_ENERGY_BUCKETS; i++) {
+        for (int i = 0; i < NUMBER_STANDARD_POWER_BUCKETS; i++) {
             assertEquals(stats.isStandardBucketSupported(i),
                     newStats.isStandardBucketSupported(i));
-            assertEquals(stats.getAccumulatedStandardBucketEnergy(i),
-                    newStats.getAccumulatedStandardBucketEnergy(i));
+            assertEquals(stats.getAccumulatedStandardBucketCharge(i),
+                    newStats.getAccumulatedStandardBucketCharge(i));
         }
         for (int i = 0; i < numCustomBuckets; i++) {
-            assertEquals(stats.getAccumulatedCustomBucketEnergy(i),
-                    newStats.getAccumulatedCustomBucketEnergy(i));
+            assertEquals(stats.getAccumulatedCustomBucketCharge(i),
+                    newStats.getAccumulatedCustomBucketCharge(i));
         }
-        assertEquals(ENERGY_DATA_UNAVAILABLE,
-                newStats.getAccumulatedCustomBucketEnergy(numCustomBuckets + 1));
+        assertEquals(POWER_DATA_UNAVAILABLE,
+                newStats.getAccumulatedCustomBucketCharge(numCustomBuckets + 1));
         parcel.recycle();
     }
 
     @Test
     public void testCreateAndReadSummaryFromParcel_existingTemplate() {
-        final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_ENERGY_BUCKETS];
+        final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_POWER_BUCKETS];
         final int numCustomBuckets = 2;
-        supportedStandardBuckets[ENERGY_BUCKET_SCREEN_ON] = true;
-        supportedStandardBuckets[ENERGY_BUCKET_SCREEN_DOZE] = false;
-        supportedStandardBuckets[ENERGY_BUCKET_SCREEN_OTHER] = true;
+        supportedStandardBuckets[POWER_BUCKET_SCREEN_ON] = true;
+        supportedStandardBuckets[POWER_BUCKET_SCREEN_DOZE] = false;
+        supportedStandardBuckets[POWER_BUCKET_SCREEN_OTHER] = true;
 
-        final MeasuredEnergyStats template
-                = new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
-        template.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 10);
-        template.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 5);
-        template.updateStandardBucket(ENERGY_BUCKET_SCREEN_OTHER, 40);
+        final MeasuredEnergyStats template =
+                new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
+        template.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 10);
+        template.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 5);
+        template.updateStandardBucket(POWER_BUCKET_SCREEN_OTHER, 40);
         template.updateCustomBucket(0, 50);
 
         final MeasuredEnergyStats stats = MeasuredEnergyStats.createFromTemplate(template);
-        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 200);
-        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 7);
-        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_OTHER, 63);
+        stats.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 200);
+        stats.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 7);
+        stats.updateStandardBucket(POWER_BUCKET_SCREEN_OTHER, 63);
         stats.updateCustomBucket(0, 315);
         stats.updateCustomBucket(1, 316);
 
         final Parcel parcel = Parcel.obtain();
         MeasuredEnergyStats.writeSummaryToParcel(stats, parcel, false);
 
-        final boolean[] newsupportedStandardBuckets = new boolean[NUMBER_STANDARD_ENERGY_BUCKETS];
-        newsupportedStandardBuckets[ENERGY_BUCKET_SCREEN_ON] = true;
-        newsupportedStandardBuckets[ENERGY_BUCKET_SCREEN_DOZE] = true; // switched false > true
-        newsupportedStandardBuckets[ENERGY_BUCKET_SCREEN_OTHER] = false; // switched true > false
-        final MeasuredEnergyStats newTemplate
-                = new MeasuredEnergyStats(newsupportedStandardBuckets, numCustomBuckets);
+        final boolean[] newsupportedStandardBuckets = new boolean[NUMBER_STANDARD_POWER_BUCKETS];
+        newsupportedStandardBuckets[POWER_BUCKET_SCREEN_ON] = true;
+        newsupportedStandardBuckets[POWER_BUCKET_SCREEN_DOZE] = true; // switched false > true
+        newsupportedStandardBuckets[POWER_BUCKET_SCREEN_OTHER] = false; // switched true > false
+        final MeasuredEnergyStats newTemplate =
+                new MeasuredEnergyStats(newsupportedStandardBuckets, numCustomBuckets);
         parcel.setDataPosition(0);
 
         final MeasuredEnergyStats newStats =
                 MeasuredEnergyStats.createAndReadSummaryFromParcel(parcel, newTemplate);
 
-        for (int i = 0; i < NUMBER_STANDARD_ENERGY_BUCKETS; i++) {
+        for (int i = 0; i < NUMBER_STANDARD_POWER_BUCKETS; i++) {
             if (!newsupportedStandardBuckets[i]) {
                 assertFalse(newStats.isStandardBucketSupported(i));
-                assertEquals(ENERGY_DATA_UNAVAILABLE,
-                        newStats.getAccumulatedStandardBucketEnergy(i));
+                assertEquals(POWER_DATA_UNAVAILABLE,
+                        newStats.getAccumulatedStandardBucketCharge(i));
             } else if (!supportedStandardBuckets[i]) {
                 assertTrue(newStats.isStandardBucketSupported(i));
-                assertEquals(0L, newStats.getAccumulatedStandardBucketEnergy(i));
+                assertEquals(0L, newStats.getAccumulatedStandardBucketCharge(i));
             } else {
                 assertTrue(newStats.isStandardBucketSupported(i));
-                assertEquals(stats.getAccumulatedStandardBucketEnergy(i),
-                        newStats.getAccumulatedStandardBucketEnergy(i));
+                assertEquals(stats.getAccumulatedStandardBucketCharge(i),
+                        newStats.getAccumulatedStandardBucketCharge(i));
             }
         }
         for (int i = 0; i < numCustomBuckets; i++) {
-            assertEquals(stats.getAccumulatedCustomBucketEnergy(i),
-                    newStats.getAccumulatedCustomBucketEnergy(i));
+            assertEquals(stats.getAccumulatedCustomBucketCharge(i),
+                    newStats.getAccumulatedCustomBucketCharge(i));
         }
-        assertEquals(ENERGY_DATA_UNAVAILABLE,
-                newStats.getAccumulatedCustomBucketEnergy(numCustomBuckets + 1));
+        assertEquals(POWER_DATA_UNAVAILABLE,
+                newStats.getAccumulatedCustomBucketCharge(numCustomBuckets + 1));
         parcel.recycle();
     }
 
     @Test
     public void testCreateAndReadSummaryFromParcel_skipZero() {
-        final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_ENERGY_BUCKETS];
+        final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_POWER_BUCKETS];
         final int numCustomBuckets = 2;
         Arrays.fill(supportedStandardBuckets, true);
 
-        final MeasuredEnergyStats stats
-                = new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
-        // Accumulate energy in one bucket and one custom bucket, the rest should be zero
-        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 200);
+        final MeasuredEnergyStats stats =
+                new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
+        // Accumulate charge in one bucket and one custom bucket, the rest should be zero
+        stats.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 200);
         stats.updateCustomBucket(1, 60);
 
         // Let's try parcelling with including zeros
@@ -254,20 +254,20 @@
         MeasuredEnergyStats newStats = MeasuredEnergyStats.createAndReadSummaryFromParcel(
                 includeZerosParcel);
 
-        for (int i = 0; i < NUMBER_STANDARD_ENERGY_BUCKETS; i++) {
-            if (i == ENERGY_BUCKET_SCREEN_ON) {
+        for (int i = 0; i < NUMBER_STANDARD_POWER_BUCKETS; i++) {
+            if (i == POWER_BUCKET_SCREEN_ON) {
                 assertEquals(stats.isStandardBucketSupported(i),
                         newStats.isStandardBucketSupported(i));
-                assertEquals(stats.getAccumulatedStandardBucketEnergy(i),
-                        newStats.getAccumulatedStandardBucketEnergy(i));
+                assertEquals(stats.getAccumulatedStandardBucketCharge(i),
+                        newStats.getAccumulatedStandardBucketCharge(i));
             } else {
                 assertTrue(newStats.isStandardBucketSupported(i));
-                assertEquals(0L, newStats.getAccumulatedStandardBucketEnergy(i));
+                assertEquals(0L, newStats.getAccumulatedStandardBucketCharge(i));
             }
         }
-        assertEquals(0L, newStats.getAccumulatedCustomBucketEnergy(0));
-        assertEquals(stats.getAccumulatedCustomBucketEnergy(1),
-                newStats.getAccumulatedCustomBucketEnergy(1));
+        assertEquals(0L, newStats.getAccumulatedCustomBucketCharge(0));
+        assertEquals(stats.getAccumulatedCustomBucketCharge(1),
+                newStats.getAccumulatedCustomBucketCharge(1));
         includeZerosParcel.recycle();
 
         // Now let's try parcelling with skipping zeros
@@ -277,37 +277,37 @@
 
         newStats = MeasuredEnergyStats.createAndReadSummaryFromParcel(skipZerosParcel);
 
-        for (int i = 0; i < NUMBER_STANDARD_ENERGY_BUCKETS; i++) {
-            if (i == ENERGY_BUCKET_SCREEN_ON) {
+        for (int i = 0; i < NUMBER_STANDARD_POWER_BUCKETS; i++) {
+            if (i == POWER_BUCKET_SCREEN_ON) {
                 assertEquals(stats.isStandardBucketSupported(i),
                         newStats.isStandardBucketSupported(i));
-                assertEquals(stats.getAccumulatedStandardBucketEnergy(i),
-                        newStats.getAccumulatedStandardBucketEnergy(i));
+                assertEquals(stats.getAccumulatedStandardBucketCharge(i),
+                        newStats.getAccumulatedStandardBucketCharge(i));
             } else {
                 assertFalse(newStats.isStandardBucketSupported(i));
-                assertEquals(ENERGY_DATA_UNAVAILABLE,
-                        newStats.getAccumulatedStandardBucketEnergy(i));
+                assertEquals(POWER_DATA_UNAVAILABLE,
+                        newStats.getAccumulatedStandardBucketCharge(i));
             }
         }
-        assertEquals(0L, newStats.getAccumulatedCustomBucketEnergy(0));
-        assertEquals(stats.getAccumulatedCustomBucketEnergy(1),
-                newStats.getAccumulatedCustomBucketEnergy(1));
+        assertEquals(0L, newStats.getAccumulatedCustomBucketCharge(0));
+        assertEquals(stats.getAccumulatedCustomBucketCharge(1),
+                newStats.getAccumulatedCustomBucketCharge(1));
         skipZerosParcel.recycle();
     }
 
     @Test
     public void testCreateAndReadSummaryFromParcel_nullTemplate() {
-        final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_ENERGY_BUCKETS];
+        final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_POWER_BUCKETS];
         final int numCustomBuckets = 2;
-        supportedStandardBuckets[ENERGY_BUCKET_SCREEN_ON] = true;
-        supportedStandardBuckets[ENERGY_BUCKET_SCREEN_DOZE] = false;
-        supportedStandardBuckets[ENERGY_BUCKET_SCREEN_OTHER] = true;
+        supportedStandardBuckets[POWER_BUCKET_SCREEN_ON] = true;
+        supportedStandardBuckets[POWER_BUCKET_SCREEN_DOZE] = false;
+        supportedStandardBuckets[POWER_BUCKET_SCREEN_OTHER] = true;
 
-        final MeasuredEnergyStats stats
-                = new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
-        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 10);
-        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 5);
-        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_OTHER, 40);
+        final MeasuredEnergyStats stats =
+                new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
+        stats.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 10);
+        stats.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 5);
+        stats.updateStandardBucket(POWER_BUCKET_SCREEN_OTHER, 40);
         stats.updateCustomBucket(0, 50);
         stats.updateCustomBucket(1, 60);
 
@@ -315,40 +315,40 @@
         MeasuredEnergyStats.writeSummaryToParcel(stats, parcel, false);
         parcel.setDataPosition(0);
 
-        MeasuredEnergyStats newStats
-                = MeasuredEnergyStats.createAndReadSummaryFromParcel(parcel, null);
+        MeasuredEnergyStats newStats =
+                MeasuredEnergyStats.createAndReadSummaryFromParcel(parcel, null);
         assertNull(newStats);
         parcel.recycle();
     }
 
     @Test
     public void testCreateAndReadSummaryFromParcel_boring() {
-        final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_ENERGY_BUCKETS];
+        final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_POWER_BUCKETS];
         final int numCustomBuckets = 2;
-        supportedStandardBuckets[ENERGY_BUCKET_SCREEN_ON] = true;
-        supportedStandardBuckets[ENERGY_BUCKET_SCREEN_DOZE] = false;
-        supportedStandardBuckets[ENERGY_BUCKET_SCREEN_OTHER] = true;
+        supportedStandardBuckets[POWER_BUCKET_SCREEN_ON] = true;
+        supportedStandardBuckets[POWER_BUCKET_SCREEN_DOZE] = false;
+        supportedStandardBuckets[POWER_BUCKET_SCREEN_OTHER] = true;
 
-        final MeasuredEnergyStats template
-                = new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
-        template.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 10);
-        template.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 5);
-        template.updateStandardBucket(ENERGY_BUCKET_SCREEN_OTHER, 40);
+        final MeasuredEnergyStats template =
+                new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
+        template.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 10);
+        template.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 5);
+        template.updateStandardBucket(POWER_BUCKET_SCREEN_OTHER, 40);
         template.updateCustomBucket(0, 50);
 
         final MeasuredEnergyStats stats = MeasuredEnergyStats.createFromTemplate(template);
-        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 0L);
-        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_OTHER, 7L);
+        stats.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 0L);
+        stats.updateStandardBucket(POWER_BUCKET_SCREEN_OTHER, 7L);
 
         final Parcel parcel = Parcel.obtain();
         MeasuredEnergyStats.writeSummaryToParcel(stats, parcel, false);
 
-        final boolean[] newSupportedStandardBuckets = new boolean[NUMBER_STANDARD_ENERGY_BUCKETS];
-        newSupportedStandardBuckets[ENERGY_BUCKET_SCREEN_ON] = true;
-        newSupportedStandardBuckets[ENERGY_BUCKET_SCREEN_DOZE] = true; // switched false > true
-        newSupportedStandardBuckets[ENERGY_BUCKET_SCREEN_OTHER] = false; // switched true > false
-        final MeasuredEnergyStats newTemplate
-                = new MeasuredEnergyStats(newSupportedStandardBuckets, numCustomBuckets);
+        final boolean[] newSupportedStandardBuckets = new boolean[NUMBER_STANDARD_POWER_BUCKETS];
+        newSupportedStandardBuckets[POWER_BUCKET_SCREEN_ON] = true;
+        newSupportedStandardBuckets[POWER_BUCKET_SCREEN_DOZE] = true; // switched false > true
+        newSupportedStandardBuckets[POWER_BUCKET_SCREEN_OTHER] = false; // switched true > false
+        final MeasuredEnergyStats newTemplate =
+                new MeasuredEnergyStats(newSupportedStandardBuckets, numCustomBuckets);
         parcel.setDataPosition(0);
 
         final MeasuredEnergyStats newStats =
@@ -361,35 +361,35 @@
 
     @Test
     public void testUpdateBucket() {
-        final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_ENERGY_BUCKETS];
+        final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_POWER_BUCKETS];
         final int numCustomBuckets = 2;
-        supportedStandardBuckets[ENERGY_BUCKET_SCREEN_ON] = true;
-        supportedStandardBuckets[ENERGY_BUCKET_SCREEN_DOZE] = false;
-        supportedStandardBuckets[ENERGY_BUCKET_SCREEN_OTHER] = true;
+        supportedStandardBuckets[POWER_BUCKET_SCREEN_ON] = true;
+        supportedStandardBuckets[POWER_BUCKET_SCREEN_DOZE] = false;
+        supportedStandardBuckets[POWER_BUCKET_SCREEN_OTHER] = true;
 
-        final MeasuredEnergyStats stats
-                = new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
-        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 10);
-        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_DOZE, 30);
-        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_OTHER, 40);
-        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 5);
+        final MeasuredEnergyStats stats =
+                new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
+        stats.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 10);
+        stats.updateStandardBucket(POWER_BUCKET_SCREEN_DOZE, 30);
+        stats.updateStandardBucket(POWER_BUCKET_SCREEN_OTHER, 40);
+        stats.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 5);
 
         stats.updateCustomBucket(0, 50);
         stats.updateCustomBucket(1, 60);
         stats.updateCustomBucket(0, 3);
 
-        assertEquals(15, stats.getAccumulatedStandardBucketEnergy(ENERGY_BUCKET_SCREEN_ON));
-        assertEquals(ENERGY_DATA_UNAVAILABLE,
-                stats.getAccumulatedStandardBucketEnergy(ENERGY_BUCKET_SCREEN_DOZE));
-        assertEquals(40, stats.getAccumulatedStandardBucketEnergy(ENERGY_BUCKET_SCREEN_OTHER));
-        assertEquals(50 + 3, stats.getAccumulatedCustomBucketEnergy(0));
-        assertEquals(60, stats.getAccumulatedCustomBucketEnergy(1));
+        assertEquals(15, stats.getAccumulatedStandardBucketCharge(POWER_BUCKET_SCREEN_ON));
+        assertEquals(POWER_DATA_UNAVAILABLE,
+                stats.getAccumulatedStandardBucketCharge(POWER_BUCKET_SCREEN_DOZE));
+        assertEquals(40, stats.getAccumulatedStandardBucketCharge(POWER_BUCKET_SCREEN_OTHER));
+        assertEquals(50 + 3, stats.getAccumulatedCustomBucketCharge(0));
+        assertEquals(60, stats.getAccumulatedCustomBucketCharge(1));
     }
 
     @Test
     public void testIsValidCustomBucket() {
-        final MeasuredEnergyStats stats
-                = new MeasuredEnergyStats(new boolean[NUMBER_STANDARD_ENERGY_BUCKETS], 3);
+        final MeasuredEnergyStats stats =
+                new MeasuredEnergyStats(new boolean[NUMBER_STANDARD_POWER_BUCKETS], 3);
         assertFalse(stats.isValidCustomBucket(-1));
         assertTrue(stats.isValidCustomBucket(0));
         assertTrue(stats.isValidCustomBucket(1));
@@ -397,24 +397,24 @@
         assertFalse(stats.isValidCustomBucket(3));
         assertFalse(stats.isValidCustomBucket(4));
 
-        final MeasuredEnergyStats boringStats
-                = new MeasuredEnergyStats(new boolean[NUMBER_STANDARD_ENERGY_BUCKETS], 0);
+        final MeasuredEnergyStats boringStats =
+                new MeasuredEnergyStats(new boolean[NUMBER_STANDARD_POWER_BUCKETS], 0);
         assertFalse(boringStats.isValidCustomBucket(-1));
         assertFalse(boringStats.isValidCustomBucket(0));
         assertFalse(boringStats.isValidCustomBucket(1));
     }
 
     @Test
-    public void testGetAccumulatedCustomBucketEnergies() {
-        final MeasuredEnergyStats stats
-                = new MeasuredEnergyStats(new boolean[NUMBER_STANDARD_ENERGY_BUCKETS], 3);
+    public void testGetAccumulatedCustomBucketCharges() {
+        final MeasuredEnergyStats stats =
+                new MeasuredEnergyStats(new boolean[NUMBER_STANDARD_POWER_BUCKETS], 3);
 
         stats.updateCustomBucket(0, 50);
         stats.updateCustomBucket(1, 60);
         stats.updateCustomBucket(2, 13);
         stats.updateCustomBucket(1, 70);
 
-        final long[] output = stats.getAccumulatedCustomBucketEnergies();
+        final long[] output = stats.getAccumulatedCustomBucketCharges();
         assertEquals(3, output.length);
 
         assertEquals(50, output[0]);
@@ -423,73 +423,73 @@
     }
 
     @Test
-    public void testGetAccumulatedCustomBucketEnergies_empty() {
-        final MeasuredEnergyStats stats
-                = new MeasuredEnergyStats(new boolean[NUMBER_STANDARD_ENERGY_BUCKETS], 0);
+    public void testGetAccumulatedCustomBucketCharges_empty() {
+        final MeasuredEnergyStats stats =
+                new MeasuredEnergyStats(new boolean[NUMBER_STANDARD_POWER_BUCKETS], 0);
 
-        final long[] output = stats.getAccumulatedCustomBucketEnergies();
+        final long[] output = stats.getAccumulatedCustomBucketCharges();
         assertEquals(0, output.length);
     }
 
     @Test
-    public void testGetNumberCustomEnergyBuckets() {
-        assertEquals(0, new MeasuredEnergyStats(new boolean[NUMBER_STANDARD_ENERGY_BUCKETS], 0)
-                .getNumberCustomEnergyBuckets());
-        assertEquals(3, new MeasuredEnergyStats(new boolean[NUMBER_STANDARD_ENERGY_BUCKETS], 3)
-                .getNumberCustomEnergyBuckets());
+    public void testGetNumberCustomChargeBuckets() {
+        assertEquals(0, new MeasuredEnergyStats(new boolean[NUMBER_STANDARD_POWER_BUCKETS], 0)
+                .getNumberCustomPowerBuckets());
+        assertEquals(3, new MeasuredEnergyStats(new boolean[NUMBER_STANDARD_POWER_BUCKETS], 3)
+                .getNumberCustomPowerBuckets());
     }
 
     @Test
     public void testReset() {
-        final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_ENERGY_BUCKETS];
+        final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_POWER_BUCKETS];
         final int numCustomBuckets = 2;
-        supportedStandardBuckets[ENERGY_BUCKET_SCREEN_ON] = true;
-        supportedStandardBuckets[ENERGY_BUCKET_SCREEN_DOZE] = false;
-        supportedStandardBuckets[ENERGY_BUCKET_SCREEN_OTHER] = true;
+        supportedStandardBuckets[POWER_BUCKET_SCREEN_ON] = true;
+        supportedStandardBuckets[POWER_BUCKET_SCREEN_DOZE] = false;
+        supportedStandardBuckets[POWER_BUCKET_SCREEN_OTHER] = true;
 
-        final MeasuredEnergyStats stats
-                = new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
-        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 10);
-        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 5);
-        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_OTHER, 40);
+        final MeasuredEnergyStats stats =
+                new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
+        stats.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 10);
+        stats.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 5);
+        stats.updateStandardBucket(POWER_BUCKET_SCREEN_OTHER, 40);
         stats.updateCustomBucket(0, 50);
         stats.updateCustomBucket(1, 60);
 
         MeasuredEnergyStats.resetIfNotNull(stats);
-        // All energy should be reset to 0
-        for (int i = 0; i < NUMBER_STANDARD_ENERGY_BUCKETS; i++) {
+        // All charges should be reset to 0
+        for (int i = 0; i < NUMBER_STANDARD_POWER_BUCKETS; i++) {
             if (supportedStandardBuckets[i]) {
                 assertTrue(stats.isStandardBucketSupported(i));
-                assertEquals(0, stats.getAccumulatedStandardBucketEnergy(i));
+                assertEquals(0, stats.getAccumulatedStandardBucketCharge(i));
             } else {
                 assertFalse(stats.isStandardBucketSupported(i));
-                assertEquals(ENERGY_DATA_UNAVAILABLE, stats.getAccumulatedStandardBucketEnergy(i));
+                assertEquals(POWER_DATA_UNAVAILABLE, stats.getAccumulatedStandardBucketCharge(i));
             }
         }
         for (int i = 0; i < numCustomBuckets; i++) {
-            assertEquals(0, stats.getAccumulatedCustomBucketEnergy(i));
+            assertEquals(0, stats.getAccumulatedCustomBucketCharge(i));
         }
 
         // Values should increase as usual.
-        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 70);
-        assertEquals(70L, stats.getAccumulatedStandardBucketEnergy(ENERGY_BUCKET_SCREEN_ON));
+        stats.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 70);
+        assertEquals(70L, stats.getAccumulatedStandardBucketCharge(POWER_BUCKET_SCREEN_ON));
 
         stats.updateCustomBucket(1, 12);
-        assertEquals(12L, stats.getAccumulatedCustomBucketEnergy(1));
+        assertEquals(12L, stats.getAccumulatedCustomBucketCharge(1));
     }
 
-    /** Test that states are mapped to the expected energy buckets. Beware of mapping changes. */
+    /** Test that states are mapped to the expected power buckets. Beware of mapping changes. */
     @Test
     public void testStandardBucketMapping() {
         int exp;
 
-        exp = ENERGY_BUCKET_SCREEN_ON;
-        assertEquals(exp, MeasuredEnergyStats.getDisplayEnergyBucket(Display.STATE_ON));
-        assertEquals(exp, MeasuredEnergyStats.getDisplayEnergyBucket(Display.STATE_VR));
-        assertEquals(exp, MeasuredEnergyStats.getDisplayEnergyBucket(Display.STATE_ON_SUSPEND));
+        exp = POWER_BUCKET_SCREEN_ON;
+        assertEquals(exp, MeasuredEnergyStats.getDisplayPowerBucket(Display.STATE_ON));
+        assertEquals(exp, MeasuredEnergyStats.getDisplayPowerBucket(Display.STATE_VR));
+        assertEquals(exp, MeasuredEnergyStats.getDisplayPowerBucket(Display.STATE_ON_SUSPEND));
 
-        exp = ENERGY_BUCKET_SCREEN_DOZE;
-        assertEquals(exp, MeasuredEnergyStats.getDisplayEnergyBucket(Display.STATE_DOZE));
-        assertEquals(exp, MeasuredEnergyStats.getDisplayEnergyBucket(Display.STATE_DOZE_SUSPEND));
+        exp = POWER_BUCKET_SCREEN_DOZE;
+        assertEquals(exp, MeasuredEnergyStats.getDisplayPowerBucket(Display.STATE_DOZE));
+        assertEquals(exp, MeasuredEnergyStats.getDisplayPowerBucket(Display.STATE_DOZE_SUSPEND));
     }
 }
diff --git a/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateManagerGlobalTest.java b/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateManagerGlobalTest.java
index 79b4d8b..055fc71 100644
--- a/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateManagerGlobalTest.java
+++ b/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateManagerGlobalTest.java
@@ -208,6 +208,11 @@
             }
 
             mCallbacks.add(callback);
+            try {
+                callback.onDeviceStateInfoChanged(getInfo());
+            } catch (RemoteException e) {
+                // Do nothing. Should never happen.
+            }
         }
 
         @Override
diff --git a/graphics/java/android/graphics/HardwareRendererObserver.java b/graphics/java/android/graphics/HardwareRendererObserver.java
index da9d03c..e2a0572 100644
--- a/graphics/java/android/graphics/HardwareRendererObserver.java
+++ b/graphics/java/android/graphics/HardwareRendererObserver.java
@@ -62,7 +62,7 @@
      * @param handler the Handler to use when invoking callbacks
      */
     public HardwareRendererObserver(@NonNull OnFrameMetricsAvailableListener listener,
-            @NonNull long[] frameMetrics, @NonNull Handler handler) {
+            @NonNull long[] frameMetrics, @NonNull Handler handler, boolean waitForPresentTime) {
         if (handler == null || handler.getLooper() == null) {
             throw new NullPointerException("handler and its looper cannot be null");
         }
@@ -74,7 +74,7 @@
         mFrameMetrics = frameMetrics;
         mHandler = handler;
         mListener = listener;
-        mNativePtr = new VirtualRefBasePtr(nCreateObserver());
+        mNativePtr = new VirtualRefBasePtr(nCreateObserver(waitForPresentTime));
     }
 
     /*package*/ long getNativeInstance() {
@@ -98,6 +98,6 @@
         });
     }
 
-    private native long nCreateObserver();
+    private native long nCreateObserver(boolean waitForPresentTime);
     private static native int nGetNextBuffer(long nativePtr, long[] data);
 }
diff --git a/keystore/java/android/security/keystore2/KeyStoreCryptoOperationUtils.java b/keystore/java/android/security/keystore2/KeyStoreCryptoOperationUtils.java
index 9924542..0006b92 100644
--- a/keystore/java/android/security/keystore2/KeyStoreCryptoOperationUtils.java
+++ b/keystore/java/android/security/keystore2/KeyStoreCryptoOperationUtils.java
@@ -18,6 +18,7 @@
 
 import android.app.ActivityThread;
 import android.hardware.biometrics.BiometricManager;
+import android.hardware.security.keymint.ErrorCode;
 import android.security.GateKeeper;
 import android.security.KeyStore;
 import android.security.KeyStoreException;
@@ -183,15 +184,19 @@
             try {
                 operation.abort();
             } catch (KeyStoreException e) {
-                // We log this error, but we can afford to ignore it. Dropping the reference
-                // to the KeyStoreOperation is enough to clean up all related resources even
-                // in the Keystore daemon. We log it anyway, because it may indicate some
-                // underlying problem that is worth debugging.
-                Log.w(
-                        "KeyStoreCryptoOperationUtils",
-                        "Encountered error trying to abort a keystore operation.",
-                        e
-                );
+                // Invalid operation handle is very common at this point. It occurs every time
+                // an already finalized operation gets aborted.
+                if (e.getErrorCode() != ErrorCode.INVALID_OPERATION_HANDLE) {
+                    // This error gets logged but ignored. Dropping the reference
+                    // to the KeyStoreOperation is enough to clean up all related resources even
+                    // in the Keystore daemon. It gets logged anyway, because it may indicate some
+                    // underlying problem that is worth debugging.
+                    Log.w(
+                            "KeyStoreCryptoOperationUtils",
+                            "Encountered error trying to abort a keystore operation.",
+                            e
+                    );
+                }
             }
         }
     }
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 9ddeb2f..cb04bd7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
@@ -28,10 +28,13 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.ActivityManager.RunningTaskInfo;
+import android.app.TaskInfo;
 import android.content.Context;
+import android.content.LocusId;
 import android.os.Binder;
 import android.os.IBinder;
 import android.util.ArrayMap;
+import android.util.ArraySet;
 import android.util.Log;
 import android.util.SparseArray;
 import android.view.SurfaceControl;
@@ -50,6 +53,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.Objects;
 
 /**
  * Unified task organizer for all components in the shell.
@@ -96,6 +100,17 @@
     }
 
     /**
+     * Callbacks for events on a task with a locus id.
+     */
+    public interface LocusIdListener {
+        /**
+         * Notifies when a task with a locusId becomes visible, when a visible task's locusId
+         * changes, or if a previously visible task with a locusId becomes invisible.
+         */
+        void onVisibilityChanged(int taskId, LocusId locus, boolean visible);
+    }
+
+    /**
      * Keys map from either a task id or {@link TaskListenerType}.
      * @see #addListenerForTaskId
      * @see #addListenerForType
@@ -109,6 +124,13 @@
     /** @see #setPendingLaunchCookieListener */
     private final ArrayMap<IBinder, TaskListener> mLaunchCookieToListener = new ArrayMap<>();
 
+    // Keeps track of taskId's with visible locusIds. Used to notify any {@link LocusIdListener}s
+    // that might be set.
+    private final SparseArray<LocusId> mVisibleTasksWithLocusId = new SparseArray<>();
+
+    /** @see #addLocusIdListener */
+    private final ArraySet<LocusIdListener> mLocusIdListeners = new ArraySet<>();
+
     private final Object mLock = new Object();
     private StartingSurface mStartingSurface;
 
@@ -162,9 +184,7 @@
      * @hide
      */
     public void initStartingSurface(StartingSurface startingSurface) {
-        synchronized (mLock) {
-            mStartingSurface = startingSurface;
-        }
+        mStartingSurface = startingSurface;
     }
 
     /**
@@ -257,6 +277,28 @@
         }
     }
 
+    /**
+     * Adds a listener to be notified for {@link LocusId} visibility changes.
+     */
+    public void addLocusIdListener(LocusIdListener listener) {
+        synchronized (mLock) {
+            mLocusIdListeners.add(listener);
+            for (int i = 0; i < mVisibleTasksWithLocusId.size(); i++) {
+                listener.onVisibilityChanged(mVisibleTasksWithLocusId.keyAt(i),
+                        mVisibleTasksWithLocusId.valueAt(i), true /* visible */);
+            }
+        }
+    }
+
+    /**
+     * Removes listener.
+     */
+    public void removeLocusIdListener(LocusIdListener listener) {
+        synchronized (mLock) {
+            mLocusIdListeners.remove(listener);
+        }
+    }
+
     @Override
     public void addStartingWindow(StartingWindowInfo info, IBinder appToken) {
         if (mStartingSurface != null) {
@@ -294,6 +336,7 @@
         if (listener != null) {
             listener.onTaskAppeared(info.getTaskInfo(), info.getLeash());
         }
+        notifyLocusVisibilityIfNeeded(info.getTaskInfo());
         notifySizeCompatUI(info.getTaskInfo(), listener);
     }
 
@@ -310,6 +353,7 @@
             if (!updated && newListener != null) {
                 newListener.onTaskInfoChanged(taskInfo);
             }
+            notifyLocusVisibilityIfNeeded(taskInfo);
             if (updated || !taskInfo.equalsForSizeCompat(data.getTaskInfo())) {
                 // Notify the size compat UI if the listener or task info changed.
                 notifySizeCompatUI(taskInfo, newListener);
@@ -338,6 +382,7 @@
             if (listener != null) {
                 listener.onTaskVanished(taskInfo);
             }
+            notifyLocusVisibilityIfNeeded(taskInfo);
             // Pass null for listener to remove the size compat UI on this task if there is any.
             notifySizeCompatUI(taskInfo, null /* taskListener */);
         }
@@ -366,6 +411,39 @@
         return true;
     }
 
+    private void notifyLocusVisibilityIfNeeded(TaskInfo taskInfo) {
+        final int taskId = taskInfo.taskId;
+        final LocusId prevLocus = mVisibleTasksWithLocusId.get(taskId);
+        final boolean sameLocus = Objects.equals(prevLocus, taskInfo.mTopActivityLocusId);
+        if (prevLocus == null) {
+            // New visible locus
+            if (taskInfo.mTopActivityLocusId != null && taskInfo.isVisible) {
+                mVisibleTasksWithLocusId.put(taskId, taskInfo.mTopActivityLocusId);
+                notifyLocusIdChange(taskId, taskInfo.mTopActivityLocusId, true /* visible */);
+            }
+        } else if (sameLocus && !taskInfo.isVisible) {
+            // Hidden locus
+            mVisibleTasksWithLocusId.remove(taskId);
+            notifyLocusIdChange(taskId, taskInfo.mTopActivityLocusId, false /* visible */);
+        } else if (!sameLocus) {
+            // Changed locus
+            if (taskInfo.isVisible) {
+                mVisibleTasksWithLocusId.put(taskId, taskInfo.mTopActivityLocusId);
+                notifyLocusIdChange(taskId, prevLocus, false /* visible */);
+                notifyLocusIdChange(taskId, taskInfo.mTopActivityLocusId, true /* visible */);
+            } else {
+                mVisibleTasksWithLocusId.remove(taskInfo.taskId);
+                notifyLocusIdChange(taskId, prevLocus, false /* visible */);
+            }
+        }
+    }
+
+    private void notifyLocusIdChange(int taskId, LocusId locus, boolean visible) {
+        for (int i = 0; i < mLocusIdListeners.size(); i++) {
+            mLocusIdListeners.valueAt(i).onVisibilityChanged(taskId, locus, visible);
+        }
+    }
+
     /**
      * Notifies {@link SizeCompatUIController} about the size compat info changed on the give Task
      * to update the UI accordingly.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
index 8697be9..d6079b6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
@@ -28,6 +28,7 @@
 import android.app.Person;
 import android.content.Context;
 import android.content.Intent;
+import android.content.LocusId;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ShortcutInfo;
@@ -62,13 +63,16 @@
     private final String mKey;
     @Nullable
     private final String mGroupKey;
+    @Nullable
+    private final LocusId mLocusId;
+
     private final Executor mMainExecutor;
 
     private long mLastUpdated;
     private long mLastAccessed;
 
     @Nullable
-    private Bubbles.NotificationSuppressionChangedListener mSuppressionListener;
+    private Bubbles.SuppressionChangedListener mSuppressionListener;
 
     /** Whether the bubble should show a dot for the notification indicating updated content. */
     private boolean mShowBubbleUpdateDot = true;
@@ -163,13 +167,14 @@
      */
     Bubble(@NonNull final String key, @NonNull final ShortcutInfo shortcutInfo,
             final int desiredHeight, final int desiredHeightResId, @Nullable final String title,
-            int taskId, Executor mainExecutor) {
+            int taskId, @Nullable final String locus, Executor mainExecutor) {
         Objects.requireNonNull(key);
         Objects.requireNonNull(shortcutInfo);
         mMetadataShortcutId = shortcutInfo.getId();
         mShortcutInfo = shortcutInfo;
         mKey = key;
         mGroupKey = null;
+        mLocusId = locus != null ? new LocusId(locus) : null;
         mFlags = 0;
         mUser = shortcutInfo.getUserHandle();
         mPackageName = shortcutInfo.getPackage();
@@ -184,11 +189,12 @@
 
     @VisibleForTesting(visibility = PRIVATE)
     Bubble(@NonNull final BubbleEntry entry,
-            @Nullable final Bubbles.NotificationSuppressionChangedListener listener,
+            @Nullable final Bubbles.SuppressionChangedListener listener,
             final Bubbles.PendingIntentCanceledListener intentCancelListener,
             Executor mainExecutor) {
         mKey = entry.getKey();
         mGroupKey = entry.getGroupKey();
+        mLocusId = entry.getLocusId();
         mSuppressionListener = listener;
         mIntentCancelListener = intent -> {
             if (mIntent != null) {
@@ -216,6 +222,10 @@
         return mGroupKey;
     }
 
+    public LocusId getLocusId() {
+        return mLocusId;
+    }
+
     public UserHandle getUser() {
         return mUser;
     }
@@ -550,6 +560,21 @@
     }
 
     /**
+     * Whether this bubble is currently being hidden from the stack.
+     */
+    boolean isSuppressed() {
+        return (mFlags & Notification.BubbleMetadata.FLAG_SUPPRESS_BUBBLE) != 0;
+    }
+
+    /**
+     * Whether this bubble is able to be suppressed (i.e. has the developer opted into the API to
+     * hide the bubble when in the same content).
+     */
+    boolean isSuppressable() {
+        return (mFlags & Notification.BubbleMetadata.FLAG_SHOULD_SUPPRESS_BUBBLE) != 0;
+    }
+
+    /**
      * Whether this notification conversation is important.
      */
     boolean isImportantConversation() {
@@ -574,6 +599,26 @@
     }
 
     /**
+     * Sets whether this bubble should be suppressed from the stack.
+     */
+    public void setSuppressBubble(boolean suppressBubble) {
+        if (!isSuppressable()) {
+            Log.e(TAG, "calling setSuppressBubble on "
+                    + getKey() + " when bubble not suppressable");
+            return;
+        }
+        boolean prevSuppressed = isSuppressed();
+        if (suppressBubble) {
+            mFlags |= Notification.BubbleMetadata.FLAG_SUPPRESS_BUBBLE;
+        } else {
+            mFlags &= ~Notification.BubbleMetadata.FLAG_SUPPRESS_BUBBLE;
+        }
+        if (prevSuppressed != suppressBubble && mSuppressionListener != null) {
+            mSuppressionListener.onBubbleNotificationSuppressionChange(this);
+        }
+    }
+
+    /**
      * Sets whether the bubble for this notification should show a dot indicating updated content.
      */
     void setShowDot(boolean showDot) {
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 d31e637b..620c382 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
@@ -16,7 +16,6 @@
 
 package com.android.wm.shell.bubbles;
 
-import static android.app.ActivityTaskManager.INVALID_TASK_ID;
 import static android.service.notification.NotificationListenerService.REASON_CANCEL;
 import static android.view.View.INVISIBLE;
 import static android.view.View.VISIBLE;
@@ -28,7 +27,6 @@
 import static com.android.wm.shell.bubbles.BubblePositioner.TASKBAR_POSITION_LEFT;
 import static com.android.wm.shell.bubbles.BubblePositioner.TASKBAR_POSITION_NONE;
 import static com.android.wm.shell.bubbles.BubblePositioner.TASKBAR_POSITION_RIGHT;
-import static com.android.wm.shell.bubbles.Bubbles.DISMISS_AGED;
 import static com.android.wm.shell.bubbles.Bubbles.DISMISS_BLOCKED;
 import static com.android.wm.shell.bubbles.Bubbles.DISMISS_GROUP_CANCELLED;
 import static com.android.wm.shell.bubbles.Bubbles.DISMISS_INVALID_INTENT;
@@ -42,7 +40,6 @@
 import android.annotation.NonNull;
 import android.annotation.UserIdInt;
 import android.app.ActivityManager;
-import android.app.ActivityTaskManager;
 import android.app.Notification;
 import android.app.PendingIntent;
 import android.content.Context;
@@ -243,15 +240,15 @@
         mBubbleData = data;
         mBubbleData.setListener(mBubbleDataListener);
         mBubbleData.setSuppressionChangedListener(bubble -> {
-            // Make sure NoMan knows it's not showing in the shade anymore so anyone querying it
-            // can tell.
+            // Make sure NoMan knows suppression state so that anyone querying it can tell.
             try {
                 mBarService.onBubbleNotificationSuppressionChanged(bubble.getKey(),
-                        !bubble.showInShade());
+                        !bubble.showInShade(), bubble.isSuppressed());
             } catch (RemoteException e) {
                 // Bad things have happened
             }
         });
+
         mBubbleData.setPendingIntentCancelledListener(bubble -> {
             if (bubble.getBubbleIntent() == null) {
                 return;
@@ -282,6 +279,8 @@
 
         mBubbleIconFactory = new BubbleIconFactory(context);
         mTaskOrganizer = organizer;
+        mTaskOrganizer.addLocusIdListener((taskId, locus, visible) ->
+                mBubbleData.onLocusVisibilityChanged(taskId, locus, visible));
 
         launcherApps.registerCallback(new LauncherApps.Callback() {
             @Override
@@ -1044,6 +1043,14 @@
                 }
             }
 
+            if (update.suppressedBubble != null && mStackView != null) {
+                mStackView.setBubbleVisibility(update.suppressedBubble, false);
+            }
+
+            if (update.unsuppressedBubble != null && mStackView != null) {
+                mStackView.setBubbleVisibility(update.unsuppressedBubble, true);
+            }
+
             // Expanding? Apply this last.
             if (update.expandedChanged && update.expanded) {
                 if (mStackView != null) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
index 53b7537..f6e6b8f3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
@@ -24,7 +24,10 @@
 import android.annotation.NonNull;
 import android.app.PendingIntent;
 import android.content.Context;
+import android.content.LocusId;
 import android.content.pm.ShortcutInfo;
+import android.util.ArrayMap;
+import android.util.ArraySet;
 import android.util.Log;
 import android.util.Pair;
 import android.view.View;
@@ -75,6 +78,8 @@
         @Nullable Bubble updatedBubble;
         @Nullable Bubble addedOverflowBubble;
         @Nullable Bubble removedOverflowBubble;
+        @Nullable Bubble suppressedBubble;
+        @Nullable Bubble unsuppressedBubble;
         // Pair with Bubble and @DismissReason Integer
         final List<Pair<Bubble, Integer>> removedBubbles = new ArrayList<>();
 
@@ -95,7 +100,9 @@
                     || !removedBubbles.isEmpty()
                     || addedOverflowBubble != null
                     || removedOverflowBubble != null
-                    || orderChanged;
+                    || orderChanged
+                    || suppressedBubble != null
+                    || unsuppressedBubble != null;
         }
 
         void bubbleRemoved(Bubble bubbleToRemove, @DismissReason int reason) {
@@ -125,6 +132,11 @@
     private final List<Bubble> mOverflowBubbles;
     /** Bubbles that are being loaded but haven't been added to the stack just yet. */
     private final HashMap<String, Bubble> mPendingBubbles;
+    /** Bubbles that are suppressed due to locusId. */
+    private final ArrayMap<LocusId, Bubble> mSuppressedBubbles = new ArrayMap<>();
+    /** Visible locusIds. */
+    private final ArraySet<LocusId> mVisibleLocusIds = new ArraySet<>();
+
     private BubbleViewProvider mSelectedBubble;
     private final BubbleOverflow mOverflow;
     private boolean mShowingOverflow;
@@ -141,7 +153,7 @@
     private Listener mListener;
 
     @Nullable
-    private Bubbles.NotificationSuppressionChangedListener mSuppressionListener;
+    private Bubbles.SuppressionChangedListener mSuppressionListener;
     private Bubbles.PendingIntentCanceledListener mCancelledListener;
 
     /**
@@ -173,7 +185,7 @@
     }
 
     public void setSuppressionChangedListener(
-            Bubbles.NotificationSuppressionChangedListener listener) {
+            Bubbles.SuppressionChangedListener listener) {
         mSuppressionListener = listener;
     }
 
@@ -321,6 +333,18 @@
         bubble.setSuppressNotification(suppress);
         bubble.setShowDot(!isBubbleExpandedAndSelected /* show */);
 
+        LocusId locusId = bubble.getLocusId();
+        if (locusId != null) {
+            boolean isSuppressed = mSuppressedBubbles.containsKey(locusId);
+            if (isSuppressed && (!bubble.isSuppressed() || !bubble.isSuppressable())) {
+                mSuppressedBubbles.remove(locusId);
+                mStateChange.unsuppressedBubble = bubble;
+            } else if (!isSuppressed && (bubble.isSuppressed()
+                    || bubble.isSuppressable() && mVisibleLocusIds.contains(locusId))) {
+                mSuppressedBubbles.put(locusId, bubble);
+                mStateChange.suppressedBubble = bubble;
+            }
+        }
         dispatchPendingChanges();
     }
 
@@ -581,6 +605,43 @@
         dispatchPendingChanges();
     }
 
+    /**
+     * Called in response to the visibility of a locusId changing. A locusId is set on a task
+     * and if there's a matching bubble for that locusId then the bubble may be hidden or shown
+     * depending on the visibility of the locusId.
+     *
+     * @param taskId the taskId associated with the locusId visibility change.
+     * @param locusId the locusId whose visibility has changed.
+     * @param visible whether the task with the locusId is visible or not.
+     */
+    public void onLocusVisibilityChanged(int taskId, LocusId locusId, boolean visible) {
+        Bubble matchingBubble = getBubbleInStackWithLocusId(locusId);
+        // Don't add the locus if it's from a bubble'd activity, we only suppress for non-bubbled.
+        if (visible && (matchingBubble == null || matchingBubble.getTaskId() != taskId)) {
+            mVisibleLocusIds.add(locusId);
+        } else {
+            mVisibleLocusIds.remove(locusId);
+        }
+        if (matchingBubble == null) {
+            return;
+        }
+        boolean isAlreadySuppressed = mSuppressedBubbles.get(locusId) != null;
+        if (visible && !isAlreadySuppressed && matchingBubble.isSuppressable()
+                && taskId != matchingBubble.getTaskId()) {
+            mSuppressedBubbles.put(locusId, matchingBubble);
+            matchingBubble.setSuppressBubble(true);
+            mStateChange.suppressedBubble = matchingBubble;
+            dispatchPendingChanges();
+        } else if (!visible) {
+            Bubble unsuppressedBubble = mSuppressedBubbles.remove(locusId);
+            if (unsuppressedBubble != null) {
+                unsuppressedBubble.setSuppressBubble(false);
+                mStateChange.unsuppressedBubble = unsuppressedBubble;
+            }
+            dispatchPendingChanges();
+        }
+    }
+
     private void dispatchPendingChanges() {
         if (mListener != null && mStateChange.anythingChanged()) {
             mListener.applyUpdate(mStateChange);
@@ -792,6 +853,18 @@
     }
 
     @Nullable
+    private Bubble getBubbleInStackWithLocusId(LocusId locusId) {
+        if (locusId == null) return null;
+        for (int i = 0; i < mBubbles.size(); i++) {
+            Bubble bubble = mBubbles.get(i);
+            if (locusId.equals(bubble.getLocusId())) {
+                return bubble;
+            }
+        }
+        return null;
+    }
+
+    @Nullable
     Bubble getBubbleWithView(View view) {
         for (int i = 0; i < mBubbles.size(); i++) {
             Bubble bubble = mBubbles.get(i);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDataRepository.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDataRepository.kt
index 2417552..bfacd1c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDataRepository.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDataRepository.kt
@@ -81,7 +81,8 @@
                     b.rawDesiredHeight,
                     b.rawDesiredHeightResId,
                     b.title,
-                    b.taskId
+                    b.taskId,
+                    b.locusId?.id
             )
         }
     }
@@ -172,6 +173,7 @@
                             entity.desiredHeightResId,
                             entity.title,
                             entity.taskId,
+                            entity.locus,
                             mainExecutor
                     ) }
         }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleEntry.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleEntry.java
index ff68861..5f42826 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleEntry.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleEntry.java
@@ -21,6 +21,7 @@
 import android.app.Notification;
 import android.app.Notification.BubbleMetadata;
 import android.app.NotificationManager.Policy;
+import android.content.LocusId;
 import android.service.notification.NotificationListenerService.Ranking;
 import android.service.notification.StatusBarNotification;
 
@@ -75,6 +76,11 @@
         return mSbn.getGroupKey();
     }
 
+    /** @return the {@link LocusId} for this notification, if it exists. */
+    public LocusId getLocusId() {
+        return mSbn.getNotification().getLocusId();
+    }
+
     /** @return the {@link BubbleMetadata} in the {@link StatusBarNotification}. */
     @Nullable
     public BubbleMetadata getBubbleMetadata() {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowContainerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowContainerView.java
index 39e4e1a..8ee2b40 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowContainerView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowContainerView.java
@@ -20,29 +20,22 @@
 import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES;
 import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
 
-import android.app.Activity;
 import android.content.Context;
-import android.content.Intent;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.Color;
-import android.os.Bundle;
-import android.os.IBinder;
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.WindowManager;
 import android.view.accessibility.AccessibilityNodeInfo;
-import android.widget.FrameLayout;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
-import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.recyclerview.widget.GridLayoutManager;
 import androidx.recyclerview.widget.RecyclerView;
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 78820a8..64a44ca 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
@@ -912,9 +912,6 @@
                     removeOnLayoutChangeListener(mOrientationChangedListener);
                 };
 
-        // This must be a separate OnDrawListener since it should be called for every draw.
-        getViewTreeObserver().addOnDrawListener(mSystemGestureExcludeUpdater);
-
         final ColorMatrix animatedMatrix = new ColorMatrix();
         final ColorMatrix darkenMatrix = new ColorMatrix();
 
@@ -1274,12 +1271,14 @@
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
         getViewTreeObserver().addOnComputeInternalInsetsListener(this);
+        getViewTreeObserver().addOnDrawListener(mSystemGestureExcludeUpdater);
     }
 
     @Override
     protected void onDetachedFromWindow() {
         super.onDetachedFromWindow();
         getViewTreeObserver().removeOnPreDrawListener(mViewUpdater);
+        getViewTreeObserver().removeOnDrawListener(mSystemGestureExcludeUpdater);
         getViewTreeObserver().removeOnComputeInternalInsetsListener(this);
         if (mBubbleOverflow != null) {
             mBubbleOverflow.cleanUpExpandedState();
@@ -1688,6 +1687,13 @@
         notifyExpansionChanged(mExpandedBubble, mIsExpanded);
     }
 
+    void setBubbleVisibility(Bubble b, boolean visible) {
+        if (b.getIconView() != null) {
+            b.getIconView().setVisibility(visible ? VISIBLE : GONE);
+        }
+        // TODO(b/181166384): Animate in / out & handle adjusting how the bubbles overlap
+    }
+
     /**
      * Asks the BubbleController to hide the IME from anywhere, whether it's focused on Bubbles or
      * not.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
index 8e061e9..98978b5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
@@ -234,8 +234,8 @@
         void onBubbleExpandChanged(boolean isExpanding, String key);
     }
 
-    /** Listener to be notified when a bubbles' notification suppression state changes.*/
-    interface NotificationSuppressionChangedListener {
+    /** Listener to be notified when the flags for notification or bubble suppression changes.*/
+    interface SuppressionChangedListener {
         /** Called when the notification suppression state of a bubble changes. */
         void onBubbleNotificationSuppressionChange(Bubble bubble);
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubbleEntity.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubbleEntity.kt
index d5cab5a..186b9b1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubbleEntity.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubbleEntity.kt
@@ -26,5 +26,6 @@
     val desiredHeight: Int,
     @DimenRes val desiredHeightResId: Int,
     val title: String? = null,
-    val taskId: Int
+    val taskId: Int,
+    val locus: String? = null
 )
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubbleXmlHelper.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubbleXmlHelper.kt
index 470011b..a74445b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubbleXmlHelper.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubbleXmlHelper.kt
@@ -40,6 +40,7 @@
 private const val ATTR_DESIRED_HEIGHT_RES_ID = "hid"
 private const val ATTR_TITLE = "t"
 private const val ATTR_TASK_ID = "tid"
+private const val ATTR_LOCUS = "l"
 
 /**
  * Writes the bubbles in xml format into given output stream.
@@ -73,6 +74,7 @@
         serializer.attribute(null, ATTR_DESIRED_HEIGHT_RES_ID, bubble.desiredHeightResId.toString())
         bubble.title?.let { serializer.attribute(null, ATTR_TITLE, it) }
         serializer.attribute(null, ATTR_TASK_ID, bubble.taskId.toString())
+        bubble.locus?.let { serializer.attribute(null, ATTR_LOCUS, it) }
         serializer.endTag(null, TAG_BUBBLE)
     } catch (e: IOException) {
         throw RuntimeException(e)
@@ -107,7 +109,8 @@
             parser.getAttributeWithName(ATTR_DESIRED_HEIGHT)?.toInt() ?: return null,
             parser.getAttributeWithName(ATTR_DESIRED_HEIGHT_RES_ID)?.toInt() ?: return null,
             parser.getAttributeWithName(ATTR_TITLE),
-            parser.getAttributeWithName(ATTR_TASK_ID)?.toInt() ?: INVALID_TASK_ID
+            parser.getAttributeWithName(ATTR_TASK_ID)?.toInt() ?: INVALID_TASK_ID,
+            parser.getAttributeWithName(ATTR_LOCUS)
     )
 }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/annotations/ShellSplashscreenThread.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/annotations/ShellSplashscreenThread.java
new file mode 100644
index 0000000..c2fd54f
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/annotations/ShellSplashscreenThread.java
@@ -0,0 +1,33 @@
+/*
+ * 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.wm.shell.common.annotations;
+
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+import javax.inject.Qualifier;
+
+/** Annotates a method or qualifies a provider that runs on the Shell splashscreen-thread */
+@Documented
+@Inherited
+@Qualifier
+@Retention(RetentionPolicy.RUNTIME)
+public @interface ShellSplashscreenThread {
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
index d2eb361..5fc7c98 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
@@ -525,7 +525,7 @@
 
     public void dump(@NonNull PrintWriter pw) {
         final String innerPrefix = "  ";
-        pw.println(TAG + "states: ");
+        pw.println(TAG + "States: ");
         pw.print(innerPrefix + "mOffSetFraction=");
         pw.println(mOffSetFraction);
         pw.print(innerPrefix + "mLockedDisabled=");
@@ -535,6 +535,10 @@
             mDisplayAreaOrganizer.dump(pw);
         }
 
+        if (mGestureHandler != null) {
+            mGestureHandler.dump(pw);
+        }
+
         if (mTouchHandler != null) {
             mTouchHandler.dump(pw);
         }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedGestureHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedGestureHandler.java
index b86b954..778876c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedGestureHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedGestureHandler.java
@@ -36,16 +36,21 @@
 import android.view.WindowManager;
 import android.window.WindowContainerTransaction;
 
+import androidx.annotation.NonNull;
 import androidx.annotation.VisibleForTesting;
 
 import com.android.wm.shell.R;
 import com.android.wm.shell.common.DisplayChangeController;
 import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.DisplayLayout;
 import com.android.wm.shell.common.ShellExecutor;
 
+import java.io.PrintWriter;
+
 /**
  * The class manage swipe up and down gesture for 3-Button mode navigation,
  * others(e.g, 2-button, full gesture mode) are handled by Launcher quick steps.
+ * TODO(b/160934654) Migrate to Launcher quick steps
  */
 public class OneHandedGestureHandler implements OneHandedTransitionCallback,
         DisplayChangeController.OnDisplayChangingListener {
@@ -72,7 +77,6 @@
     InputMonitor mInputMonitor;
     @VisibleForTesting
     InputEventReceiver mInputEventReceiver;
-    private final DisplayController mDisplayController;
     private final ShellExecutor mMainExecutor;
     @VisibleForTesting
     @Nullable
@@ -91,11 +95,10 @@
             DisplayController displayController, ViewConfiguration viewConfig,
             ShellExecutor mainExecutor) {
         mWindowManager = windowManager;
-        mDisplayController = displayController;
         mMainExecutor = mainExecutor;
         displayController.addDisplayChangingController(this);
-        mNavGestureHeight = context.getResources().getDimensionPixelSize(
-                com.android.internal.R.dimen.navigation_bar_gesture_larger_height);
+        mNavGestureHeight = getNavBarSize(context,
+                displayController.getDisplayLayout(DEFAULT_DISPLAY));
         mDragDistThreshold = context.getResources().getDimensionPixelSize(
                 R.dimen.gestures_onehanded_drag_threshold);
         final float slop = viewConfig.getScaledTouchSlop();
@@ -208,10 +211,23 @@
         return mGestureRegion.contains(Math.round(x), Math.round(y));
     }
 
+    private int getNavBarSize(Context context, @Nullable DisplayLayout displayLayout) {
+        if (displayLayout != null) {
+            return displayLayout.navBarFrameHeight();
+        } else {
+            return isRotated()
+                    ? context.getResources().getDimensionPixelSize(
+                    com.android.internal.R.dimen.navigation_bar_height_landscape)
+                    : context.getResources().getDimensionPixelSize(
+                            com.android.internal.R.dimen.navigation_bar_height);
+        }
+    }
+
     private void updateIsEnabled() {
         disposeInputChannel();
 
-        if (mIsEnabled && mIsThreeButtonModeEnabled) {
+        // Either OHM or swipe notification shade can activate in portrait mode only
+        if (mIsEnabled && mIsThreeButtonModeEnabled && !isRotated()) {
             final Rect displaySize = mWindowManager.getCurrentWindowMetrics().getBounds();
             // Register input event receiver to monitor the touch region of NavBar gesture height
             mGestureRegion.set(0, displaySize.height() - mNavGestureHeight, displaySize.width(),
@@ -239,6 +255,7 @@
     public void onRotateDisplay(int displayId, int fromRotation, int toRotation,
             WindowContainerTransaction t) {
         mRotation = toRotation;
+        updateIsEnabled();
     }
 
     // TODO: Use BatchedInputEventReceiver
@@ -253,6 +270,10 @@
         }
     }
 
+    private boolean isRotated() {
+        return mRotation == Surface.ROTATION_90 || mRotation == Surface.ROTATION_270;
+    }
+
     private boolean isValidStartAngle(float deltaX, float deltaY) {
         final float angle = (float) Math.toDegrees(Math.atan2(deltaY, deltaX));
         return angle > -(ANGLE_MAX) && angle < -(ANGLE_MIN);
@@ -267,6 +288,19 @@
         return x * x + y * y;
     }
 
+    void dump(@NonNull PrintWriter pw) {
+        final String innerPrefix = "  ";
+        pw.println(TAG + "States: ");
+        pw.print(innerPrefix + "mIsEnabled=");
+        pw.println(mIsEnabled);
+        pw.print(innerPrefix + "mNavGestureHeight=");
+        pw.println(mNavGestureHeight);
+        pw.print(innerPrefix + "mIsThreeButtonModeEnabled=");
+        pw.println(mIsThreeButtonModeEnabled);
+        pw.print(innerPrefix + "isLandscape=");
+        pw.println(isRotated());
+    }
+
     /**
      * The touch(gesture) events to notify {@link OneHandedController} start or stop one handed
      */
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 7ed7fd0..9ec7c0d 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
@@ -58,13 +58,13 @@
 import android.window.TaskOrganizer;
 import android.window.WindowContainerToken;
 import android.window.WindowContainerTransaction;
-import android.window.WindowContainerTransactionCallback;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.wm.shell.R;
 import com.android.wm.shell.ShellTaskOrganizer;
 import com.android.wm.shell.common.DisplayController;
 import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.common.SyncTransactionQueue;
 import com.android.wm.shell.common.annotations.ShellMainThread;
 import com.android.wm.shell.legacysplitscreen.LegacySplitScreenController;
 import com.android.wm.shell.pip.phone.PipMotionHelper;
@@ -123,6 +123,7 @@
         }
     }
 
+    private final SyncTransactionQueue mSyncTransactionQueue;
     private final PipBoundsState mPipBoundsState;
     private final PipBoundsAlgorithm mPipBoundsAlgorithm;
     private final @NonNull PipMenuController mPipMenuController;
@@ -205,7 +206,9 @@
      */
     private boolean mInSwipePipToHomeTransition;
 
-    public PipTaskOrganizer(Context context, @NonNull PipBoundsState pipBoundsState,
+    public PipTaskOrganizer(Context context,
+            @NonNull SyncTransactionQueue syncTransactionQueue,
+            @NonNull PipBoundsState pipBoundsState,
             @NonNull PipBoundsAlgorithm boundsHandler,
             @NonNull PipMenuController pipMenuController,
             @NonNull PipAnimationController pipAnimationController,
@@ -216,6 +219,7 @@
             @NonNull PipUiEventLogger pipUiEventLogger,
             @NonNull ShellTaskOrganizer shellTaskOrganizer,
             @ShellMainThread ShellExecutor mainExecutor) {
+        mSyncTransactionQueue = syncTransactionQueue;
         mPipBoundsState = pipBoundsState;
         mPipBoundsAlgorithm = boundsHandler;
         mPipMenuController = pipMenuController;
@@ -337,21 +341,16 @@
                         : WINDOWING_MODE_FULLSCREEN);
         wct.setBounds(mToken, destinationBounds);
         wct.setBoundsChangeTransaction(mToken, tx);
-        mTaskOrganizer.applySyncTransaction(wct, new WindowContainerTransactionCallback() {
-            @Override
-            public void onTransactionReady(int id, SurfaceControl.Transaction t) {
-                mMainExecutor.execute(() -> {
-                    t.apply();
-                    // Make sure to grab the latest source hint rect as it could have been
-                    // updated right after applying the windowing mode change.
-                    final Rect sourceHintRect = PipBoundsAlgorithm.getValidSourceHintRect(
-                            mPictureInPictureParams, destinationBounds);
-                    scheduleAnimateResizePip(mPipBoundsState.getBounds(), destinationBounds,
-                            0 /* startingAngle */, sourceHintRect, direction,
-                            animationDurationMs, null /* updateBoundsCallback */);
-                    mState = State.EXITING_PIP;
-                });
-            }
+        mSyncTransactionQueue.queue(wct);
+        mSyncTransactionQueue.runInSync(t -> {
+            // Make sure to grab the latest source hint rect as it could have been
+            // updated right after applying the windowing mode change.
+            final Rect sourceHintRect = PipBoundsAlgorithm.getValidSourceHintRect(
+                    mPictureInPictureParams, destinationBounds);
+            scheduleAnimateResizePip(mPipBoundsState.getBounds(), destinationBounds,
+                    0 /* startingAngle */, sourceHintRect, direction,
+                    animationDurationMs, null /* updateBoundsCallback */);
+            mState = State.EXITING_PIP;
         });
     }
 
@@ -502,18 +501,10 @@
         wct.setActivityWindowingMode(mToken, WINDOWING_MODE_UNDEFINED);
         wct.setBounds(mToken, destinationBounds);
         wct.scheduleFinishEnterPip(mToken, destinationBounds);
-        // TODO: Migrate to SyncTransactionQueue
-        mTaskOrganizer.applySyncTransaction(wct, new WindowContainerTransactionCallback() {
-            @Override
-            public void onTransactionReady(int id, SurfaceControl.Transaction t) {
-                mMainExecutor.execute(() -> {
-                    t.apply();
-                    if (runnable != null) {
-                        runnable.run();
-                    }
-                });
-            }
-        });
+        mSyncTransactionQueue.queue(wct);
+        if (runnable != null) {
+            mSyncTransactionQueue.runInSync(t -> runnable.run());
+        }
     }
 
     private void sendOnPipTransitionStarted(
@@ -951,40 +942,37 @@
             final SurfaceControl snapshotSurface = mTaskOrganizer.takeScreenshot(mToken);
             mSurfaceTransactionHelper.reparentAndShowSurfaceSnapshot(
                     mSurfaceControlTransactionFactory.getTransaction(), mLeash, snapshotSurface);
-            mTaskOrganizer.applySyncTransaction(wct, new WindowContainerTransactionCallback() {
-                @Override
-                public void onTransactionReady(int id, @NonNull SurfaceControl.Transaction t) {
-                    // Scale the snapshot from its pre-resize bounds to the post-resize bounds.
-                    final Rect snapshotSrc = new Rect(0, 0, snapshotSurface.getWidth(),
-                            snapshotSurface.getHeight());
-                    final Rect snapshotDest = new Rect(0, 0, destinationBounds.width(),
-                            destinationBounds.height());
-                    mSurfaceTransactionHelper.scale(t, snapshotSurface, snapshotSrc, snapshotDest);
-                    t.apply();
+            mSyncTransactionQueue.queue(wct);
+            mSyncTransactionQueue.runInSync(t -> {
+                // Scale the snapshot from its pre-resize bounds to the post-resize bounds.
+                final Rect snapshotSrc = new Rect(0, 0, snapshotSurface.getWidth(),
+                        snapshotSurface.getHeight());
+                final Rect snapshotDest = new Rect(0, 0, destinationBounds.width(),
+                        destinationBounds.height());
+                mSurfaceTransactionHelper.scale(t, snapshotSurface, snapshotSrc, snapshotDest);
 
-                    mMainExecutor.execute(() -> {
-                        // Start animation to fade out the snapshot.
-                        final ValueAnimator animator = ValueAnimator.ofFloat(1.0f, 0.0f);
-                        animator.setDuration(mEnterExitAnimationDuration);
-                        animator.addUpdateListener(animation -> {
-                            final float alpha = (float) animation.getAnimatedValue();
+                mMainExecutor.execute(() -> {
+                    // Start animation to fade out the snapshot.
+                    final ValueAnimator animator = ValueAnimator.ofFloat(1.0f, 0.0f);
+                    animator.setDuration(mEnterExitAnimationDuration);
+                    animator.addUpdateListener(animation -> {
+                        final float alpha = (float) animation.getAnimatedValue();
+                        final SurfaceControl.Transaction transaction =
+                                mSurfaceControlTransactionFactory.getTransaction();
+                        transaction.setAlpha(snapshotSurface, alpha);
+                        transaction.apply();
+                    });
+                    animator.addListener(new AnimatorListenerAdapter() {
+                        @Override
+                        public void onAnimationEnd(Animator animation) {
                             final SurfaceControl.Transaction tx =
                                     mSurfaceControlTransactionFactory.getTransaction();
-                            tx.setAlpha(snapshotSurface, alpha);
+                            tx.remove(snapshotSurface);
                             tx.apply();
-                        });
-                        animator.addListener(new AnimatorListenerAdapter() {
-                            @Override
-                            public void onAnimationEnd(Animator animation) {
-                                final SurfaceControl.Transaction tx =
-                                        mSurfaceControlTransactionFactory.getTransaction();
-                                tx.remove(snapshotSurface);
-                                tx.apply();
-                            }
-                        });
-                        animator.start();
+                        }
                     });
-                }
+                    animator.start();
+                });
             });
         } else {
             applyFinishBoundsResize(wct, direction);
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 d742aa6..81a7ae1 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
@@ -37,7 +37,6 @@
 import com.android.wm.shell.animation.FloatProperties;
 import com.android.wm.shell.animation.PhysicsAnimator;
 import com.android.wm.shell.common.FloatingContentCoordinator;
-import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.magnetictarget.MagnetizedObject;
 import com.android.wm.shell.pip.PipBoundsState;
 import com.android.wm.shell.pip.PipSnapAlgorithm;
@@ -64,8 +63,11 @@
     private static final int LEAVE_PIP_DURATION = 300;
     private static final int SHIFT_DURATION = 300;
 
+    private static final float PIP_STIFFNESS = 700f;
+    private static final float PIP_DAMPING_RATIO = SpringForce.DAMPING_RATIO_NO_BOUNCY;
+
     /** Friction to use for PIP when it moves via physics fling animations. */
-    private static final float DEFAULT_FRICTION = 2f;
+    private static final float DEFAULT_FRICTION = 1.9f;
 
     private final Context mContext;
     private final PipTaskOrganizer mPipTaskOrganizer;
@@ -119,13 +121,11 @@
 
     /** SpringConfig to use for fling-then-spring animations. */
     private final PhysicsAnimator.SpringConfig mSpringConfig =
-            new PhysicsAnimator.SpringConfig(
-                    SpringForce.STIFFNESS_MEDIUM, SpringForce.DAMPING_RATIO_LOW_BOUNCY);
+            new PhysicsAnimator.SpringConfig(PIP_STIFFNESS, PIP_DAMPING_RATIO);
 
     /** SpringConfig to use for springing PIP away from conflicting floating content. */
     private final PhysicsAnimator.SpringConfig mConflictResolutionSpringConfig =
-                new PhysicsAnimator.SpringConfig(
-                        SpringForce.STIFFNESS_LOW, SpringForce.DAMPING_RATIO_LOW_BOUNCY);
+                new PhysicsAnimator.SpringConfig(SpringForce.STIFFNESS_LOW, PIP_DAMPING_RATIO);
 
     private final Consumer<Rect> mUpdateBoundsCallback = (Rect newBounds) -> {
         mMenuController.updateMenuLayout(newBounds);
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 7649770..2973b50 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
@@ -31,7 +31,6 @@
 import android.graphics.drawable.LayerDrawable;
 import android.os.Build;
 import android.util.Slog;
-import android.view.Window;
 import android.window.SplashScreenView;
 
 import com.android.internal.R;
@@ -91,12 +90,13 @@
         return new ColorDrawable(getSystemBGColor());
     }
 
-    SplashScreenView makeSplashScreenContentView(Window win, Context context, int iconRes,
+    SplashScreenView makeSplashScreenContentView(Context context, int iconRes,
             int splashscreenContentResId) {
         updateDensity();
         // splash screen content will be deprecated after S.
         final SplashScreenView ssc =
-                makeSplashscreenContentDrawable(win, context, splashscreenContentResId);
+                makeSplashscreenContentDrawable(context, splashscreenContentResId);
+
         if (ssc != null) {
             return ssc;
         }
@@ -127,7 +127,6 @@
         }
         // TODO (b/173975965) Tracking the performance on improved splash screen.
         return builder
-                .setWindow(win)
                 .setContext(context)
                 .setThemeDrawable(themeBGDrawable)
                 .setIconDrawable(iconDrawable)
@@ -169,7 +168,6 @@
     private class StartingWindowViewBuilder {
         private Drawable mThemeBGDrawable;
         private Drawable mIconDrawable;
-        private Window mWindow;
         private int mIconAnimationDuration;
         private Context mContext;
         private Drawable mBrandingDrawable;
@@ -193,12 +191,6 @@
             return this;
         }
 
-        StartingWindowViewBuilder setWindow(Window window) {
-            mWindow = window;
-            mBuildComplete = false;
-            return this;
-        }
-
         StartingWindowViewBuilder setIconAnimationDuration(int iconAnimationDuration) {
             mIconAnimationDuration = iconAnimationDuration;
             mBuildComplete = false;
@@ -221,7 +213,7 @@
             if (mBuildComplete) {
                 return mCachedResult;
             }
-            if (mWindow == null || mContext == null) {
+            if (mContext == null) {
                 Slog.e(TAG, "Unable to create StartingWindowView, lack of materials!");
                 return null;
             }
@@ -237,7 +229,7 @@
                 mFinalIconDrawable = mIconDrawable;
             }
             final int iconSize = mFinalIconDrawable != null ? (int) (mIconSize * mScale) : 0;
-            mCachedResult = fillViewWithIcon(mWindow, mContext, iconSize, mFinalIconDrawable);
+            mCachedResult = fillViewWithIcon(mContext, iconSize, mFinalIconDrawable);
             mBuildComplete = true;
             return mCachedResult;
         }
@@ -313,7 +305,7 @@
             return true;
         }
 
-        private SplashScreenView fillViewWithIcon(Window win, Context context,
+        private SplashScreenView fillViewWithIcon(Context context,
                 int iconSize, Drawable iconDrawable) {
             final SplashScreenView.Builder builder = new SplashScreenView.Builder(context);
             builder.setIconSize(iconSize).setBackgroundColor(mThemeColor);
@@ -329,8 +321,6 @@
             if (DEBUG) {
                 Slog.d(TAG, "fillViewWithIcon surfaceWindowView " + splashScreenView);
             }
-            win.setContentView(splashScreenView);
-            splashScreenView.cacheRootWindow(win);
             splashScreenView.makeSystemUIColorsTransparent();
             return splashScreenView;
         }
@@ -363,8 +353,8 @@
         return root < 0.1;
     }
 
-    private static SplashScreenView makeSplashscreenContentDrawable(Window win,
-            Context ctx, int splashscreenContentResId) {
+    private static SplashScreenView makeSplashscreenContentDrawable(Context ctx,
+            int splashscreenContentResId) {
         // doesn't support windowSplashscreenContent after S
         // TODO add an allowlist to skip some packages if needed
         final int targetSdkVersion = ctx.getApplicationInfo().targetSdkVersion;
@@ -384,7 +374,6 @@
         SplashScreenView view = new SplashScreenView(ctx);
         view.setNotCopyable();
         view.setBackground(drawable);
-        win.setContentView(view);
         return view;
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
index 8144071..2d1d65b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
@@ -33,8 +33,10 @@
 import android.os.IBinder;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.view.Choreographer;
 import android.view.Display;
 import android.view.View;
+import android.view.Window;
 import android.view.WindowManager;
 import android.window.SplashScreenView;
 import android.window.SplashScreenView.SplashScreenViewParcelable;
@@ -58,20 +60,25 @@
 
     private final Context mContext;
     private final DisplayManager mDisplayManager;
-    final ShellExecutor mMainExecutor;
+    private final ShellExecutor mSplashScreenExecutor;
     private final SplashscreenContentDrawer mSplashscreenContentDrawer;
+    protected Choreographer mChoreographer;
 
     // TODO(b/131727939) remove this when clearing ActivityRecord
     private static final int REMOVE_WHEN_TIMEOUT = 2000;
 
-    public StartingSurfaceDrawer(Context context, ShellExecutor mainExecutor) {
+    public StartingSurfaceDrawer(Context context, ShellExecutor splashScreenExecutor) {
         mContext = context;
         mDisplayManager = mContext.getSystemService(DisplayManager.class);
-        mMainExecutor = mainExecutor;
-
+        mSplashScreenExecutor = splashScreenExecutor;
         final int maxIconAnimDuration = context.getResources().getInteger(
                 com.android.wm.shell.R.integer.max_starting_window_intro_icon_anim_duration);
         mSplashscreenContentDrawer = new SplashscreenContentDrawer(mContext, maxIconAnimDuration);
+        mSplashScreenExecutor.execute(this::initChoreographer);
+    }
+
+    protected void initChoreographer() {
+        mChoreographer = Choreographer.getInstance();
     }
 
     private final SparseArray<StartingWindowRecord> mStartingWindowRecords = new SparseArray<>();
@@ -170,7 +177,9 @@
         }
 
         int windowFlags = 0;
-        if ((activityInfo.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0) {
+        final boolean enableHardAccelerated =
+                (activityInfo.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0;
+        if (enableHardAccelerated) {
             windowFlags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
         }
 
@@ -247,22 +256,100 @@
         }
 
         params.setTitle("Splash Screen " + activityInfo.packageName);
-        final SplashScreenView splashScreenView =
-                mSplashscreenContentDrawer.makeSplashScreenContentView(win, context, iconRes,
-                        splashscreenContentResId[0]);
-        if (splashScreenView == null) {
-            Slog.w(TAG, "Adding splash screen window for " + activityInfo.packageName + " failed!");
-            return;
+
+        // TODO(b/173975965) If the target activity doesn't request FLAG_HARDWARE_ACCELERATED, we
+        // cannot replace the content view after first view was drawn, sounds like an issue.
+        new AddSplashScreenViewRunnable(taskInfo.taskId, win, context, appToken, params, iconRes,
+                        splashscreenContentResId[0], enableHardAccelerated).run();
+    }
+
+    private class AddSplashScreenViewRunnable implements Runnable {
+        private final int mTaskId;
+        private final Window mWin;
+        private final IBinder mAppToken;
+        private final WindowManager.LayoutParams mLayoutParams;
+        private final Context mContext;
+        private final int mIconRes;
+        private final int mSplashscreenContentResId;
+        private final boolean mReplaceSplashScreenView;
+        private int mSequence;
+
+        AddSplashScreenViewRunnable(int taskId, Window window, Context context,
+                IBinder appToken, WindowManager.LayoutParams params, int iconRes,
+                int splashscreenContentResId, boolean replaceSplashScreenView) {
+            mTaskId = taskId;
+            mWin = window;
+            mAppToken = appToken;
+            mContext = context;
+            mLayoutParams = params;
+            mIconRes = iconRes;
+            mSplashscreenContentResId = splashscreenContentResId;
+            mReplaceSplashScreenView = replaceSplashScreenView;
         }
 
-        final View view = win.getDecorView();
-
-        if (DEBUG_SPLASH_SCREEN) {
-            Slog.d(TAG, "Adding splash screen window for "
-                    + activityInfo.packageName + " / " + appToken + ": " + view);
+        private void createInitialView() {
+            View tempView = new View(mContext);
+            mWin.setContentView(tempView);
+            mSequence++;
+            final View view = mWin.getDecorView();
+            final WindowManager wm = mContext.getSystemService(WindowManager.class);
+            if (postAddWindow(mTaskId, mAppToken, view, wm, mLayoutParams)) {
+                mChoreographer.postCallback(Choreographer.CALLBACK_COMMIT, this, null);
+            }
         }
-        final WindowManager wm = context.getSystemService(WindowManager.class);
-        postAddWindow(taskInfo.taskId, appToken, view, wm, params, splashScreenView);
+
+        private SplashScreenView replaceRealView() {
+            final SplashScreenView sView =
+                    mSplashscreenContentDrawer.makeSplashScreenContentView(mContext,
+                            mIconRes, mSplashscreenContentResId);
+            mWin.setContentView(sView);
+            sView.cacheRootWindow(mWin);
+            return sView;
+        }
+
+        private SplashScreenView initiateOnce() {
+            final SplashScreenView sView =
+                    mSplashscreenContentDrawer.makeSplashScreenContentView(mContext, mIconRes,
+                            mSplashscreenContentResId);
+            final View view = mWin.getDecorView();
+            final WindowManager wm = mContext.getSystemService(WindowManager.class);
+            if (postAddWindow(mTaskId, mAppToken, view, wm, mLayoutParams)) {
+                mWin.setContentView(sView);
+                sView.cacheRootWindow(mWin);
+            }
+            return sView;
+        }
+
+        @Override
+        public void run() {
+            SplashScreenView view = null;
+            boolean setRecord = false;
+            try {
+                if (mReplaceSplashScreenView) {
+                    // Tricky way to make animation start faster... create the real content after
+                    // first window drawn. The first empty window won't been see because wm will
+                    // still need to wait for transition ready.
+                    if (mSequence == 0) {
+                        createInitialView();
+                    } else if (mSequence == 1) {
+                        setRecord = true;
+                        view = replaceRealView();
+                    }
+                } else {
+                    setRecord = true;
+                    view = initiateOnce();
+                }
+            } catch (RuntimeException e) {
+                // don't crash if something else bad happens, for example a
+                // failure loading resources because we are loading from an app
+                // on external storage that has been unmounted.
+                Slog.w(TAG, " failed creating starting window", e);
+            } finally {
+                if (setRecord) {
+                    setSplashScreenRecord(mTaskId, view);
+                }
+            }
+        }
     }
 
     /**
@@ -272,10 +359,10 @@
             TaskSnapshot snapshot) {
         final int taskId = startingWindowInfo.taskInfo.taskId;
         final TaskSnapshotWindow surface = TaskSnapshotWindow.create(startingWindowInfo, appToken,
-                snapshot, mMainExecutor, () -> removeWindowSynced(taskId) /* clearWindow */);
-        mMainExecutor.executeDelayed(() -> removeWindowSynced(taskId), REMOVE_WHEN_TIMEOUT);
+                snapshot, mSplashScreenExecutor, () -> removeWindowSynced(taskId));
+        mSplashScreenExecutor.executeDelayed(() -> removeWindowSynced(taskId), REMOVE_WHEN_TIMEOUT);
         final StartingWindowRecord tView =
-                new StartingWindowRecord(null/* decorView */, surface, null /* splashScreenView */);
+                new StartingWindowRecord(null/* decorView */, surface);
         mStartingWindowRecords.put(taskId, tView);
     }
 
@@ -296,6 +383,13 @@
     public void copySplashScreenView(int taskId) {
         final StartingWindowRecord preView = mStartingWindowRecords.get(taskId);
         SplashScreenViewParcelable parcelable;
+        if (preView != null) {
+            if (preView.isWaitForContent()) {
+                mChoreographer.postCallback(Choreographer.CALLBACK_COMMIT,
+                        () -> copySplashScreenView(taskId), null);
+                return;
+            }
+        }
         if (preView != null && preView.mContentView != null
                 && preView.mContentView.isCopyable()) {
             parcelable = new SplashScreenViewParcelable(preView.mContentView);
@@ -309,45 +403,63 @@
         ActivityTaskManager.getInstance().onSplashScreenViewCopyFinished(taskId, parcelable);
     }
 
-    protected void postAddWindow(int taskId, IBinder appToken,
-            View view, WindowManager wm, WindowManager.LayoutParams params,
-            SplashScreenView splashScreenView) {
-        mMainExecutor.execute(() -> {
-            boolean shouldSaveView = true;
-            try {
-                wm.addView(view, params);
-            } catch (WindowManager.BadTokenException e) {
-                // ignore
-                Slog.w(TAG, appToken + " already running, starting window not displayed. "
-                        + e.getMessage());
+    protected boolean postAddWindow(int taskId, IBinder appToken, View view, WindowManager wm,
+            WindowManager.LayoutParams params) {
+        boolean shouldSaveView = true;
+        try {
+            wm.addView(view, params);
+        } catch (WindowManager.BadTokenException e) {
+            // ignore
+            Slog.w(TAG, appToken + " already running, starting window not displayed. "
+                    + e.getMessage());
+            shouldSaveView = false;
+        } catch (RuntimeException e) {
+            // don't crash if something else bad happens, for example a
+            // failure loading resources because we are loading from an app
+            // on external storage that has been unmounted.
+            Slog.w(TAG, appToken + " failed creating starting window", e);
+            shouldSaveView = false;
+        } finally {
+            if (view != null && view.getParent() == null) {
+                Slog.w(TAG, "view not successfully added to wm, removing view");
+                wm.removeViewImmediate(view);
                 shouldSaveView = false;
-            } catch (RuntimeException e) {
-                // don't crash if something else bad happens, for example a
-                // failure loading resources because we are loading from an app
-                // on external storage that has been unmounted.
-                Slog.w(TAG, appToken + " failed creating starting window", e);
-                shouldSaveView = false;
-            } finally {
-                if (view != null && view.getParent() == null) {
-                    Slog.w(TAG, "view not successfully added to wm, removing view");
-                    wm.removeViewImmediate(view);
-                    shouldSaveView = false;
-                }
             }
-            if (shouldSaveView) {
-                removeWindowSynced(taskId);
-                mMainExecutor.executeDelayed(() -> removeWindowSynced(taskId), REMOVE_WHEN_TIMEOUT);
-                final StartingWindowRecord tView = new StartingWindowRecord(view,
-                        null /* TaskSnapshotWindow */, splashScreenView);
-                splashScreenView.startIntroAnimation();
-                mStartingWindowRecords.put(taskId, tView);
-            }
-        });
+        }
+        if (shouldSaveView) {
+            removeWindowSynced(taskId);
+            mSplashScreenExecutor.executeDelayed(() -> removeWindowSynced(taskId),
+                    REMOVE_WHEN_TIMEOUT);
+            saveSplashScreenRecord(taskId, view);
+        }
+        return shouldSaveView;
+    }
+
+    private void saveSplashScreenRecord(int taskId, View view) {
+        final StartingWindowRecord tView = new StartingWindowRecord(view,
+                null/* TaskSnapshotWindow */);
+        mStartingWindowRecords.put(taskId, tView);
+    }
+
+    private void setSplashScreenRecord(int taskId, SplashScreenView splashScreenView) {
+        final StartingWindowRecord record = mStartingWindowRecords.get(taskId);
+        if (record != null) {
+            record.setSplashScreenView(splashScreenView);
+            splashScreenView.startIntroAnimation();
+        }
     }
 
     protected void removeWindowSynced(int taskId) {
         final StartingWindowRecord record = mStartingWindowRecords.get(taskId);
         if (record != null) {
+            if (record.isWaitForContent()) {
+                if (DEBUG_SPLASH_SCREEN) {
+                    Slog.v(TAG, "splash screen window haven't been draw yet");
+                }
+                mChoreographer.postCallback(Choreographer.CALLBACK_COMMIT,
+                        () -> removeWindowSynced(taskId), null);
+                return;
+            }
             if (record.mDecorView != null) {
                 if (DEBUG_SPLASH_SCREEN) {
                     Slog.v(TAG, "Removing splash screen window for task: " + taskId);
@@ -378,13 +490,24 @@
     private static class StartingWindowRecord {
         private final View mDecorView;
         private final TaskSnapshotWindow mTaskSnapshotWindow;
-        private final SplashScreenView mContentView;
+        private SplashScreenView mContentView;
+        private boolean mSetSplashScreen;
 
-        StartingWindowRecord(View decorView, TaskSnapshotWindow taskSnapshotWindow,
-                SplashScreenView splashScreenView) {
+        StartingWindowRecord(View decorView, TaskSnapshotWindow taskSnapshotWindow) {
             mDecorView = decorView;
             mTaskSnapshotWindow = taskSnapshotWindow;
+        }
+
+        private void setSplashScreenView(SplashScreenView splashScreenView) {
+            if (mSetSplashScreen) {
+                return;
+            }
             mContentView = splashScreenView;
+            mSetSplashScreen = true;
+        }
+
+        private boolean isWaitForContent() {
+            return mDecorView != null && !mSetSplashScreen;
         }
     }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java
index 1ac05fb..5eb7071 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java
@@ -47,6 +47,12 @@
  * starting window and attached to the Task, then when the Task want to remove the starting window,
  * the TaskOrganizer will receive {@link TaskOrganizer#removeStartingWindow} callback then use this
  * class to remove the starting window of the Task.
+ * Besides add/remove starting window, There is an API #setStartingWindowListener to register
+ * a callback when starting window is about to create which let the registerer knows the next
+ * starting window's type.
+ * So far all classes in this package is an enclose system so there is no interact with other shell
+ * component, all the methods must be executed in splash screen thread or the thread used in
+ * constructor to keep everything synchronized.
  * @hide
  */
 public class StartingWindowController {
@@ -59,9 +65,11 @@
 
     private BiConsumer<Integer, Integer> mTaskLaunchingCallback;
     private final StartingSurfaceImpl mImpl = new StartingSurfaceImpl();
+    private final ShellExecutor mSplashScreenExecutor;
 
-    public StartingWindowController(Context context, ShellExecutor mainExecutor) {
-        mStartingSurfaceDrawer = new StartingSurfaceDrawer(context, mainExecutor);
+    public StartingWindowController(Context context, ShellExecutor splashScreenExecutor) {
+        mStartingSurfaceDrawer = new StartingSurfaceDrawer(context, splashScreenExecutor);
+        mSplashScreenExecutor = splashScreenExecutor;
     }
 
     /**
@@ -198,22 +206,26 @@
 
         @Override
         public void addStartingWindow(StartingWindowInfo windowInfo, IBinder appToken) {
-            StartingWindowController.this.addStartingWindow(windowInfo, appToken);
+            mSplashScreenExecutor.execute(() ->
+                    StartingWindowController.this.addStartingWindow(windowInfo, appToken));
         }
 
         @Override
         public void removeStartingWindow(int taskId) {
-            StartingWindowController.this.removeStartingWindow(taskId);
+            mSplashScreenExecutor.execute(() ->
+                    StartingWindowController.this.removeStartingWindow(taskId));
         }
 
         @Override
         public void copySplashScreenView(int taskId) {
-            StartingWindowController.this.copySplashScreenView(taskId);
+            mSplashScreenExecutor.execute(() ->
+                    StartingWindowController.this.copySplashScreenView(taskId));
         }
 
         @Override
         public void setStartingWindowListener(BiConsumer<Integer, Integer> listener) {
-            StartingWindowController.this.setStartingWindowListener(listener);
+            mSplashScreenExecutor.execute(() ->
+                    StartingWindowController.this.setStartingWindowListener(listener));
         }
     }
 }
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 b7fd3cb..6e43741 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
@@ -83,7 +83,6 @@
 import com.android.internal.policy.DecorView;
 import com.android.internal.view.BaseIWindow;
 import com.android.wm.shell.common.ShellExecutor;
-import com.android.wm.shell.common.annotations.ExternalThread;
 
 /**
  * This class represents a starting window that shows a snapshot.
@@ -123,7 +122,7 @@
     private final Window mWindow;
     private final Surface mSurface;
     private final Runnable mClearWindowHandler;
-    private final ShellExecutor mMainExecutor;
+    private final ShellExecutor mSplashScreenExecutor;
     private SurfaceControl mSurfaceControl;
     private SurfaceControl mChildSurfaceControl;
     private final IWindowSession mSession;
@@ -252,8 +251,8 @@
             TaskSnapshot snapshot, CharSequence title, TaskDescription taskDescription,
             int appearance, int windowFlags, int windowPrivateFlags, Rect taskBounds,
             int currentOrientation, int activityType, InsetsState topWindowInsetsState,
-            Runnable clearWindowHandler, ShellExecutor mainExecutor) {
-        mMainExecutor = mainExecutor;
+            Runnable clearWindowHandler, ShellExecutor splashScreenExecutor) {
+        mSplashScreenExecutor = splashScreenExecutor;
         mSurface = new Surface();
         mSession = WindowManagerGlobal.getWindowSession();
         mWindow = new Window();
@@ -296,7 +295,7 @@
                 // Show the latest content as soon as possible for unlocking to home.
                 && mActivityType != ACTIVITY_TYPE_HOME) {
             final long delayTime = mShownTime + SIZE_MISMATCH_MINIMUM_TIME_MS - now;
-            mMainExecutor.executeDelayed(() -> remove(), delayTime);
+            mSplashScreenExecutor.executeDelayed(() -> remove(), delayTime);
             if (DEBUG) {
                 Slog.d(TAG, "Defer removing snapshot surface in " + delayTime);
             }
@@ -512,7 +511,7 @@
                 MergedConfiguration mergedConfiguration, boolean forceLayout,
                 boolean alwaysConsumeSystemBars, int displayId) {
             if (mOuter != null) {
-                mOuter.mMainExecutor.execute(() -> {
+                mOuter.mSplashScreenExecutor.execute(() -> {
                     if (mergedConfiguration != null
                             && mOuter.mOrientationOnCreation
                             != mergedConfiguration.getMergedConfiguration().orientation) {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
index 83dca53..2f08db1 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
@@ -107,7 +107,7 @@
         @JvmStatic
         fun getParams(): List<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance()
-                .getConfigRotationTests(supportedRotations = listOf(Surface.ROTATION_0),
+                .getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0),
                     repetitions = 5)
         }
     }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java
index 06b492d..df0a856 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java
@@ -27,6 +27,7 @@
 import static com.android.wm.shell.ShellTaskOrganizer.TASK_LISTENER_TYPE_MULTI_WINDOW;
 import static com.android.wm.shell.ShellTaskOrganizer.TASK_LISTENER_TYPE_PIP;
 
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
@@ -37,10 +38,12 @@
 
 import android.app.ActivityManager.RunningTaskInfo;
 import android.content.Context;
+import android.content.LocusId;
 import android.content.pm.ParceledListSlice;
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.RemoteException;
+import android.util.SparseArray;
 import android.view.SurfaceControl;
 import android.window.ITaskOrganizer;
 import android.window.ITaskOrganizerController;
@@ -105,6 +108,20 @@
         }
     }
 
+    private class TrackingLocusIdListener implements ShellTaskOrganizer.LocusIdListener {
+        final SparseArray<LocusId> visibleLocusTasks = new SparseArray<>();
+        final SparseArray<LocusId> invisibleLocusTasks = new SparseArray<>();
+        @Override
+        public void onVisibilityChanged(int taskId, LocusId locus, boolean visible) {
+            if (visible) {
+                visibleLocusTasks.put(taskId, locus);
+            } else {
+                invisibleLocusTasks.put(taskId, locus);
+            }
+        }
+    }
+
+
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
@@ -299,6 +316,123 @@
                 null /* taskConfig */, null /* sizeCompatActivity*/, null /* taskListener */);
     }
 
+    @Test
+    public void testAddLocusListener() {
+        RunningTaskInfo task1 = createTaskInfo(1, WINDOWING_MODE_MULTI_WINDOW);
+        task1.isVisible = true;
+        task1.mTopActivityLocusId = new LocusId("10");
+
+        RunningTaskInfo task2 = createTaskInfo(2, WINDOWING_MODE_FULLSCREEN);
+        task2.isVisible = true;
+        task2.mTopActivityLocusId = new LocusId("20");
+
+        RunningTaskInfo task3 = createTaskInfo(3, WINDOWING_MODE_FULLSCREEN);
+        task3.isVisible = true;
+
+        mOrganizer.onTaskAppeared(task1, null);
+        mOrganizer.onTaskAppeared(task2, null);
+        mOrganizer.onTaskAppeared(task3, null);
+
+        TrackingLocusIdListener listener = new TrackingLocusIdListener();
+        mOrganizer.addLocusIdListener(listener);
+
+        // Listener should have the locus tasks even if added after the tasks appear
+        assertEquals(listener.visibleLocusTasks.get(task1.taskId), task1.mTopActivityLocusId);
+        assertEquals(listener.visibleLocusTasks.get(task2.taskId), task2.mTopActivityLocusId);
+        assertFalse(listener.visibleLocusTasks.contains(task3.taskId));
+    }
+
+    @Test
+    public void testLocusListener_appearVanish() {
+        TrackingLocusIdListener listener = new TrackingLocusIdListener();
+        mOrganizer.addLocusIdListener(listener);
+
+        RunningTaskInfo task1 = createTaskInfo(1, WINDOWING_MODE_FULLSCREEN);
+        task1.mTopActivityLocusId = new LocusId("10");
+
+        task1.isVisible = true;
+        mOrganizer.onTaskAppeared(task1, null);
+        assertTrue(listener.visibleLocusTasks.contains(task1.taskId));
+        assertEquals(listener.visibleLocusTasks.get(task1.taskId), task1.mTopActivityLocusId);
+
+        task1.isVisible = false;
+        mOrganizer.onTaskVanished(task1);
+        assertTrue(listener.invisibleLocusTasks.contains(task1.taskId));
+        assertEquals(listener.invisibleLocusTasks.get(task1.taskId), task1.mTopActivityLocusId);
+    }
+
+    @Test
+    public void testLocusListener_infoChanged() {
+        TrackingLocusIdListener listener = new TrackingLocusIdListener();
+        mOrganizer.addLocusIdListener(listener);
+
+        RunningTaskInfo task1 = createTaskInfo(1, WINDOWING_MODE_MULTI_WINDOW);
+        task1.isVisible = true;
+        mOrganizer.onTaskAppeared(task1, null);
+        assertEquals(listener.visibleLocusTasks.size(), 0);
+
+        task1.mTopActivityLocusId = new LocusId("10");
+        mOrganizer.onTaskInfoChanged(task1);
+        assertTrue(listener.visibleLocusTasks.contains(task1.taskId));
+        assertEquals(listener.visibleLocusTasks.get(task1.taskId), task1.mTopActivityLocusId);
+
+        LocusId prevLocus = task1.mTopActivityLocusId;
+        task1.mTopActivityLocusId = new LocusId("20");
+        mOrganizer.onTaskInfoChanged(task1);
+
+        // New locus is in visible list
+        assertTrue(listener.visibleLocusTasks.contains(task1.taskId));
+        assertEquals(listener.visibleLocusTasks.get(task1.taskId), task1.mTopActivityLocusId);
+        // Old locus in invisible list
+        assertTrue(listener.invisibleLocusTasks.contains(task1.taskId));
+        assertEquals(listener.invisibleLocusTasks.get(task1.taskId), prevLocus);
+    }
+
+    @Test
+    public void testLocusListener_infoChanged_notVisible() {
+        TrackingLocusIdListener listener = new TrackingLocusIdListener();
+        mOrganizer.addLocusIdListener(listener);
+
+        RunningTaskInfo task1 = createTaskInfo(1, WINDOWING_MODE_FULLSCREEN);
+        task1.isVisible = true;
+        mOrganizer.onTaskAppeared(task1, null);
+
+        task1.mTopActivityLocusId = new LocusId("10");
+        mOrganizer.onTaskInfoChanged(task1);
+        assertTrue(listener.visibleLocusTasks.contains(task1.taskId));
+        assertEquals(listener.visibleLocusTasks.get(task1.taskId), task1.mTopActivityLocusId);
+
+        LocusId prevLocus = task1.mTopActivityLocusId;
+        task1.mTopActivityLocusId = new LocusId("20");
+        task1.isVisible = false;
+        mOrganizer.onTaskInfoChanged(task1);
+
+        // New locus for previously reported task in invisible list (since the task wasn't visible).
+        assertTrue(listener.invisibleLocusTasks.contains(task1.taskId));
+        assertEquals(listener.invisibleLocusTasks.get(task1.taskId), prevLocus);
+    }
+
+    @Test
+    public void testLocusListener_noLocusNotNotified() {
+        TrackingLocusIdListener listener = new TrackingLocusIdListener();
+        mOrganizer.addLocusIdListener(listener);
+
+        RunningTaskInfo task1 = createTaskInfo(1, WINDOWING_MODE_MULTI_WINDOW);
+        task1.isVisible = true;
+        mOrganizer.onTaskAppeared(task1, null);
+        assertEquals(listener.visibleLocusTasks.size(), 0);
+        assertEquals(listener.invisibleLocusTasks.size(), 0);
+
+        mOrganizer.onTaskInfoChanged(task1);
+        assertEquals(listener.visibleLocusTasks.size(), 0);
+        assertEquals(listener.invisibleLocusTasks.size(), 0);
+
+        task1.isVisible = false;
+        mOrganizer.onTaskVanished(task1);
+        assertEquals(listener.visibleLocusTasks.size(), 0);
+        assertEquals(listener.invisibleLocusTasks.size(), 0);
+    }
+
     private static RunningTaskInfo createTaskInfo(int taskId, int windowingMode) {
         RunningTaskInfo taskInfo = new RunningTaskInfo();
         taskInfo.taskId = taskId;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java
index d3a736e..9a80a55 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java
@@ -106,7 +106,7 @@
     private ArgumentCaptor<BubbleData.Update> mUpdateCaptor;
 
     @Mock
-    private Bubbles.NotificationSuppressionChangedListener mSuppressionListener;
+    private Bubbles.SuppressionChangedListener mSuppressionListener;
 
     @Mock
     private Bubbles.PendingIntentCanceledListener mPendingIntentCanceledListener;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleTest.java
index fc828b3..819a984 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleTest.java
@@ -63,7 +63,7 @@
     private Bubble mBubble;
 
     @Mock
-    private Bubbles.NotificationSuppressionChangedListener mSuppressionListener;
+    private Bubbles.SuppressionChangedListener mSuppressionListener;
 
     @Before
     public void setUp() {
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubblePersistentRepositoryTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubblePersistentRepositoryTest.kt
index bdf75fc..2f064ac 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubblePersistentRepositoryTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubblePersistentRepositoryTest.kt
@@ -32,10 +32,12 @@
 class BubblePersistentRepositoryTest : ShellTestCase() {
 
     private val bubbles = listOf(
-            BubbleEntity(0, "com.example.messenger", "shortcut-1", "key-1", 120, 0, null, 1),
-            BubbleEntity(10, "com.example.chat", "alice and bob", "key-2", 0, 16537428, "title", 2),
+            // user, package, shortcut, notification key, height, res-height, title, taskId, locusId
+            BubbleEntity(0, "com.example.messenger", "shortcut-1", "key-1", 120, 0, null, 1, null),
+            BubbleEntity(10, "com.example.chat", "alice and bob", "key-2", 0, 16537428, "title",
+                    2, null),
             BubbleEntity(0, "com.example.messenger", "shortcut-2", "key-3", 120, 0, null,
-                    INVALID_TASK_ID)
+                    INVALID_TASK_ID, "key-3")
     )
     private lateinit var repository: BubblePersistentRepository
 
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubbleVolatileRepositoryTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubbleVolatileRepositoryTest.kt
index 05795fd..03aa6c2 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubbleVolatileRepositoryTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubbleVolatileRepositoryTest.kt
@@ -38,12 +38,13 @@
     private val user0 = UserHandle.of(0)
     private val user10 = UserHandle.of(10)
 
+    // user, package, shortcut, notification key, height, res-height, title, taskId, locusId
     private val bubble1 = BubbleEntity(0, "com.example.messenger", "shortcut-1", "key-1", 120, 0,
-            null, 1)
+            null, 1, null)
     private val bubble2 = BubbleEntity(10, "com.example.chat", "alice and bob",
-            "key-2", 0, 16537428, "title", 2)
+            "key-2", 0, 16537428, "title", 2, null)
     private val bubble3 = BubbleEntity(0, "com.example.messenger", "shortcut-2", "key-3", 120, 0,
-            null, INVALID_TASK_ID)
+            null, INVALID_TASK_ID, "key-3")
 
     private val bubbles = listOf(bubble1, bubble2, bubble3)
 
@@ -108,13 +109,14 @@
 
     @Test
     fun testAddBubbleMatchesByKey() {
-        val bubble = BubbleEntity(0, "com.example.pkg", "shortcut-id", "key", 120, 0, "title", 1)
+        val bubble = BubbleEntity(0, "com.example.pkg", "shortcut-id", "key", 120, 0, "title",
+                1, null)
         repository.addBubbles(listOf(bubble))
         assertEquals(bubble, repository.bubbles.get(0))
 
         // Same key as first bubble but different entry
         val bubbleModified = BubbleEntity(0, "com.example.pkg", "shortcut-id", "key", 120, 0,
-                "different title", 2)
+                "different title", 2, null)
         repository.addBubbles(listOf(bubbleModified))
         assertEquals(bubbleModified, repository.bubbles.get(0))
     }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubbleXmlHelperTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubbleXmlHelperTest.kt
index 839b873..8d719e7 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubbleXmlHelperTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubbleXmlHelperTest.kt
@@ -32,10 +32,12 @@
 class BubbleXmlHelperTest : ShellTestCase() {
 
     private val bubbles = listOf(
+            // user, package, shortcut, notification key, height, res-height, title, taskId, locusId
             BubbleEntity(0, "com.example.messenger", "shortcut-1", "k1", 120, 0, null, 1),
-            BubbleEntity(10, "com.example.chat", "alice and bob", "k2", 0, 16537428, "title", 2),
+            BubbleEntity(10, "com.example.chat", "alice and bob", "k2", 0, 16537428, "title",
+                    2, null),
             BubbleEntity(0, "com.example.messenger", "shortcut-2", "k3", 120, 0, null,
-                    INVALID_TASK_ID)
+                    INVALID_TASK_ID, "l3")
     )
 
     @Test
@@ -43,7 +45,7 @@
         val expectedEntries = """
 <bb uid="0" pkg="com.example.messenger" sid="shortcut-1" key="k1" h="120" hid="0" tid="1" />
 <bb uid="10" pkg="com.example.chat" sid="alice and bob" key="k2" h="0" hid="16537428" t="title" tid="2" />
-<bb uid="0" pkg="com.example.messenger" sid="shortcut-2" key="k3" h="120" hid="0" tid="-1" />
+<bb uid="0" pkg="com.example.messenger" sid="shortcut-2" key="k3" h="120" hid="0" tid="-1" l="l3" />
         """.trimIndent()
         ByteArrayOutputStream().use {
             writeXml(it, bubbles)
@@ -60,7 +62,7 @@
 <bs v="1">
 <bb uid="0" pkg="com.example.messenger" sid="shortcut-1" key="k1" h="120" hid="0" tid="1" />
 <bb uid="10" pkg="com.example.chat" sid="alice and bob" key="k2" h="0" hid="16537428" t="title" tid="2" />
-<bb uid="0" pkg="com.example.messenger" sid="shortcut-2" key="k3" h="120" hid="0" tid="-1" />
+<bb uid="0" pkg="com.example.messenger" sid="shortcut-2" key="k3" h="120" hid="0" tid="-1" l="l3" />
 </bs>
         """.trimIndent()
         val actual = readXml(ByteArrayInputStream(src.toByteArray(Charsets.UTF_8)))
@@ -97,7 +99,32 @@
                 BubbleEntity(0, "com.example.messenger", "shortcut-2", "k3", 120, 0, null,
                         INVALID_TASK_ID)
         )
+        val src = """
+<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
+<bs v="1">
+<bb uid="0" pkg="com.example.messenger" sid="shortcut-1" key="k1" h="120" hid="0" />
+<bb uid="10" pkg="com.example.chat" sid="alice and bob" key="k2" h="0" hid="16537428" t="title" />
+<bb uid="0" pkg="com.example.messenger" sid="shortcut-2" key="k3" h="120" hid="0" />
+</bs>
+        """.trimIndent()
+        val actual = readXml(ByteArrayInputStream(src.toByteArray(Charsets.UTF_8)))
+        assertEquals("failed parsing bubbles from xml\n$src", expectedBubbles, actual)
+    }
 
+    /**
+     * LocusId is optional so it can be added without a version change, this test makes sure that
+     * works.
+     */
+    @Test
+    fun testXMLWithoutLocusToLocus() {
+        val expectedBubbles = listOf(
+            BubbleEntity(0, "com.example.messenger", "shortcut-1", "k1", 120, 0, null,
+                    INVALID_TASK_ID, null),
+            BubbleEntity(10, "com.example.chat", "alice and bob", "k2", 0, 16537428, "title",
+                    INVALID_TASK_ID, null),
+            BubbleEntity(0, "com.example.messenger", "shortcut-2", "k3", 120, 0, null,
+                    INVALID_TASK_ID, null)
+        )
         val src = """
 <?xml version='1.0' encoding='utf-8' standalone='yes' ?>
 <bs v="1">
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedGestureHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedGestureHandlerTest.java
index f58affc..f683e4a 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedGestureHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedGestureHandlerTest.java
@@ -16,14 +16,22 @@
 
 package com.android.wm.shell.onehanded;
 
+import static android.view.Display.DEFAULT_DISPLAY;
+
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.when;
+
 import android.testing.AndroidTestingRunner;
+import android.view.Surface;
 import android.view.ViewConfiguration;
+import android.window.WindowContainerTransaction;
 
 import androidx.test.filters.SmallTest;
 
 import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.DisplayLayout;
 import com.android.wm.shell.common.ShellExecutor;
 
 import org.junit.Before;
@@ -39,14 +47,21 @@
     @Mock
     DisplayController mMockDisplayController;
     @Mock
+    DisplayLayout mMockDisplayLayout;
+    @Mock
     ShellExecutor mMockShellMainExecutor;
+    @Mock
+    WindowContainerTransaction mMockWct;
 
     @Before
     public void setUp() {
+        final int mockNavBarHeight = 100;
         MockitoAnnotations.initMocks(this);
         mGestureHandler = new OneHandedGestureHandler(mContext, mWindowManager,
                 mMockDisplayController, ViewConfiguration.get(mTestContext),
                 mMockShellMainExecutor);
+        when(mMockDisplayLayout.navBarFrameHeight()).thenReturn(mockNavBarHeight);
+        when(mMockDisplayController.getDisplayLayout(anyInt())).thenReturn(mMockDisplayLayout);
     }
 
     @Test
@@ -80,4 +95,14 @@
         assertThat(mGestureHandler.mInputMonitor).isNull();
         assertThat(mGestureHandler.mInputEventReceiver).isNull();
     }
+
+    @Test
+    public void testOnlyHandleGestureInPortraitMode() {
+        mGestureHandler.onOneHandedEnabled(true);
+        mGestureHandler.onRotateDisplay(DEFAULT_DISPLAY, Surface.ROTATION_0, Surface.ROTATION_90,
+                mMockWct);
+
+        assertThat(mGestureHandler.mInputMonitor).isNull();
+        assertThat(mGestureHandler.mInputEventReceiver).isNull();
+    }
 }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
index 195b701..d687e8d 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
@@ -45,6 +45,7 @@
 import com.android.wm.shell.TestShellExecutor;
 import com.android.wm.shell.common.DisplayController;
 import com.android.wm.shell.common.DisplayLayout;
+import com.android.wm.shell.common.SyncTransactionQueue;
 import com.android.wm.shell.legacysplitscreen.LegacySplitScreenController;
 import com.android.wm.shell.pip.phone.PhonePipMenuController;
 
@@ -65,8 +66,8 @@
 public class PipTaskOrganizerTest extends ShellTestCase {
     private PipTaskOrganizer mSpiedPipTaskOrganizer;
 
-    @Mock private DisplayController mMockdDisplayController;
-
+    @Mock private DisplayController mMockDisplayController;
+    @Mock private SyncTransactionQueue mMockSyncTransactionQueue;
     @Mock private PhonePipMenuController mMockPhonePipMenuController;
     @Mock private PipAnimationController mMockPipAnimationController;
     @Mock private PipTransitionController mMockPipTransitionController;
@@ -89,10 +90,11 @@
         mPipBoundsState = new PipBoundsState(mContext);
         mPipBoundsAlgorithm = new PipBoundsAlgorithm(mContext, mPipBoundsState);
         mMainExecutor = new TestShellExecutor();
-        mSpiedPipTaskOrganizer = spy(new PipTaskOrganizer(mContext, mPipBoundsState,
+        mSpiedPipTaskOrganizer = spy(new PipTaskOrganizer(mContext,
+                mMockSyncTransactionQueue, mPipBoundsState,
                 mPipBoundsAlgorithm, mMockPhonePipMenuController,
                 mMockPipAnimationController, mMockPipSurfaceTransactionHelper,
-                mMockPipTransitionController, mMockOptionalSplitScreen, mMockdDisplayController,
+                mMockPipTransitionController, mMockOptionalSplitScreen, mMockDisplayController,
                 mMockPipUiEventLogger, mMockShellTaskOrganizer, mMainExecutor));
         mMainExecutor.flushAll();
         preparePipTaskOrg();
@@ -105,7 +107,7 @@
 
     @Test
     public void instantiatePipTaskOrganizer_addsDisplayWindowListener() {
-        verify(mMockdDisplayController).addDisplayWindowListener(any());
+        verify(mMockDisplayController).addDisplayWindowListener(any());
     }
 
     @Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
index b9af9ce..a531ef5 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
@@ -37,10 +37,10 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.testing.TestableContext;
+import android.view.Choreographer;
 import android.view.View;
 import android.view.WindowManager;
 import android.view.WindowMetrics;
-import android.window.SplashScreenView;
 import android.window.StartingWindowInfo;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -67,6 +67,8 @@
     private IBinder mBinder;
     @Mock
     private WindowManager mMockWindowManager;
+    @Mock
+    private static Choreographer sFakeChoreographer;
 
     TestStartingSurfaceDrawer mStartingSurfaceDrawer;
 
@@ -79,12 +81,17 @@
         }
 
         @Override
-        protected void postAddWindow(int taskId, IBinder appToken,
-                View view, WindowManager wm, WindowManager.LayoutParams params,
-                SplashScreenView splashScreenView) {
+        protected void initChoreographer() {
+            mChoreographer = sFakeChoreographer;
+        }
+
+        @Override
+        protected boolean postAddWindow(int taskId, IBinder appToken,
+                View view, WindowManager wm, WindowManager.LayoutParams params) {
             // listen for addView
             mAddWindowForTask = taskId;
             mViewThemeResId = view.getContext().getThemeResId();
+            return true;
         }
 
         @Override
@@ -127,8 +134,7 @@
                 createWindowInfo(taskId, android.R.style.Theme);
         mStartingSurfaceDrawer.addSplashScreenStartingWindow(windowInfo, mBinder);
         waitHandlerIdle(mainLoop);
-        verify(mStartingSurfaceDrawer).postAddWindow(
-                eq(taskId), eq(mBinder), any(), any(), any(), any());
+        verify(mStartingSurfaceDrawer).postAddWindow(eq(taskId), eq(mBinder), any(), any(), any());
         assertEquals(mStartingSurfaceDrawer.mAddWindowForTask, taskId);
 
         mStartingSurfaceDrawer.removeStartingWindow(windowInfo.taskInfo.taskId);
@@ -145,8 +151,7 @@
                 createWindowInfo(taskId, 0);
         mStartingSurfaceDrawer.addSplashScreenStartingWindow(windowInfo, mBinder);
         waitHandlerIdle(mainLoop);
-        verify(mStartingSurfaceDrawer).postAddWindow(
-                eq(taskId), eq(mBinder), any(), any(), any(), any());
+        verify(mStartingSurfaceDrawer).postAddWindow(eq(taskId), eq(mBinder), any(), any(), any());
         assertNotEquals(mStartingSurfaceDrawer.mViewThemeResId, 0);
     }
 
diff --git a/libs/hwui/FrameMetricsObserver.h b/libs/hwui/FrameMetricsObserver.h
index b93f078..ef1f5aa 100644
--- a/libs/hwui/FrameMetricsObserver.h
+++ b/libs/hwui/FrameMetricsObserver.h
@@ -24,6 +24,24 @@
 class FrameMetricsObserver : public VirtualLightRefBase {
 public:
     virtual void notify(const int64_t* buffer) = 0;
+    bool waitForPresentTime() const { return mWaitForPresentTime; };
+
+    /**
+     * Create a new metrics observer. An observer that watches present time gets notified at a
+     * different time than the observer that doesn't.
+     *
+     * The observer that doesn't want present time is notified about metrics just after the frame
+     * is completed. This is the default behaviour that's used by public API's.
+     *
+     * An observer that watches present time is notified about metrics after the actual display
+     * present time is known.
+     * WARNING! This observer may not receive metrics for the last several frames that the app
+     * produces.
+     */
+    FrameMetricsObserver(bool waitForPresentTime) : mWaitForPresentTime(waitForPresentTime) {}
+
+private:
+    const bool mWaitForPresentTime;
 };
 
 }  // namespace uirenderer
diff --git a/libs/hwui/FrameMetricsReporter.h b/libs/hwui/FrameMetricsReporter.h
index 0643e79..3f2dc12 100644
--- a/libs/hwui/FrameMetricsReporter.h
+++ b/libs/hwui/FrameMetricsReporter.h
@@ -55,13 +55,24 @@
         return mObservers.size() > 0;
     }
 
-    void reportFrameMetrics(const int64_t* stats) {
+    /**
+     * Notify observers about the metrics contained in 'stats'.
+     * If an observer is waiting for present time, notify when 'stats' has present time.
+     *
+     * If an observer does not want present time, only notify when 'hasPresentTime' is false.
+     * Never notify both types of observers from the same callback, because the callback with
+     * 'hasPresentTime' is sent at a different time than the one without.
+     */
+    void reportFrameMetrics(const int64_t* stats, bool hasPresentTime) {
         FatVector<sp<FrameMetricsObserver>, 10> copy;
         {
             std::lock_guard lock(mObserversLock);
             copy.reserve(mObservers.size());
             for (size_t i = 0; i < mObservers.size(); i++) {
-                copy.push_back(mObservers[i]);
+                const bool wantsPresentTime = mObservers[i]->waitForPresentTime();
+                if (hasPresentTime == wantsPresentTime) {
+                    copy.push_back(mObservers[i]);
+                }
             }
         }
         for (size_t i = 0; i < copy.size(); i++) {
diff --git a/libs/hwui/jni/android_graphics_HardwareRendererObserver.cpp b/libs/hwui/jni/android_graphics_HardwareRendererObserver.cpp
index 5b3e656..e5d5e75 100644
--- a/libs/hwui/jni/android_graphics_HardwareRendererObserver.cpp
+++ b/libs/hwui/jni/android_graphics_HardwareRendererObserver.cpp
@@ -35,7 +35,9 @@
     return env;
 }
 
-HardwareRendererObserver::HardwareRendererObserver(JavaVM *vm, jobject observer) : mVm(vm) {
+HardwareRendererObserver::HardwareRendererObserver(JavaVM* vm, jobject observer,
+                                                   bool waitForPresentTime)
+        : uirenderer::FrameMetricsObserver(waitForPresentTime), mVm(vm) {
     mObserverWeak = getenv(mVm)->NewWeakGlobalRef(observer);
     LOG_ALWAYS_FATAL_IF(mObserverWeak == nullptr,
             "unable to create frame stats observer reference");
@@ -86,14 +88,16 @@
 }
 
 static jlong android_graphics_HardwareRendererObserver_createObserver(JNIEnv* env,
-                                                                      jobject observerObj) {
+                                                                      jobject observerObj,
+                                                                      jboolean waitForPresentTime) {
     JavaVM* vm = nullptr;
     if (env->GetJavaVM(&vm) != JNI_OK) {
         LOG_ALWAYS_FATAL("Unable to get Java VM");
         return 0;
     }
 
-    HardwareRendererObserver* observer = new HardwareRendererObserver(vm, observerObj);
+    HardwareRendererObserver* observer =
+            new HardwareRendererObserver(vm, observerObj, waitForPresentTime);
     return reinterpret_cast<jlong>(observer);
 }
 
@@ -110,10 +114,10 @@
 }
 
 static const std::array gMethods = {
-    MAKE_JNI_NATIVE_METHOD("nCreateObserver", "()J",
-                           android_graphics_HardwareRendererObserver_createObserver),
-    MAKE_JNI_NATIVE_METHOD("nGetNextBuffer", "(J[J)I",
-                           android_graphics_HardwareRendererObserver_getNextBuffer),
+        MAKE_JNI_NATIVE_METHOD("nCreateObserver", "(Z)J",
+                               android_graphics_HardwareRendererObserver_createObserver),
+        MAKE_JNI_NATIVE_METHOD("nGetNextBuffer", "(J[J)I",
+                               android_graphics_HardwareRendererObserver_getNextBuffer),
 };
 
 int register_android_graphics_HardwareRendererObserver(JNIEnv* env) {
diff --git a/libs/hwui/jni/android_graphics_HardwareRendererObserver.h b/libs/hwui/jni/android_graphics_HardwareRendererObserver.h
index 62111fd..d307614 100644
--- a/libs/hwui/jni/android_graphics_HardwareRendererObserver.h
+++ b/libs/hwui/jni/android_graphics_HardwareRendererObserver.h
@@ -26,7 +26,7 @@
  */
 class HardwareRendererObserver : public uirenderer::FrameMetricsObserver {
 public:
-    HardwareRendererObserver(JavaVM *vm, jobject observer);
+    HardwareRendererObserver(JavaVM* vm, jobject observer, bool waitForPresentTime);
     ~HardwareRendererObserver();
 
     /**
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index f69ddac..9793300 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -599,10 +599,41 @@
     // TODO (b/169858044): Move this into JankTracker to adjust deadline when queue is
     // double-stuffed.
     if (CC_UNLIKELY(mFrameMetricsReporter.get() != nullptr)) {
-        mFrameMetricsReporter->reportFrameMetrics(frameInfo->data());
+        mFrameMetricsReporter->reportFrameMetrics(frameInfo->data(), false /*hasPresentTime*/);
     }
 }
 
+void CanvasContext::reportMetricsWithPresentTime() {
+    if (mFrameMetricsReporter == nullptr) {
+        return;
+    }
+    if (mNativeSurface == nullptr) {
+        return;
+    }
+    FrameInfo* forthBehind;
+    int64_t frameNumber;
+    {  // acquire lock
+        std::scoped_lock lock(mLast4FrameInfosMutex);
+        if (mLast4FrameInfos.size() != mLast4FrameInfos.capacity()) {
+            // Not enough frames yet
+            return;
+        }
+        // Surface object keeps stats for the last 8 frames.
+        std::tie(forthBehind, frameNumber) = mLast4FrameInfos.front();
+    }  // release lock
+
+    nsecs_t presentTime = 0;
+    native_window_get_frame_timestamps(
+            mNativeSurface->getNativeWindow(), frameNumber, nullptr /*outRequestedPresentTime*/,
+            nullptr /*outAcquireTime*/, nullptr /*outLatchTime*/,
+            nullptr /*outFirstRefreshStartTime*/, nullptr /*outLastRefreshStartTime*/,
+            nullptr /*outGpuCompositionDoneTime*/, &presentTime, nullptr /*outDequeueReadyTime*/,
+            nullptr /*outReleaseTime*/);
+
+    forthBehind->set(FrameInfoIndex::DisplayPresentTime) = presentTime;
+    mFrameMetricsReporter->reportFrameMetrics(forthBehind->data(), true /*hasPresentTime*/);
+}
+
 void CanvasContext::onSurfaceStatsAvailable(void* context, ASurfaceControl* control,
             ASurfaceControlStats* stats) {
 
@@ -624,6 +655,9 @@
             }
         }
     }
+
+    instance->reportMetricsWithPresentTime();
+
     if (frameInfo != nullptr) {
         if (gpuCompleteTime == -1) {
             gpuCompleteTime = frameInfo->get(FrameInfoIndex::SwapBuffersCompleted);
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 2e7b2f6..74f426e 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -219,6 +219,12 @@
     SkRect computeDirtyRect(const Frame& frame, SkRect* dirty);
     void finishFrame(FrameInfo* frameInfo);
 
+    /**
+     * Invoke 'reportFrameMetrics' on the last frame stored in 'mLast4FrameInfos'.
+     * Populate the 'presentTime' field before calling.
+     */
+    void reportMetricsWithPresentTime();
+
     // The same type as Frame.mWidth and Frame.mHeight
     int32_t mLastFrameWidth = 0;
     int32_t mLastFrameHeight = 0;
diff --git a/location/java/android/location/CorrelationVector.java b/location/java/android/location/CorrelationVector.java
index eca35dd..4b6e688 100644
--- a/location/java/android/location/CorrelationVector.java
+++ b/location/java/android/location/CorrelationVector.java
@@ -17,7 +17,6 @@
 package android.location;
 
 import android.annotation.FloatRange;
-import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.os.Parcel;
@@ -39,7 +38,7 @@
 
     private final double mSamplingWidthMeters;
     private final double mSamplingStartMeters;
-    private final int mFrequencyOffsetMetersPerSecond;
+    private final double mFrequencyOffsetMetersPerSecond;
     @NonNull private final int[] mMagnitude;
 
     /**
@@ -66,8 +65,8 @@
     /**
      * Returns the frequency offset from reported pseudorange rate for this CorrelationVector.
      */
-    @IntRange(from = 0)
-    public int getFrequencyOffsetMetersPerSecond() {
+    @FloatRange(from = 0.0f)
+    public double getFrequencyOffsetMetersPerSecond() {
         return mFrequencyOffsetMetersPerSecond;
     }
 
@@ -88,7 +87,7 @@
         Preconditions.checkNotNull(builder.mMagnitude, "Magnitude array must not be null");
         Preconditions.checkArgumentPositive(builder.mMagnitude.length,
                 "Magnitude array must have non-zero length");
-        Preconditions.checkArgumentNonNegative(builder.mFrequencyOffsetMetersPerSecond,
+        Preconditions.checkArgument(builder.mFrequencyOffsetMetersPerSecond >= 0.0,
                 "FrequencyOffsetMetersPerSecond must be non-negative (greater than or equal to 0)");
         Preconditions.checkArgument(builder.mSamplingWidthMeters > 0.0,
                 "SamplingWidthMeters must be positive (greater than 0)");
@@ -103,7 +102,7 @@
     private CorrelationVector(Parcel in) {
         mSamplingWidthMeters = in.readDouble();
         mSamplingStartMeters = in.readDouble();
-        mFrequencyOffsetMetersPerSecond = in.readInt();
+        mFrequencyOffsetMetersPerSecond = in.readDouble();
         mMagnitude = new int[in.readInt()];
         in.readIntArray(mMagnitude);
     }
@@ -144,7 +143,7 @@
     public void writeToParcel(@NonNull Parcel dest, int flags) {
         dest.writeDouble(mSamplingWidthMeters);
         dest.writeDouble(mSamplingStartMeters);
-        dest.writeInt(mFrequencyOffsetMetersPerSecond);
+        dest.writeDouble(mFrequencyOffsetMetersPerSecond);
         dest.writeInt(mMagnitude.length);
         dest.writeIntArray(mMagnitude);
     }
@@ -165,7 +164,7 @@
         return Arrays.equals(mMagnitude, c.getMagnitude())
                 && Double.compare(mSamplingWidthMeters, c.getSamplingWidthMeters()) == 0
                 && Double.compare(mSamplingStartMeters, c.getSamplingStartMeters()) == 0
-                && Integer.compare(mFrequencyOffsetMetersPerSecond,
+                && Double.compare(mFrequencyOffsetMetersPerSecond,
                         c.getFrequencyOffsetMetersPerSecond()) == 0;
     }
 
@@ -182,7 +181,7 @@
 
         private double mSamplingWidthMeters;
         private double mSamplingStartMeters;
-        private int mFrequencyOffsetMetersPerSecond;
+        private double mFrequencyOffsetMetersPerSecond;
         @NonNull private int[] mMagnitude;
 
         /** Sets the space between correlation samples in meters. */
@@ -203,7 +202,7 @@
         /** Sets the frequency offset from reported pseudorange rate for this CorrelationVector */
         @NonNull
         public Builder setFrequencyOffsetMetersPerSecond(
-                @IntRange(from = 0) int frequencyOffsetMetersPerSecond) {
+                @FloatRange(from = 0.0f) double frequencyOffsetMetersPerSecond) {
             mFrequencyOffsetMetersPerSecond = frequencyOffsetMetersPerSecond;
             return this;
         }
diff --git a/media/java/android/media/ImageWriter.java b/media/java/android/media/ImageWriter.java
index 9ab4aac..b073638 100644
--- a/media/java/android/media/ImageWriter.java
+++ b/media/java/android/media/ImageWriter.java
@@ -437,13 +437,11 @@
         // For images from other components that have non-null owner, need to detach first,
         // then attach. Images without owners must already be attachable.
         if (!ownedByMe) {
-            if (image.getOwner() == null) {
-
-            } else if ((image.getOwner() instanceof ImageReader)) {
+            if ((image.getOwner() instanceof ImageReader)) {
                 ImageReader prevOwner = (ImageReader) image.getOwner();
 
                 prevOwner.detachImage(image);
-            } else {
+            } else if (image.getOwner() != null) {
                 throw new IllegalArgumentException("Only images from ImageReader can be queued to"
                         + " ImageWriter, other image source is not supported yet!");
             }
diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java
index ff52a1a..dc9c58e 100644
--- a/media/java/android/media/MediaRouter2.java
+++ b/media/java/android/media/MediaRouter2.java
@@ -23,6 +23,7 @@
 import android.annotation.Nullable;
 import android.annotation.TestApi;
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
@@ -67,6 +68,10 @@
     private static final long MANAGER_REQUEST_ID_NONE = MediaRoute2ProviderService.REQUEST_ID_NONE;
 
     @GuardedBy("sRouterLock")
+    private static Map<String, MediaRouter2> sMediaRouter2Map = new ArrayMap<>();
+    private static MediaRouter2Manager sManager;
+
+    @GuardedBy("sRouterLock")
     private static MediaRouter2 sInstance;
 
     private final Context mContext;
@@ -82,7 +87,9 @@
     private final CopyOnWriteArrayList<ControllerCreationRequest> mControllerCreationRequests =
             new CopyOnWriteArrayList<>();
 
+    private final String mClientPackageName;
     private final String mPackageName;
+
     @GuardedBy("sRouterLock")
     final Map<String, MediaRoute2Info> mRoutes = new ArrayMap<>();
 
@@ -120,6 +127,42 @@
         }
     }
 
+    /**
+     * Gets an instance of the media router which controls the app's media routing.
+     * Returns {@code null} if the given package name is invalid.
+     *
+     * @param clientPackageName the package name of the app to control
+     * @hide
+     */
+    //@SystemApi
+    @Nullable
+    public static MediaRouter2 getInstance(@NonNull Context context,
+            @NonNull String clientPackageName) {
+        Objects.requireNonNull(context, "context must not be null");
+        Objects.requireNonNull(clientPackageName, "clientPackageName must not be null");
+
+        PackageManager pm = context.getPackageManager();
+        try {
+            pm.getPackageInfo(clientPackageName, 0);
+        } catch (PackageManager.NameNotFoundException ex) {
+            Log.e(TAG, "Package " + clientPackageName + " not found. Ignoring.");
+            return null;
+        }
+
+        synchronized (sRouterLock) {
+            MediaRouter2 instance = sMediaRouter2Map.get(clientPackageName);
+            if (instance == null) {
+                // TODO: Add permission check here using MODIFY_AUDIO_ROUTING.
+                if (sManager == null) {
+                    sManager = MediaRouter2Manager.getInstance(context.getApplicationContext());
+                }
+                instance = new MediaRouter2(context, clientPackageName);
+                sMediaRouter2Map.put(clientPackageName, instance);
+            }
+            return instance;
+        }
+    }
+
     private MediaRouter2(Context appContext) {
         mContext = appContext;
         mMediaRouterService = IMediaRouterService.Stub.asInterface(
@@ -148,6 +191,17 @@
             mRoutes.put(route.getId(), route);
         }
         mSystemController = new SystemRoutingController(currentSystemSessionInfo);
+
+        mClientPackageName = null;
+    }
+
+    private MediaRouter2(Context context, String clientPackageName) {
+        mClientPackageName = clientPackageName;
+        mContext = context;
+        mMediaRouterService = null;
+        mPackageName = null;
+        mHandler = new Handler(Looper.getMainLooper());
+        mSystemController = null;
     }
 
     /**
@@ -166,6 +220,19 @@
     }
 
     /**
+     * Gets the target package name of the app which this media router controls.
+     * This is only non-null when the router instance is created with the target package name.
+     *
+     * @see #getInstance(Context, String)
+     * @hide
+     */
+    //@SystemApi
+    @Nullable
+    public String getClientPackageName() {
+        return mClientPackageName;
+    }
+
+    /**
      * Registers a callback to discover routes and to receive events when they change.
      * <p>
      * If the specified callback is already registered, its registration will be updated for the
@@ -270,6 +337,10 @@
      */
     @NonNull
     public List<MediaRoute2Info> getRoutes() {
+        if (mClientPackageName != null) {
+            return sManager.getAvailableRoutes(mClientPackageName);
+        }
+
         synchronized (sRouterLock) {
             if (mShouldUpdateRoutes) {
                 mShouldUpdateRoutes = false;
@@ -378,6 +449,11 @@
      * @see TransferCallback#onTransferFailure
      */
     public void transferTo(@NonNull MediaRoute2Info route) {
+        if (mClientPackageName != null) {
+            sManager.selectRoute(mClientPackageName, route);
+            return;
+        }
+
         Objects.requireNonNull(route, "route must not be null");
         Log.v(TAG, "Transferring to route: " + route);
         transfer(getCurrentController(), route);
@@ -388,6 +464,12 @@
      * controls the media routing, this method is a no-op.
      */
     public void stop() {
+        if (mClientPackageName != null) {
+            List<RoutingSessionInfo> sessionInfos = sManager.getRoutingSessions(mClientPackageName);
+            RoutingSessionInfo sessionToRelease = sessionInfos.get(sessionInfos.size() - 1);
+            sManager.releaseSession(sessionToRelease);
+            return;
+        }
         getCurrentController().release();
     }
 
@@ -397,7 +479,13 @@
      * @param route the route you want to transfer the media to.
      * @hide
      */
-    void transfer(@NonNull RoutingController controller, @NonNull MediaRoute2Info route) {
+    //@SystemApi
+    public void transfer(@NonNull RoutingController controller, @NonNull MediaRoute2Info route) {
+        if (mClientPackageName != null) {
+            sManager.transfer(controller.getRoutingSessionInfo(), route);
+            return;
+        }
+
         Objects.requireNonNull(controller, "controller must not be null");
         Objects.requireNonNull(route, "route must not be null");
 
@@ -486,6 +574,14 @@
      */
     @NonNull
     public List<RoutingController> getControllers() {
+        // TODO: Do not create the controller instances every time,
+        //       Instead, update the list using the sessions' ID and session related callbacks.
+        if (mClientPackageName != null) {
+            return sManager.getRoutingSessions(mClientPackageName).stream()
+                    .map(info -> new RoutingController(info))
+                    .collect(Collectors.toList());
+        }
+
         List<RoutingController> result = new ArrayList<>();
         result.add(0, mSystemController);
         synchronized (sRouterLock) {
diff --git a/media/java/android/media/RoutingSessionInfo.java b/media/java/android/media/RoutingSessionInfo.java
index a5d25e0..3bea73f 100644
--- a/media/java/android/media/RoutingSessionInfo.java
+++ b/media/java/android/media/RoutingSessionInfo.java
@@ -326,6 +326,7 @@
                 .append("RoutingSessionInfo{ ")
                 .append("sessionId=").append(getId())
                 .append(", name=").append(getName())
+                .append(", clientPackageName=").append(getClientPackageName())
                 .append(", selectedRoutes={")
                 .append(String.join(",", getSelectedRoutes()))
                 .append("}")
diff --git a/packages/CompanionDeviceManager/res/values/strings.xml b/packages/CompanionDeviceManager/res/values/strings.xml
index 731bdcc..4dd012a 100644
--- a/packages/CompanionDeviceManager/res/values/strings.xml
+++ b/packages/CompanionDeviceManager/res/values/strings.xml
@@ -29,15 +29,15 @@
     <string name="profile_name_watch">watch</string>
 
     <!-- Title of the device association confirmation dialog. -->
-    <string name="confirmation_title">Set &lt;strong&gt;<xliff:g id="app_name" example="Android Wear">%1$s</xliff:g>&lt;/strong&gt; to manage your <xliff:g id="profile_name" example="watch">%2$s</xliff:g> - &lt;strong&gt;<xliff:g id="device_name" example="ASUS ZenWatch 2">%3$s</xliff:g>&lt;/strong&gt;</string>
+    <string name="confirmation_title">Set &lt;strong&gt;<xliff:g id="app_name" example="Android Wear">%1$s</xliff:g>&lt;/strong&gt; to manage your &lt;strong&gt;<xliff:g id="device_name" example="ASUS ZenWatch 2">%2$s</xliff:g>&lt;/strong&gt;</string>
 
     <!-- Text of the device profile permissions explanation in the association dialog. -->
-    <string name="profile_summary"><xliff:g id="app_name" example="Android Wear">%1$s</xliff:g> is needed to manage your <xliff:g id="profile_name" example="watch">%2$s</xliff:g>. <xliff:g id="privileges_discplaimer" example="Android Wear will get access to your Notifications, Calendar and Contacts.">%3$s</xliff:g></string>
+    <string name="profile_summary">This app is needed to manage your <xliff:g id="profile_name" example="watch">%1$s</xliff:g>. <xliff:g id="privileges_discplaimer" example="Android Wear will get access to your Notifications, Calendar and Contacts.">%2$s</xliff:g></string>
 
     <!-- Positive button for the device-app association consent dialog [CHAR LIMIT=30] -->
-    <string name="consent_yes">Yes</string>
+    <string name="consent_yes">Allow</string>
 
     <!-- Negative button for the device-app association consent dialog [CHAR LIMIT=30] -->
-    <string name="consent_no">No thanks</string>
+    <string name="consent_no">Don\u2019t allow</string>
 
 </resources>
diff --git a/packages/Connectivity/framework/api/module-lib-current.txt b/packages/Connectivity/framework/api/module-lib-current.txt
index d2ed73e..6df57c1 100644
--- a/packages/Connectivity/framework/api/module-lib-current.txt
+++ b/packages/Connectivity/framework/api/module-lib-current.txt
@@ -51,6 +51,14 @@
     field public static final String TEST_TAP_PREFIX = "testtap";
   }
 
+  public final class TestNetworkSpecifier extends android.net.NetworkSpecifier implements android.os.Parcelable {
+    ctor public TestNetworkSpecifier(@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.TestNetworkSpecifier> CREATOR;
+  }
+
   public final class VpnTransportInfo implements android.os.Parcelable android.net.TransportInfo {
     ctor public VpnTransportInfo(int);
     method public int describeContents();
diff --git a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
index d7c6854..bbf4559 100644
--- a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
+++ b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
@@ -2905,10 +2905,14 @@
         ResultReceiver wrappedListener = new ResultReceiver(null) {
             @Override
             protected void onReceiveResult(int resultCode, Bundle resultData) {
-                Binder.withCleanCallingIdentity(() ->
-                            executor.execute(() -> {
-                                listener.onTetheringEntitlementResult(resultCode);
-                            }));
+                final long token = Binder.clearCallingIdentity();
+                try {
+                    executor.execute(() -> {
+                        listener.onTetheringEntitlementResult(resultCode);
+                    });
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                }
             }
         };
 
diff --git a/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java b/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
index ab58f1b..c82cd3b 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
@@ -1866,7 +1866,7 @@
                 final ArraySet<T> result = new ArraySet<>(size);
                 for (int i = 0; i < size; i++) {
                     final T value = in.readParcelable(loader);
-                    result.append(value);
+                    result.add(value);
                 }
                 return result;
             }
diff --git a/packages/Connectivity/framework/src/android/net/NetworkRequest.java b/packages/Connectivity/framework/src/android/net/NetworkRequest.java
index b4a651c..17a8ee1 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkRequest.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkRequest.java
@@ -31,6 +31,7 @@
 import static android.net.NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
+import static android.net.NetworkCapabilities.TRANSPORT_TEST;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -382,11 +383,17 @@
                 return setNetworkSpecifier(new TelephonyNetworkSpecifier.Builder()
                         .setSubscriptionId(subId).build());
             } catch (NumberFormatException nfe) {
-                // A StringNetworkSpecifier does not accept null or empty ("") strings. When network
-                // specifiers were strings a null string and an empty string were considered
-                // equivalent. Hence no meaning is attached to a null or empty ("") string.
-                return setNetworkSpecifier(TextUtils.isEmpty(networkSpecifier) ? null
-                        : new StringNetworkSpecifier(networkSpecifier));
+                // An EthernetNetworkSpecifier or TestNetworkSpecifier does not accept null or empty
+                // ("") strings. When network specifiers were strings a null string and an empty
+                // string were considered equivalent. Hence no meaning is attached to a null or
+                // empty ("") string.
+                if (TextUtils.isEmpty(networkSpecifier)) {
+                    return setNetworkSpecifier((NetworkSpecifier) null);
+                } else if (mNetworkCapabilities.hasTransport(TRANSPORT_TEST)) {
+                    return setNetworkSpecifier(new TestNetworkSpecifier(networkSpecifier));
+                } else {
+                    return setNetworkSpecifier(new EthernetNetworkSpecifier(networkSpecifier));
+                }
             }
         }
 
diff --git a/packages/Connectivity/framework/src/android/net/TestNetworkSpecifier.java b/packages/Connectivity/framework/src/android/net/TestNetworkSpecifier.java
new file mode 100644
index 0000000..b7470a5
--- /dev/null
+++ b/packages/Connectivity/framework/src/android/net/TestNetworkSpecifier.java
@@ -0,0 +1,97 @@
+/*
+ * 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 android.text.TextUtils;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.Objects;
+
+/**
+ * A {@link NetworkSpecifier} used to identify test interfaces.
+ *
+ * @see TestNetworkManager
+ * @hide
+ */
+@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+public final class TestNetworkSpecifier extends NetworkSpecifier implements Parcelable {
+
+    /**
+     * Name of the network interface.
+     */
+    @NonNull
+    private final String mInterfaceName;
+
+    public TestNetworkSpecifier(@NonNull String interfaceName) {
+        Preconditions.checkStringNotEmpty(interfaceName);
+        mInterfaceName = interfaceName;
+    }
+
+    // This may be null in the future to support specifiers based on data other than the interface
+    // name.
+    @Nullable
+    public String getInterfaceName() {
+        return mInterfaceName;
+    }
+
+    @Override
+    public boolean canBeSatisfiedBy(@Nullable NetworkSpecifier other) {
+        return equals(other);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (!(o instanceof TestNetworkSpecifier)) return false;
+        return TextUtils.equals(mInterfaceName, ((TestNetworkSpecifier) o).mInterfaceName);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(mInterfaceName);
+    }
+
+    @Override
+    public String toString() {
+        return "TestNetworkSpecifier (" + mInterfaceName + ")";
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeString(mInterfaceName);
+    }
+
+    public static final @NonNull Creator<TestNetworkSpecifier> CREATOR =
+            new Creator<TestNetworkSpecifier>() {
+        public TestNetworkSpecifier createFromParcel(Parcel in) {
+            return new TestNetworkSpecifier(in.readString());
+        }
+        public TestNetworkSpecifier[] newArray(int size) {
+            return new TestNetworkSpecifier[size];
+        }
+    };
+}
diff --git a/packages/Connectivity/service/Android.bp b/packages/Connectivity/service/Android.bp
index e65b7b4..2fb9f72 100644
--- a/packages/Connectivity/service/Android.bp
+++ b/packages/Connectivity/service/Android.bp
@@ -50,12 +50,11 @@
 }
 
 java_library {
-    name: "service-connectivity",
+    name: "service-connectivity-pre-jarjar",
     srcs: [
+        ":framework-connectivity-shared-srcs",
         ":connectivity-service-srcs",
     ],
-    installable: true,
-    jarjar_rules: "jarjar-rules.txt",
     libs: [
         "android.net.ipsec.ike",
         "services.core",
@@ -73,3 +72,16 @@
         "com.android.tethering",
     ],
 }
+
+java_library {
+    name: "service-connectivity",
+    installable: true,
+    static_libs:[
+        "service-connectivity-pre-jarjar",
+    ],
+    jarjar_rules: "jarjar-rules.txt",
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.tethering",
+    ],
+}
diff --git a/packages/Connectivity/service/jarjar-rules.txt b/packages/Connectivity/service/jarjar-rules.txt
index d8205bf..d8c60a4 100644
--- a/packages/Connectivity/service/jarjar-rules.txt
+++ b/packages/Connectivity/service/jarjar-rules.txt
@@ -1,2 +1,13 @@
 rule com.android.net.module.util.** com.android.connectivity.net-utils.@1
-rule com.android.modules.utils.** com.android.connectivity.modules-utils.@1
\ No newline at end of file
+rule com.android.modules.utils.** com.android.connectivity.modules-utils.@1
+
+# internal util classes
+# Exclude AsyncChannel. TODO: remove AsyncChannel usage in ConnectivityService
+rule com.android.internal.util.AsyncChannel* @0
+# Exclude LocationPermissionChecker. This is going to be moved to libs/net
+rule com.android.internal.util.LocationPermissionChecker* @0
+rule android.util.LocalLog* com.android.connectivity.util.LocalLog@1
+# android.util.IndentingPrintWriter* should use a different package name from
+# the one in com.android.internal.util
+rule android.util.IndentingPrintWriter* android.connectivity.util.IndentingPrintWriter@1
+rule com.android.internal.util.** com.android.connectivity.util.@1
diff --git a/packages/CtsShim/OWNERS b/packages/CtsShim/OWNERS
new file mode 100644
index 0000000..ba9f2b9
--- /dev/null
+++ b/packages/CtsShim/OWNERS
@@ -0,0 +1,2 @@
+ioffe@google.com
+toddke@google.com
\ No newline at end of file
diff --git a/packages/CtsShim/build/shim/AndroidManifest.xml b/packages/CtsShim/build/shim/AndroidManifest.xml
index 7d2626d..1ffe56c 100644
--- a/packages/CtsShim/build/shim/AndroidManifest.xml
+++ b/packages/CtsShim/build/shim/AndroidManifest.xml
@@ -53,6 +53,9 @@
             </intent-filter>
         </activity>
 
+        <!-- The stub shared library for package visibility test -->
+        <library android:name="com.android.cts.ctsshim.shared_library" />
+
     </application>
 </manifest>
 
diff --git a/packages/SettingsLib/MainSwitchPreference/Android.bp b/packages/SettingsLib/MainSwitchPreference/Android.bp
index 1feec21..7b7496c 100644
--- a/packages/SettingsLib/MainSwitchPreference/Android.bp
+++ b/packages/SettingsLib/MainSwitchPreference/Android.bp
@@ -15,7 +15,6 @@
 
     static_libs: [
           "androidx.preference_preference",
-          "SettingsLibRestrictedLockUtils",
     ],
 
     sdk_version: "system_current",
diff --git a/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java b/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java
index 1c9298e..8d9a562 100644
--- a/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java
+++ b/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java
@@ -24,16 +24,12 @@
 import android.view.LayoutInflater;
 import android.view.View;
 import android.widget.CompoundButton;
-import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.Switch;
 import android.widget.TextView;
 
-import androidx.annotation.VisibleForTesting;
 import androidx.core.content.res.TypedArrayUtils;
 
-import com.android.settingslib.RestrictedLockUtils;
-
 import java.util.ArrayList;
 import java.util.List;
 
@@ -48,12 +44,8 @@
 
     private View mAboveDivider;
     private View mBelowDivider;
-    private TextView mTextView;
-    private ImageView mRestrictedIcon;
-    private Switch mSwitch;
-
-    private RestrictedLockUtils.EnforcedAdmin mEnforcedAdmin;
-    private boolean mDisabledByAdmin;
+    protected TextView mTextView;
+    protected Switch mSwitch;
 
     public MainSwitchBar(Context context) {
         this(context, null);
@@ -81,14 +73,6 @@
 
         addOnSwitchChangeListener((switchView, isChecked) -> setChecked(isChecked));
 
-        mRestrictedIcon = findViewById(R.id.restricted_icon);
-        mRestrictedIcon.setOnClickListener((View v) -> {
-            if (mDisabledByAdmin) {
-                RestrictedLockUtils.sendShowAdminSupportDetailsIntent(context, mEnforcedAdmin);
-                onRestrictedIconClick();
-            }
-        });
-
         setChecked(mSwitch.isChecked());
 
         if (attrs != null) {
@@ -110,7 +94,7 @@
 
     @Override
     public boolean performClick() {
-        return getDelegatingView().performClick();
+        return mSwitch.performClick();
     }
 
     /**
@@ -189,51 +173,14 @@
     }
 
     /**
-     * If admin is not null, disables the text and switch but keeps the view clickable.
-     * Otherwise, calls setEnabled which will enables the entire view including
-     * the text and switch.
-     */
-    public void setDisabledByAdmin(RestrictedLockUtils.EnforcedAdmin admin) {
-        mEnforcedAdmin = admin;
-        if (admin != null) {
-            super.setEnabled(true);
-            mDisabledByAdmin = true;
-            mTextView.setEnabled(false);
-            mSwitch.setEnabled(false);
-            mSwitch.setVisibility(View.GONE);
-            mRestrictedIcon.setVisibility(View.VISIBLE);
-        } else {
-            mDisabledByAdmin = false;
-            mSwitch.setVisibility(View.VISIBLE);
-            mRestrictedIcon.setVisibility(View.GONE);
-            setEnabled(true);
-        }
-    }
-
-    /**
      * Enable or disable the text and switch.
      */
     public void setEnabled(boolean enabled) {
-        if (enabled && mDisabledByAdmin) {
-            setDisabledByAdmin(null);
-            return;
-        }
         super.setEnabled(enabled);
         mTextView.setEnabled(enabled);
         mSwitch.setEnabled(enabled);
     }
 
-    /**
-     * Called by the restricted icon clicked.
-     */
-    protected void onRestrictedIconClick() {
-    }
-
-    @VisibleForTesting
-    View getDelegatingView() {
-        return mDisabledByAdmin ? mRestrictedIcon : mSwitch;
-    }
-
     private void propagateChecked(boolean isChecked) {
         final int count = mSwitchChangeListeners.size();
         for (int n = 0; n < count; n++) {
diff --git a/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchPreference.java b/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchPreference.java
index 35afec3..ebeffcc 100644
--- a/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchPreference.java
+++ b/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchPreference.java
@@ -24,8 +24,6 @@
 import androidx.preference.PreferenceViewHolder;
 import androidx.preference.TwoStatePreference;
 
-import com.android.settingslib.RestrictedLockUtils;
-
 import java.util.ArrayList;
 import java.util.List;
 
@@ -41,8 +39,6 @@
     private MainSwitchBar mMainSwitchBar;
     private CharSequence mTitle;
 
-    private RestrictedLockUtils.EnforcedAdmin mEnforcedAdmin;
-
     public MainSwitchPreference(Context context) {
         super(context);
         init(context, null);
@@ -115,7 +111,6 @@
         if (mMainSwitchBar != null) {
             mMainSwitchBar.setChecked(checked);
             mMainSwitchBar.setTitle(mTitle);
-            mMainSwitchBar.setDisabledByAdmin(mEnforcedAdmin);
             mMainSwitchBar.show();
         }
     }
@@ -142,18 +137,6 @@
         }
     }
 
-    /**
-     * If admin is not null, disables the text and switch but keeps the view clickable.
-     * Otherwise, calls setEnabled which will enables the entire view including
-     * the text and switch.
-     */
-    public void setDisabledByAdmin(RestrictedLockUtils.EnforcedAdmin admin) {
-        mEnforcedAdmin = admin;
-        if (mMainSwitchBar != null) {
-            mMainSwitchBar.setDisabledByAdmin(mEnforcedAdmin);
-        }
-    }
-
     private void registerListenerToSwitchBar() {
         for (OnMainSwitchChangeListener listener : mSwitchChangeListeners) {
             mMainSwitchBar.addOnSwitchChangeListener(listener);
diff --git a/packages/SettingsLib/UsageProgressBarPreference/src/com/android/settingslib/widget/UsageProgressBarPreference.java b/packages/SettingsLib/UsageProgressBarPreference/src/com/android/settingslib/widget/UsageProgressBarPreference.java
index af64a1d..2185950 100644
--- a/packages/SettingsLib/UsageProgressBarPreference/src/com/android/settingslib/widget/UsageProgressBarPreference.java
+++ b/packages/SettingsLib/UsageProgressBarPreference/src/com/android/settingslib/widget/UsageProgressBarPreference.java
@@ -160,6 +160,7 @@
             customLayout.removeAllViews();
             customLayout.setVisibility(View.GONE);
         } else {
+            customLayout.removeAllViews();
             customLayout.addView(mCustomImageView);
             customLayout.setVisibility(View.VISIBLE);
         }
diff --git a/packages/SettingsLib/res/drawable/ic_mobile_call_strength_0.xml b/packages/SettingsLib/res/drawable/ic_mobile_call_strength_0.xml
new file mode 100644
index 0000000..8da3320
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_mobile_call_strength_0.xml
@@ -0,0 +1,28 @@
+<!--
+     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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M13.47,17.91l-2.18,-0.43c-0.22,-0.05 -0.45,0.03 -0.6,0.18L9.34,19C7.5,18.01 5.99,16.5 5,14.66l1.35,-1.35c0.16,-0.16 0.23,-0.39 0.18,-0.6l-0.43,-2.18C6.03,10.23 5.76,10 5.44,10H2.67C2.29,10 1.98,10.31 2,10.69c0.11,1.94 0.69,3.76 1.62,5.35c1.05,1.8 2.54,3.29 4.34,4.34c1.59,0.93 3.41,1.51 5.35,1.62c0.37,0.02 0.69,-0.29 0.69,-0.67v-2.77C14,18.24 13.78,17.97 13.47,17.91z"/>
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M22,2L9,15h13V2z"
+        android:fillAlpha="0.3"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_mobile_call_strength_1.xml b/packages/SettingsLib/res/drawable/ic_mobile_call_strength_1.xml
index 46e2d45..52d9de2 100644
--- a/packages/SettingsLib/res/drawable/ic_mobile_call_strength_1.xml
+++ b/packages/SettingsLib/res/drawable/ic_mobile_call_strength_1.xml
@@ -1,5 +1,5 @@
 <!--
-     Copyright (C) 2020 The Android Open Source Project
+     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.
@@ -20,16 +20,12 @@
         android:viewportHeight="24.0">
     <path
         android:fillColor="#FF000000"
-        android:pathData="M20.17,14.84l-3.26,-0.65c-0.33,-0.07 -0.67,0.04 -0.9,0.27l-2.62,2.62c-2.75,-1.49 -5.01,-3.75 -6.5,-6.5l2.62,-2.62c0.24,-0.24 0.34,-0.58 0.27,-0.9L9.13,3.8C9.04,3.34 8.63,3 8.15,3H4C3.44,3 2.97,3.47 3,4.03c0.17,2.91 1.04,5.63 2.43,8.01c1.57,2.69 3.81,4.93 6.5,6.5c2.38,1.39 5.1,2.26 8.01,2.43c0.56,0.03 1.03,-0.44 1.03,-1v-4.15C20.97,15.34 20.64,14.93 20.17,14.84z"/>
+        android:pathData="M13.47,17.91l-2.18,-0.43c-0.22,-0.05 -0.45,0.03 -0.6,0.18L9.34,19C7.5,18.01 5.99,16.5 5,14.66l1.35,-1.35c0.16,-0.16 0.23,-0.39 0.18,-0.6l-0.43,-2.18C6.03,10.23 5.76,10 5.44,10H2.67C2.29,10 1.98,10.31 2,10.69c0.11,1.94 0.69,3.76 1.62,5.35c1.05,1.8 2.54,3.29 4.34,4.34c1.59,0.93 3.41,1.51 5.35,1.62c0.37,0.02 0.69,-0.29 0.69,-0.67v-2.77C14,18.24 13.78,17.97 13.47,17.91z"/>
     <path
         android:fillColor="#FF000000"
-        android:pathData="M13,8h2v3h-2z"/>
-    <path
-        android:fillColor="#FF000000"
-        android:pathData="M16.5,5h2v6h-2z"
+        android:pathData="M22,2L9,15h13V2z"
         android:fillAlpha="0.3"/>
     <path
         android:fillColor="#FF000000"
-        android:pathData="M20,3h2v8h-2z"
-        android:fillAlpha="0.3"/>
+        android:pathData="M14,10l-5,5h5V10z"/>
 </vector>
diff --git a/packages/SettingsLib/res/drawable/ic_mobile_call_strength_2.xml b/packages/SettingsLib/res/drawable/ic_mobile_call_strength_2.xml
index d9cd590..cbd2ea2 100644
--- a/packages/SettingsLib/res/drawable/ic_mobile_call_strength_2.xml
+++ b/packages/SettingsLib/res/drawable/ic_mobile_call_strength_2.xml
@@ -1,5 +1,5 @@
 <!--
-     Copyright (C) 2020 The Android Open Source Project
+     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.
@@ -20,15 +20,12 @@
         android:viewportHeight="24.0">
     <path
         android:fillColor="#FF000000"
-        android:pathData="M20.17,14.84l-3.26,-0.65c-0.33,-0.07 -0.67,0.04 -0.9,0.27l-2.62,2.62c-2.75,-1.49 -5.01,-3.75 -6.5,-6.5l2.62,-2.62c0.24,-0.24 0.34,-0.58 0.27,-0.9L9.13,3.8C9.04,3.34 8.63,3 8.15,3H4C3.44,3 2.97,3.47 3,4.03c0.17,2.91 1.04,5.63 2.43,8.01c1.57,2.69 3.81,4.93 6.5,6.5c2.38,1.39 5.1,2.26 8.01,2.43c0.56,0.03 1.03,-0.44 1.03,-1v-4.15C20.97,15.34 20.64,14.93 20.17,14.84z"/>
+        android:pathData="M13.47,17.91l-2.18,-0.43c-0.22,-0.05 -0.45,0.03 -0.6,0.18L9.34,19C7.5,18.01 5.99,16.5 5,14.66l1.35,-1.35c0.16,-0.16 0.23,-0.39 0.18,-0.6l-0.43,-2.18C6.03,10.23 5.76,10 5.44,10H2.67C2.29,10 1.98,10.31 2,10.69c0.11,1.94 0.69,3.76 1.62,5.35c1.05,1.8 2.54,3.29 4.34,4.34c1.59,0.93 3.41,1.51 5.35,1.62c0.37,0.02 0.69,-0.29 0.69,-0.67v-2.77C14,18.24 13.78,17.97 13.47,17.91z"/>
     <path
         android:fillColor="#FF000000"
-        android:pathData="M13,8h2v3h-2z"/>
-    <path
-        android:fillColor="#FF000000"
-        android:pathData="M16.5,5h2v6h-2z"/>
-    <path
-        android:fillColor="#FF000000"
-        android:pathData="M20,3h2v8h-2z"
+        android:pathData="M22,2L9,15h13V2z"
         android:fillAlpha="0.3"/>
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M18,6l-9,9h9V6z"/>
 </vector>
diff --git a/packages/SettingsLib/res/drawable/ic_mobile_call_strength_3.xml b/packages/SettingsLib/res/drawable/ic_mobile_call_strength_3.xml
index e80fd08..4935322 100644
--- a/packages/SettingsLib/res/drawable/ic_mobile_call_strength_3.xml
+++ b/packages/SettingsLib/res/drawable/ic_mobile_call_strength_3.xml
@@ -1,5 +1,5 @@
 <!--
-     Copyright (C) 2020 The Android Open Source Project
+     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.
@@ -20,14 +20,12 @@
         android:viewportHeight="24.0">
     <path
         android:fillColor="#FF000000"
-        android:pathData="M20.17,14.84l-3.26,-0.65c-0.33,-0.07 -0.67,0.04 -0.9,0.27l-2.62,2.62c-2.75,-1.49 -5.01,-3.75 -6.5,-6.5l2.62,-2.62c0.24,-0.24 0.34,-0.58 0.27,-0.9L9.13,3.8C9.04,3.34 8.63,3 8.15,3H4C3.44,3 2.97,3.47 3,4.03c0.17,2.91 1.04,5.63 2.43,8.01c1.57,2.69 3.81,4.93 6.5,6.5c2.38,1.39 5.1,2.26 8.01,2.43c0.56,0.03 1.03,-0.44 1.03,-1v-4.15C20.97,15.34 20.64,14.93 20.17,14.84z"/>
+        android:pathData="M13.47,17.91l-2.18,-0.43c-0.22,-0.05 -0.45,0.03 -0.6,0.18L9.34,19C7.5,18.01 5.99,16.5 5,14.66l1.35,-1.35c0.16,-0.16 0.23,-0.39 0.18,-0.6l-0.43,-2.18C6.03,10.23 5.76,10 5.44,10H2.67C2.29,10 1.98,10.31 2,10.69c0.11,1.94 0.69,3.76 1.62,5.35c1.05,1.8 2.54,3.29 4.34,4.34c1.59,0.93 3.41,1.51 5.35,1.62c0.37,0.02 0.69,-0.29 0.69,-0.67v-2.77C14,18.24 13.78,17.97 13.47,17.91z"/>
     <path
         android:fillColor="#FF000000"
-        android:pathData="M13,8h2v3h-2z"/>
+        android:pathData="M22,2L9,15h13V2z"
+        android:fillAlpha="0.3"/>
     <path
         android:fillColor="#FF000000"
-        android:pathData="M16.5,5h2v6h-2z"/>
-    <path
-        android:fillColor="#FF000000"
-        android:pathData="M20,3h2v8h-2z"/>
+        android:pathData="M20,4L9,15h11V4z"/>
 </vector>
diff --git a/packages/SettingsLib/res/drawable/ic_mobile_call_strength_4.xml b/packages/SettingsLib/res/drawable/ic_mobile_call_strength_4.xml
new file mode 100644
index 0000000..deedafa
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_mobile_call_strength_4.xml
@@ -0,0 +1,31 @@
+<!--
+     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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M22,2L9,15h13V2z"
+        android:fillAlpha="0.3"/>
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M13.47,17.91l-2.18,-0.43c-0.22,-0.05 -0.45,0.03 -0.6,0.18L9.34,19C7.5,18.01 5.99,16.5 5,14.66l1.35,-1.35c0.16,-0.16 0.23,-0.39 0.18,-0.6l-0.43,-2.18C6.03,10.23 5.76,10 5.44,10H2.67C2.29,10 1.98,10.31 2,10.69c0.11,1.94 0.69,3.76 1.62,5.35c1.05,1.8 2.54,3.29 4.34,4.34c1.59,0.93 3.41,1.51 5.35,1.62c0.37,0.02 0.69,-0.29 0.69,-0.67v-2.77C14,18.24 13.78,17.97 13.47,17.91z"/>
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M9,15l13,0l0,-13z"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_wifi_call_strength_0.xml b/packages/SettingsLib/res/drawable/ic_wifi_call_strength_0.xml
new file mode 100644
index 0000000..31b2e75
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_wifi_call_strength_0.xml
@@ -0,0 +1,28 @@
+<!--
+     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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M13.47,17.91l-2.18,-0.43c-0.22,-0.05 -0.45,0.03 -0.6,0.18L9.34,19C7.5,18.01 5.99,16.5 5,14.66l1.35,-1.35c0.16,-0.16 0.23,-0.39 0.18,-0.6l-0.43,-2.18C6.03,10.23 5.76,10 5.44,10H2.67C2.29,10 1.98,10.31 2,10.69c0.11,1.94 0.69,3.76 1.62,5.35c1.05,1.8 2.54,3.29 4.34,4.34c1.59,0.93 3.41,1.51 5.35,1.62c0.37,0.02 0.69,-0.29 0.69,-0.67v-2.77C14,18.24 13.78,17.97 13.47,17.91z"/>
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M23.5,6c-4.42,-4.42 -11.58,-4.42 -16,0l8,8L23.5,6z"
+        android:fillAlpha="0.3"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_wifi_call_strength_1.xml b/packages/SettingsLib/res/drawable/ic_wifi_call_strength_1.xml
index 493912b..e6eaaca 100644
--- a/packages/SettingsLib/res/drawable/ic_wifi_call_strength_1.xml
+++ b/packages/SettingsLib/res/drawable/ic_wifi_call_strength_1.xml
@@ -1,5 +1,5 @@
 <!--
-     Copyright (C) 2020 The Android Open Source Project
+     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.
@@ -20,16 +20,12 @@
         android:viewportHeight="24.0">
     <path
         android:fillColor="#FF000000"
-        android:pathData="M20.17,14.84l-3.26,-0.65c-0.33,-0.07 -0.67,0.04 -0.9,0.27l-2.62,2.62c-2.75,-1.49 -5.01,-3.75 -6.5,-6.5l2.62,-2.62c0.24,-0.24 0.34,-0.58 0.27,-0.9L9.13,3.8C9.04,3.34 8.63,3 8.15,3H4C3.44,3 2.97,3.47 3,4.03c0.17,2.91 1.04,5.63 2.43,8.01c1.57,2.69 3.81,4.93 6.5,6.5c2.38,1.39 5.1,2.26 8.01,2.43c0.56,0.03 1.03,-0.44 1.03,-1v-4.15C20.97,15.34 20.64,14.93 20.17,14.84z"/>
+        android:pathData="M13.47,17.91l-2.18,-0.43c-0.22,-0.05 -0.45,0.03 -0.6,0.18L9.34,19C7.5,18.01 5.99,16.5 5,14.66l1.35,-1.35c0.16,-0.16 0.23,-0.39 0.18,-0.6l-0.43,-2.18C6.03,10.23 5.76,10 5.44,10H2.67C2.29,10 1.98,10.31 2,10.69c0.11,1.94 0.69,3.76 1.62,5.35c1.05,1.8 2.54,3.29 4.34,4.34c1.59,0.93 3.41,1.51 5.35,1.62c0.37,0.02 0.69,-0.29 0.69,-0.67v-2.77C14,18.24 13.78,17.97 13.47,17.91z"/>
     <path
         android:fillColor="#FF000000"
-        android:pathData="M18.05,9.59C17.69,9.22 17.19,9 16.64,9c-0.55,0 -1.05,0.22 -1.41,0.59L16.64,11L18.05,9.59z"/>
-    <path
-        android:fillColor="#FF000000"
-        android:pathData="M16.64,7.5c0.96,0 1.84,0.39 2.47,1.03l1.42,-1.42c-1,-1 -2.37,-1.61 -3.89,-1.61c-1.52,0 -2.89,0.62 -3.89,1.61l1.42,1.42C14.8,7.89 15.67,7.5 16.64,7.5z"
+        android:pathData="M23.5,6c-4.42,-4.42 -11.58,-4.42 -16,0l8,8L23.5,6z"
         android:fillAlpha="0.3"/>
     <path
         android:fillColor="#FF000000"
-        android:pathData="M16.64,4c1.93,0 3.68,0.79 4.95,2.05L23,4.64C21.37,3.01 19.12,2 16.64,2c-2.49,0 -4.74,1.01 -6.36,2.64l1.42,1.42C12.96,4.79 14.71,4 16.64,4z"
-        android:fillAlpha="0.3"/>
+        android:pathData="M18.75,10.75c-1.79,-1.79 -4.71,-1.79 -6.5,0L15.5,14L18.75,10.75z"/>
 </vector>
diff --git a/packages/SettingsLib/res/drawable/ic_wifi_call_strength_2.xml b/packages/SettingsLib/res/drawable/ic_wifi_call_strength_2.xml
index af677fb..bc9c582 100644
--- a/packages/SettingsLib/res/drawable/ic_wifi_call_strength_2.xml
+++ b/packages/SettingsLib/res/drawable/ic_wifi_call_strength_2.xml
@@ -1,5 +1,5 @@
 <!--
-     Copyright (C) 2020 The Android Open Source Project
+     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.
@@ -20,15 +20,12 @@
         android:viewportHeight="24.0">
     <path
         android:fillColor="#FF000000"
-        android:pathData="M20.17,14.84l-3.26,-0.65c-0.33,-0.07 -0.67,0.04 -0.9,0.27l-2.62,2.62c-2.75,-1.49 -5.01,-3.75 -6.5,-6.5l2.62,-2.62c0.24,-0.24 0.34,-0.58 0.27,-0.9L9.13,3.8C9.04,3.34 8.63,3 8.15,3H4C3.44,3 2.97,3.47 3,4.03c0.17,2.91 1.04,5.63 2.43,8.01c1.57,2.69 3.81,4.93 6.5,6.5c2.38,1.39 5.1,2.26 8.01,2.43c0.56,0.03 1.03,-0.44 1.03,-1v-4.15C20.97,15.34 20.64,14.93 20.17,14.84z"/>
+        android:pathData="M13.47,17.91l-2.18,-0.43c-0.22,-0.05 -0.45,0.03 -0.6,0.18L9.34,19C7.5,18.01 5.99,16.5 5,14.66l1.35,-1.35c0.16,-0.16 0.23,-0.39 0.18,-0.6l-0.43,-2.18C6.03,10.23 5.76,10 5.44,10H2.67C2.29,10 1.98,10.31 2,10.69c0.11,1.94 0.69,3.76 1.62,5.35c1.05,1.8 2.54,3.29 4.34,4.34c1.59,0.93 3.41,1.51 5.35,1.62c0.37,0.02 0.69,-0.29 0.69,-0.67v-2.77C14,18.24 13.78,17.97 13.47,17.91z"/>
     <path
         android:fillColor="#FF000000"
-        android:pathData="M18.05,9.59C17.69,9.22 17.19,9 16.64,9c-0.55,0 -1.05,0.22 -1.41,0.59L16.64,11L18.05,9.59z"/>
-    <path
-        android:fillColor="#FF000000"
-        android:pathData="M16.64,7.5c0.96,0 1.84,0.39 2.47,1.03l1.42,-1.42c-1,-1 -2.37,-1.61 -3.89,-1.61c-1.52,0 -2.89,0.62 -3.89,1.61l1.42,1.42C14.8,7.89 15.67,7.5 16.64,7.5z"/>
-    <path
-        android:fillColor="#FF000000"
-        android:pathData="M16.64,4c1.93,0 3.68,0.79 4.95,2.05L23,4.64C21.37,3.01 19.12,2 16.64,2c-2.49,0 -4.74,1.01 -6.36,2.64l1.42,1.42C12.96,4.79 14.71,4 16.64,4z"
+        android:pathData="M23.5,6c-4.42,-4.42 -11.58,-4.42 -16,0l8,8L23.5,6z"
         android:fillAlpha="0.3"/>
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M20.75,8.75c-2.9,-2.9 -7.6,-2.9 -10.5,0L15.5,14L20.75,8.75z"/>
 </vector>
diff --git a/packages/SettingsLib/res/drawable/ic_wifi_call_strength_3.xml b/packages/SettingsLib/res/drawable/ic_wifi_call_strength_3.xml
index 68b39da..1fb8cf3 100644
--- a/packages/SettingsLib/res/drawable/ic_wifi_call_strength_3.xml
+++ b/packages/SettingsLib/res/drawable/ic_wifi_call_strength_3.xml
@@ -1,5 +1,5 @@
 <!--
-     Copyright (C) 2020 The Android Open Source Project
+     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.
@@ -20,14 +20,12 @@
         android:viewportHeight="24.0">
     <path
         android:fillColor="#FF000000"
-        android:pathData="M20.17,14.84l-3.26,-0.65c-0.33,-0.07 -0.67,0.04 -0.9,0.27l-2.62,2.62c-2.75,-1.49 -5.01,-3.75 -6.5,-6.5l2.62,-2.62c0.24,-0.24 0.34,-0.58 0.27,-0.9L9.13,3.8C9.04,3.34 8.63,3 8.15,3H4C3.44,3 2.97,3.47 3,4.03c0.17,2.91 1.04,5.63 2.43,8.01c1.57,2.69 3.81,4.93 6.5,6.5c2.38,1.39 5.1,2.26 8.01,2.43c0.56,0.03 1.03,-0.44 1.03,-1v-4.15C20.97,15.34 20.64,14.93 20.17,14.84z"/>
+        android:pathData="M13.47,17.91l-2.18,-0.43c-0.22,-0.05 -0.45,0.03 -0.6,0.18L9.34,19C7.5,18.01 5.99,16.5 5,14.66l1.35,-1.35c0.16,-0.16 0.23,-0.39 0.18,-0.6l-0.43,-2.18C6.03,10.23 5.76,10 5.44,10H2.67C2.29,10 1.98,10.31 2,10.69c0.11,1.94 0.69,3.76 1.62,5.35c1.05,1.8 2.54,3.29 4.34,4.34c1.59,0.93 3.41,1.51 5.35,1.62c0.37,0.02 0.69,-0.29 0.69,-0.67v-2.77C14,18.24 13.78,17.97 13.47,17.91z"/>
     <path
         android:fillColor="#FF000000"
-        android:pathData="M18.05,9.59C17.69,9.22 17.19,9 16.64,9c-0.55,0 -1.05,0.22 -1.41,0.59L16.64,11L18.05,9.59z"/>
+        android:pathData="M23.5,6c-4.42,-4.42 -11.58,-4.42 -16,0l8,8L23.5,6z"
+        android:fillAlpha="0.3"/>
     <path
         android:fillColor="#FF000000"
-        android:pathData="M16.64,7.5c0.96,0 1.84,0.39 2.47,1.03l1.42,-1.42c-1,-1 -2.37,-1.61 -3.89,-1.61c-1.52,0 -2.89,0.62 -3.89,1.61l1.42,1.42C14.8,7.89 15.67,7.5 16.64,7.5z"/>
-    <path
-        android:fillColor="#FF000000"
-        android:pathData="M16.64,4c1.93,0 3.68,0.79 4.95,2.05L23,4.64C21.37,3.01 19.12,2 16.64,2c-2.49,0 -4.74,1.01 -6.36,2.64l1.42,1.42C12.96,4.79 14.71,4 16.64,4z"/>
+        android:pathData="M22.25,7.25c-3.73,-3.73 -9.77,-3.73 -13.5,0L15.5,14L22.25,7.25z"/>
 </vector>
diff --git a/packages/SettingsLib/res/drawable/ic_wifi_call_strength_4.xml b/packages/SettingsLib/res/drawable/ic_wifi_call_strength_4.xml
new file mode 100644
index 0000000..8aec587
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_wifi_call_strength_4.xml
@@ -0,0 +1,27 @@
+<!--
+     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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M13.47,17.91l-2.18,-0.43c-0.22,-0.05 -0.45,0.03 -0.6,0.18L9.34,19C7.5,18.01 5.99,16.5 5,14.66l1.35,-1.35c0.16,-0.16 0.23,-0.39 0.18,-0.6l-0.43,-2.18C6.03,10.23 5.76,10 5.44,10H2.67C2.29,10 1.98,10.31 2,10.69c0.11,1.94 0.69,3.76 1.62,5.35c1.05,1.8 2.54,3.29 4.34,4.34c1.59,0.93 3.41,1.51 5.35,1.62c0.37,0.02 0.69,-0.29 0.69,-0.67v-2.77C14,18.24 13.78,17.97 13.47,17.91z"/>
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M23.5,6c-4.42,-4.42 -11.58,-4.42 -16,0l8,8L23.5,6z"/>
+</vector>
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index eafc614..1a67b5e 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -424,7 +424,8 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalie (rooi-groen)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalie (blou-geel)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Kleurregstelling"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Kleurregstelling stel jou in staat om te verstel hoe kleure op jou toestel vertoon word"</string>
+    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
+    <skip />
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Geneutraliseer deur <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Ongeveer <xliff:g id="TIME_REMAINING">%1$s</xliff:g> oor"</string>
@@ -515,6 +516,8 @@
     <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="2716555073132169240">"Foonluidspreker"</string>
+    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
+    <skip />
     <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>
     <string name="help_label" msgid="3528360748637781274">"Hulp en terugvoer"</string>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index 547d0af..97abce1 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -424,7 +424,8 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"ፕሮታኖማሊ (ቀይ-አረንጓዴ)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"ትራይታኖማሊ (ሰማያዊ-ቢጫ)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"የቀለም ማስተካከያ"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"ቀለም ማስተካከያ ቀለሞች በመሣሪያዎ ላይ እንዴት እንደሚታዩ እንዲያስተካክሉ ያስችሉዎታል"</string>
+    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
+    <skip />
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"በ<xliff:g id="TITLE">%1$s</xliff:g> ተሽሯል"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> ገደማ ቀርቷል"</string>
@@ -515,6 +516,8 @@
     <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="2716555073132169240">"የስልክ ድምጽ ማጉያ"</string>
+    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"መገናኘት ላይ ችግር። መሳሪያውን ያጥፉት እና እንደገና ያብሩት"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ባለገመድ የኦዲዮ መሣሪያ"</string>
     <string name="help_label" msgid="3528360748637781274">"እገዛ እና ግብረመልስ"</string>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index c6a1d18f..f9e12c7 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -424,7 +424,8 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"غطش الأحمر (الأحمر والأخضر)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"غمش الأزرق (الأزرق والأصفر)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"تصحيح الألوان"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"تسمح لك ميزة تصحيح الألوان بتعديل كيفية عرض الألوان على جهازك."</string>
+    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
+    <skip />
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"تم الاستبدال بـ <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"يتبقى <xliff:g id="TIME_REMAINING">%1$s</xliff:g> تقريبًا"</string>
@@ -519,6 +520,8 @@
     <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="2716555073132169240">"مكبر صوت الهاتف"</string>
+    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"حدثت مشكلة أثناء الاتصال. يُرجى إيقاف الجهاز ثم إعادة تشغيله."</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"جهاز سماعي سلكي"</string>
     <string name="help_label" msgid="3528360748637781274">"المساعدة والملاحظات والآراء"</string>
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index e9deb46..efd813a 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -424,7 +424,8 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"প্ৰ’টানোমালি (ৰঙা-সেউজীয়া)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"ট্ৰাইটান\'মেলী (নীলা-হালধীয়া)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"ৰং শুধৰণী"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"ৰং শুধৰণি সুবিধাটোৰে আপোনাক আপোনাৰ ডিভাইচত ৰংবোৰ কেনেকৈ প্ৰদর্শন কৰা হয় সেয়া মিলাবলৈ দিয়ে"</string>
+    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
+    <skip />
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g>ৰ দ্বাৰা অগ্ৰাহ্য কৰা হৈছে"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"প্রায় <xliff:g id="TIME_REMAINING">%1$s</xliff:g> বাকী আছে"</string>
@@ -515,6 +516,8 @@
     <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="2716555073132169240">"ফ’নৰ স্পীকাৰ"</string>
+    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"সংযোগ হোৱাত সমস্যা হৈছে। ডিভাইচটো অফ কৰি পুনৰ অন কৰক"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"তাঁৰযুক্ত অডিঅ’ ডিভাইচ"</string>
     <string name="help_label" msgid="3528360748637781274">"সহায় আৰু মতামত"</string>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index d04409c..2b0fa86 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaliya (qırmızı-yaşıl)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaliya (göy-sarı)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Rəng düzəlişi"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Rəng korreksiyası sizə rənglərin cihazınızda necə göstərilməsini tənzimləmək imkanı verir"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Cihazınızda rənglərin necə göstərilməsini tənzimləyin. Bu, aşağıdakıları etmək istədikdə faydalı ola bilər:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; Rəngləri daha dəqiq görmək&lt;/li&gt; &lt;li&gt; Fokuslanmaq üçün rəngləri ləğv etmək&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> tərəfindən qəbul edilmir"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Təxminən <xliff:g id="TIME_REMAINING">%1$s</xliff:g> qalıb"</string>
@@ -515,6 +515,7 @@
     <string name="zen_mode_forever" msgid="3339224497605461291">"Deaktiv edənə qədər"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"İndicə"</string>
     <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Telefon dinamiki"</string>
+    <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>
     <string name="help_label" msgid="3528360748637781274">"Yardım və rəy"</string>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index ecd70a2..b318637 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalija (crveno-zeleno)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalija (plavo-žuto)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Korekcija boja"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Korekcija boja vam omogućava da prilagodite način na koji se boje prikazuju na uređaju"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Prilagodite način na koji se boje prikazuju na uređaju. To može da bude korisno kada želite:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; da vam se boje tačnije prikazuju&lt;/li&gt; &lt;li&gt; da uklonite boje kako biste se fokusirali&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Zamenjuje ga <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g>–<xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Preostalo je oko <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -516,6 +516,7 @@
     <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="2716555073132169240">"Zvučnik telefona"</string>
+    <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>
     <string name="help_label" msgid="3528360748637781274">"Pomoć i povratne informacije"</string>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index 6a3b961..7a5aec4 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -424,7 +424,8 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Пратанамалія (чырвоны-зялёны)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Трытанамалія (сіні-жоўты)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Карэкцыя колеру"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Карэкцыя колеру дазволіць вам наладзіць адлюстраванне колераў на экране прылады"</string>
+    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
+    <skip />
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Перавызначаны <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Зараду хопіць прыблізна на <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -517,6 +518,8 @@
     <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="2716555073132169240">"Дынамік тэлефона"</string>
+    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Праблема з падключэннем. Выключыце і зноў уключыце прыладу"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Правадная аўдыяпрылада"</string>
     <string name="help_label" msgid="3528360748637781274">"Даведка і водгукі"</string>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index d2bf705..9ff2531 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Протаномалия (червено – зелено)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Тританомалия (синьо – жълто)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Корекция на цветове"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Функцията „Корекция на цветове“ ви позволява да коригирате това, как цветовете се показват на устройството ви"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Коригирайте как цветовете се показват на устройството ви. Това може да бъде полезно, когато искате да:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; видите цветовете по-ясно;&lt;/li&gt; &lt;li&gt; премахнете цветовете, за да се фокусирате.&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Заменено от „<xliff:g id="TITLE">%1$s</xliff:g>“"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Още около <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -515,6 +515,7 @@
     <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="2716555073132169240">"Високоговорител"</string>
+    <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>
     <string name="help_label" msgid="3528360748637781274">"Помощ и отзиви"</string>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index 3ccf0e4..675d179 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -424,7 +424,8 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"প্রোটানোম্যালি (লাল-সবুজ)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"ট্রিট্যানোম্যালি (নীল-হলুদ)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"রঙ সংশোধন"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"ডিভাইসে রঙগুলি কেমনভাবে দেখানো হবে তা অ্যাডজাস্ট করতে \'রঙ সংশোধন করুন\' বিকল্প ব্যবহার করা যেতে পারে"</string>
+    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
+    <skip />
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> এর দ্বারা ওভাররাইড করা হয়েছে"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"আর আনুমানিক <xliff:g id="TIME_REMAINING">%1$s</xliff:g> চলবে"</string>
@@ -515,6 +516,8 @@
     <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="2716555073132169240">"ফোনের স্পিকার"</string>
+    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"কানেক্ট করতে সমস্যা হচ্ছে। ডিভাইস বন্ধ করে আবার চালু করুন"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ওয়্যার অডিও ডিভাইস"</string>
     <string name="help_label" msgid="3528360748637781274">"সহায়তা ও মতামত"</string>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index f01eef3..97083ad 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -424,7 +424,8 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalija (crveno-zeleno)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalija (plavo-žuto)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Ispravka boje"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Ispravka boje vam dozvoljava da prilagodite način prikazivanja boja na uređaju"</string>
+    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
+    <skip />
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Zamjenjuje <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Preostalo je još oko <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -516,6 +517,8 @@
     <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="2716555073132169240">"Zvučnik telefona"</string>
+    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
+    <skip />
     <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>
     <string name="help_label" msgid="3528360748637781274">"Pomoć i povratne informacije"</string>
diff --git a/packages/SettingsLib/res/values-ca/arrays.xml b/packages/SettingsLib/res/values-ca/arrays.xml
index 3fd968b..9202013 100644
--- a/packages/SettingsLib/res/values-ca/arrays.xml
+++ b/packages/SettingsLib/res/values-ca/arrays.xml
@@ -234,7 +234,7 @@
     <item msgid="4433736508877934305">"Cap"</item>
     <item msgid="9140053004929079158">"Logcat"</item>
     <item msgid="3866871644917859262">"Systrace (gràfics)"</item>
-    <item msgid="7345673972166571060">"Pila de trucades a glGetError"</item>
+    <item msgid="7345673972166571060">"Pila de crides a glGetError"</item>
   </string-array>
   <string-array name="show_non_rect_clip_entries">
     <item msgid="2482978351289846212">"Desactivat"</item>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index 7069999..4889220 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -424,7 +424,8 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalia (vermell-verd)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalia (blau-groc)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Correcció de color"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"La correcció de color permet ajustar com es mostren els colors al teu dispositiu"</string>
+    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
+    <skip />
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"S\'ha substituït per <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g>: <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Temps restant aproximat: <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -515,6 +516,8 @@
     <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="2716555073132169240">"Altaveu del telèfon"</string>
+    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Hi ha hagut un problema amb la connexió. Desactiva el dispositiu i torna\'l a activar."</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositiu d\'àudio amb cable"</string>
     <string name="help_label" msgid="3528360748637781274">"Ajuda i suggeriments"</string>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index c677fef..e857e60 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -424,7 +424,8 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomálie (červená a zelená)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomálie (modrá a žlutá)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Korekce barev"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Korekce barev umožňuje upravit zobrazování barev na zařízení"</string>
+    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
+    <skip />
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Přepsáno nastavením <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Zbývá asi <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -517,6 +518,8 @@
     <string name="zen_mode_forever" msgid="3339224497605461291">"Dokud tuto funkci nevypnete"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"Právě teď"</string>
     <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Reproduktor telefonu"</string>
+    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
+    <skip />
     <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>
     <string name="help_label" msgid="3528360748637781274">"Nápověda a zpětná vazba"</string>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index 84247a6..53e21ba 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -424,7 +424,8 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanopi (rød-grøn)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanopi (blå-gul)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Korriger farver"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Ved hjælp af farvekorrigering kan du justere, hvordan farver ser ud på din enhed"</string>
+    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
+    <skip />
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Tilsidesat af <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Ca. <xliff:g id="TIME_REMAINING">%1$s</xliff:g> tilbage"</string>
@@ -515,6 +516,8 @@
     <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="2716555073132169240">"Telefonens højttaler"</string>
+    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
+    <skip />
     <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>
     <string name="help_label" msgid="3528360748637781274">"Hjælp og feedback"</string>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index 4cc79d3..a4a976f 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -424,7 +424,8 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalie (Rot-Grün-Sehschwäche)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalie (Blau-Gelb-Sehschwäche)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Farbkorrektur"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Mit der Farbkorrektur kannst du anpassen, wie Farben auf deinem Display angezeigt werden"</string>
+    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
+    <skip />
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Außer Kraft gesetzt von \"<xliff:g id="TITLE">%1$s</xliff:g>\""</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Noch etwa <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -515,6 +516,8 @@
     <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="2716555073132169240">"Smartphone-Lautsprecher"</string>
+    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
+    <skip />
     <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>
     <string name="help_label" msgid="3528360748637781274">"Hilfe und Feedback"</string>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index 30705a1..76faa4c 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Πρωτανοπία (κόκκινο-πράσινο)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Τριτανοπία (μπλε-κίτρινο)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Διόρθωση χρωμάτων"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Η διόρθωση χρωμάτων σάς επιτρέπει να ρυθμίσετε τον τρόπο εμφάνισης των χρωμάτων στη συσκευή σας"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Προσαρμόστε πώς θα εμφανίζονται τα χρώματα στη συσκευή σας. Αυτό μπορεί να είναι χρήσιμο όταν θέλετε:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; Να βλέπετε τα χρώματα με μεγαλύτερη ακρίβεια&lt;/li&gt; &lt;li&gt; Να καταργήσετε τα χρώματα για να συγκεντρωθείτε&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Αντικαταστάθηκε από <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Απομένει/ουν περίπου <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -515,6 +515,7 @@
     <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="2716555073132169240">"Ηχείο τηλεφώνου"</string>
+    <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>
     <string name="help_label" msgid="3528360748637781274">"Βοήθεια και σχόλια"</string>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index b3d80ab..9a63404 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaly (red-green)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaly (blue-yellow)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Colour correction"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Colour correction allows you to adjust how colours are displayed on your device"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Adjust how colours display on your device. This can be helpful when you want to:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; See colours more accurately&lt;/li&gt; &lt;li&gt; Remove colours to help you focus&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Overridden by <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"About <xliff:g id="TIME_REMAINING">%1$s</xliff:g> left"</string>
@@ -515,6 +515,7 @@
     <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="2716555073132169240">"Phone speaker"</string>
+    <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>
     <string name="help_label" msgid="3528360748637781274">"Help and feedback"</string>
diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml
index ecf97ad..49271db 100644
--- a/packages/SettingsLib/res/values-en-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-en-rCA/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaly (red-green)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaly (blue-yellow)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Colour correction"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Colour correction allows you to adjust how colours are displayed on your device"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Adjust how colours display on your device. This can be helpful when you want to:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; See colours more accurately&lt;/li&gt; &lt;li&gt; Remove colours to help you focus&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Overridden by <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"About <xliff:g id="TIME_REMAINING">%1$s</xliff:g> left"</string>
@@ -515,6 +515,7 @@
     <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="2716555073132169240">"Phone speaker"</string>
+    <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>
     <string name="help_label" msgid="3528360748637781274">"Help and feedback"</string>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index b3d80ab..9a63404 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaly (red-green)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaly (blue-yellow)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Colour correction"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Colour correction allows you to adjust how colours are displayed on your device"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Adjust how colours display on your device. This can be helpful when you want to:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; See colours more accurately&lt;/li&gt; &lt;li&gt; Remove colours to help you focus&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Overridden by <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"About <xliff:g id="TIME_REMAINING">%1$s</xliff:g> left"</string>
@@ -515,6 +515,7 @@
     <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="2716555073132169240">"Phone speaker"</string>
+    <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>
     <string name="help_label" msgid="3528360748637781274">"Help and feedback"</string>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index b3d80ab..9a63404 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaly (red-green)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaly (blue-yellow)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Colour correction"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Colour correction allows you to adjust how colours are displayed on your device"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Adjust how colours display on your device. This can be helpful when you want to:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; See colours more accurately&lt;/li&gt; &lt;li&gt; Remove colours to help you focus&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Overridden by <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"About <xliff:g id="TIME_REMAINING">%1$s</xliff:g> left"</string>
@@ -515,6 +515,7 @@
     <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="2716555073132169240">"Phone speaker"</string>
+    <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>
     <string name="help_label" msgid="3528360748637781274">"Help and feedback"</string>
diff --git a/packages/SettingsLib/res/values-en-rXC/strings.xml b/packages/SettingsLib/res/values-en-rXC/strings.xml
index c3a3f3f..3476b97 100644
--- a/packages/SettingsLib/res/values-en-rXC/strings.xml
+++ b/packages/SettingsLib/res/values-en-rXC/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‏‏‎‎‎‏‎‏‎‎‏‏‎‎‎‎‎‎‎‎‏‎‏‎‏‎‎‏‎‏‏‎‎‎‏‎‏‎‎‏‎‏‎‏‎‎‎‎‎‏‏‏‎‎‏‏‏‎‎‎‎Protanomaly (red-green)‎‏‎‎‏‎"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‎‎‏‏‎‎‎‎‎‏‎‏‏‎‎‎‏‏‏‎‏‏‎‏‏‎‎‏‎‏‏‏‎‎‏‎‏‎‏‎‎‎‏‎‏‎‏‏‎‏‎‏‎‏‏‎‏‎‏‏‎Tritanomaly (blue-yellow)‎‏‎‎‏‎"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‏‏‏‎‎‏‎‎‏‎‎‎‎‎‏‏‏‎‎‎‎‎‎‎‏‏‎‏‎‏‏‎‏‎‏‏‎‎‎‏‎‏‏‎‎‏‏‎‎‏‏‏‎‏‎‎‎‏‎‏‏‎‎Color correction‎‏‎‎‏‎"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‏‏‎‎‎‏‏‏‎‏‎‏‎‎‎‏‎‏‎‏‎‏‏‎‏‏‏‎‏‎‎‎‏‎‎‎‏‏‎‏‎‏‏‏‎‎‏‏‎‎‎‎‎‏‏‎‏‎‎‎‏‏‎Color correction allows you to adjust how colors are displayed on your device‎‏‎‎‏‎"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‎‏‏‏‏‎‏‏‎‏‎‎‎‎‎‎‎‏‏‏‏‏‎‏‎‏‎‏‏‎‎‎‎‎‎‎‎‏‏‎‏‎‎‏‎‎‎‏‎‎‏‏‎‏‎‏‏‎‏‎‎Adjust how colors display on your device. This can be helpful when you want to:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; See colors more accurately&lt;/li&gt; &lt;li&gt; Remove colors to help you focus&lt;/li&gt; &lt;/ol&gt;‎‏‎‎‏‎"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‏‏‏‎‏‎‎‏‎‏‎‏‎‏‎‏‎‏‎‏‏‎‏‎‎‎‎‏‎‏‏‎‏‏‎‎‎‎‎‏‎‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‎‎‏‎Overridden by ‎‏‎‎‏‏‎<xliff:g id="TITLE">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‎‎‎‏‏‏‏‎‎‏‎‏‏‏‎‎‏‏‎‎‎‎‏‏‎‎‏‏‏‎‎‎‏‏‏‎‎‏‏‎‎‏‎‎‏‏‎‎‏‏‎‏‎‎‎‎‏‏‏‎‏‎‎‏‎‎‏‏‎<xliff:g id="PERCENTAGE">%1$s</xliff:g>‎‏‎‎‏‏‏‎ - ‎‏‎‎‏‏‎<xliff:g id="TIME_STRING">%2$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‎‎‏‎‏‎‏‏‎‎‎‎‎‏‎‏‎‏‎‏‎‏‎‏‏‎‎‏‎‏‏‎‎‏‎‏‏‎‏‏‎‎‏‎‏‏‎‏‏‏‎‏‏‎‏‎‎‏‏‏‎About ‎‏‎‎‏‏‎<xliff:g id="TIME_REMAINING">%1$s</xliff:g>‎‏‎‎‏‏‏‎ left‎‏‎‎‏‎"</string>
@@ -515,6 +515,7 @@
     <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="2716555073132169240">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‎‏‎‏‏‎‏‏‎‎‏‏‎‎‏‎‎‏‎‎‎‏‏‏‎‎‏‎‎‎‏‏‎‎‏‎‏‏‎‏‎‏‎‎‎‎‎‎‏‎‎‎‎‎‎‏‏‎‎‎‎Phone speaker‎‏‎‎‏‎"</string>
+    <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>
     <string name="help_label" msgid="3528360748637781274">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‎‎‎‎‏‏‏‏‎‏‏‏‎‏‎‎‎‎‎‏‎‏‏‎‏‎‎‎‎‎‏‎‎‏‎‏‏‏‏‏‏‏‎‎‎‏‏‏‏‏‎‏‎‎‎‏‏‎‏‎‎Help &amp; feedback‎‏‎‎‏‎"</string>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index eb2a23b..71cf5cb 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -220,7 +220,7 @@
     <string name="adb_wireless_device_connected_summary" msgid="3039660790249148713">"Conectado actualmente"</string>
     <string name="adb_wireless_device_details_title" msgid="7129369670526565786">"Detalles del dispositivo"</string>
     <string name="adb_device_forget" msgid="193072400783068417">"Olvidar"</string>
-    <string name="adb_device_fingerprint_title_format" msgid="291504822917843701">"Huellas digitales del dispositivo: <xliff:g id="FINGERPRINT_PARAM">%1$s</xliff:g>"</string>
+    <string name="adb_device_fingerprint_title_format" msgid="291504822917843701">"Huellas dactilares del dispositivo: <xliff:g id="FINGERPRINT_PARAM">%1$s</xliff:g>"</string>
     <string name="adb_wireless_connection_failed_title" msgid="664211177427438438">"Error de conexión"</string>
     <string name="adb_wireless_connection_failed_message" msgid="9213896700171602073">"Asegúrate de que <xliff:g id="DEVICE_NAME">%1$s</xliff:g> esté conectado a la red correcta."</string>
     <string name="adb_pairing_device_dialog_title" msgid="7141739231018530210">"Vincular con dispositivo"</string>
@@ -424,7 +424,8 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalía (rojo-verde)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalía (azul-amarillo)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Corrección de color"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"La corrección de color te permite ajustar la manera en que se muestran los colores en el dispositivo"</string>
+    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
+    <skip />
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Reemplazado por <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Tiempo restante: aproximadamente <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -515,6 +516,8 @@
     <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="2716555073132169240">"Altavoz del teléfono"</string>
+    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
+    <skip />
     <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>
     <string name="help_label" msgid="3528360748637781274">"Ayuda y comentarios"</string>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index fe9984b..a7d7b21 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -424,7 +424,8 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalía (rojo-verde)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalía (azul-amarillo)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Corrección de color"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"La corrección de color te permite ajustar cómo se muestran los colores en tu dispositivo"</string>
+    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
+    <skip />
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Anulado por <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g>: <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Tiempo restante aproximado: <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -515,6 +516,8 @@
     <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="2716555073132169240">"Altavoz del teléfono"</string>
+    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
+    <skip />
     <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>
     <string name="help_label" msgid="3528360748637781274">"Ayuda y comentarios"</string>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index c70700d..add25f8 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -424,7 +424,8 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaalia (punane-roheline)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaalia (sinine-kollane)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Värvide korrigeerimine"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Värvide korrigeerimine võimaldab kohandada seadmes kuvatavaid värve"</string>
+    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
+    <skip />
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Alistas <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Ligikaudu <xliff:g id="TIME_REMAINING">%1$s</xliff:g> jäänud"</string>
@@ -515,6 +516,8 @@
     <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="2716555073132169240">"Telefoni kõlar"</string>
+    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
+    <skip />
     <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>
     <string name="help_label" msgid="3528360748637781274">"Abi ja tagasiside"</string>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index 09c964a..c95d157 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -424,7 +424,8 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanopia (gorri-berdeak)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanopia (urdin-horia)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Koloreen zuzenketa"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Koloreen zuzenketaren bidez, gailuan koloreak bistaratzen diren modua doi dezakezu"</string>
+    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
+    <skip />
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> hobespena gainjarri zaio"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> inguru gelditzen dira"</string>
@@ -515,6 +516,8 @@
     <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="2716555073132169240">"Telefonoaren bozgorailua"</string>
+    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Arazoren bat izan da konektatzean. Itzali gailua eta pitz ezazu berriro."</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Audio-gailu kableduna"</string>
     <string name="help_label" msgid="3528360748637781274">"Laguntza eta iritziak"</string>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index 22cd6ae..631ff5e 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -424,7 +424,8 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"قرمزدشواربینی (قرمز-سبز)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"آبی‌دشواربینی (آبی-زرد)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"تصحیح رنگ"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"تصحیح رنگ به شما امکان می‌دهد نحوه نمایش رنگ‌ها را در دستگاهتان تنظیم کنید"</string>
+    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
+    <skip />
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"توسط <xliff:g id="TITLE">%1$s</xliff:g> لغو شد"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"تقریباً <xliff:g id="TIME_REMAINING">%1$s</xliff:g> شارژ باقی مانده است"</string>
@@ -515,6 +516,8 @@
     <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="2716555073132169240">"بلندگوی تلفن"</string>
+    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"مشکل در اتصال. دستگاه را خاموش و دوباره روشن کنید"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"دستگاه صوتی سیمی"</string>
     <string name="help_label" msgid="3528360748637781274">"راهنما و بازخورد"</string>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index 22dde69..7591c91 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -424,7 +424,8 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalia (puna-vihersokeus)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalia (sini-keltasokeus)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Värinkorjaus"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Värinkorjauksella voit muuttaa värien näkymistä laitteellasi"</string>
+    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
+    <skip />
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Tämän ohittaa <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Noin <xliff:g id="TIME_REMAINING">%1$s</xliff:g> jäljellä"</string>
@@ -515,6 +516,8 @@
     <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="2716555073132169240">"Puhelimen kaiutin"</string>
+    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
+    <skip />
     <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>
     <string name="help_label" msgid="3528360748637781274">"Ohje ja palaute"</string>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index d189f72..a390257 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -424,7 +424,8 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalie (rouge/vert)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalie (bleu/jaune)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Correction des couleurs"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"La correction des couleurs vous permet d\'ajuster la manière dont les couleurs s\'affichent sur votre appareil"</string>
+    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
+    <skip />
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Remplacé par <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> : <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Il reste environ <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -515,6 +516,8 @@
     <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="2716555073132169240">"Haut-parleur du téléphone"</string>
+    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
+    <skip />
     <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>
     <string name="help_label" msgid="3528360748637781274">"Aide et commentaires"</string>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index 49d7faa..8cf8c6e 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -424,7 +424,8 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalie (rouge/vert)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalie (bleu-jaune)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Correction des couleurs"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"La correction des couleurs vous permet d\'ajuster l\'affichage des couleurs sur votre appareil"</string>
+    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
+    <skip />
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Remplacé par <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Temps restant : environ <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -515,6 +516,8 @@
     <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="2716555073132169240">"Haut-parleur du téléphone"</string>
+    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
+    <skip />
     <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>
     <string name="help_label" msgid="3528360748637781274">"Aide et commentaires"</string>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index 0922c3d..c1ba51d 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -424,7 +424,8 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalía (vermello-verde)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalía (azul-amarelo)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Corrección da cor"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"A corrección da cor permíteche axustar como se mostran as cores no dispositivo"</string>
+    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
+    <skip />
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Anulado por <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Tempo restante aproximado: <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -515,6 +516,8 @@
     <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="2716555073132169240">"Altofalante do teléfono"</string>
+    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
+    <skip />
     <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>
     <string name="help_label" msgid="3528360748637781274">"Axuda e comentarios"</string>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index 10c5cc8..94d83e0 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -424,7 +424,8 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"પ્રોટેનોમલી (લાલ-લીલો)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"ટ્રાઇટેનોમલી(વાદળી-પીળો)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"રંગ સુધારણા"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"રંગ સુધારણા તમને તમારા ડિવાઇસ પર રંગો કેવી રીતે બતાવવામાં આવે તેની ગોઠવણી કરવાની મંજૂરી આપે છે"</string>
+    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
+    <skip />
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> દ્વારા ઓવરરાઇડ થયું"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"લગભગ <xliff:g id="TIME_REMAINING">%1$s</xliff:g> બાકી છે"</string>
@@ -515,6 +516,8 @@
     <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="2716555073132169240">"ફોન સ્પીકર"</string>
+    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"કનેક્ટ કરવામાં સમસ્યા આવી રહી છે. ડિવાઇસને બંધ કરીને ફરી ચાલુ કરો"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"વાયરવાળો ઑડિયો ડિવાઇસ"</string>
     <string name="help_label" msgid="3528360748637781274">"સહાય અને પ્રતિસાદ"</string>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index ea25406..835e760 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"लाल रंग पहचान न पाना (लाल-हरा)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"नीला रंग पहचान न पाना (नीला-पीला)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"रंग में सुधार करने की सुविधा"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"रंग में सुधार करने की सुविधा, आपके डिवाइस पर दिखने वाले रंगों में बदलाव करने में मदद करती है"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"आपके डिवाइस पर रंगों के दिखने के तरीके में बदलाव करें. इससे, आपको इनमें मदद मिलेगी:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; रंगों को बेहतर तरीके से देखने में&lt;/li&gt; &lt;li&gt; आसानी से फ़ोकस करने के लिए, रंग हटाने में&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> के द्वारा ओवरराइड किया गया"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"बैटरी करीब <xliff:g id="TIME_REMAINING">%1$s</xliff:g> में खत्म हो जाएगी"</string>
@@ -515,6 +515,7 @@
     <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="2716555073132169240">"फ़ोन का स्पीकर"</string>
+    <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>
     <string name="help_label" msgid="3528360748637781274">"सहायता और सुझाव"</string>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index 27a7a6e..e99d4cb 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -424,7 +424,8 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalija (crveno – zeleno)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalija (plavo – žuto)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Korekcija boje"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Korekcija boje omogućuje vam prilagodbu načina prikazivanja boja na vašem uređaju"</string>
+    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
+    <skip />
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Premošćeno postavkom <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Još otprilike <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -516,6 +517,8 @@
     <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="2716555073132169240">"Zvučnik telefona"</string>
+    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
+    <skip />
     <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>
     <string name="help_label" msgid="3528360748637781274">"Pomoć i povratne informacije"</string>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index 70a48b6..503ee60 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -424,7 +424,8 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomália (piros– zöld)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomália (kék–sárga)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Színkorrekció"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"A színkorrekcióval módosíthatja a színek megjelenítésének módját az eszközön"</string>
+    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
+    <skip />
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Felülírva erre: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Körülbelül <xliff:g id="TIME_REMAINING">%1$s</xliff:g> maradt hátra"</string>
@@ -515,6 +516,8 @@
     <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="2716555073132169240">"Telefon hangszórója"</string>
+    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
+    <skip />
     <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>
     <string name="help_label" msgid="3528360748637781274">"Súgó és visszajelzés"</string>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index c39e966..3686dd1 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -404,7 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Չեղարկել վերակոդավորման կանխադրված կարգավորումները"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Միացնել վերակոդավորումը"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Ենթադրել, որ հավելվածներն աջակցում են ժամանակակից ձևաչափեր"</string>
-    <string name="transcode_notification" msgid="5560515979793436168">"Ցուցադրել անդրկոդավորման ծանուցումներ"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"Ցույց տալ տրանսկոդավորման մասին ծանուցումները"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Աշխատող ծառայություններ"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Դիտել և վերահսկել ընթացիկ աշխատող ծառայությունները"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView ծառայություն"</string>
@@ -424,7 +424,8 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Պրոտանոմալիա (կարմիր-կանաչ)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Տրիտանոմալիա (կապույտ-դեղին)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Գունաշտկում"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Գունաշտկումը թույլ է տալիս կարգավորել գույների ցուցադրումն այս սարքում"</string>
+    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
+    <skip />
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Գերազանցված է <xliff:g id="TITLE">%1$s</xliff:g>-ից"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Լիցքը կբավարարի մոտ <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -515,6 +516,8 @@
     <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="2716555073132169240">"Հեռախոսի բարձրախոս"</string>
+    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Կապի խնդիր կա: Սարքն անջատեք և նորից միացրեք:"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Լարով աուդիո սարք"</string>
     <string name="help_label" msgid="3528360748637781274">"Օգնություն և հետադարձ կապ"</string>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index 037c1b3..035be7d 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -424,7 +424,8 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomali (merah-hijau)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomali (biru-kuning)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Koreksi warna"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Koreksi warna memungkinkan Anda untuk menyesuaikan cara warna ditampilkan pada perangkat Anda"</string>
+    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
+    <skip />
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Digantikan oleh <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Sekitar <xliff:g id="TIME_REMAINING">%1$s</xliff:g> lagi"</string>
@@ -515,6 +516,8 @@
     <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="2716555073132169240">"Speaker ponsel"</string>
+    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
+    <skip />
     <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>
     <string name="help_label" msgid="3528360748637781274">"Bantuan &amp; masukan"</string>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index 3f87830..718b5be 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -424,7 +424,8 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Litblinda (rauðgræn)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Litblinda (blágul)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Litaleiðrétting"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Litaleiðrétting gerir þér kleift að stilla hvernig litir birtast í tækinu þínu"</string>
+    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
+    <skip />
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Hnekkt af <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Um það bil <xliff:g id="TIME_REMAINING">%1$s</xliff:g> eftir"</string>
@@ -515,6 +516,8 @@
     <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="2716555073132169240">"Símahátalari"</string>
+    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
+    <skip />
     <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>
     <string name="help_label" msgid="3528360748637781274">"Hjálp og ábendingar"</string>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index 80ab57b..d2176d9 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -424,7 +424,8 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalìa (rosso-verde)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalìa (blu-giallo)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Correzione del colore"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"La correzione del colore ti consente di regolare la visualizzazione dei colori sul tuo dispositivo"</string>
+    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
+    <skip />
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Valore sostituito da <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Tempo rimanente: <xliff:g id="TIME_REMAINING">%1$s</xliff:g> circa"</string>
@@ -515,6 +516,8 @@
     <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="2716555073132169240">"Altoparlante telefono"</string>
+    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
+    <skip />
     <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>
     <string name="help_label" msgid="3528360748637781274">"Guida e feedback"</string>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index 4355f31..1357cae 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -424,7 +424,8 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"פרוטנומליה (אדום-ירוק)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"טריטנומליה (כחול-צהוב)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"תיקון צבע"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"תיקון צבע מאפשר לשנות את האופן שבו צבעים מוצגים במכשיר שלך"</string>
+    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
+    <skip />
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"נעקף על ידי <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"הזמן הנותר: בערך <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -517,6 +518,8 @@
     <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="2716555073132169240">"רמקול של טלפון"</string>
+    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"יש בעיה בחיבור. עליך לכבות את המכשיר ולהפעיל אותו מחדש"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"התקן אודיו חוטי"</string>
     <string name="help_label" msgid="3528360748637781274">"עזרה ומשוב"</string>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index ea4a683..4a9126f 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"第一色弱(赤緑)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"第三色弱(青黄)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"色補正"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"色補正機能では、デバイスで色をどのように表示するかを調整できます"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"デバイスで色をどのように表示するかを調整できます。この設定は以下の場合に役立ちます。&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; 色をより正確に表示したい場合&lt;/li&gt; &lt;li&gt; はっきり読み取れるよう色を取り除きたい場合&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g>によって上書き済み"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"残り時間: 約 <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -515,6 +515,7 @@
     <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="2716555073132169240">"スマートフォンのスピーカー"</string>
+    <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>
     <string name="help_label" msgid="3528360748637781274">"ヘルプとフィードバック"</string>
diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml
index 5798a46..8bb6ba8 100644
--- a/packages/SettingsLib/res/values-ka/strings.xml
+++ b/packages/SettingsLib/res/values-ka/strings.xml
@@ -424,7 +424,8 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"პროტოანომალია (წითელი-მწვანე)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"ტრიტანომალია (ლურჯი-ყვითელი)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"ფერის კორექცია"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"ფერთა კორექცია საშუალებას გაძლევთ დაარეგულიროთ, თუ როგორ გამოჩნდება ფერები თქვენს მოწყობილობაზე"</string>
+    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
+    <skip />
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"უკუგებულია <xliff:g id="TITLE">%1$s</xliff:g>-ის მიერ"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"დარჩა დაახლოებით <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -515,6 +516,8 @@
     <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="2716555073132169240">"ტელეფონის დინამიკი"</string>
+    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"დაკავშირებისას წარმოიქმნა პრობლემა. გამორთეთ და კვლავ ჩართეთ მოწყობილობა"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"სადენიანი აუდიო მოწყობილობა"</string>
     <string name="help_label" msgid="3528360748637781274">"დახმარება და გამოხმაურება"</string>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index 5ce4e3a..6a2c21e 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -424,7 +424,8 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Протаномалия (қызыл-жасыл)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Тританомалия (көк-сары)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Түсті түзету"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Түсті түзету функциясының көмегімен құрылғыңызда көрсетілетін түстерді реттеуге болады."</string>
+    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
+    <skip />
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> үстінен басқан"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Шамамен <xliff:g id="TIME_REMAINING">%1$s</xliff:g> қалды"</string>
@@ -515,6 +516,8 @@
     <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="2716555073132169240">"Телефон динамигі"</string>
+    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Байланыс орнату қатесі шығуып жатыр. Құрылғыны өшіріп, қайта қосыңыз."</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Сымды аудио құрылғысы"</string>
     <string name="help_label" msgid="3528360748637781274">"Анықтама және пікір"</string>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index e6f2cb0..f4cece4 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaly (ក្រហម​ពណ៌​បៃតង​)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaly (ពណ៌​ខៀវ​-លឿង​)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"ការ​កែ​ពណ៌"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"ការកែតម្រូវ​ពណ៌​អនុញ្ញាតឱ្យ​អ្នក​កែតម្រូវ​របៀប​បង្ហាញ​ពណ៌​នៅលើ​ឧបករណ៍​របស់អ្នក"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"កែតម្រូវ​របៀបដែលពណ៌​បង្ហាញនៅលើ​ឧបករណ៍​របស់អ្នក។ ចំណុចនេះ​អាចមានប្រយោជន៍ នៅពេលដែល​អ្នកចង់៖&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; មើលឃើញពណ៌​កាន់តែត្រឹមត្រូវ&lt;/li&gt; &lt;li&gt; លុបពណ៌ ដើម្បីជួយអ្នក​ក្នុងការផ្ដោត&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"បដិសេធ​ដោយ <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"នៅសល់​ប្រហែល <xliff:g id="TIME_REMAINING">%1$s</xliff:g> ទៀត"</string>
@@ -515,6 +515,7 @@
     <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="2716555073132169240">"ឧបករណ៍​បំពង​សំឡេង​ទូរសព្ទ"</string>
+    <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>
     <string name="help_label" msgid="3528360748637781274">"ជំនួយ និងមតិកែលម្អ"</string>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index 561e6be..a844ee6 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -404,8 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"ಟ್ರಾನ್ಸ್‌ಕೋಡಿಂಗ್ ಡೀಫಾಲ್ಟ್‌ಗಳನ್ನು ಅತಿಕ್ರಮಿಸಿ"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"ಟ್ರಾನ್ಸ್‌ಕೋಡಿಂಗ್ ಅನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
     <string name="transcode_default" msgid="3784803084573509491">"ಆ್ಯಪ್‌ಗಳು ಆಧುನಿಕ ಫಾರ್ಮ್ಯಾಟ್‌ಗಳನ್ನು ಬೆಂಬಲಿಸುತ್ತದೆ ಎಂದು ಊಹಿಸಿ"</string>
-    <!-- no translation found for transcode_notification (5560515979793436168) -->
-    <skip />
+    <string name="transcode_notification" msgid="5560515979793436168">"ಟ್ರಾನ್ಸ್‌ಕೋಡಿಂಗ್ ಅಧಿಸೂಚನೆಗಳನ್ನು ತೋರಿಸಿ"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"ರನ್‌ ಆಗುತ್ತಿರುವ ಸೇವೆಗಳು"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"ಈಗ ರನ್‌ ಆಗುತ್ತಿರುವ ಸೇವೆಗಳನ್ನು ವೀಕ್ಷಿಸಿ ಮತ್ತು ನಿಯಂತ್ರಿಸಿ"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView ಹೊಂದಿಸಿ"</string>
@@ -425,7 +424,8 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"ಪ್ರೊಟನೋಮಲಿ (ಕೆಂಪು-ಹಸಿರು)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"ಟ್ರಿಟನೋಮಲಿ (ನೀಲಿ-ಹಳದಿ)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"ಬಣ್ಣದ ತಿದ್ದುಪಡಿ"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"ನಿಮ್ಮ ಸಾಧನದಲ್ಲಿ ಬಣ್ಣಗಳನ್ನು ಹೇಗೆ ಪ್ರದರ್ಶಿಸಲಾಗುತ್ತದೆ ಎಂಬುದನ್ನು ಹೊಂದಾಣಿಕೆ ಮಾಡಲು ಬಣ್ಣ ತಿದ್ದುಪಡಿಯು ಅವಕಾಶ ನೀಡುತ್ತದೆ"</string>
+    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
+    <skip />
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> ಮೂಲಕ ಅತಿಕ್ರಮಿಸುತ್ತದೆ"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> ಸಮಯ ಬಾಕಿ ಉಳಿದಿದೆ"</string>
@@ -516,6 +516,8 @@
     <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="2716555073132169240">"ಫೋನ್ ಸ್ಪೀಕರ್"</string>
+    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"ಕನೆಕ್ಟ್ ಮಾಡುವಾಗ ಸಮಸ್ಯೆ ಎದುರಾಗಿದೆ ಸಾಧನವನ್ನು ಆಫ್ ಮಾಡಿ ಹಾಗೂ ನಂತರ ಪುನಃ ಆನ್ ಮಾಡಿ"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ವೈರ್ ಹೊಂದಿರುವ ಆಡಿಯೋ ಸಾಧನ"</string>
     <string name="help_label" msgid="3528360748637781274">"ಸಹಾಯ ಮತ್ತು ಪ್ರತಿಕ್ರಿಯೆ"</string>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index cd3b8b8..c9960c4 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"적색약(적녹)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"청색약(청황)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"색상 보정"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"색상 보정을 사용하면 기기에 표시되는 색상을 조절할 수 있습니다."</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"기기에 색상이 표시되는 방식을 조정합니다. 색상을 더 정확하게 보고 싶거나 집중을 위해 일부 색상을 제거할 때 유용합니다."</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> 우선 적용됨"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g>, <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"남은 시간 약 <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -515,6 +515,7 @@
     <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="2716555073132169240">"휴대전화 스피커"</string>
+    <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>
     <string name="help_label" msgid="3528360748637781274">"고객센터"</string>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index 1990353..4ca6567 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -424,7 +424,8 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Протаномалия (кызыл-жашыл)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Тританомалия (көк-сары)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Түсүн тууралоо"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Түстөрдү тууралоо менен, түзмөгүңүздүн экранынын түстөрүн өзгөртө аласыз"</string>
+    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
+    <skip />
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> менен алмаштырылган"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Болжол менен <xliff:g id="TIME_REMAINING">%1$s</xliff:g> калды"</string>
@@ -515,6 +516,8 @@
     <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="2716555073132169240">"Телефондун динамиги"</string>
+    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Туташууда маселе келип чыкты. Түзмөктү өчүрүп, кайра күйгүзүп көрүңүз"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Зымдуу аудио түзмөк"</string>
     <string name="help_label" msgid="3528360748637781274">"Жардам/Пикир билдирүү"</string>
diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index 4997ea1..176c80f 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -424,7 +424,8 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaly (ສີ​ແດງ​-ສີ​ຂຽວ​)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaly (ສີ​ຟ້າ​-ສີ​ເຫຼືອງ​)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"ການ​ປັບ​ແຕ່ງ​ສີ"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"ການແກ້ໄຂສີຈະເຮັດໃຫ້ທ່ານສາມາດປັບແຕ່ງການສະແດງຜົນຂອງສີຢູ່ອຸປະກອນຂອງທ່ານໄດ້"</string>
+    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
+    <skip />
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"ຖືກແທນໂດຍ <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"ເຫຼືອອີກປະມານ <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -515,6 +516,8 @@
     <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="2716555073132169240">"ລຳໂພງໂທລະສັບ"</string>
+    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"ເກີດບັນຫາໃນການເຊື່ອມຕໍ່. ປິດອຸປະກອນແລ້ວເປີດກັບຄືນມາໃໝ່"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ອຸປະກອນສຽງແບບມີສາຍ"</string>
     <string name="help_label" msgid="3528360748637781274">"ຊ່ວຍເຫຼືອ ແລະ ຕິຊົມ"</string>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index ec3cb0d..b0ab8f4 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -424,7 +424,8 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalija (raudona, žalia)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalija (mėlyna, geltona)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Spalvų taisymas"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Spalvų taisymo funkcija padės koreguoti, kaip spalvos rodomos jūsų įrenginyje"</string>
+    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
+    <skip />
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Nepaisyta naudojant nuostatą „<xliff:g id="TITLE">%1$s</xliff:g>“"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Liko maždaug <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -517,6 +518,8 @@
     <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="2716555073132169240">"Telefono garsiakalbis"</string>
+    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
+    <skip />
     <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>
     <string name="help_label" msgid="3528360748637781274">"Pagalba ir atsiliepimai"</string>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index ff9f0a1..2633f13 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -424,7 +424,8 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomālija (sarkans/zaļš)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomālija (zils/dzeltens)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Krāsu korekcija"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Izmantojot krāsu korekciju, varat koriģēt krāsu attēlojumu savā ierīcē"</string>
+    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
+    <skip />
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Jaunā preference: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> — <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Aptuvenais atlikušais laiks: <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -516,6 +517,8 @@
     <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="2716555073132169240">"Tālruņa skaļrunis"</string>
+    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
+    <skip />
     <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>
     <string name="help_label" msgid="3528360748637781274">"Palīdzība un atsauksmes"</string>
diff --git a/packages/SettingsLib/res/values-mk/arrays.xml b/packages/SettingsLib/res/values-mk/arrays.xml
index d1c74e6..03128c1 100644
--- a/packages/SettingsLib/res/values-mk/arrays.xml
+++ b/packages/SettingsLib/res/values-mk/arrays.xml
@@ -138,9 +138,9 @@
     <item msgid="1333279807604675720">"Стерео"</item>
   </string-array>
   <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="1241278021345116816">"Оптимизирано за квалитет на аудиото (990 кб/с - 909 кб/с)"</item>
+    <item msgid="1241278021345116816">"Оптимизирано за квалитет на аудиото (990 kbps - 909 kbps)"</item>
     <item msgid="3523665555859696539">"Балансиран квалитет на звукот и врската (660 kb/s/606 kb/s)"</item>
-    <item msgid="886408010459747589">"Оптимизирано за квалитет на врската (330 кб/с - 303 кб/с)"</item>
+    <item msgid="886408010459747589">"Оптимизирано за квалитет на врската (330 kbps - 303 kbps)"</item>
     <item msgid="3808414041654351577">"Најдобар напор (приспособлива стапка на битови)"</item>
   </string-array>
   <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index 507f65c..e4173d0 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -424,7 +424,8 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Протаномалија (слепило за црвена и зелена)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Тританомалија (слепило за сина и жолта)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Корекција на бои"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Корекцијата на боите ви овозможува да го приспособите начинот на прикажување на боите на вашиот уред"</string>
+    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
+    <skip />
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Прескокнато според <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Уште околу <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -515,6 +516,8 @@
     <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="2716555073132169240">"Телефонски звучник"</string>
+    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Проблем со поврзување. Исклучете го уредот и повторно вклучете го"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Жичен аудиоуред"</string>
     <string name="help_label" msgid="3528360748637781274">"Помош и повратни информации"</string>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index 8a09801..3cfe479 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -424,7 +424,8 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"പ്രോട്ടാനോമലി (ചുവപ്പ്-പച്ച)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"ട്രിട്ടാനോമലി (നീല-മഞ്ഞ)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"നിറം ക്രമീകരിക്കൽ"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"നിങ്ങളുടെ ഉപകരണത്തിൽ നിറങ്ങൾ എങ്ങനെ പ്രദർശിപ്പിക്കുന്നു എന്നത് ക്രമീകരിക്കാൻ \'നിറം ക്രമീകരിക്കൽ\' അനുവദിക്കുന്നു"</string>
+    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
+    <skip />
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> ഉപയോഗിച്ച് അസാധുവാക്കി"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"ഏതാണ്ട് <xliff:g id="TIME_REMAINING">%1$s</xliff:g> ശേഷിക്കുന്നു"</string>
@@ -515,6 +516,8 @@
     <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="2716555073132169240">"ഫോൺ സ്‌പീക്കർ"</string>
+    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"കണക്‌റ്റ് ചെയ്യുന്നതിൽ പ്രശ്‌നമുണ്ടായി. ഉപകരണം ഓഫാക്കി വീണ്ടും ഓണാക്കുക"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"വയർ മുഖേന ബന്ധിപ്പിച്ച ഓഡിയോ ഉപകരണം"</string>
     <string name="help_label" msgid="3528360748637781274">"സഹായവും ഫീഡ്‌ബാക്കും"</string>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index 27ca8f5..7c833f7 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Протаномаль (улаан-ногоон)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Тританомаль (цэнхэр-шар)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Өнгө тохируулах"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Өнгө тохируулга нь танд төхөөрөмж дээрээ өнгө хэрхэн харагдахыг тохируулах боломжийг олгодог"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Таны төхөөрөмж дээр өнгийг хэрхэн үзүүлэхийг тохируулна уу. Энэ нь таныг дараахыг хийхийг хүссэн үед хэрэгтэй байж болно:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; Өнгийг илүү оновчтой харах&lt;/li&gt; &lt;li&gt; Төвлөрөхийн тулд өнгийг хасах&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Давхарласан <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Ойролцоогоор <xliff:g id="TIME_REMAINING">%1$s</xliff:g> үлдсэн"</string>
@@ -515,6 +515,7 @@
     <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="2716555073132169240">"Утасны чанга яригч"</string>
+    <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>
     <string name="help_label" msgid="3528360748637781274">"Тусламж, санал хүсэлт"</string>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index b6c5460..f8d9089 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -404,8 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"ट्रान्सकोडिंग डीफॉल्ट ओव्हरराइड करा"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"ट्रान्सकोडिंग सुरू करा"</string>
     <string name="transcode_default" msgid="3784803084573509491">"असे गृहीत धरा की, ॲप्स आधुनिक फॉरमॅटना सपोर्ट करतात"</string>
-    <!-- no translation found for transcode_notification (5560515979793436168) -->
-    <skip />
+    <string name="transcode_notification" msgid="5560515979793436168">"ट्रान्सकोडिंग सूचना दाखवा"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"सुरू सेवा"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"सध्या सुरू असलेल्या सेवा पहा आणि नियंत्रित करा"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"वेबदृश्य अंमलबजावणी"</string>
@@ -425,7 +424,8 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"क्षीण रक्तवर्णांधता (लाल-हिरवा)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"रंग दृष्टी कमतरता (निळा-पिवळा)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"रंग सुधारणा"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"कलर इन्व्हर्जन तुमच्या डिव्हाइसवर रंग कसे प्रदर्शित केले जातात ते अ‍ॅडजस्ट करू देते"</string>
+    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
+    <skip />
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> द्वारे अधिलिखित"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"अंदाजे <xliff:g id="TIME_REMAINING">%1$s</xliff:g> बाकी आहे"</string>
@@ -516,6 +516,8 @@
     <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="2716555073132169240">"फोनचा स्पीकर"</string>
+    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"कनेक्‍ट करण्‍यात समस्‍या आली. डिव्हाइस बंद करा आणि नंतर सुरू करा"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"वायर असलेले ऑडिओ डिव्हाइस"</string>
     <string name="help_label" msgid="3528360748637781274">"मदत आणि फीडबॅक"</string>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index 53a4398..4df3855 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -68,7 +68,7 @@
     <string name="bluetooth_disconnecting" msgid="7638892134401574338">"Memutuskan sambungan..."</string>
     <string name="bluetooth_connecting" msgid="5871702668260192755">"Menyambung..."</string>
     <string name="bluetooth_connected" msgid="8065345572198502293">"<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g> disambungkan"</string>
-    <string name="bluetooth_pairing" msgid="4269046942588193600">"Memasangkan..."</string>
+    <string name="bluetooth_pairing" msgid="4269046942588193600">"Menggandingkan..."</string>
     <string name="bluetooth_connected_no_headset" msgid="2224101138659967604">"Disambungkan (tiada telefon)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
     <string name="bluetooth_connected_no_a2dp" msgid="8566874395813947092">"Disambungkan (tiada media)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
     <string name="bluetooth_connected_no_map" msgid="3381860077002724689">"Disambungkan (tiada akses mesej)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
@@ -113,7 +113,7 @@
     <string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Gunakan untuk pemindahan fail"</string>
     <string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Gunakan untuk input"</string>
     <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"Gunakan untuk Alat Bantu Dengar"</string>
-    <string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Jadikan pasangan"</string>
+    <string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Gandingkan"</string>
     <string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"JADIKAN PASANGAN"</string>
     <string name="bluetooth_pairing_decline" msgid="6483118841204885890">"Batal"</string>
     <string name="bluetooth_pairing_will_share_phonebook" msgid="3064334458659165176">"Berpasangan memberi anda akses kepada kenalan dan sejarah panggilan apabila disambungkan."</string>
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomali (merah-hijau)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomali (biru-kuning)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Pembetulan warna"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Pembetulan warna membolehkan anda melaraskan cara warna dipaparkan pada peranti anda"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Laraskan cara warna dipaparkan pada peranti anda. Ini boleh membantu apabila anda ingin:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; Lihat warna dengan lebih tepat&lt;/li&gt; &lt;li&gt; Alih keluar warna untuk membantu anda fokus&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Diatasi oleh <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Kira-kira <xliff:g id="TIME_REMAINING">%1$s</xliff:g> lagi"</string>
@@ -515,6 +515,7 @@
     <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="2716555073132169240">"Pembesar suara telefon"</string>
+    <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>
     <string name="help_label" msgid="3528360748637781274">"Bantuan &amp; maklum balas"</string>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index 0fef5ab..f10e539 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -424,7 +424,8 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaly (အနီ-အစိမ်း)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaly (အပြာ-အဝါ)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"အရောင်ပြင်ဆင်မှု"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"အရောင်အမှန်ပြင်ခြင်းက သင့်စက်ပေါ်တွင် အရောင်များပြနေပုံကို ချိန်ညှိခွင့်ပြုသည်"</string>
+    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
+    <skip />
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> မှ ကျော်၍ လုပ်ထားသည်။"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> ခန့် ကျန်သည်"</string>
@@ -515,6 +516,8 @@
     <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="2716555073132169240">"ဖုန်းစပီကာ"</string>
+    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"ချိတ်ဆက်ရာတွင် ပြဿနာရှိပါသည်။ စက်ကိုပိတ်ပြီး ပြန်ဖွင့်ပါ"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ကြိုးတပ် အသံစက်ပစ္စည်း"</string>
     <string name="help_label" msgid="3528360748637781274">"အကူအညီနှင့် အကြံပြုချက်"</string>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index 0ca8d51..9fb68d0 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -424,7 +424,8 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomali (rød-grønn)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomali (blå-gul)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Fargekorrigering"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Med fargekorrigering kan du justere hvordan farger vises på enheten din"</string>
+    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
+    <skip />
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Overstyres av <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Omtrent <xliff:g id="TIME_REMAINING">%1$s</xliff:g> gjenstår"</string>
@@ -515,6 +516,8 @@
     <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="2716555073132169240">"Telefonhøyttaler"</string>
+    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
+    <skip />
     <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>
     <string name="help_label" msgid="3528360748637781274">"Hjelp og tilbakemelding"</string>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index 75b4537..4c847cf 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -404,8 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"ट्रान्सकोडिङसम्बन्धी पूर्वनिर्धारित सेटिङ परिवर्तन गर्नुहोस्"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"ट्रान्सकोडिङ अन गर्नुहोस्"</string>
     <string name="transcode_default" msgid="3784803084573509491">"एपहरूमा आधुनिक फर्म्याट प्रयोग गर्न मिल्छ भनी मान्नुहोस्"</string>
-    <!-- no translation found for transcode_notification (5560515979793436168) -->
-    <skip />
+    <string name="transcode_notification" msgid="5560515979793436168">"ट्रान्सकोडिङसम्बन्धी सूचना देखाइयोस्"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"चलिरहेका सेवाहरू"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"हाल चालु भइरहेका सेवाहरू हेर्नुहोस् र नियन्त्रण गर्नुहोस्"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView कार्यान्वयन"</string>
@@ -425,7 +424,8 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"प्रोटानेमली (रातो, हरियो)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"ट्रिटानोमेली (निलो-पंहेलो)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"रङ्ग सुधार"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"रंङ सच्याउने सुविधाले तपाईंलाई आफ्नो यन्त्रमा रंङहरू कसरी देखाउने भन्ने कुरा निर्धारण गर्न दिन्छ"</string>
+    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
+    <skip />
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> द्वारा अधिरोहित"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"लगभग <xliff:g id="TIME_REMAINING">%1$s</xliff:g> बाँकी छ"</string>
@@ -516,6 +516,8 @@
     <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="2716555073132169240">"फोनको स्पिकर"</string>
+    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"जोड्ने क्रममा समस्या भयो। यन्त्रलाई निष्क्रिय पारेर फेरि सक्रिय गर्नुहोस्"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"तारयुक्त अडियो यन्त्र"</string>
     <string name="help_label" msgid="3528360748637781274">"मद्दत र प्रतिक्रिया"</string>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index 71d6acc..4cb755b 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalie (rood-groen)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalie (blauw-geel)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Kleurcorrectie"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Met kleurcorrectie kun je aanpassen hoe kleuren op je apparaat worden weergegeven"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Aanpassen hoe kleuren worden getoond op je apparaat. In de volgende gevallen kan dit handig zijn:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; Je wilt kleuren duidelijker zien.&lt;/li&gt; &lt;li&gt; Je wilt kleuren verwijderen zodat je je beter kunt focussen.&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Overschreven door <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Nog ongeveer <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -515,6 +515,7 @@
     <string name="zen_mode_forever" msgid="3339224497605461291">"Totdat je uitschakelt"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"Zojuist"</string>
     <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Telefoonspeaker"</string>
+    <string name="media_transfer_this_phone" msgid="7194341457812151531">"Deze telefoon"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Probleem bij verbinding maken. Schakel het apparaat uit en weer in."</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Bedraad audioapparaat"</string>
     <string name="help_label" msgid="3528360748637781274">"Hulp en feedback"</string>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index 1d6e34f..b7c93e5 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -424,7 +424,8 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"ପ୍ରୋଟାନୋମାଲି (ଲାଲ୍‌-ସବୁଜ)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaly (ନୀଳ-ହଳଦିଆ)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"ରଙ୍ଗ ସଂଶୋଧନ"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"ଆପଣଙ୍କ ଡିଭାଇସରେ ରଙ୍ଗଗୁଡ଼ିକ କିପରି ଡିସପ୍ଲେ ହୁଏ, ତାହା ଆଡଜଷ୍ଟ କରିବାକୁ \'ରଙ୍ଗ ସଂଶୋଧନ’ ଆପଣଙ୍କୁ ଅନୁମତି ଦିଏ"</string>
+    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
+    <skip />
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> ଦ୍ୱାରା ଓଭର୍‌ରାଇଡ୍‌ କରାଯାଇଛି"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"ପାଖାପାଖି <xliff:g id="TIME_REMAINING">%1$s</xliff:g> ବଳକା ଅଛି"</string>
@@ -515,6 +516,8 @@
     <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="2716555073132169240">"ଫୋନ୍ ସ୍ପିକର୍"</string>
+    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"ସଂଯୋଗ କରିବାରେ ସମସ୍ୟା ହେଉଛି। ଡିଭାଇସ୍ ବନ୍ଦ କରି ପୁଣି ଚାଲୁ କରନ୍ତୁ"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ତାରଯୁକ୍ତ ଅଡିଓ ଡିଭାଇସ୍"</string>
     <string name="help_label" msgid="3528360748637781274">"ସାହାଯ୍ୟ ଓ ମତାମତ"</string>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index 9d91aae..896a100 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -404,8 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"ਟ੍ਰਾਂਸਕੋਡਿੰਗ ਦੀਆਂ ਪੂਰਵ-ਨਿਰਧਾਰਤ ਸੈਟਿੰਗਾਂ ਨੂੰ ਓਵਰਰਾਈਡ ਕਰੋ"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"ਟ੍ਰਾਂਸਕੋਡਿੰਗ ਚਾਲੂ ਕਰੋ"</string>
     <string name="transcode_default" msgid="3784803084573509491">"ਮੰਨ ਲਓ ਕਿ ਐਪਾਂ ਆਧੁਨਿਕ ਫਾਰਮੈਟਾਂ ਦਾ ਸਮਰਥਨ ਕਰਦੀਆਂ ਹਨ"</string>
-    <!-- no translation found for transcode_notification (5560515979793436168) -->
-    <skip />
+    <string name="transcode_notification" msgid="5560515979793436168">"ਟ੍ਰਾਂਸਕੋਡਿੰਗ ਸੂਚਨਾਵਾਂ ਦਿਖਾਓ"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"ਚੱਲ ਰਹੀਆਂ ਸੇਵਾਵਾਂ"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"ਇਸ ਵੇਲੇ ਚੱਲ ਰਹੀਆਂ ਸੇਵਾਵਾਂ ਦੇਖੋ ਅਤੇ ਇਹਨਾਂ ਨੂੰ ਕੰਟਰੋਲ ਕਰੋ"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView ਅਮਲ"</string>
@@ -425,7 +424,8 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaly (ਲਾਲ-ਹਰਾ)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaly (ਨੀਲਾ-ਪੀਲਾ)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"ਰੰਗ ਸੁਧਾਈ"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"ਰੰਗ ਸੁਧਾਈ ਨਾਲ ਤੁਹਾਨੂੰ ਆਪਣੇ ਡੀਵਾਈਸ \'ਤੇ ਰੰਗਾਂ ਦੇ ਪ੍ਰਦਰਸ਼ਿਤ ਹੋਣ ਨੂੰ ਵਿਵਸਥਿਤ ਕਰਨ ਦਿੱਤਾ ਜਾਂਦਾ ਹੈ"</string>
+    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
+    <skip />
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> ਦੁਆਰਾ ਓਵਰਰਾਈਡ ਕੀਤਾ"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"ਲਗਭਗ <xliff:g id="TIME_REMAINING">%1$s</xliff:g> ਬਾਕੀ"</string>
@@ -516,6 +516,8 @@
     <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="2716555073132169240">"ਫ਼ੋਨ ਦਾ ਸਪੀਕਰ"</string>
+    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"ਕਨੈਕਟ ਕਰਨ ਵਿੱਚ ਸਮੱਸਿਆ ਆਈ। ਡੀਵਾਈਸ ਨੂੰ ਬੰਦ ਕਰਕੇ ਵਾਪਸ ਚਾਲੂ ਕਰੋ"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ਤਾਰ ਵਾਲਾ ਆਡੀਓ ਡੀਵਾਈਸ"</string>
     <string name="help_label" msgid="3528360748637781274">"ਮਦਦ ਅਤੇ ਵਿਚਾਰ"</string>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index f48b05f..663f3fc 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -424,7 +424,8 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalia (czerwony-zielony)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalia (niebieski-żółty)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Korekcja kolorów"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Korekcja kolorów pozwala na dostosowanie sposobu wyświetlania kolorów na urządzeniu"</string>
+    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
+    <skip />
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Nadpisana przez <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Jeszcze około <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -517,6 +518,8 @@
     <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="2716555073132169240">"Głośnik telefonu"</string>
+    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
+    <skip />
     <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>
     <string name="help_label" msgid="3528360748637781274">"Pomoc i opinie"</string>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index b9c9191..8eab928 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -424,7 +424,8 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalia (vermelho-verde)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalia (azul-amarelo)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Correção de cor"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"A correção de cor permite ajustar como as cores são exibidas no dispositivo"</string>
+    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
+    <skip />
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Substituído por <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Tempo restante aproximado: <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -515,6 +516,8 @@
     <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="2716555073132169240">"Alto-falante do smartphone"</string>
+    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
+    <skip />
     <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>
     <string name="help_label" msgid="3528360748637781274">"Ajuda e feedback"</string>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index 57e38c078..f28d70a 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -424,7 +424,8 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalia (vermelho-verde)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalia (azul-amarelo)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Correção da cor"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"A correção da cor permite-lhe ajustar a forma como as cores são apresentadas no seu dispositivo."</string>
+    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
+    <skip />
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Substituído por <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Resta(m) cerca de <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -515,6 +516,8 @@
     <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="2716555073132169240">"Altifalante do telemóvel"</string>
+    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
+    <skip />
     <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>
     <string name="help_label" msgid="3528360748637781274">"Ajuda e comentários"</string>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index b9c9191..8eab928 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -424,7 +424,8 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalia (vermelho-verde)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalia (azul-amarelo)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Correção de cor"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"A correção de cor permite ajustar como as cores são exibidas no dispositivo"</string>
+    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
+    <skip />
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Substituído por <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Tempo restante aproximado: <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -515,6 +516,8 @@
     <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="2716555073132169240">"Alto-falante do smartphone"</string>
+    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
+    <skip />
     <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>
     <string name="help_label" msgid="3528360748637781274">"Ajuda e feedback"</string>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index c2da73c..0a4e462 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -424,7 +424,8 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalie (roșu-verde)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalie (albastru-galben)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Corecția culorii"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Folosind corecția culorii, puteți ajusta modul în care se afișează culorile pe dispozitiv"</string>
+    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
+    <skip />
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Valoare înlocuită de <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Timp aproximativ rămas: <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -516,6 +517,8 @@
     <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="2716555073132169240">"Difuzorul telefonului"</string>
+    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
+    <skip />
     <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>
     <string name="help_label" msgid="3528360748637781274">"Ajutor și feedback"</string>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index efcce75..b030715 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -424,7 +424,8 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Протаномалия (красный/зеленый)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Тританомалия (синий/желтый)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Коррекция цвета"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Коррекция цвета позволяет изменить настройки цветопередачи на экране устройства."</string>
+    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
+    <skip />
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Новая настройка: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"Уровень заряда – <xliff:g id="PERCENTAGE">%1$s</xliff:g>. <xliff:g id="TIME_STRING">%2$s</xliff:g>."</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Заряда хватит примерно на <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -517,6 +518,8 @@
     <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="2716555073132169240">"Встроенный динамик"</string>
+    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Ошибка подключения. Выключите и снова включите устройство."</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Проводное аудиоустройство"</string>
     <string name="help_label" msgid="3528360748637781274">"Справка/отзыв"</string>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index 590e0e4..035a159 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"වර්ණ දුර්වලතාවය (රතු-කොළ)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"වර්ණ අන්ධතාවය (නිල්-කහ)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"වර්ණ නිවැරදි කිරීම"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"වර්ණ නිවැරදි කිරීම ඔබට ඔබේ උපාංගයෙහි වර්ණ සංදර්ශනය වන ආකාරය සීරුමාරු කිරීමට ඉඩ දේ"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"ඔබගේ උපාංගයේ වර්ණ සංදර්ශනය වන ආකාරය සීරුමාරු කරන්න. මෙය ඔබට පහත දේවල් සිදු කිරීමට අවශ්‍ය විට ප්‍රයෝජනවත් විය හැකිය:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; වර්ණ වඩාත් නිවැරදිව බැලීම&lt;/li&gt; &lt;li&gt; ඔබට අවධානය යොමු කිරීමට උදව් වීමට වර්ණ ඉවත් කිරීම&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> මගින් ඉක්මවන ලදී"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> ක් පමණ ඉතිරියි"</string>
@@ -515,6 +515,7 @@
     <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="2716555073132169240">"දුරකථන ස්පීකරය"</string>
+    <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>
     <string name="help_label" msgid="3528360748637781274">"උදවු &amp; ප්‍රතිපෝෂණ"</string>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index c817ed0..d9d5351 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -424,7 +424,8 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomália (červená a zelená)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomália (modrá a žltá)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Úprava farieb"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Úprava farieb umožňuje nastaviť spôsob zobrazovania farieb vo vašom zariadení"</string>
+    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
+    <skip />
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Prekonané predvoľbou <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Zostáva približne <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -517,6 +518,8 @@
     <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="2716555073132169240">"Reproduktor telefónu"</string>
+    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
+    <skip />
     <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>
     <string name="help_label" msgid="3528360748637781274">"Pomocník a spätná väzba"</string>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index 464b235..81b1b60 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -424,7 +424,8 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalija (rdeča – zelena)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalija (modra – rumena)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Popravljanje barv"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Popravljanje barv vam omogoča prilagajanje prikaza barv v napravi"</string>
+    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
+    <skip />
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Preglasila nastavitev: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Še približno <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -517,6 +518,8 @@
     <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="2716555073132169240">"Zvočnik telefona"</string>
+    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
+    <skip />
     <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>
     <string name="help_label" msgid="3528360748637781274">"Pomoč in povratne informacije"</string>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index a2a63e1..b71e51f 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -424,7 +424,8 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomali (e kuqe - e gjelbër)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomali (e kaltër - e verdhë)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Korrigjimi i ngjyrës"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Korrigjimi i ngjyrave të lejon të rregullosh mënyrën se si shfaqen ngjyrat në pajisjen tënde"</string>
+    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
+    <skip />
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Mbivendosur nga <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Rreth <xliff:g id="TIME_REMAINING">%1$s</xliff:g> të mbetura"</string>
@@ -515,6 +516,8 @@
     <string name="zen_mode_forever" msgid="3339224497605461291">"Deri sa ta çaktivizosh"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"Pikërisht tani"</string>
     <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Altoparlanti i telefonit"</string>
+    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
+    <skip />
     <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>
     <string name="help_label" msgid="3528360748637781274">"Ndihma dhe komentet"</string>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index 2119303..4f37180c 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Протаномалија (црвено-зелено)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Тританомалија (плаво-жуто)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Корекција боја"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Корекција боја вам омогућава да прилагодите начин на који се боје приказују на уређају"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Прилагодите начин на који се боје приказују на уређају. То може да буде корисно када желите:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; да вам се боје тачније приказују&lt;/li&gt; &lt;li&gt; да уклоните боје како бисте се фокусирали&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Замењује га <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g>–<xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Преостало је око <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -516,6 +516,7 @@
     <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="2716555073132169240">"Звучник телефона"</string>
+    <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>
     <string name="help_label" msgid="3528360748637781274">"Помоћ и повратне информације"</string>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index c7a2169..2ec2ded 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -424,7 +424,8 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomali (rött-grönt)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomali (blått-gult)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Färgkorrigering"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Med färgkorrigering kan du ändra hur färger visas på enheten"</string>
+    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
+    <skip />
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Har åsidosatts av <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Cirka <xliff:g id="TIME_REMAINING">%1$s</xliff:g> kvar"</string>
@@ -515,6 +516,8 @@
     <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="2716555073132169240">"Telefonens högtalare"</string>
+    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
+    <skip />
     <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>
     <string name="help_label" msgid="3528360748637781274">"Hjälp och feedback"</string>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index 60014f4..410a4aa 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaly (nyekundu-kijani)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaly (samawati-manjano)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Usahihishaji wa rangi"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Urekebishaji rangi hukuruhusu ubadilishe jinsi rangi zinavyoonyeshwa kwenye kifaa chako"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Badilisha jinsi rangi zinavyoonekana kwenye kifaa chako. Hali hii inaweza kuwa muhimu unapotaka:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; Kuona rangi kwa usahihi zaidi&lt;/li&gt; &lt;li&gt; Kuondoa rangi ili kukusaidia kuwa makini&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Imetanguliwa na <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Zimesalia takribani <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -515,6 +515,7 @@
     <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="2716555073132169240">"Spika ya simu"</string>
+    <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>
     <string name="help_label" msgid="3528360748637781274">"Usaidizi na maoni"</string>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index 82cce12..14eb25d 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -424,7 +424,8 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"நிறம் அடையாளங்காண முடியாமை (சிவப்பு-பச்சை)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"நிறம் அடையாளங்காண முடியாமை (நீலம்-மஞ்சள்)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"வண்ணத்திருத்தம்"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"கலர் கரெக்‌ஷனைப் பயன்படுத்தி உங்கள் சாதனத்தில் வண்ணங்கள் காண்பிக்கப்படும் விதத்தைச் சரிசெய்யலாம்"</string>
+    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
+    <skip />
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> மூலம் மேலெழுதப்பட்டது"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"கிட்டத்தட்ட <xliff:g id="TIME_REMAINING">%1$s</xliff:g> மீதமுள்ளது"</string>
@@ -515,6 +516,8 @@
     <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="2716555073132169240">"மொபைல் ஸ்பீக்கர்"</string>
+    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"இணைப்பதில் சிக்கல். சாதனத்தை ஆஃப் செய்து மீண்டும் ஆன் செய்யவும்"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"வயருடன்கூடிய ஆடியோ சாதனம்"</string>
     <string name="help_label" msgid="3528360748637781274">"உதவியும் கருத்தும்"</string>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index 3b04eb4..e652ab7 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -424,7 +424,8 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"ప్రొటానోమలీ (ఎరుపు-ఆకుపచ్చ రంగు)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"ట్రైటనోమలీ (నీలం-పసుపు రంగు)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"కలర్ సరిచేయడం"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"\'కలర్ సరిచేయడం\' అనే ఫీచర్ సాయంతో, మీ పరికరంలో రంగులు కనిపించే పద్ధతిని మీరు మార్చగలుగుతారు"</string>
+    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
+    <skip />
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> ద్వారా భర్తీ చేయబడింది"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> సమయం మిగిలి ఉంది"</string>
@@ -515,6 +516,8 @@
     <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="2716555073132169240">"ఫోన్ స్పీకర్"</string>
+    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"కనెక్ట్ చేయడంలో సమస్య ఉంది. పరికరాన్ని ఆఫ్ చేసి, ఆపై తిరిగి ఆన్ చేయండి"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"వైర్ గల ఆడియో పరికరం"</string>
     <string name="help_label" msgid="3528360748637781274">"సహాయం &amp; ఫీడ్‌బ్యాక్"</string>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index a970321..4bd7b6d 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"ตาบอดจางสีแดง (สีแดง/เขียว)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"ตาบอดจางสีน้ำเงิน (สีน้ำเงิน/เหลือง)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"การแก้สี"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"การแก้สีช่วยให้คุณปรับการแสดงสีในอุปกรณ์ได้"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"ปรับวิธีแสดงสีในอุปกรณ์ การดำเนินการนี้จะเป็นประโยชน์เมื่อคุณต้องการดังนี้&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; เห็นสีได้ถูกต้องยิ่งขึ้น&lt;/li&gt; &lt;li&gt; นำสีออกเพื่อช่วยให้เห็นชัดเจนยิ่งขึ้น&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"แทนที่โดย <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"เหลืออีกประมาณ <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -515,6 +515,7 @@
     <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="2716555073132169240">"ลำโพงโทรศัพท์"</string>
+    <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>
     <string name="help_label" msgid="3528360748637781274">"ความช่วยเหลือและความคิดเห็น"</string>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index bedd005..e56e5b9 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaly (pula-berde)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaly (asul-dilaw)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Pagtatama ng kulay"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Nagbibigay-daan sa iyo ang pagtatama ng kulay na maisaayos kung paano ipinapakita ang mga kulay sa iyong device"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Isaayos kung paano ipinapakita ang mga kulay sa iyong device. Makakatulong ito kapag gusto mong:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; Makakita ng mas tumpak na mga kulay&lt;/li&gt; &lt;li&gt; Mag-alis ng mga kulay para matulungan kang mag-focus&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Na-override ng <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Humigit-kumulang <xliff:g id="TIME_REMAINING">%1$s</xliff:g> ang natitira"</string>
@@ -515,6 +515,7 @@
     <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="2716555073132169240">"Speaker ng telepono"</string>
+    <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>
     <string name="help_label" msgid="3528360748637781274">"Tulong at feedback"</string>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index 2b2b44e..5fbf5d4 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -424,7 +424,8 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomali (kırmızı-yeşil)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomali (mavi-sarı)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Renk düzeltme"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Renk düzeltme, renklerin cihazınızda nasıl görüntüleneceğini düzenlemenize olanak sağlar."</string>
+    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
+    <skip />
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> tarafından geçersiz kılındı"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Yaklaşık <xliff:g id="TIME_REMAINING">%1$s</xliff:g> kaldı"</string>
@@ -515,6 +516,8 @@
     <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="2716555073132169240">"Telefon hoparlörü"</string>
+    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
+    <skip />
     <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>
     <string name="help_label" msgid="3528360748637781274">"Yardım ve geri bildirim"</string>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index 9c5e2aa..4511a4b 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -424,7 +424,8 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Протаномалія (червоний – зелений)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Тританомалія (синій – жовтий)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Корекція кольору"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Корекція кольору дає змогу регулювати відтінки зображення на екрані пристрою"</string>
+    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
+    <skip />
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Замінено на <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Залишилося приблизно <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -517,6 +518,8 @@
     <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="2716555073132169240">"Динамік телефона"</string>
+    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Не вдається підключитися. Перезавантажте пристрій."</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Дротовий аудіопристрій"</string>
     <string name="help_label" msgid="3528360748637781274">"Довідка й відгуки"</string>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index ee06623..e61d281 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -424,7 +424,8 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"‏Protanomaly (سرخ سبز)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"‏Tritanomaly (نیلا پیلا)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"رنگ کی اصلاح"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"رنگ کی اصلاح آپ کو یہ ایڈجسٹ کرنے کی سہولت دیتی ہے کہ آپ کے آلے پر رنگ کیسے ڈسپلے کئے جاتے ہیں"</string>
+    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
+    <skip />
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> کے ذریعہ منسوخ کردیا گیا"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"تقریباً <xliff:g id="TIME_REMAINING">%1$s</xliff:g> باقی ہے"</string>
@@ -515,6 +516,8 @@
     <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="2716555073132169240">"فون اسپیکر"</string>
+    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"منسلک کرنے میں مسئلہ پیش آ گیا۔ آلہ کو آف اور بیک آن کریں"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"وائرڈ آڈیو آلہ"</string>
     <string name="help_label" msgid="3528360748637781274">"مدد اور تاثرات"</string>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index 29c0f91..0730c6c 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaliya (qizil/yashil)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaliya (ko‘k/sariq)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Rangni tuzatish"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Ranglarni tuzatish orqali qurilmangizda ranglar qanday chiqishini tuzatish mumkin"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Qurilmadagi ranglar qanday chiqishini moslash Bu quyidagi amallarni bajarishga yordam beradi:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; Ranglarni yanada aniq koʻrish&lt;/li&gt; &lt;li&gt; Diqqatni jamlash uchun ranglarni olib tashlash&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> bilan almashtirildi"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Taxminan <xliff:g id="TIME_REMAINING">%1$s</xliff:g> qoldi"</string>
@@ -515,6 +515,7 @@
     <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="2716555073132169240">"Telefon karnayi"</string>
+    <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>
     <string name="help_label" msgid="3528360748637781274">"Yordam/fikr-mulohaza"</string>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index 39beecd..148ed89 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Mù màu đỏ không hoàn toàn (đỏ-xanh lục)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Mù màu (xanh lam-vàng)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Chỉnh màu"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Với chế độ chỉnh màu, bạn có thể điều chỉnh cách các màu hiển thị trên thiết bị"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Điều chỉnh cách các màu hiển thị trên thiết bị. Tùy chọn này có thể hữu ích khi bạn muốn:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; Xem các màu chính xác hơn&lt;/li&gt; &lt;li&gt; Loại bỏ các màu để giúp bạn tập trung&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Bị ghi đè bởi <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Còn khoảng <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -515,6 +515,7 @@
     <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="2716555073132169240">"Loa điện thoại"</string>
+    <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>
     <string name="help_label" msgid="3528360748637781274">"Trợ giúp và phản hồi"</string>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index 010a4dc..7d1bde3 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -424,7 +424,8 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"红色弱视(红绿不分)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"蓝色弱视(蓝黄不分)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"色彩校正"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"借助色彩校正功能,您可以调整设备上的颜色显示方式"</string>
+    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
+    <skip />
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"已被“<xliff:g id="TITLE">%1$s</xliff:g>”覆盖"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"大约还可使用 <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -515,6 +516,8 @@
     <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="2716555073132169240">"手机扬声器"</string>
+    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
+    <skip />
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"连接时遇到问题。请关闭并重新开启设备"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"有线音频设备"</string>
     <string name="help_label" msgid="3528360748637781274">"帮助和反馈"</string>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index 1e06a91..06b5cd0 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"紅色弱視 (紅綠)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"藍色弱視 (藍黃)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"色彩校正"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"色彩校正功能讓您調整裝置顯示的顏色"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"調整裝置顯示顏色的方式。這項設定適用於以下情況:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; 想讓裝置更準確地顯示顏色&lt;/li&gt; &lt;li&gt; 移除顏色以提高專注力&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"已由「<xliff:g id="TITLE">%1$s</xliff:g>」覆寫"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"還有大約 <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -515,6 +515,7 @@
     <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="2716555073132169240">"手機喇叭"</string>
+    <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>
     <string name="help_label" msgid="3528360748637781274">"說明與意見反映"</string>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index 2c077e7..dcfc599 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"紅色弱視 (紅-綠)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"藍色弱視 (藍-黃)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"色彩校正"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"色彩校正可讓你調整裝置上顯示的顏色"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"調整裝置顯示顏色的方式。這項設定適用於以下情況:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; 想讓裝置更準確地顯示顏色&lt;/li&gt; &lt;li&gt; 移除顏色以提高專注力&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"已改為<xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"還能使用約 <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -515,6 +515,7 @@
     <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="2716555073132169240">"手機喇叭"</string>
+    <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>
     <string name="help_label" msgid="3528360748637781274">"說明與意見回饋"</string>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index 87cf75b..2297cbe 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -424,7 +424,8 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"I-Protanomaly (bomvu-luhlaza)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"I-Tritanomaly (luhlaza okwesibhakabhaka-phuzi)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Ukulungiswa kombala"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Ukulungisa umbala kukuvumela ukuthi ulungise indlela imibala eboniswa ngayo kudivayisi yakho"</string>
+    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
+    <skip />
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Igitshezwe ngaphezulu yi-<xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Cishe u-<xliff:g id="TIME_REMAINING">%1$s</xliff:g> osele"</string>
@@ -515,6 +516,8 @@
     <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="2716555073132169240">"Isipikha sefoni"</string>
+    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
+    <skip />
     <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>
     <string name="help_label" msgid="3528360748637781274">"Usizo nempendulo"</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index ff70eda..9c0c80b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -25,6 +25,7 @@
 import android.media.AudioManager;
 import android.net.ConnectivityManager;
 import android.net.NetworkCapabilities;
+import android.net.TetheringManager;
 import android.net.vcn.VcnTransportInfo;
 import android.net.wifi.WifiInfo;
 import android.os.BatteryManager;
@@ -90,10 +91,10 @@
      * Return string resource that best describes combination of tethering
      * options available on this device.
      */
-    public static int getTetheringLabel(ConnectivityManager cm) {
-        String[] usbRegexs = cm.getTetherableUsbRegexs();
-        String[] wifiRegexs = cm.getTetherableWifiRegexs();
-        String[] bluetoothRegexs = cm.getTetherableBluetoothRegexs();
+    public static int getTetheringLabel(TetheringManager tm) {
+        String[] usbRegexs = tm.getTetherableUsbRegexs();
+        String[] wifiRegexs = tm.getTetherableWifiRegexs();
+        String[] bluetoothRegexs = tm.getTetherableBluetoothRegexs();
 
         boolean usbAvailable = usbRegexs.length != 0;
         boolean wifiAvailable = wifiRegexs.length != 0;
diff --git a/packages/SettingsLib/src/com/android/settingslib/mobile/TelephonyIcons.java b/packages/SettingsLib/src/com/android/settingslib/mobile/TelephonyIcons.java
index e3413aa..f8565bc 100644
--- a/packages/SettingsLib/src/com/android/settingslib/mobile/TelephonyIcons.java
+++ b/packages/SettingsLib/src/com/android/settingslib/mobile/TelephonyIcons.java
@@ -319,19 +319,19 @@
     }
 
     public static final int[] WIFI_CALL_STRENGTH_ICONS = {
-        R.drawable.ic_wifi_call_strength_1,
+        R.drawable.ic_wifi_call_strength_0,
         R.drawable.ic_wifi_call_strength_1,
         R.drawable.ic_wifi_call_strength_2,
         R.drawable.ic_wifi_call_strength_3,
-        R.drawable.ic_wifi_call_strength_3
+        R.drawable.ic_wifi_call_strength_4
     };
 
     public static final int[] MOBILE_CALL_STRENGTH_ICONS = {
-        R.drawable.ic_mobile_call_strength_1,
+        R.drawable.ic_mobile_call_strength_0,
         R.drawable.ic_mobile_call_strength_1,
         R.drawable.ic_mobile_call_strength_2,
         R.drawable.ic_mobile_call_strength_3,
-        R.drawable.ic_mobile_call_strength_3
+        R.drawable.ic_mobile_call_strength_4
     };
 }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/net/UidDetailProvider.java b/packages/SettingsLib/src/com/android/settingslib/net/UidDetailProvider.java
index dad82ee..02326ea 100644
--- a/packages/SettingsLib/src/com/android/settingslib/net/UidDetailProvider.java
+++ b/packages/SettingsLib/src/com/android/settingslib/net/UidDetailProvider.java
@@ -26,7 +26,7 @@
 import android.content.pm.UserInfo;
 import android.content.res.Resources;
 import android.graphics.drawable.Drawable;
-import android.net.ConnectivityManager;
+import android.net.TetheringManager;
 import android.net.TrafficStats;
 import android.os.Process;
 import android.os.RemoteException;
@@ -123,9 +123,8 @@
                 detail.icon = pm.getDefaultActivityIcon();
                 return detail;
             case TrafficStats.UID_TETHERING:
-                final ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService(
-                        Context.CONNECTIVITY_SERVICE);
-                detail.label = res.getString(Utils.getTetheringLabel(cm));
+                final TetheringManager tm = mContext.getSystemService(TetheringManager.class);
+                detail.label = res.getString(Utils.getTetheringLabel(tm));
                 detail.icon = pm.getDefaultActivityIcon();
                 return detail;
             case Process.OTA_UPDATE_UID:
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/widget/UsageProgressBarPreferenceTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/widget/UsageProgressBarPreferenceTest.java
index 1a8477d..fe76b06 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/widget/UsageProgressBarPreferenceTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/widget/UsageProgressBarPreferenceTest.java
@@ -127,4 +127,20 @@
         assertThat(customContent.getChildAt(0)).isEqualTo(imageView);
         assertThat(customContent.getVisibility()).isEqualTo(View.VISIBLE);
     }
+
+    @Test
+    public void setCustomContent_setImageViewTwice_oneAndLatestChild() {
+        final ImageView imageViewLegacy = mock(ImageView.class);
+        final ImageView imageViewNew = mock(ImageView.class);
+        mUsageProgressBarPreference.setCustomContent(imageViewLegacy);
+        mUsageProgressBarPreference.setCustomContent(imageViewNew);
+
+        mUsageProgressBarPreference.onBindViewHolder(mViewHolder);
+
+        final FrameLayout customContent =
+                (FrameLayout) mViewHolder.findViewById(R.id.custom_content);
+        assertThat(customContent.getChildCount()).isEqualTo(1);
+        assertThat(customContent.getChildAt(0)).isEqualTo(imageViewNew);
+        assertThat(customContent.getVisibility()).isEqualTo(View.VISIBLE);
+    }
 }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/MainSwitchBarTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/MainSwitchBarTest.java
index 9347609..a807753 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/MainSwitchBarTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/MainSwitchBarTest.java
@@ -23,8 +23,6 @@
 import android.widget.Switch;
 import android.widget.TextView;
 
-import com.android.settingslib.RestrictedLockUtils;
-
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -80,11 +78,4 @@
 
         assertThat(mBar.getVisibility()).isEqualTo(View.GONE);
     }
-
-    @Test
-    public void disabledByAdmin_shouldDelegateToRestrictedIcon() {
-        mBar.setDisabledByAdmin(new RestrictedLockUtils.EnforcedAdmin());
-
-        assertThat(mBar.getDelegatingView().getId()).isEqualTo(R.id.restricted_icon);
-    }
 }
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index eed1c69..a28a1e3 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -296,6 +296,9 @@
     <!-- Permission needed for CTS test - MusicRecognitionManagerTest -->
     <uses-permission android:name="android.permission.MANAGE_MUSIC_RECOGNITION" />
 
+    <!-- Permission needed for CTS test - CtsVoiceRecognitionTestCases -->
+    <uses-permission android:name="android.permission.MANAGE_SPEECH_RECOGNITION" />
+
     <!-- Permissions required to test ambient display. -->
     <uses-permission android:name="android.permission.READ_DREAM_STATE"/>
     <uses-permission android:name="android.permission.WRITE_DREAM_STATE"/>
@@ -407,7 +410,6 @@
     <!-- Permission required for GTS test - GtsAssistIntentTestCases -->
     <uses-permission android:name="android.permission.MANAGE_SOUND_TRIGGER" />
     <uses-permission android:name="android.permission.CAPTURE_AUDIO_HOTWORD" />
-    <uses-permission android:name="android.permission.BIND_VOICE_INTERACTION" />
     <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
     <uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION" />
     <uses-permission android:name="android.permission.BIND_RESUME_ON_REBOOT_SERVICE" />
diff --git a/packages/SystemUI/res/drawable/end_guest_button_background.xml b/packages/SystemUI/res/drawable/end_guest_button_background.xml
deleted file mode 100644
index 5644b65..0000000
--- a/packages/SystemUI/res/drawable/end_guest_button_background.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?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
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT 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"
-       android:shape="rectangle">
-    <stroke
-        android:width="@dimen/end_guest_button_border_size"
-        android:color="?android:attr/colorControlHighlight" />
-    <corners android:radius="@dimen/end_guest_button_corner_radius" />
-</shape>
diff --git a/packages/SystemUI/res/layout/keyguard_user_switcher.xml b/packages/SystemUI/res/layout/keyguard_user_switcher.xml
index 253c03e..7aafd89 100644
--- a/packages/SystemUI/res/layout/keyguard_user_switcher.xml
+++ b/packages/SystemUI/res/layout/keyguard_user_switcher.xml
@@ -30,34 +30,4 @@
         android:layout_gravity="top|end"
         android:gravity="end" />
 
-    <LinearLayout
-        android:id="@+id/end_guest_button"
-        android:layout_height="@dimen/end_guest_button_layout_height"
-        android:layout_width="wrap_content"
-        android:layout_gravity="center_horizontal|bottom"
-        android:layout_centerHorizontal="true"
-        android:layout_marginBottom="@dimen/end_guest_button_margin_bottom"
-        android:orientation="horizontal"
-        android:gravity="center"
-        android:paddingLeft="@dimen/end_guest_button_padding_horizontal"
-        android:paddingRight="@dimen/end_guest_button_padding_horizontal"
-        android:background="@drawable/end_guest_button_background"
-        android:visibility="gone">
-        <ImageView
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:gravity="center"
-            android:src="@drawable/ic_exit_to_app"
-            android:background="@android:color/transparent"
-            android:color="?attr/wallpaperTextColor" />
-        <TextView
-            android:layout_height="wrap_content"
-            android:layout_width="wrap_content"
-            android:gravity="center"
-            android:fontFamily="@*android:string/config_bodyFontFamilyMedium"
-            android:textColor="?attr/wallpaperTextColor"
-            android:textSize="13sp"
-            android:text="@string/guest_exit_button" />
-    </LinearLayout>
-
 </com.android.systemui.statusbar.policy.KeyguardUserSwitcherView>
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index bbb6107..6b9b365 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -69,7 +69,7 @@
             android:id="@+id/qs_edge_guideline"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            systemui:layout_constraintGuide_percent="0.4"
+            systemui:layout_constraintGuide_percent="0.5"
             android:orientation="vertical"/>
 
         <com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout
diff --git a/packages/SystemUI/res/layout/tv_notification_panel.xml b/packages/SystemUI/res/layout/tv_notification_panel.xml
index 8f00a72..eae44c8 100644
--- a/packages/SystemUI/res/layout/tv_notification_panel.xml
+++ b/packages/SystemUI/res/layout/tv_notification_panel.xml
@@ -20,7 +20,7 @@
     android:layout_width="@dimen/tv_notification_panel_width"
     android:layout_height="match_parent"
     android:layout_gravity="end"
-    android:background="@color/tv_notification_background_color"
+    android:background="@android:color/transparent"
     android:orientation="vertical">
 
     <TextView
diff --git a/packages/SystemUI/res/values/colors_tv.xml b/packages/SystemUI/res/values/colors_tv.xml
index 0961f50..64c942de8 100644
--- a/packages/SystemUI/res/values/colors_tv.xml
+++ b/packages/SystemUI/res/values/colors_tv.xml
@@ -34,6 +34,7 @@
     <color name="tv_volume_dialog_seek_bar_fill">#FFF8F9FA</color>
     <color name="tv_volume_dialog_accent">#FFDADCE0</color>
 
-    <color name="tv_notification_background_color">#383838</color>
+    <color name="tv_notification_default_background_color">#383838</color>
+    <color name="tv_notification_blur_background_color">#a0383838</color>
     <color name="tv_notification_text_color">#FFFFFF</color>
 </resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index ea0ea5e..392eb49 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1333,13 +1333,6 @@
     <!-- Keyguard user switcher -->
     <dimen name="kg_user_switcher_text_size">16sp</dimen>
 
-    <!-- End guest session button -->
-    <dimen name="end_guest_button_layout_height">32dp</dimen>
-    <dimen name="end_guest_button_padding_horizontal">16dp</dimen>
-    <dimen name="end_guest_button_margin_bottom">96dp</dimen>
-    <dimen name="end_guest_button_border_size">1dp</dimen>
-    <dimen name="end_guest_button_corner_radius">16dp</dimen>
-
     <!-- Opacity at which the background for the shutdown UI will be drawn. -->
     <item name="shutdown_scrim_behind_alpha" format="float" type="dimen">0.95</item>
 
diff --git a/packages/SystemUI/res/values/dimens_tv.xml b/packages/SystemUI/res/values/dimens_tv.xml
index 9545bfd..5bd95eb 100644
--- a/packages/SystemUI/res/values/dimens_tv.xml
+++ b/packages/SystemUI/res/values/dimens_tv.xml
@@ -16,4 +16,5 @@
   -->
 <resources>
     <dimen name="tv_notification_panel_width">360dp</dimen>
+    <dimen name="tv_notification_blur_radius">100dp</dimen>
 </resources>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index b5ded01..783f80c 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1121,9 +1121,6 @@
     <!-- Name for a freshly added user [CHAR LIMIT=30] -->
     <string name="user_new_user_name">New user</string>
 
-    <!-- Label for button that exits guest session and clears the guest user data [CHAR LIMIT=50]-->
-    <string name="guest_exit_button">End guest session</string>
-
     <!-- Title of the confirmation dialog when exiting guest session [CHAR LIMIT=NONE] -->
     <string name="guest_exit_guest_dialog_title">Remove guest?</string>
 
diff --git a/packages/SystemUI/res/values/styles_tv.xml b/packages/SystemUI/res/values/styles_tv.xml
index cb433f3..3e09026 100644
--- a/packages/SystemUI/res/values/styles_tv.xml
+++ b/packages/SystemUI/res/values/styles_tv.xml
@@ -30,5 +30,6 @@
         <item name="android:backgroundDimEnabled">false</item>
         <item name="android:windowNoTitle">true</item>
         <item name="android:windowContentOverlay">@null</item>
+        <item name="android:windowIsFloating">true</item>
     </style>
 </resources>
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index 3296cb8..1d789ca 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -20,7 +20,10 @@
 import static com.android.internal.util.Preconditions.checkNotNull;
 
 import android.annotation.SuppressLint;
+import android.content.BroadcastReceiver;
 import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.res.Resources;
 import android.graphics.PixelFormat;
 import android.graphics.Point;
@@ -29,6 +32,8 @@
 import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
 import android.hardware.fingerprint.IUdfpsOverlayController;
 import android.os.SystemClock;
+import android.hardware.fingerprint.IUdfpsOverlayControllerCallback;
+import android.os.RemoteException;
 import android.util.Log;
 import android.view.Gravity;
 import android.view.LayoutInflater;
@@ -91,11 +96,8 @@
     private long mTouchLogTime;
 
     @Nullable private UdfpsView mView;
-    // Indicates whether the overlay has been requested.
-    private boolean mIsOverlayRequested;
-    // Reason the overlay has been requested. See IUdfpsOverlayController for definitions.
-    private int mRequestReason;
-    @Nullable UdfpsEnrollHelper mEnrollHelper;
+    // The current request from FingerprintService. Null if no current request.
+    @Nullable ServerRequest mServerRequest;
 
     // The fingerprint AOD trigger doesn't provide an ACTION_UP/ACTION_CANCEL event to tell us when
     // to turn off high brightness mode. To get around this limitation, the state of the AOD
@@ -104,39 +106,84 @@
     private boolean mIsAodInterruptActive;
     @Nullable private Runnable mCancelAodTimeoutAction;
 
+    /**
+     * Keeps track of state within a single FingerprintService request. Note that this state
+     * persists across configuration changes, etc, since it is considered a single request.
+     *
+     * TODO: Perhaps we can move more global variables into here
+     */
+    private static class ServerRequest {
+        // Reason the overlay has been requested. See IUdfpsOverlayController for definitions.
+        final int mRequestReason;
+        @NonNull final IUdfpsOverlayControllerCallback mCallback;
+        @Nullable final UdfpsEnrollHelper mEnrollHelper;
+
+        ServerRequest(int requestReason, @NonNull IUdfpsOverlayControllerCallback callback,
+                @Nullable UdfpsEnrollHelper enrollHelper) {
+            mRequestReason = requestReason;
+            mCallback = callback;
+            mEnrollHelper = enrollHelper;
+        }
+
+        void onEnrollmentProgress(int remaining) {
+            if (mEnrollHelper != null) {
+                mEnrollHelper.onEnrollmentProgress(remaining);
+            }
+        }
+
+        void onEnrollmentHelp() {
+            if (mEnrollHelper != null) {
+                mEnrollHelper.onEnrollmentHelp();
+            }
+        }
+
+        void onUserCanceled() {
+            try {
+                mCallback.onUserCanceled();
+            } catch (RemoteException e) {
+                Log.e(TAG, "Remote exception", e);
+            }
+        }
+    }
+
     public class UdfpsOverlayController extends IUdfpsOverlayController.Stub {
         @Override
-        public void showUdfpsOverlay(int sensorId, int reason) {
+        public void showUdfpsOverlay(int sensorId, int reason,
+                @NonNull IUdfpsOverlayControllerCallback callback) {
+            final UdfpsEnrollHelper enrollHelper;
             if (reason == IUdfpsOverlayController.REASON_ENROLL_FIND_SENSOR
                     || reason == IUdfpsOverlayController.REASON_ENROLL_ENROLLING) {
-                mEnrollHelper = new UdfpsEnrollHelper(mContext, reason);
+                enrollHelper = new UdfpsEnrollHelper(mContext, reason);
             } else {
-                mEnrollHelper = null;
+                enrollHelper = null;
             }
-            UdfpsController.this.showOverlay(reason);
+
+            mServerRequest = new ServerRequest(reason, callback, enrollHelper);
+            updateOverlay();
         }
 
         @Override
         public void hideUdfpsOverlay(int sensorId) {
-            UdfpsController.this.hideOverlay();
+            mServerRequest = null;
+            updateOverlay();
         }
 
         @Override
         public void onEnrollmentProgress(int sensorId, int remaining) {
-            if (mEnrollHelper == null) {
-                Log.e(TAG, "onEnrollProgress received but helper is null");
+            if (mServerRequest == null) {
+                Log.e(TAG, "onEnrollProgress received but serverRequest is null");
                 return;
             }
-            mEnrollHelper.onEnrollmentProgress(remaining);
+            mServerRequest.onEnrollmentProgress(remaining);
         }
 
         @Override
         public void onEnrollmentHelp(int sensorId) {
-            if (mEnrollHelper == null) {
-                Log.e(TAG, "onEnrollmentHelp received but helper is null");
+            if (mServerRequest == null) {
+                Log.e(TAG, "onEnrollmentHelp received but serverRequest is null");
                 return;
             }
-            mEnrollHelper.onEnrollmentHelp();
+            mServerRequest.onEnrollmentHelp();
         }
 
         @Override
@@ -165,6 +212,19 @@
         return (float) Math.sqrt(Math.pow(vx, 2.0) + Math.pow(vy, 2.0));
     }
 
+    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (mServerRequest != null
+                    && Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(intent.getAction())) {
+                Log.d(TAG, "ACTION_CLOSE_SYSTEM_DIALOGS received");
+                mServerRequest.onUserCanceled();
+                mServerRequest = null;
+                updateOverlay();
+            }
+        }
+    };
+
     @SuppressLint("ClickableViewAccessibility")
     private final UdfpsView.OnTouchListener mOnTouchListener = (view, event) -> {
         UdfpsView udfpsView = (UdfpsView) view;
@@ -270,6 +330,7 @@
                 WindowManager.LayoutParams.TYPE_BOOT_PROGRESS,
                 WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
                         | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+                        | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                         | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
                 PixelFormat.TRANSLUCENT);
         mCoreLayoutParams.setTitle(TAG);
@@ -280,6 +341,10 @@
         mCoreLayoutParams.privateFlags = WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
 
         mFingerprintManager.setUdfpsOverlayController(new UdfpsOverlayController());
+
+        final IntentFilter filter = new IntentFilter();
+        filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
+        context.registerReceiver(mBroadcastReceiver, filter);
     }
 
     @Nullable
@@ -314,27 +379,9 @@
                 mSensorProps.sensorLocationY + mSensorProps.sensorRadius);
     }
 
-    private void showOverlay(int reason) {
-        if (mIsOverlayRequested) {
-            return;
-        }
-        mIsOverlayRequested = true;
-        mRequestReason = reason;
-        updateOverlay();
-    }
-
-    private void hideOverlay() {
-        if (!mIsOverlayRequested) {
-            return;
-        }
-        mIsOverlayRequested = false;
-        mRequestReason = IUdfpsOverlayController.REASON_UNKNOWN;
-        updateOverlay();
-    }
-
     private void updateOverlay() {
-        if (mIsOverlayRequested) {
-            showUdfpsOverlay(mRequestReason);
+        if (mServerRequest != null) {
+            showUdfpsOverlay(mServerRequest.mRequestReason);
         } else {
             hideUdfpsOverlay();
         }
@@ -427,7 +474,7 @@
             case IUdfpsOverlayController.REASON_ENROLL_ENROLLING: {
                 final UdfpsAnimationViewEnroll view = (UdfpsAnimationViewEnroll)
                         inflater.inflate(R.layout.udfps_animation_view_enroll, null, false);
-                view.setEnrollHelper(mEnrollHelper);
+                view.setEnrollHelper(mServerRequest.mEnrollHelper);
                 return view;
             }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileViewHorizontal.kt b/packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileViewHorizontal.kt
index 4ffcd8c..f8c0dd4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileViewHorizontal.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileViewHorizontal.kt
@@ -1,7 +1,6 @@
 package com.android.systemui.qs.customize
 
 import android.content.Context
-import android.graphics.drawable.Drawable
 import android.view.View
 import com.android.systemui.plugins.qs.QSIconView
 import com.android.systemui.plugins.qs.QSTile
@@ -42,9 +41,4 @@
     override fun changeState(state: QSTile.State) {
         handleStateChanged(state)
     }
-
-    override fun newTileBackground(): Drawable? {
-        super.newTileBackground()
-        return paintDrawable
-    }
 }
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewHorizontal.kt b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewHorizontal.kt
index 231037f..328c2c3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewHorizontal.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewHorizontal.kt
@@ -21,8 +21,8 @@
 import android.content.res.ColorStateList
 import android.graphics.Color
 import android.graphics.drawable.Drawable
-import android.graphics.drawable.PaintDrawable
-import android.graphics.drawable.RippleDrawable
+import android.graphics.drawable.ShapeDrawable
+import android.graphics.drawable.shapes.RoundRectShape
 import android.service.quicksettings.Tile.STATE_ACTIVE
 import android.view.Gravity
 import android.widget.LinearLayout
@@ -34,13 +34,14 @@
 
 // Placeholder
 private const val CORNER_RADIUS = 40f
+private val RADII = (1..8).map { CORNER_RADIUS }.toFloatArray()
 
 open class QSTileViewHorizontal(
     context: Context,
     icon: QSIconView
 ) : QSTileView(context, icon, false) {
 
-    protected var paintDrawable: PaintDrawable? = null
+    protected var backgroundDrawable: ShapeDrawable? = null
     private var paintColor = Color.WHITE
     private var paintAnimator: ValueAnimator? = null
 
@@ -74,28 +75,13 @@
     }
 
     override fun newTileBackground(): Drawable? {
-        val d = super.newTileBackground()
-        if (paintDrawable == null) {
-            paintDrawable = PaintDrawable(paintColor).apply {
-                setCornerRadius(CORNER_RADIUS)
-            }
-        }
-        if (d is RippleDrawable) {
-            d.addLayer(paintDrawable)
-            return d
-        } else {
-            return paintDrawable
-        }
+        backgroundDrawable = ShapeDrawable(RoundRectShape(RADII, null, null))
+        return backgroundDrawable
     }
 
     override fun setClickable(clickable: Boolean) {
         super.setClickable(clickable)
         background = mTileBackground
-        if (clickable && mShowRippleEffect) {
-            mRipple?.setHotspotBounds(left, top, right, bottom)
-        } else {
-            mRipple?.setHotspotBounds(0, 0, 0, 0)
-        }
     }
 
     override fun handleStateChanged(state: QSTile.State) {
@@ -110,11 +96,10 @@
         } else {
             if (newColor != paintColor) {
                 clearAnimator()
-                paintDrawable?.paint?.color = newColor
-                paintDrawable?.invalidateSelf()
+                backgroundDrawable?.setTintList(ColorStateList.valueOf(newColor))
+                paintColor = newColor
             }
         }
-        paintColor = newColor
     }
 
     private fun animateToNewState(newColor: Int) {
@@ -123,8 +108,9 @@
             paintAnimator = ValueAnimator.ofArgb(paintColor, newColor)
                 .setDuration(QSIconViewImpl.QS_ANIM_LENGTH).apply {
                     addUpdateListener { animation: ValueAnimator ->
-                        paintDrawable?.paint?.color = animation.animatedValue as Int
-                        paintDrawable?.invalidateSelf()
+                        val c = animation.animatedValue as Int
+                        backgroundDrawable?.setTintList(ColorStateList.valueOf(c))
+                        paintColor = c
                     }
                     start()
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
index 4bf27e2..c46cc4f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
@@ -71,7 +71,7 @@
 
     @Override
     public Intent getLongClickIntent() {
-        return new Intent(Settings.ACTION_DISPLAY_SETTINGS);
+        return new Intent(Settings.ACTION_AUTO_ROTATE_SETTINGS);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ImageExporter.java b/packages/SystemUI/src/com/android/systemui/screenshot/ImageExporter.java
index 8fc2830..bc8adc9 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ImageExporter.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ImageExporter.java
@@ -41,6 +41,7 @@
 
 import java.io.File;
 import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.time.Duration;
@@ -110,6 +111,39 @@
     }
 
     /**
+     * Stores the given Bitmap to a temp file.
+     */
+    ListenableFuture<File> exportAsTempFile(Executor executor, Bitmap bitmap) {
+        return CallbackToFutureAdapter.getFuture(
+                (completer) -> {
+                    executor.execute(() -> {
+                        File cachePath;
+                        try {
+                            cachePath = File.createTempFile("long_screenshot_cache_", ".tmp");
+                            try (FileOutputStream stream = new FileOutputStream(cachePath)) {
+                                bitmap.compress(mCompressFormat, mQuality, stream);
+                            } catch (IOException e) {
+                                if (cachePath.exists()) {
+                                    //noinspection ResultOfMethodCallIgnored
+                                    cachePath.delete();
+                                    cachePath = null;
+                                }
+                                completer.setException(e);
+                            }
+                            if (cachePath != null) {
+                                completer.set(cachePath);
+                            }
+                        } catch (IOException e) {
+                            // Failed to create a new file
+                            completer.setException(e);
+                        }
+                    });
+                    return "Bitmap#compress";
+                }
+        );
+    }
+
+    /**
      * Export the image using the given executor.
      *
      * @param executor the thread for execution
@@ -122,7 +156,7 @@
     }
 
     /**
-     * Export the image using the given executor.
+     * Export the image to MediaStore and publish.
      *
      * @param executor the thread for execution
      * @param bitmap the bitmap to export
@@ -131,8 +165,10 @@
      */
     ListenableFuture<Result> export(Executor executor, UUID requestId, Bitmap bitmap,
             ZonedDateTime captureTime) {
-        final Task task =
-                new Task(mResolver, requestId, bitmap, captureTime, mCompressFormat, mQuality);
+
+        final Task task = new Task(mResolver, requestId, bitmap, captureTime, mCompressFormat,
+                mQuality, /* publish */ true);
+
         return CallbackToFutureAdapter.getFuture(
                 (completer) -> {
                     executor.execute(() -> {
@@ -147,12 +183,36 @@
         );
     }
 
+    /**
+     * Delete the entry.
+     *
+     * @param executor the thread for execution
+     * @param uri the uri of the image to publish
+     *
+     * @return a listenable future result
+     */
+    ListenableFuture<Result> delete(Executor executor, Uri uri) {
+        return CallbackToFutureAdapter.getFuture((completer) -> {
+            executor.execute(() -> {
+                mResolver.delete(uri, null);
+
+                Result result = new Result();
+                result.uri = uri;
+                result.deleted = true;
+                completer.set(result);
+            });
+            return "ContentResolver#delete";
+        });
+    }
+
     static class Result {
+        Uri uri;
         UUID requestId;
         String fileName;
         long timestamp;
-        Uri uri;
         CompressFormat format;
+        boolean published;
+        boolean deleted;
     }
 
     private static class Task {
@@ -163,9 +223,10 @@
         private final CompressFormat mFormat;
         private final int mQuality;
         private final String mFileName;
+        private final boolean mPublish;
 
         Task(ContentResolver resolver, UUID requestId, Bitmap bitmap, ZonedDateTime captureTime,
-                CompressFormat format, int quality) {
+                CompressFormat format, int quality, boolean publish) {
             mResolver = resolver;
             mRequestId = requestId;
             mBitmap = bitmap;
@@ -173,6 +234,7 @@
             mFormat = format;
             mQuality = quality;
             mFileName = createFilename(mCaptureTime, mFormat);
+            mPublish = publish;
         }
 
         public Result execute() throws ImageExportException, InterruptedException {
@@ -186,16 +248,21 @@
                     start = Instant.now();
                 }
 
-                uri = createEntry(mFormat, mCaptureTime, mFileName);
+                uri = createEntry(mResolver, mFormat, mCaptureTime, mFileName);
                 throwIfInterrupted();
 
-                writeImage(mBitmap, mFormat, mQuality, uri);
+                writeImage(mResolver, mBitmap, mFormat, mQuality, uri);
                 throwIfInterrupted();
 
-                writeExif(uri, mRequestId, mBitmap.getWidth(), mBitmap.getHeight(), mCaptureTime);
+                int width = mBitmap.getWidth();
+                int height = mBitmap.getHeight();
+                writeExif(mResolver, uri, mRequestId, width, height, mCaptureTime);
                 throwIfInterrupted();
 
-                publishEntry(uri);
+                if (mPublish) {
+                    publishEntry(mResolver, uri);
+                    result.published = true;
+                }
 
                 result.timestamp = mCaptureTime.toInstant().toEpochMilli();
                 result.requestId = mRequestId;
@@ -218,88 +285,89 @@
             return result;
         }
 
-        Uri createEntry(CompressFormat format, ZonedDateTime time, String fileName)
-                throws ImageExportException {
-            Trace.beginSection("ImageExporter_createEntry");
-            try {
-                final ContentValues values = createMetadata(time, format, fileName);
-
-                Uri uri = mResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
-                if (uri == null) {
-                    throw new ImageExportException(RESOLVER_INSERT_RETURNED_NULL);
-                }
-                return uri;
-            } finally {
-                Trace.endSection();
-            }
-        }
-
-        void writeImage(Bitmap bitmap, CompressFormat format, int quality,
-                Uri contentUri) throws ImageExportException {
-            Trace.beginSection("ImageExporter_writeImage");
-            try (OutputStream out = mResolver.openOutputStream(contentUri)) {
-                long start = SystemClock.elapsedRealtime();
-                if (!bitmap.compress(format, quality, out)) {
-                    throw new ImageExportException(IMAGE_COMPRESS_RETURNED_FALSE);
-                } else if (LogConfig.DEBUG_STORAGE) {
-                    Log.d(TAG, "Bitmap.compress took "
-                            + (SystemClock.elapsedRealtime() - start) + " ms");
-                }
-            } catch (IOException ex) {
-                throw new ImageExportException(OPEN_OUTPUT_STREAM_EXCEPTION, ex);
-            } finally {
-                Trace.endSection();
-            }
-        }
-
-        void writeExif(Uri uri, UUID requestId, int width, int height, ZonedDateTime captureTime)
-                throws ImageExportException {
-            Trace.beginSection("ImageExporter_writeExif");
-            ParcelFileDescriptor pfd = null;
-            try {
-                pfd = mResolver.openFile(uri, "rw", null);
-                if (pfd == null) {
-                    throw new ImageExportException(RESOLVER_OPEN_FILE_RETURNED_NULL);
-                }
-                ExifInterface exif;
-                try {
-                    exif = new ExifInterface(pfd.getFileDescriptor());
-                } catch (IOException e) {
-                    throw new ImageExportException(EXIF_READ_EXCEPTION, e);
-                }
-
-                updateExifAttributes(exif, requestId, width, height, captureTime);
-                try {
-                    exif.saveAttributes();
-                } catch (IOException e) {
-                    throw new ImageExportException(EXIF_WRITE_EXCEPTION, e);
-                }
-            } catch (FileNotFoundException e) {
-                throw new ImageExportException(RESOLVER_OPEN_FILE_EXCEPTION, e);
-            } finally {
-                closeQuietly(pfd);
-                Trace.endSection();
-            }
-        }
-
-        void publishEntry(Uri uri) throws ImageExportException {
-            Trace.beginSection("ImageExporter_publishEntry");
-            try {
-                ContentValues values = new ContentValues();
-                values.put(MediaStore.MediaColumns.IS_PENDING, 0);
-                values.putNull(MediaStore.MediaColumns.DATE_EXPIRES);
-                final int rowsUpdated = mResolver.update(uri, values, /* extras */ null);
-                if (rowsUpdated < 1) {
-                    throw new ImageExportException(RESOLVER_UPDATE_ZERO_ROWS);
-                }
-            } finally {
-                Trace.endSection();
-            }
-        }
-
         @Override
         public String toString() {
-            return "compress [" + mBitmap + "] to [" + mFormat + "] at quality " + mQuality;
+            return "export [" + mBitmap + "] to [" + mFormat + "] at quality " + mQuality;
+        }
+    }
+
+    private static Uri createEntry(ContentResolver resolver, CompressFormat format,
+            ZonedDateTime time, String fileName) throws ImageExportException {
+        Trace.beginSection("ImageExporter_createEntry");
+        try {
+            final ContentValues values = createMetadata(time, format, fileName);
+
+            Uri uri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
+            if (uri == null) {
+                throw new ImageExportException(RESOLVER_INSERT_RETURNED_NULL);
+            }
+            return uri;
+        } finally {
+            Trace.endSection();
+        }
+    }
+
+    private static void writeImage(ContentResolver resolver, Bitmap bitmap, CompressFormat format,
+            int quality, Uri contentUri) throws ImageExportException {
+        Trace.beginSection("ImageExporter_writeImage");
+        try (OutputStream out = resolver.openOutputStream(contentUri)) {
+            long start = SystemClock.elapsedRealtime();
+            if (!bitmap.compress(format, quality, out)) {
+                throw new ImageExportException(IMAGE_COMPRESS_RETURNED_FALSE);
+            } else if (LogConfig.DEBUG_STORAGE) {
+                Log.d(TAG, "Bitmap.compress took "
+                        + (SystemClock.elapsedRealtime() - start) + " ms");
+            }
+        } catch (IOException ex) {
+            throw new ImageExportException(OPEN_OUTPUT_STREAM_EXCEPTION, ex);
+        } finally {
+            Trace.endSection();
+        }
+    }
+
+    private static void writeExif(ContentResolver resolver, Uri uri, UUID requestId, int width,
+            int height, ZonedDateTime captureTime) throws ImageExportException {
+        Trace.beginSection("ImageExporter_writeExif");
+        ParcelFileDescriptor pfd = null;
+        try {
+            pfd = resolver.openFile(uri, "rw", null);
+            if (pfd == null) {
+                throw new ImageExportException(RESOLVER_OPEN_FILE_RETURNED_NULL);
+            }
+            ExifInterface exif;
+            try {
+                exif = new ExifInterface(pfd.getFileDescriptor());
+            } catch (IOException e) {
+                throw new ImageExportException(EXIF_READ_EXCEPTION, e);
+            }
+
+            updateExifAttributes(exif, requestId, width, height, captureTime);
+            try {
+                exif.saveAttributes();
+            } catch (IOException e) {
+                throw new ImageExportException(EXIF_WRITE_EXCEPTION, e);
+            }
+        } catch (FileNotFoundException e) {
+            throw new ImageExportException(RESOLVER_OPEN_FILE_EXCEPTION, e);
+        } finally {
+            closeQuietly(pfd);
+            Trace.endSection();
+        }
+    }
+
+    private static void publishEntry(ContentResolver resolver, Uri uri)
+            throws ImageExportException {
+        Trace.beginSection("ImageExporter_publishEntry");
+        try {
+            ContentValues values = new ContentValues();
+            values.put(MediaStore.MediaColumns.IS_PENDING, 0);
+            values.putNull(MediaStore.MediaColumns.DATE_EXPIRES);
+            final int rowsUpdated = resolver.update(uri, values, /* extras */ null);
+            if (rowsUpdated < 1) {
+                throw new ImageExportException(RESOLVER_UPDATE_ZERO_ROWS);
+            }
+        } finally {
+            Trace.endSection();
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ImageLoader.java b/packages/SystemUI/src/com/android/systemui/screenshot/ImageLoader.java
new file mode 100644
index 0000000..988b93c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ImageLoader.java
@@ -0,0 +1,94 @@
+/*
+ * 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.screenshot;
+
+import android.annotation.Nullable;
+import android.content.ContentResolver;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.net.Uri;
+import android.os.ParcelFileDescriptor;
+
+import androidx.concurrent.futures.CallbackToFutureAdapter;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import javax.inject.Inject;
+
+/** Loads images. */
+public class ImageLoader {
+    private final ContentResolver mResolver;
+
+    static class Result {
+        @Nullable Uri uri;
+        @Nullable File fileName;
+        @Nullable Bitmap bitmap;
+    }
+
+    @Inject
+    ImageLoader(ContentResolver resolver) {
+        mResolver = resolver;
+    }
+
+    /**
+     * Loads an image via URI from ContentResolver.
+     *
+     * @param uri the identifier of the image to load
+     * @return a listenable future result
+     */
+    ListenableFuture<Result> load(Uri uri) {
+        return CallbackToFutureAdapter.getFuture(completer -> {
+            Result result = new Result();
+            try (InputStream in = mResolver.openInputStream(uri)) {
+                result.uri = uri;
+                result.bitmap = BitmapFactory.decodeStream(in);
+                completer.set(result);
+            }
+            catch (IOException e) {
+                completer.setException(e);
+            }
+            return "BitmapFactory#decodeStream";
+        });
+    }
+
+    /**
+     * Loads an image by physical filesystem name. The current user must have filesystem
+     * permissions to read this file/path.
+     *
+     * @param file the system file path of the image to load
+     * @return a listenable future result
+     */
+    ListenableFuture<Result> load(File file) {
+        return CallbackToFutureAdapter.getFuture(completer -> {
+            try (InputStream in = new BufferedInputStream(new FileInputStream(file))) {
+                Result result = new Result();
+                result.fileName = file;
+                result.bitmap = BitmapFactory.decodeStream(in);
+                completer.set(result);
+            } catch (IOException e) {
+                completer.setException(e);
+            }
+            return "BitmapFactory#decodeStream";
+        });
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ImageTileSet.java b/packages/SystemUI/src/com/android/systemui/screenshot/ImageTileSet.java
index ae3cd99..6743afa 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ImageTileSet.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ImageTileSet.java
@@ -15,6 +15,7 @@
  */
 package com.android.systemui.screenshot;
 
+import android.annotation.AnyThread;
 import android.graphics.Bitmap;
 import android.graphics.HardwareRenderer;
 import android.graphics.RecordingCanvas;
@@ -26,6 +27,9 @@
 
 import androidx.annotation.UiThread;
 
+import com.android.internal.util.CallbackRegistry;
+import com.android.internal.util.CallbackRegistry.NotifierCallback;
+
 import java.util.ArrayList;
 import java.util.List;
 
@@ -34,10 +38,14 @@
  * <p>
  * To display on-screen, use {@link #getDrawable()}.
  */
+@UiThread
 class ImageTileSet {
 
     private static final String TAG = "ImageTileSet";
 
+    private CallbackRegistry<OnBoundsChangedListener, ImageTileSet, Rect> mOnBoundsListeners;
+    private CallbackRegistry<OnContentChangedListener, ImageTileSet, Rect> mContentListeners;
+
     ImageTileSet(@UiThread Handler handler) {
         mHandler = handler;
     }
@@ -64,15 +72,43 @@
     private OnContentChangedListener mOnContentChangedListener;
     private OnBoundsChangedListener mOnBoundsChangedListener;
 
-    void setOnBoundsChangedListener(OnBoundsChangedListener listener) {
-        mOnBoundsChangedListener = listener;
+    void addOnBoundsChangedListener(OnBoundsChangedListener listener) {
+        if (mOnBoundsListeners == null) {
+            mOnBoundsListeners = new CallbackRegistry<>(
+                    new NotifierCallback<OnBoundsChangedListener, ImageTileSet, Rect>() {
+                        @Override
+                        public void onNotifyCallback(OnBoundsChangedListener callback,
+                                ImageTileSet sender,
+                                int arg, Rect newBounds) {
+                            callback.onBoundsChanged(newBounds.left, newBounds.top, newBounds.right,
+                                    newBounds.bottom);
+                        }
+                    });
+        }
+        mOnBoundsListeners.add(listener);
     }
 
-    void setOnContentChangedListener(OnContentChangedListener listener) {
-        mOnContentChangedListener = listener;
+    void addOnContentChangedListener(OnContentChangedListener listener) {
+        if (mContentListeners == null) {
+            mContentListeners = new CallbackRegistry<>(
+                    new NotifierCallback<OnContentChangedListener, ImageTileSet, Rect>() {
+                        @Override
+                        public void onNotifyCallback(OnContentChangedListener callback,
+                                ImageTileSet sender,
+                                int arg, Rect newBounds) {
+                            callback.onContentChanged();
+                        }
+                    });
+        }
+        mContentListeners.add(listener);
     }
 
+    @AnyThread
     void addTile(ImageTile tile) {
+        if (!mHandler.getLooper().isCurrentThread()) {
+            mHandler.post(() -> addTile(tile));
+            return;
+        }
         final Rect newBounds = new Rect(mBounds);
         final Rect newRect = tile.getLocation();
         mTiles.add(tile);
@@ -84,27 +120,15 @@
         notifyContentChanged();
     }
 
-    void notifyContentChanged() {
-        if (mOnContentChangedListener == null) {
-            return;
-        }
-        if (mHandler.getLooper().isCurrentThread()) {
-            mOnContentChangedListener.onContentChanged();
-        } else {
-            mHandler.post(() -> mOnContentChangedListener.onContentChanged());
+    private void notifyContentChanged() {
+        if (mContentListeners != null) {
+            mContentListeners.notifyCallbacks(this, 0, null);
         }
     }
 
-    void notifyBoundsChanged(Rect bounds) {
-        if (mOnBoundsChangedListener == null) {
-            return;
-        }
-        if (mHandler.getLooper().isCurrentThread()) {
-            mOnBoundsChangedListener.onBoundsChanged(
-                    bounds.left, bounds.top, bounds.right, bounds.bottom);
-        } else {
-            mHandler.post(() -> mOnBoundsChangedListener.onBoundsChanged(
-                    bounds.left, bounds.top, bounds.right, bounds.bottom));
+    private void notifyBoundsChanged(Rect bounds) {
+        if (mOnBoundsListeners != null) {
+            mOnBoundsListeners.notifyCallbacks(this, 0, bounds);
         }
     }
 
@@ -180,8 +204,13 @@
         return mBounds.height();
     }
 
+    @AnyThread
     void clear() {
-        if (mBounds.isEmpty()) {
+        if (!mHandler.getLooper().isCurrentThread()) {
+            mHandler.post(this::clear);
+            return;
+        }
+        if (mTiles.isEmpty()) {
             return;
         }
         mBounds.setEmpty();
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/TiledImageDrawable.java b/packages/SystemUI/src/com/android/systemui/screenshot/TiledImageDrawable.java
index 4ec8eb2..71df369 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/TiledImageDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/TiledImageDrawable.java
@@ -38,9 +38,10 @@
 
     public TiledImageDrawable(ImageTileSet tiles) {
         mTiles = tiles;
-        mTiles.setOnContentChangedListener(this::onContentChanged);
+        mTiles.addOnContentChangedListener(this::onContentChanged);
     }
 
+
     private void onContentChanged() {
         if (mNode != null && mNode.hasDisplayList()) {
             mNode.discardDisplayList();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index 5e8245f..3496581 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -713,66 +713,45 @@
             return;
         }
         ExpandableNotificationRow row = (ExpandableNotificationRow) view;
-
         StatusBarIconView icon = row.getShelfIcon();
         NotificationIconContainer.IconState iconState = getIconState(icon);
-        View rowIcon = row.getShelfTransformationTarget();
-
-        // Let's resolve the relative positions of the icons
-        int iconStartPadding;
-        if (rowIcon != null) {
-            iconStartPadding = row.getRelativeStartPadding(rowIcon);
-        } else {
-            iconStartPadding = 0;
+        if (iconState == null) {
+            return;
         }
+        iconState.hidden = transitionAmount == 0.0f && !iconState.isAnimating(icon);
+        boolean isAppearing = row.isDrawingAppearAnimation() && !row.isInShelf();
+        if (isAppearing) {
+            iconState.hidden = true;
+            iconState.iconAppearAmount = 0.0f;
+        }
+        iconState.alpha = transitionAmount;
+
+        // Fade in icons at shelf start
+        // This is important for conversation icons, which are badged and need x reset
+        iconState.xTranslation = mShelfIcons.getActualPaddingStart();
+
         boolean stayingInShelf = row.isInShelf() && !row.isTransformingIntoShelf();
-
-        // Get the icon correctly positioned in X
-        // Even in RTL it's the left, since we're inverting the location in post
-        float shelfIconPositionX = icon.getLeft();
-        shelfIconPositionX += (1.0f - icon.getIconScale()) * icon.getWidth() / 2.0f;
-        float iconXTranslation = NotificationUtils.interpolate(
-                iconStartPadding - shelfIconPositionX,
-                mShelfIcons.getActualPaddingStart(),
-                transitionAmount);
-
-        // Let's handle the case that there's no Icon
-        boolean noIcon = !row.isShowingIcon();
-        if (noIcon) {
-            // The view currently doesn't have an icon, lets transform it in!
-            iconXTranslation = mShelfIcons.getActualPaddingStart();
+        if (stayingInShelf) {
+            iconState.iconAppearAmount = 1.0f;
+            iconState.alpha = 1.0f;
+            iconState.scaleX = 1.0f;
+            iconState.scaleY = 1.0f;
+            iconState.hidden = false;
         }
-        if (iconState != null) {
-            iconState.hidden = transitionAmount == 0.0f && !iconState.isAnimating(icon);
-            boolean isAppearing = row.isDrawingAppearAnimation() && !row.isInShelf();
-            if (isAppearing) {
-                iconState.hidden = true;
-                iconState.iconAppearAmount = 0.0f;
-            }
-            iconState.alpha = transitionAmount;
-            iconState.xTranslation = iconXTranslation;
-            if (stayingInShelf) {
-                iconState.iconAppearAmount = 1.0f;
-                iconState.alpha = 1.0f;
-                iconState.scaleX = 1.0f;
-                iconState.scaleY = 1.0f;
-                iconState.hidden = false;
-            }
-            if (row.isAboveShelf()
-                    || row.showingPulsing()
-                    || (!row.isInShelf() && (isLastChild && row.areGutsExposed()
-                    || row.getTranslationZ() > mAmbientState.getBaseZHeight()))) {
-                iconState.hidden = true;
-            }
-            int backgroundColor = getBackgroundColorWithoutTint();
-            int shelfColor = icon.getContrastedStaticDrawableColor(backgroundColor);
-            if (!noIcon && shelfColor != StatusBarIconView.NO_COLOR) {
-                int iconColor = row.getOriginalIconColor();
-                shelfColor = NotificationUtils.interpolateColors(iconColor, shelfColor,
-                        iconState.iconAppearAmount);
-            }
-            iconState.iconColor = shelfColor;
+        if (row.isAboveShelf()
+                || row.showingPulsing()
+                || (!row.isInShelf() && (isLastChild && row.areGutsExposed()
+                || row.getTranslationZ() > mAmbientState.getBaseZHeight()))) {
+            iconState.hidden = true;
         }
+        int backgroundColor = getBackgroundColorWithoutTint();
+        int shelfColor = icon.getContrastedStaticDrawableColor(backgroundColor);
+        if (row.isShowingIcon() && shelfColor != StatusBarIconView.NO_COLOR) {
+            int iconColor = row.getOriginalIconColor();
+            shelfColor = NotificationUtils.interpolateColors(iconColor, shelfColor,
+                    iconState.iconAppearAmount);
+        }
+        iconState.iconColor = shelfColor;
     }
 
     private NotificationIconContainer.IconState getIconState(StatusBarIconView icon) {
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 ae14fa9..19b9895 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -1051,9 +1051,7 @@
                     .getVisibleNotificationCount() != 0 || mMediaDataManager.hasActiveMedia();
             mKeyguardStatusViewController.setHasVisibleNotifications(hasVisibleNotifications);
             int userIconHeight = mKeyguardQsUserSwitchController != null
-                    ? mKeyguardQsUserSwitchController.getUserIconHeight()
-                    : (mKeyguardUserSwitcherController != null
-                            ? mKeyguardUserSwitcherController.getUserIconHeight() : 0);
+                    ? mKeyguardQsUserSwitchController.getUserIconHeight() : 0;
             mClockPositionAlgorithm.setup(mStatusBarHeaderHeightKeyguard,
                     totalHeight - bottomPadding,
                     mNotificationStackScrollLayoutController.getIntrinsicContentHeight(),
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 7b2330b..270a0f8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -124,6 +124,12 @@
     public static final float BUSY_SCRIM_ALPHA = 1f;
 
     /**
+     * The default scrim under the expanded bubble stack.
+     * This should not be lower than 0.54, otherwise we won't pass GAR.
+     */
+    public static final float BUBBLE_SCRIM_ALPHA = 0.6f;
+
+    /**
      * Scrim opacity that can have text on top.
      */
     public static final float GAR_SCRIM_ALPHA = 0.6f;
@@ -207,8 +213,7 @@
             FeatureFlags featureFlags, @Main Executor mainExecutor) {
         mScrimStateListener = lightBarController::setScrimState;
         mDefaultScrimAlpha = featureFlags.isShadeOpaque() ? BUSY_SCRIM_ALPHA : GAR_SCRIM_ALPHA;
-        ScrimState.BUBBLE_EXPANDED.setBubbleAlpha(featureFlags.isShadeOpaque()
-                ? BUSY_SCRIM_ALPHA : GAR_SCRIM_ALPHA);
+        ScrimState.BUBBLE_EXPANDED.setBubbleAlpha(BUBBLE_SCRIM_ALPHA);
         mBlurUtils = blurUtils;
 
         mKeyguardStateController = keyguardStateController;
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 b4c687d..5083e33 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -739,8 +739,13 @@
     }
 
     public void onThemeChanged() {
+        boolean wasShowing = mBouncer.isShowing();
+        boolean wasScrimmed = mBouncer.isScrimmed();
+
         hideBouncer(true /* destroyView */);
         mBouncer.prepare();
+
+        if (wasShowing) showBouncer(wasScrimmed);
     }
 
     public void onKeyguardFadedAway() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java
index 5a80c05..25e9084 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java
@@ -33,7 +33,6 @@
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
-import android.widget.LinearLayout;
 
 import com.android.keyguard.KeyguardConstants;
 import com.android.keyguard.KeyguardUpdateMonitor;
@@ -83,12 +82,10 @@
 
     // Child views of KeyguardUserSwitcherView
     private KeyguardUserSwitcherListView mListView;
-    private LinearLayout mEndGuestButton;
 
     // State info for the user switcher
     private boolean mUserSwitcherOpen;
     private int mCurrentUserId = UserHandle.USER_NULL;
-    private boolean mCurrentUserIsGuest;
     private int mBarState;
     private float mDarkAmount;
 
@@ -185,11 +182,6 @@
         if (DEBUG) Log.d(TAG, "onInit");
 
         mListView = mView.findViewById(R.id.keyguard_user_switcher_list);
-        mEndGuestButton = mView.findViewById(R.id.end_guest_button);
-
-        mEndGuestButton.setOnClickListener(v -> {
-            mUserSwitcherController.showExitGuestDialog(mCurrentUserId);
-        });
 
         mView.setOnTouchListener((v, event) -> {
             if (!isListAnimating()) {
@@ -209,9 +201,14 @@
         mKeyguardUpdateMonitor.registerCallback(mInfoCallback);
         mStatusBarStateController.addCallback(mStatusBarStateListener);
         mScreenLifecycle.addObserver(mScreenObserver);
-        mView.addOnLayoutChangeListener(mBackground);
-        mView.setBackground(mBackground);
-        mBackground.setAlpha(0);
+        if (isSimpleUserSwitcher()) {
+            // Don't use the background for the simple user switcher
+            setUserSwitcherOpened(true /* open */, true /* animate */);
+        } else {
+            mView.addOnLayoutChangeListener(mBackground);
+            mView.setBackground(mBackground);
+            mBackground.setAlpha(0);
+        }
     }
 
     @Override
@@ -291,7 +288,6 @@
                     }
                     foundCurrentUser = true;
                     mCurrentUserId = userTag.info.id;
-                    mCurrentUserIsGuest = userTag.isGuest;
                     // Current user is always visible
                     newView.updateVisibilities(true /* showItem */,
                             mUserSwitcherOpen /* showTextName */, false /* animate */);
@@ -317,19 +313,10 @@
         if (!foundCurrentUser) {
             Log.w(TAG, "Current user is not listed");
             mCurrentUserId = UserHandle.USER_NULL;
-            mCurrentUserIsGuest = false;
         }
     }
 
     /**
-     * Get the height of the keyguard user switcher view when closed.
-     */
-    public int getUserIconHeight() {
-        View firstChild = mListView.getChildAt(0);
-        return firstChild == null ? 0 : firstChild.getHeight();
-    }
-
-    /**
      * Set the visibility of the keyguard user switcher view based on some new state.
      */
     public void setKeyguardUserSwitcherVisibility(
@@ -406,7 +393,6 @@
 
     private void updateVisibilities(boolean animate) {
         if (DEBUG) Log.d(TAG, String.format("updateVisibilities: animate=%b", animate));
-        mEndGuestButton.animate().cancel();
         if (mBgAnimator != null) {
             mBgAnimator.cancel();
         }
@@ -434,44 +420,6 @@
             });
             mBgAnimator.start();
         }
-
-        if (mUserSwitcherOpen && mCurrentUserIsGuest) {
-            // Show the "End guest session" button
-            mEndGuestButton.setVisibility(View.VISIBLE);
-            if (animate) {
-                mEndGuestButton.setAlpha(0f);
-                mEndGuestButton.animate()
-                        .alpha(1f)
-                        .setDuration(360)
-                        .setInterpolator(Interpolators.ALPHA_IN)
-                        .withEndAction(() -> {
-                            mEndGuestButton.setClickable(true);
-                        });
-            } else {
-                mEndGuestButton.setClickable(true);
-                mEndGuestButton.setAlpha(1f);
-            }
-        } else {
-            // Hide the "End guest session" button. If it's already GONE, don't try to
-            // animate it or it will appear again for an instant.
-            mEndGuestButton.setClickable(false);
-            if (animate && mEndGuestButton.getVisibility() != View.GONE) {
-                mEndGuestButton.setVisibility(View.VISIBLE);
-                mEndGuestButton.setAlpha(1f);
-                mEndGuestButton.animate()
-                        .alpha(0f)
-                        .setDuration(360)
-                        .setInterpolator(Interpolators.ALPHA_OUT)
-                        .withEndAction(() -> {
-                            mEndGuestButton.setVisibility(View.GONE);
-                            mEndGuestButton.setAlpha(1f);
-                        });
-            } else {
-                mEndGuestButton.setVisibility(View.GONE);
-                mEndGuestButton.setAlpha(1f);
-            }
-        }
-
         mListView.updateVisibilities(mUserSwitcherOpen, animate);
     }
 
@@ -532,15 +480,6 @@
             return createUserDetailItemView(convertView, parent, item);
         }
 
-        @Override
-        public String getName(Context context, UserSwitcherController.UserRecord item) {
-            if (item.isGuest) {
-                return context.getString(com.android.settingslib.R.string.guest_nickname);
-            } else {
-                return super.getName(context, item);
-            }
-        }
-
         KeyguardUserDetailItemView convertOrInflate(View convertView, ViewGroup parent) {
             if (!(convertView instanceof KeyguardUserDetailItemView)
                     || !(convertView.getTag() instanceof UserSwitcherController.UserRecord)) {
@@ -608,18 +547,11 @@
             }
 
             if (mKeyguardUserSwitcherController.isUserSwitcherOpen()) {
-                if (user.isCurrent) {
-                    // Close the switcher if tapping the current user
-                    mKeyguardUserSwitcherController.setUserSwitcherOpened(
-                            false /* open */, true /* animate */);
-                } else if (user.isSwitchToEnabled) {
-                    if (!user.isAddUser && !user.isRestricted && !user.isDisabledByAdmin) {
-                        if (mCurrentUserView != null) {
-                            mCurrentUserView.setActivated(false);
-                        }
-                        v.setActivated(true);
-                    }
+                if (!user.isCurrent || user.isGuest) {
                     onUserListItemClicked(user);
+                } else {
+                    mKeyguardUserSwitcherController.closeSwitcherIfOpenAndNotSimple(
+                            true /* animate */);
                 }
             } else {
                 // If switcher is closed, tapping anywhere in the view will open it
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherListView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherListView.java
index 7c82c11..a815adf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherListView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherListView.java
@@ -35,20 +35,22 @@
     private static final String TAG = "KeyguardUserSwitcherListView";
     private static final boolean DEBUG = KeyguardConstants.DEBUG;
 
-    private static final int ANIMATION_DURATION_OPENING = 360;
-    private static final int ANIMATION_DURATION_CLOSING = 240;
-
     private boolean mAnimating;
     private final AppearAnimationUtils mAppearAnimationUtils;
     private final DisappearAnimationUtils mDisappearAnimationUtils;
 
     public KeyguardUserSwitcherListView(Context context, AttributeSet attrs) {
         super(context, attrs);
-        setClipChildren(false);
-        mAppearAnimationUtils = new AppearAnimationUtils(context, ANIMATION_DURATION_OPENING,
-                -0.5f, 0.5f, Interpolators.FAST_OUT_SLOW_IN);
-        mDisappearAnimationUtils = new DisappearAnimationUtils(context, ANIMATION_DURATION_CLOSING,
-                0.5f, 0.5f, Interpolators.FAST_OUT_LINEAR_IN);
+        mAppearAnimationUtils = new AppearAnimationUtils(context,
+                AppearAnimationUtils.DEFAULT_APPEAR_DURATION,
+                -0.5f /* translationScaleFactor */,
+                0.5f /* delayScaleFactor */,
+                Interpolators.FAST_OUT_SLOW_IN);
+        mDisappearAnimationUtils = new DisappearAnimationUtils(context,
+                AppearAnimationUtils.DEFAULT_APPEAR_DURATION,
+                0.2f /* translationScaleFactor */,
+                0.2f /* delayScaleFactor */,
+                Interpolators.FAST_OUT_SLOW_IN_REVERSE);
     }
 
     /**
@@ -82,69 +84,40 @@
 
         mAnimating = false;
 
-        int userListCount = getChildCount();
-        if (userListCount > 0) {
-            // The first child is always the current user.
-            KeyguardUserDetailItemView currentUserView = ((KeyguardUserDetailItemView) getChildAt(
-                    0));
-            currentUserView.updateVisibilities(true /* showItem */, open /* showTextName */,
-                    animate);
-            currentUserView.setClickable(true);
-            currentUserView.clearAnimation();
-        }
-
-        if (userListCount <= 1) {
-            return;
+        int childCount = getChildCount();
+        KeyguardUserDetailItemView[] userItemViews = new KeyguardUserDetailItemView[childCount];
+        for (int i = 0; i < childCount; i++) {
+            userItemViews[i] = (KeyguardUserDetailItemView) getChildAt(i);
+            userItemViews[i].clearAnimation();
+            if (i == 0) {
+                // The first child is always the current user.
+                userItemViews[i].updateVisibilities(true /* showItem */, open /* showTextName */,
+                        animate);
+                userItemViews[i].setClickable(true);
+            } else {
+                // Update clickable state immediately so that the menu feels more responsive
+                userItemViews[i].setClickable(open);
+                // Before running the animation, ensure visibility is set correctly
+                userItemViews[i].updateVisibilities(animate || open /* showItem */,
+                        true /* showTextName */, false /* animate */);
+            }
         }
 
         if (animate) {
-            // Create an array of all the remaining users (that aren't the current user).
-            KeyguardUserDetailItemView[] otherUserViews =
-                    new KeyguardUserDetailItemView[userListCount - 1];
-            for (int i = 1, n = 0; i < userListCount; i++, n++) {
-                otherUserViews[n] = (KeyguardUserDetailItemView) getChildAt(i);
-
-                // Update clickable state immediately so that the menu feels more responsive
-                otherUserViews[n].setClickable(open);
-
-                // Before running the animation, ensure visibility is set correctly
-                otherUserViews[n].updateVisibilities(
-                        true /* showItem */, true /* showTextName */, false /* animate */);
-                otherUserViews[n].clearAnimation();
-            }
+            // AnimationUtils will immediately hide/show the first item in the array. Since the
+            // first view is the current user, we want to manage its visibility separately.
+            // Set first item to null so AnimationUtils ignores it.
+            userItemViews[0] = null;
 
             setClipChildren(false);
             setClipToPadding(false);
-
             mAnimating = true;
-
-            final int nonCurrentUserCount = otherUserViews.length;
-            if (open) {
-                mAppearAnimationUtils.startAnimation(otherUserViews, () -> {
-                    setClipChildren(true);
-                    setClipToPadding(true);
-                    mAnimating = false;
-                });
-            } else {
-                mDisappearAnimationUtils.startAnimation(otherUserViews, () -> {
-                    setClipChildren(true);
-                    setClipToPadding(true);
-                    for (int i = 0; i < nonCurrentUserCount; i++) {
-                        otherUserViews[i].updateVisibilities(
-                                false /* showItem */, true /* showTextName */, false /* animate */);
-                    }
-                    mAnimating = false;
-                });
-            }
-        } else {
-            for (int i = 1; i < userListCount; i++) {
-                KeyguardUserDetailItemView nonCurrentUserView =
-                        ((KeyguardUserDetailItemView) getChildAt(i));
-                nonCurrentUserView.clearAnimation();
-                nonCurrentUserView.updateVisibilities(
-                        open /* showItem */, true /* showTextName */, false /* animate */);
-                nonCurrentUserView.setClickable(open);
-            }
+            (open ? mAppearAnimationUtils : mDisappearAnimationUtils)
+                    .startAnimation(userItemViews, () -> {
+                        setClipChildren(true);
+                        setClipToPadding(true);
+                        mAnimating = false;
+                    });
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/notifications/TvNotificationPanelActivity.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/notifications/TvNotificationPanelActivity.java
index 30f401b..b325b10 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/notifications/TvNotificationPanelActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/notifications/TvNotificationPanelActivity.java
@@ -20,15 +20,19 @@
 import android.app.Activity;
 import android.app.NotificationManager;
 import android.content.Intent;
+import android.graphics.drawable.ColorDrawable;
 import android.os.Bundle;
 import android.service.notification.StatusBarNotification;
 import android.util.SparseArray;
+import android.view.Gravity;
 import android.view.View;
 
 import androidx.leanback.widget.VerticalGridView;
 
 import com.android.systemui.R;
 
+import java.util.function.Consumer;
+
 import javax.inject.Inject;
 
 /**
@@ -42,6 +46,7 @@
     private VerticalGridView mNotificationListView;
     private View mNotificationPlaceholder;
     private boolean mPanelAlreadyOpen = false;
+    private final Consumer<Boolean> mBlurConsumer = this::enableBlur;
 
     @Inject
     public TvNotificationPanelActivity(TvNotificationHandler tvNotificationHandler) {
@@ -103,6 +108,33 @@
     }
 
     @Override
+    public void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        getWindow().setGravity(Gravity.END);
+        getWindowManager().addCrossWindowBlurEnabledListener(mBlurConsumer);
+    }
+
+    private void enableBlur(boolean enabled) {
+        if (enabled) {
+            int blurRadius = getResources().getDimensionPixelSize(
+                    R.dimen.tv_notification_blur_radius);
+            getWindow().setBackgroundDrawable(
+                    new ColorDrawable(getColor(R.color.tv_notification_blur_background_color)));
+            getWindow().setBackgroundBlurRadius(blurRadius);
+        } else {
+            getWindow().setBackgroundDrawable(
+                    new ColorDrawable(getColor(R.color.tv_notification_default_background_color)));
+            getWindow().setBackgroundBlurRadius(0);
+        }
+    }
+
+    @Override
+    public void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        getWindowManager().removeCrossWindowBlurEnabledListener(mBlurConsumer);
+    }
+
+    @Override
     public void onDestroy() {
         super.onDestroy();
         mTvNotificationHandler.setTvNotificationListener(null);
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java
index e9e4380..7244ffe 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java
@@ -300,7 +300,7 @@
         dialog.setButton(DialogInterface.BUTTON_NEGATIVE, mContext.getString(R.string.cancel),
                 (DialogInterface.OnClickListener) null);
         dialog.setButton(DialogInterface.BUTTON_POSITIVE,
-                mContext.getString(R.string.guest_exit_guest_dialog_remove), (d, which) -> {
+                mContext.getString(R.string.qs_customize_remove), (d, which) -> {
                     // Tell the tuner (in main SysUI process) to clear all its settings.
                     mContext.sendBroadcast(new Intent(TunerService.ACTION_CLEAR));
                     // Disable access to tuner.
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java
index ff28819..82dad68 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java
@@ -19,16 +19,15 @@
 import android.content.Context;
 import android.os.Handler;
 
-import com.android.systemui.dagger.WMComponent;
 import com.android.systemui.dagger.WMSingleton;
 import com.android.wm.shell.ShellTaskOrganizer;
 import com.android.wm.shell.WindowManagerShellWrapper;
 import com.android.wm.shell.common.DisplayController;
 import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.common.SyncTransactionQueue;
 import com.android.wm.shell.common.SystemWindows;
 import com.android.wm.shell.common.TaskStackListenerImpl;
 import com.android.wm.shell.common.annotations.ShellMainThread;
-import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
 import com.android.wm.shell.legacysplitscreen.LegacySplitScreenController;
 import com.android.wm.shell.pip.Pip;
 import com.android.wm.shell.pip.PipAnimationController;
@@ -140,6 +139,7 @@
     @Provides
     static PipTaskOrganizer providePipTaskOrganizer(Context context,
             TvPipMenuController tvPipMenuController,
+            SyncTransactionQueue syncTransactionQueue,
             PipBoundsState pipBoundsState,
             PipBoundsAlgorithm pipBoundsAlgorithm,
             PipAnimationController pipAnimationController,
@@ -149,7 +149,8 @@
             DisplayController displayController,
             PipUiEventLogger pipUiEventLogger, ShellTaskOrganizer shellTaskOrganizer,
             @ShellMainThread ShellExecutor mainExecutor) {
-        return new PipTaskOrganizer(context, pipBoundsState, pipBoundsAlgorithm,
+        return new PipTaskOrganizer(context,
+                syncTransactionQueue, pipBoundsState, pipBoundsAlgorithm,
                 tvPipMenuController, pipAnimationController, pipSurfaceTransactionHelper,
                 pipTransitionController, splitScreenOptional, displayController, pipUiEventLogger,
                 shellTaskOrganizer, mainExecutor);
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
index d67bd76..a123269 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
@@ -17,6 +17,7 @@
 package com.android.systemui.wmshell;
 
 import static android.os.Process.THREAD_PRIORITY_DISPLAY;
+import static android.os.Process.THREAD_PRIORITY_TOP_APP_BOOST;
 
 import android.animation.AnimationHandler;
 import android.app.ActivityTaskManager;
@@ -61,6 +62,7 @@
 import com.android.wm.shell.common.annotations.ChoreographerSfVsync;
 import com.android.wm.shell.common.annotations.ShellAnimationThread;
 import com.android.wm.shell.common.annotations.ShellMainThread;
+import com.android.wm.shell.common.annotations.ShellSplashscreenThread;
 import com.android.wm.shell.draganddrop.DragAndDropController;
 import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout;
 import com.android.wm.shell.hidedisplaycutout.HideDisplayCutoutController;
@@ -165,6 +167,19 @@
     }
 
     /**
+     * Provides a Shell splashscreen-thread Executor
+     */
+    @WMSingleton
+    @Provides
+    @ShellSplashscreenThread
+    public static ShellExecutor provideSplashScreenExecutor() {
+        HandlerThread shellSplashscreenThread = new HandlerThread("wmshell.splashscreen",
+                THREAD_PRIORITY_TOP_APP_BOOST);
+        shellSplashscreenThread.start();
+        return new HandlerExecutor(shellSplashscreenThread.getThreadHandler());
+    }
+
+    /**
      * Provide a Shell main-thread AnimationHandler.  The AnimationHandler can be set on
      * {@link android.animation.ValueAnimator}s and will ensure that the animation will run on
      * the Shell main-thread with the SF vsync.
@@ -465,8 +480,8 @@
     @WMSingleton
     @Provides
     static StartingWindowController provideStartingWindowController(Context context,
-            @ShellMainThread ShellExecutor mainExecutor) {
-        return new StartingWindowController(context, mainExecutor);
+            @ShellSplashscreenThread ShellExecutor executor) {
+        return new StartingWindowController(context, executor);
     }
 
     //
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
index 754b6a6..d5183f8 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
@@ -172,6 +172,7 @@
     @WMSingleton
     @Provides
     static PipTaskOrganizer providePipTaskOrganizer(Context context,
+            SyncTransactionQueue syncTransactionQueue,
             PipBoundsState pipBoundsState,
             PipBoundsAlgorithm pipBoundsAlgorithm,
             PhonePipMenuController menuPhoneController,
@@ -182,7 +183,8 @@
             DisplayController displayController,
             PipUiEventLogger pipUiEventLogger, ShellTaskOrganizer shellTaskOrganizer,
             @ShellMainThread ShellExecutor mainExecutor) {
-        return new PipTaskOrganizer(context, pipBoundsState, pipBoundsAlgorithm,
+        return new PipTaskOrganizer(context,
+                syncTransactionQueue, pipBoundsState, pipBoundsAlgorithm,
                 menuPhoneController, pipAnimationController, pipSurfaceTransactionHelper,
                 pipTransitionController, splitScreenOptional, displayController, pipUiEventLogger,
                 shellTaskOrganizer, mainExecutor);
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 f84aa59..0768618 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -31,6 +31,7 @@
 import android.hardware.fingerprint.FingerprintSensorProperties;
 import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
 import android.hardware.fingerprint.IUdfpsOverlayController;
+import android.hardware.fingerprint.IUdfpsOverlayControllerCallback;
 import android.os.PowerManager;
 import android.os.RemoteException;
 import android.testing.AndroidTestingRunner;
@@ -89,6 +90,8 @@
     private StatusBarStateController mStatusBarStateController;
     @Mock
     private StatusBar mStatusBar;
+    @Mock
+    private IUdfpsOverlayControllerCallback mUdfpsOverlayControllerCallback;
 
     private FakeExecutor mFgExecutor;
 
@@ -152,7 +155,7 @@
     @Test
     public void dozeTimeTick() throws RemoteException {
         mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
-                IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD);
+                IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD, mUdfpsOverlayControllerCallback);
         mFgExecutor.runAllReady();
         mUdfpsController.dozeTimeTick();
         verify(mUdfpsView).dozeTimeTick();
@@ -161,7 +164,7 @@
     @Test
     public void showUdfpsOverlay_addsViewToWindow() throws RemoteException {
         mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
-                IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD);
+                IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD, mUdfpsOverlayControllerCallback);
         mFgExecutor.runAllReady();
         verify(mWindowManager).addView(eq(mUdfpsView), any());
     }
@@ -169,7 +172,7 @@
     @Test
     public void hideUdfpsOverlay_removesViewFromWindow() throws RemoteException {
         mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
-                IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD);
+                IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD, mUdfpsOverlayControllerCallback);
         mOverlayController.hideUdfpsOverlay(TEST_UDFPS_SENSOR_ID);
         mFgExecutor.runAllReady();
         verify(mWindowManager).removeView(eq(mUdfpsView));
@@ -183,7 +186,7 @@
 
         // GIVEN that the overlay is showing
         mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
-                IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD);
+                IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD, mUdfpsOverlayControllerCallback);
         mFgExecutor.runAllReady();
         // WHEN ACTION_DOWN is received
         verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
@@ -205,7 +208,7 @@
     public void aodInterrupt() throws RemoteException {
         // GIVEN that the overlay is showing
         mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
-                IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD);
+                IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD, mUdfpsOverlayControllerCallback);
         mFgExecutor.runAllReady();
         // WHEN fingerprint is requested because of AOD interrupt
         mUdfpsController.onAodInterrupt(0, 0, 2f, 3f);
@@ -221,7 +224,7 @@
     public void cancelAodInterrupt() throws RemoteException {
         // GIVEN AOD interrupt
         mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
-                IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD);
+                IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD, mUdfpsOverlayControllerCallback);
         mFgExecutor.runAllReady();
         mUdfpsController.onAodInterrupt(0, 0, 0f, 0f);
         // WHEN it is cancelled
@@ -234,7 +237,7 @@
     public void aodInterruptTimeout() throws RemoteException {
         // GIVEN AOD interrupt
         mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
-                IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD);
+                IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD, mUdfpsOverlayControllerCallback);
         mFgExecutor.runAllReady();
         mUdfpsController.onAodInterrupt(0, 0, 0f, 0f);
         // WHEN it times out
@@ -247,7 +250,7 @@
     @Test
     public void registersAndUnregistersViewForCallbacks() throws RemoteException {
         mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
-                IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD);
+                IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD, mUdfpsOverlayControllerCallback);
         mFgExecutor.runAllReady();
         verify(mStatusBarStateController).addCallback(mUdfpsController.mStatusBarStateListener);
         verify(mStatusBar).addExpansionChangedListener(
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 21368d6..b1f1b5e 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
@@ -542,7 +542,7 @@
         Assert.assertEquals(ScrimController.BUSY_SCRIM_ALPHA,
                 mScrimBehind.getViewAlpha(), 0.0f);
         // Bubble scrim should be visible
-        Assert.assertEquals(ScrimController.BUSY_SCRIM_ALPHA,
+        Assert.assertEquals(ScrimController.BUBBLE_SCRIM_ALPHA,
                 mScrimForBubble.getViewAlpha(), 0.0f);
     }
 
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 f1fc0b77..9b9937b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -955,8 +955,8 @@
 
     @Test
     public void testNotifyShadeSuppressionChange_notificationDismiss() {
-        Bubbles.NotificationSuppressionChangedListener listener =
-                mock(Bubbles.NotificationSuppressionChangedListener.class);
+        Bubbles.SuppressionChangedListener listener =
+                mock(Bubbles.SuppressionChangedListener.class);
         mBubbleData.setSuppressionChangedListener(listener);
 
         mEntryListener.onPendingEntryAdded(mRow.getEntry());
@@ -979,8 +979,8 @@
 
     @Test
     public void testNotifyShadeSuppressionChange_bubbleExpanded() {
-        Bubbles.NotificationSuppressionChangedListener listener =
-                mock(Bubbles.NotificationSuppressionChangedListener.class);
+        Bubbles.SuppressionChangedListener listener =
+                mock(Bubbles.SuppressionChangedListener.class);
         mBubbleData.setSuppressionChangedListener(listener);
 
         mEntryListener.onPendingEntryAdded(mRow.getEntry());
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 9e10b21..b0ec628 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java
@@ -789,8 +789,8 @@
 
     @Test
     public void testNotifyShadeSuppressionChange_notificationDismiss() {
-        Bubbles.NotificationSuppressionChangedListener listener =
-                mock(Bubbles.NotificationSuppressionChangedListener.class);
+        Bubbles.SuppressionChangedListener listener =
+                mock(Bubbles.SuppressionChangedListener.class);
         mBubbleData.setSuppressionChangedListener(listener);
 
         mEntryListener.onEntryAdded(mRow.getEntry());
@@ -812,8 +812,8 @@
 
     @Test
     public void testNotifyShadeSuppressionChange_bubbleExpanded() {
-        Bubbles.NotificationSuppressionChangedListener listener =
-                mock(Bubbles.NotificationSuppressionChangedListener.class);
+        Bubbles.SuppressionChangedListener listener =
+                mock(Bubbles.SuppressionChangedListener.class);
         mBubbleData.setSuppressionChangedListener(listener);
 
         mEntryListener.onEntryAdded(mRow.getEntry());
diff --git a/rs/java/android/renderscript/RenderScript.java b/rs/java/android/renderscript/RenderScript.java
index 39efe73..806a25a7 100644
--- a/rs/java/android/renderscript/RenderScript.java
+++ b/rs/java/android/renderscript/RenderScript.java
@@ -1363,13 +1363,6 @@
             mApplicationContext = ctx.getApplicationContext();
         }
         mRWLock = new ReentrantReadWriteLock();
-        try {
-            registerNativeAllocation.invoke(sRuntime, 4 * 1024 * 1024); // 4MB for GC sake
-        } catch (Exception e) {
-            Log.e(RenderScript.LOG_TAG, "Couldn't invoke registerNativeAllocation:" + e);
-            throw new RSRuntimeException("Couldn't invoke registerNativeAllocation:" + e);
-        }
-
     }
 
     /**
diff --git a/services/accessibility/java/com/android/server/accessibility/ActionReplacingCallback.java b/services/accessibility/java/com/android/server/accessibility/ActionReplacingCallback.java
index 6828dd9..bafb641 100644
--- a/services/accessibility/java/com/android/server/accessibility/ActionReplacingCallback.java
+++ b/services/accessibility/java/com/android/server/accessibility/ActionReplacingCallback.java
@@ -40,34 +40,29 @@
     private final IAccessibilityInteractionConnectionCallback mServiceCallback;
     private final IAccessibilityInteractionConnection mConnectionWithReplacementActions;
     private final int mInteractionId;
-    private final int mNodeWithReplacementActionsInteractionId;
     private final Object mLock = new Object();
 
     @GuardedBy("mLock")
-    private boolean mReplacementNodeIsReadyOrFailed;
-
-    @GuardedBy("mLock")
-    AccessibilityNodeInfo mNodeWithReplacementActions;
+    List<AccessibilityNodeInfo> mNodesWithReplacementActions;
 
     @GuardedBy("mLock")
     List<AccessibilityNodeInfo> mNodesFromOriginalWindow;
 
     @GuardedBy("mLock")
-    boolean mSetFindNodeFromOriginalWindowCalled = false;
-
-    @GuardedBy("mLock")
     AccessibilityNodeInfo mNodeFromOriginalWindow;
 
+    // Keep track of whether or not we've been called back for a single node
     @GuardedBy("mLock")
-    boolean mSetFindNodesFromOriginalWindowCalled = false;
+    boolean mSingleNodeCallbackHappened;
 
-
+    // Keep track of whether or not we've been called back for multiple node
     @GuardedBy("mLock")
-    List<AccessibilityNodeInfo> mPrefetchedNodesFromOriginalWindow;
+    boolean mMultiNodeCallbackHappened;
 
+    // We shouldn't get any more callbacks after we've called back the original service, but
+    // keep track to make sure we catch such strange things
     @GuardedBy("mLock")
-    boolean mSetPrefetchFromOriginalWindowCalled = false;
-
+    boolean mDone;
 
     public ActionReplacingCallback(IAccessibilityInteractionConnectionCallback serviceCallback,
             IAccessibilityInteractionConnection connectionWithReplacementActions,
@@ -75,20 +70,19 @@
         mServiceCallback = serviceCallback;
         mConnectionWithReplacementActions = connectionWithReplacementActions;
         mInteractionId = interactionId;
-        mNodeWithReplacementActionsInteractionId = interactionId + 1;
 
         // Request the root node of the replacing window
         final long identityToken = Binder.clearCallingIdentity();
         try {
             mConnectionWithReplacementActions.findAccessibilityNodeInfoByAccessibilityId(
-                    AccessibilityNodeInfo.ROOT_NODE_ID, null,
-                    mNodeWithReplacementActionsInteractionId, this, 0,
+                    AccessibilityNodeInfo.ROOT_NODE_ID, null, interactionId + 1, this, 0,
                     interrogatingPid, interrogatingTid, null, null);
         } catch (RemoteException re) {
             if (DEBUG) {
                 Slog.e(LOG_TAG, "Error calling findAccessibilityNodeInfoByAccessibilityId()");
             }
-            mReplacementNodeIsReadyOrFailed = true;
+            // Pretend we already got a (null) list of replacement nodes
+            mMultiNodeCallbackHappened = true;
         } finally {
             Binder.restoreCallingIdentity(identityToken);
         }
@@ -96,67 +90,46 @@
 
     @Override
     public void setFindAccessibilityNodeInfoResult(AccessibilityNodeInfo info, int interactionId) {
-        synchronized (mLock) {
+        boolean readyForCallback;
+        synchronized(mLock) {
             if (interactionId == mInteractionId) {
                 mNodeFromOriginalWindow = info;
-                mSetFindNodeFromOriginalWindowCalled = true;
-            } else if (interactionId == mNodeWithReplacementActionsInteractionId) {
-                mNodeWithReplacementActions = info;
-                mReplacementNodeIsReadyOrFailed = true;
             } else {
                 Slog.e(LOG_TAG, "Callback with unexpected interactionId");
                 return;
             }
+
+            mSingleNodeCallbackHappened = true;
+            readyForCallback = mMultiNodeCallbackHappened;
         }
-        replaceInfoActionsAndCallServiceIfReady();
+        if (readyForCallback) {
+            replaceInfoActionsAndCallService();
+        }
     }
 
     @Override
     public void setFindAccessibilityNodeInfosResult(List<AccessibilityNodeInfo> infos,
             int interactionId) {
-        synchronized (mLock) {
+        boolean callbackForSingleNode;
+        boolean callbackForMultipleNodes;
+        synchronized(mLock) {
             if (interactionId == mInteractionId) {
                 mNodesFromOriginalWindow = infos;
-                mSetFindNodesFromOriginalWindowCalled = true;
-            } else if (interactionId == mNodeWithReplacementActionsInteractionId) {
-                setNodeWithReplacementActionsFromList(infos);
-                mReplacementNodeIsReadyOrFailed = true;
+            } else if (interactionId == mInteractionId + 1) {
+                mNodesWithReplacementActions = infos;
             } else {
                 Slog.e(LOG_TAG, "Callback with unexpected interactionId");
                 return;
             }
+            callbackForSingleNode = mSingleNodeCallbackHappened;
+            callbackForMultipleNodes = mMultiNodeCallbackHappened;
+            mMultiNodeCallbackHappened = true;
         }
-        replaceInfoActionsAndCallServiceIfReady();
-    }
-
-    @Override
-    public void setPrefetchAccessibilityNodeInfoResult(List<AccessibilityNodeInfo> infos,
-                                                       int interactionId)
-            throws RemoteException {
-        synchronized (mLock) {
-            if (interactionId == mInteractionId) {
-                mPrefetchedNodesFromOriginalWindow = infos;
-                mSetPrefetchFromOriginalWindowCalled = true;
-            }  else {
-                Slog.e(LOG_TAG, "Callback with unexpected interactionId");
-                return;
-            }
+        if (callbackForSingleNode) {
+            replaceInfoActionsAndCallService();
         }
-        replaceInfoActionsAndCallServiceIfReady();
-    }
-
-    private void replaceInfoActionsAndCallServiceIfReady() {
-        replaceInfoActionsAndCallService();
-        replaceInfosActionsAndCallService();
-        replacePrefetchInfosActionsAndCallService();
-    }
-
-    private void setNodeWithReplacementActionsFromList(List<AccessibilityNodeInfo> infos) {
-        for (int i = 0; i < infos.size(); i++) {
-            AccessibilityNodeInfo info = infos.get(i);
-            if (info.getSourceNodeId() == AccessibilityNodeInfo.ROOT_NODE_ID) {
-                mNodeWithReplacementActions = info;
-            }
+        if (callbackForMultipleNodes) {
+            replaceInfosActionsAndCallService();
         }
     }
 
@@ -169,81 +142,55 @@
 
     private void replaceInfoActionsAndCallService() {
         final AccessibilityNodeInfo nodeToReturn;
-        boolean doCallback = false;
         synchronized (mLock) {
-            doCallback = mReplacementNodeIsReadyOrFailed
-                    && mSetFindNodeFromOriginalWindowCalled;
-            if (doCallback && mNodeFromOriginalWindow != null) {
-                replaceActionsOnInfoLocked(mNodeFromOriginalWindow);
-                mSetFindNodeFromOriginalWindowCalled = false;
-            }
-            nodeToReturn = mNodeFromOriginalWindow;
-        }
-        if (doCallback) {
-            try {
-                mServiceCallback.setFindAccessibilityNodeInfoResult(nodeToReturn, mInteractionId);
-            } catch (RemoteException re) {
+            if (mDone) {
                 if (DEBUG) {
-                    Slog.e(LOG_TAG, "Failed to setFindAccessibilityNodeInfoResult");
+                    Slog.e(LOG_TAG, "Extra callback");
                 }
+                return;
+            }
+            if (mNodeFromOriginalWindow != null) {
+                replaceActionsOnInfoLocked(mNodeFromOriginalWindow);
+            }
+            recycleReplaceActionNodesLocked();
+            nodeToReturn = mNodeFromOriginalWindow;
+            mDone = true;
+        }
+        try {
+            mServiceCallback.setFindAccessibilityNodeInfoResult(nodeToReturn, mInteractionId);
+        } catch (RemoteException re) {
+            if (DEBUG) {
+                Slog.e(LOG_TAG, "Failed to setFindAccessibilityNodeInfoResult");
             }
         }
     }
 
     private void replaceInfosActionsAndCallService() {
-        List<AccessibilityNodeInfo> nodesToReturn = null;
-        boolean doCallback = false;
+        final List<AccessibilityNodeInfo> nodesToReturn;
         synchronized (mLock) {
-            doCallback = mReplacementNodeIsReadyOrFailed
-                    && mSetFindNodesFromOriginalWindowCalled;
-            if (doCallback) {
-                nodesToReturn = replaceActionsLocked(mNodesFromOriginalWindow);
-                mSetFindNodesFromOriginalWindowCalled = false;
-            }
-        }
-        if (doCallback) {
-            try {
-                mServiceCallback.setFindAccessibilityNodeInfosResult(nodesToReturn, mInteractionId);
-            } catch (RemoteException re) {
+            if (mDone) {
                 if (DEBUG) {
-                    Slog.e(LOG_TAG, "Failed to setFindAccessibilityNodeInfosResult");
+                    Slog.e(LOG_TAG, "Extra callback");
+                }
+                return;
+            }
+            if (mNodesFromOriginalWindow != null) {
+                for (int i = 0; i < mNodesFromOriginalWindow.size(); i++) {
+                    replaceActionsOnInfoLocked(mNodesFromOriginalWindow.get(i));
                 }
             }
+            recycleReplaceActionNodesLocked();
+            nodesToReturn = (mNodesFromOriginalWindow == null)
+                    ? null : new ArrayList<>(mNodesFromOriginalWindow);
+            mDone = true;
         }
-    }
-
-    private void replacePrefetchInfosActionsAndCallService() {
-        List<AccessibilityNodeInfo> nodesToReturn = null;
-        boolean doCallback = false;
-        synchronized (mLock) {
-            doCallback = mReplacementNodeIsReadyOrFailed
-                    && mSetPrefetchFromOriginalWindowCalled;
-            if (doCallback) {
-                nodesToReturn = replaceActionsLocked(mPrefetchedNodesFromOriginalWindow);
-                mSetPrefetchFromOriginalWindowCalled = false;
+        try {
+            mServiceCallback.setFindAccessibilityNodeInfosResult(nodesToReturn, mInteractionId);
+        } catch (RemoteException re) {
+            if (DEBUG) {
+                Slog.e(LOG_TAG, "Failed to setFindAccessibilityNodeInfosResult");
             }
         }
-        if (doCallback) {
-            try {
-                mServiceCallback.setPrefetchAccessibilityNodeInfoResult(
-                        nodesToReturn, mInteractionId);
-            } catch (RemoteException re) {
-                if (DEBUG) {
-                    Slog.e(LOG_TAG, "Failed to setFindAccessibilityNodeInfosResult");
-                }
-            }
-        }
-    }
-
-    @GuardedBy("mLock")
-    private List<AccessibilityNodeInfo> replaceActionsLocked(List<AccessibilityNodeInfo> infos) {
-        if (infos != null) {
-            for (int i = 0; i < infos.size(); i++) {
-                replaceActionsOnInfoLocked(infos.get(i));
-            }
-        }
-        return (infos == null)
-                ? null : new ArrayList<>(infos);
     }
 
     @GuardedBy("mLock")
@@ -257,22 +204,40 @@
         info.setDismissable(false);
         // We currently only replace actions for the root node
         if ((info.getSourceNodeId() == AccessibilityNodeInfo.ROOT_NODE_ID)
-                && mNodeWithReplacementActions != null) {
-            List<AccessibilityAction> actions = mNodeWithReplacementActions.getActionList();
-            if (actions != null) {
-                for (int j = 0; j < actions.size(); j++) {
-                    info.addAction(actions.get(j));
+                && mNodesWithReplacementActions != null) {
+            // This list should always contain a single node with the root ID
+            for (int i = 0; i < mNodesWithReplacementActions.size(); i++) {
+                AccessibilityNodeInfo nodeWithReplacementActions =
+                        mNodesWithReplacementActions.get(i);
+                if (nodeWithReplacementActions.getSourceNodeId()
+                        == AccessibilityNodeInfo.ROOT_NODE_ID) {
+                    List<AccessibilityAction> actions = nodeWithReplacementActions.getActionList();
+                    if (actions != null) {
+                        for (int j = 0; j < actions.size(); j++) {
+                            info.addAction(actions.get(j));
+                        }
+                        // The PIP needs to be able to take accessibility focus
+                        info.addAction(AccessibilityAction.ACTION_ACCESSIBILITY_FOCUS);
+                        info.addAction(AccessibilityAction.ACTION_CLEAR_ACCESSIBILITY_FOCUS);
+                    }
+                    info.setClickable(nodeWithReplacementActions.isClickable());
+                    info.setFocusable(nodeWithReplacementActions.isFocusable());
+                    info.setContextClickable(nodeWithReplacementActions.isContextClickable());
+                    info.setScrollable(nodeWithReplacementActions.isScrollable());
+                    info.setLongClickable(nodeWithReplacementActions.isLongClickable());
+                    info.setDismissable(nodeWithReplacementActions.isDismissable());
                 }
-                // The PIP needs to be able to take accessibility focus
-                info.addAction(AccessibilityAction.ACTION_ACCESSIBILITY_FOCUS);
-                info.addAction(AccessibilityAction.ACTION_CLEAR_ACCESSIBILITY_FOCUS);
             }
-            info.setClickable(mNodeWithReplacementActions.isClickable());
-            info.setFocusable(mNodeWithReplacementActions.isFocusable());
-            info.setContextClickable(mNodeWithReplacementActions.isContextClickable());
-            info.setScrollable(mNodeWithReplacementActions.isScrollable());
-            info.setLongClickable(mNodeWithReplacementActions.isLongClickable());
-            info.setDismissable(mNodeWithReplacementActions.isDismissable());
         }
     }
+
+    @GuardedBy("mLock")
+    private void recycleReplaceActionNodesLocked() {
+        if (mNodesWithReplacementActions == null) return;
+        for (int i = mNodesWithReplacementActions.size() - 1; i >= 0; i--) {
+            AccessibilityNodeInfo nodeWithReplacementAction = mNodesWithReplacementActions.get(i);
+            nodeWithReplacementAction.recycle();
+        }
+        mNodesWithReplacementActions = null;
+    }
 }
diff --git a/services/autofill/java/com/android/server/autofill/ClientSuggestionsSession.java b/services/autofill/java/com/android/server/autofill/ClientSuggestionsSession.java
new file mode 100644
index 0000000..715697d
--- /dev/null
+++ b/services/autofill/java/com/android/server/autofill/ClientSuggestionsSession.java
@@ -0,0 +1,293 @@
+/*
+ * 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 2aa5d26..b7f736e 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -26,6 +26,7 @@
 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;
 
@@ -53,6 +54,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentSender;
+import android.content.pm.ApplicationInfo;
 import android.graphics.Bitmap;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
@@ -346,6 +348,9 @@
      */
     private final AssistDataReceiverImpl mAssistReceiver = new AssistDataReceiverImpl();
 
+    @Nullable
+    private ClientSuggestionsSession mClientSuggestionsSession;
+
     void onSwitchInputMethodLocked() {
         // One caveat is that for the case where the focus is on a field for which regular autofill
         // returns null, and augmented autofill is triggered,  and then the user switches the input
@@ -416,6 +421,10 @@
         /** Whether the current {@link FillResponse} is expired. */
         @GuardedBy("mLock")
         private boolean mExpiredResponse;
+
+        /** Whether the client is using {@link android.view.autofill.AutofillRequestCallback}. */
+        @GuardedBy("mLock")
+        private boolean mClientSuggestionsEnabled;
     }
 
     /**
@@ -728,30 +737,39 @@
     }
 
     /**
-     * Cancels the last request sent to the {@link #mRemoteFillService}.
+     * Cancels the last request sent to the {@link #mRemoteFillService} or the
+     * {@link #mClientSuggestionsSession}.
      */
     @GuardedBy("mLock")
     private void cancelCurrentRequestLocked() {
-        if (mRemoteFillService == null) {
-            wtf(null, "cancelCurrentRequestLocked() called without a remote service. "
-                    + "mForAugmentedAutofillOnly: %s", mSessionFlags.mAugmentedAutofillOnly);
+        if (mRemoteFillService == null && mClientSuggestionsSession == null) {
+            wtf(null, "cancelCurrentRequestLocked() called without a remote service or a "
+                    + "client suggestions session.  mForAugmentedAutofillOnly: %s",
+                    mSessionFlags.mAugmentedAutofillOnly);
             return;
         }
-        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();
+        if (mRemoteFillService != null) {
+            final int canceledRequest = mRemoteFillService.cancelCurrentRequest();
 
-            // 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;
+            // 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;
+                    }
                 }
             }
         }
+
+        if (mClientSuggestionsSession != null) {
+            mClientSuggestionsSession.cancelCurrentRequest();
+        }
     }
 
     private boolean isViewFocusedLocked(int flags) {
@@ -816,17 +834,30 @@
         // structure is taken. This causes only one fill request per burst of focus changes.
         cancelCurrentRequestLocked();
 
-        // 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.
+        // 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.)
         final RemoteInlineSuggestionRenderService remoteRenderService =
                 mService.getRemoteInlineSuggestionRenderServiceLocked();
-        if (mSessionFlags.mInlineSupportedByService
+        if ((mSessionFlags.mInlineSupportedByService || mSessionFlags.mClientSuggestionsEnabled)
                 && remoteRenderService != null
                 && isViewFocusedLocked(flags)) {
-            Consumer<InlineSuggestionsRequest> inlineSuggestionsRequestConsumer =
-                    mAssistReceiver.newAutofillRequestLocked(viewState,
-                            /* isInlineRequest= */ true);
+            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);
+            }
             if (inlineSuggestionsRequestConsumer != null) {
                 final AutofillId focusedId = mCurrentViewId;
                 final int requestIdCopy = requestId;
@@ -842,10 +873,18 @@
                 );
                 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.
         try {
             final Bundle receiverExtras = new Bundle();
@@ -895,10 +934,13 @@
         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);
         }
 
@@ -3030,13 +3072,22 @@
             filterText = value.getTextValue().toString();
         }
 
-        final CharSequence serviceLabel;
-        final Drawable serviceIcon;
+        final CharSequence targetLabel;
+        final Drawable targetIcon;
         synchronized (mLock) {
-            serviceLabel = mService.getServiceLabelLocked();
-            serviceIcon = mService.getServiceIconLocked();
+            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();
+            }
         }
-        if (serviceLabel == null || serviceIcon == null) {
+        if (targetLabel == null || targetIcon == null) {
             wtf(null, "onFillReady(): no service label or icon");
             return;
         }
@@ -3056,7 +3107,7 @@
 
         getUiForShowing().showFillUi(filledId, response, filterText,
                 mService.getServicePackageName(), mComponentName,
-                serviceLabel, serviceIcon, this, id, mCompatMode);
+                targetLabel, targetIcon, this, id, mCompatMode);
 
         mService.logDatasetShown(id, mClientState);
 
@@ -3712,6 +3763,21 @@
         }
     }
 
+    @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);
+        }
+
+        mClientSuggestionsSession.onFillRequest(requestId, inlineSuggestionsRequest, mFlags);
+    }
+
     /**
      * The result of checking whether to show the save dialog, when session can be saved.
      *
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index 342208c..c295778 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -69,7 +69,6 @@
             PACKAGE_BROWSER,
             PACKAGE_SYSTEM_TEXT_CLASSIFIER,
             PACKAGE_PERMISSION_CONTROLLER,
-            PACKAGE_WELLBEING,
             PACKAGE_DOCUMENTER,
             PACKAGE_CONFIGURATOR,
             PACKAGE_INCIDENT_REPORT_APPROVER,
diff --git a/services/core/java/com/android/server/BootReceiver.java b/services/core/java/com/android/server/BootReceiver.java
index d83e2fd..b7c5fba 100644
--- a/services/core/java/com/android/server/BootReceiver.java
+++ b/services/core/java/com/android/server/BootReceiver.java
@@ -128,6 +128,9 @@
     // Location of ftrace pipe for notifications from kernel memory tools like KFENCE and KASAN.
     private static final String ERROR_REPORT_TRACE_PIPE =
             "/sys/kernel/tracing/instances/bootreceiver/trace_pipe";
+    // Stop after sending this many reports. See http://b/182159975.
+    private static final int MAX_ERROR_REPORTS = 8;
+    private static int sSentReports = 0;
     // Avoid reporing the same bug from processDmesg() twice.
     private static String sLastReportedBug = null;
 
@@ -301,7 +304,7 @@
      *    - repeat the above steps till the last report is found.
      */
     private void processDmesg(Context ctx) throws IOException {
-
+        if (sSentReports == MAX_ERROR_REPORTS) return;
         /*
          * Only SYSTEM_KASAN_ERROR_REPORT and SYSTEM_KFENCE_ERROR_REPORT are supported at the
          * moment.
@@ -352,7 +355,7 @@
         }
 
         // Avoid sending the same bug report twice.
-        if (bugTitle == sLastReportedBug) return;
+        if (bugTitle.equals(sLastReportedBug)) return;
 
         final String reportTag = "SYSTEM_" + tool + "_ERROR_REPORT";
         final DropBoxManager db = ctx.getSystemService(DropBoxManager.class);
@@ -361,6 +364,7 @@
 
         addTextToDropBox(db, reportTag, reportText, "/dev/kmsg", LOG_SIZE);
         sLastReportedBug = bugTitle;
+        sSentReports++;
     }
 
     private void removeOldUpdatePackages(Context context) {
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 2c9837d..07b473c 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -1038,6 +1038,16 @@
         public IBatteryStats getBatteryStatsService() {
             return BatteryStatsService.getService();
         }
+
+        /**
+         * @see BatteryStatsManager
+         */
+        public void reportNetworkInterfaceForTransports(Context context, String iface,
+                int[] transportTypes) {
+            final BatteryStatsManager  batteryStats =
+                    context.getSystemService(BatteryStatsManager.class);
+            batteryStats.reportNetworkInterfaceForTransports(iface, transportTypes);
+        }
     }
 
     public ConnectivityService(Context context) {
@@ -3604,11 +3614,10 @@
     // pendingIntent => NetworkRequestInfo map.
     // This method assumes that every non-null PendingIntent maps to exactly 1 NetworkRequestInfo.
     private NetworkRequestInfo findExistingNetworkRequestInfo(PendingIntent pendingIntent) {
-        Intent intent = pendingIntent.getIntent();
         for (Map.Entry<NetworkRequest, NetworkRequestInfo> entry : mNetworkRequests.entrySet()) {
             PendingIntent existingPendingIntent = entry.getValue().mPendingIntent;
             if (existingPendingIntent != null &&
-                    existingPendingIntent.getIntent().filterEquals(intent)) {
+                    existingPendingIntent.intentFilterEquals(pendingIntent)) {
                 return entry.getValue();
             }
         }
@@ -3651,6 +3660,13 @@
                     }
                 }
             }
+            // If this NRI has a satisfier already, it is replacing an older request that
+            // has been removed. Track it.
+            final NetworkRequest activeRequest = nri.getActiveRequest();
+            if (null != activeRequest) {
+                // If there is an active request, then for sure there is a satisfier.
+                nri.getSatisfier().addRequest(activeRequest);
+            }
         }
 
         rematchAllNetworksAndRequests();
@@ -5271,14 +5287,26 @@
             ensureAllNetworkRequestsHaveType(r);
             mRequests = initializeRequests(r);
             mNetworkRequestForCallback = nri.getNetworkRequestForCallback();
-            // Note here that the satisfier may have corresponded to an old request, that
-            // this code doesn't try to take over. While it is a small discrepancy in the
-            // structure of these requests, it will be fixed by the next rematch and it's
-            // not as bad as having an NRI not storing its real satisfier.
-            // Fixing this discrepancy would require figuring out in the copying code what
-            // is the new request satisfied by this, which is a bit complex and not very
-            // useful as no code is using it until rematch fixes it.
-            mSatisfier = nri.mSatisfier;
+            final NetworkAgentInfo satisfier = nri.getSatisfier();
+            if (null != satisfier) {
+                // If the old NRI was satisfied by an NAI, then it may have had an active request.
+                // The active request is necessary to figure out what callbacks to send, in
+                // particular then a network updates its capabilities.
+                // As this code creates a new NRI with a new set of requests, figure out which of
+                // the list of requests should be the active request. It is always the first
+                // request of the list that can be satisfied by the satisfier since the order of
+                // requests is a priority order.
+                // Note even in the presence of a satisfier there may not be an active request,
+                // when the satisfier is the no-service network.
+                NetworkRequest activeRequest = null;
+                for (final NetworkRequest candidate : r) {
+                    if (candidate.canBeSatisfiedBy(satisfier.networkCapabilities)) {
+                        activeRequest = candidate;
+                        break;
+                    }
+                }
+                setSatisfier(satisfier, activeRequest);
+            }
             mMessenger = nri.mMessenger;
             mBinder = nri.mBinder;
             mPid = nri.mPid;
@@ -6281,13 +6309,13 @@
                 oldLp != null ? oldLp.getAllInterfaceNames() : null,
                 newLp != null ? newLp.getAllInterfaceNames() : null);
         if (!interfaceDiff.added.isEmpty()) {
-            final IBatteryStats bs = mDeps.getBatteryStatsService();
             for (final String iface : interfaceDiff.added) {
                 try {
                     if (DBG) log("Adding iface " + iface + " to network " + netId);
                     mNetd.networkAddInterface(netId, iface);
                     wakeupModifyInterface(iface, caps, true);
-                    bs.noteNetworkInterfaceForTransports(iface, caps.getTransportTypes());
+                    mDeps.reportNetworkInterfaceForTransports(mContext, iface,
+                            caps.getTransportTypes());
                 } catch (Exception e) {
                     loge("Exception adding interface: " + e);
                 }
diff --git a/services/core/java/com/android/server/TestNetworkService.java b/services/core/java/com/android/server/TestNetworkService.java
index 55408ea..ee61067 100644
--- a/services/core/java/com/android/server/TestNetworkService.java
+++ b/services/core/java/com/android/server/TestNetworkService.java
@@ -33,8 +33,8 @@
 import android.net.NetworkCapabilities;
 import android.net.NetworkProvider;
 import android.net.RouteInfo;
-import android.net.StringNetworkSpecifier;
 import android.net.TestNetworkInterface;
+import android.net.TestNetworkSpecifier;
 import android.net.util.NetdService;
 import android.os.Binder;
 import android.os.Handler;
@@ -242,7 +242,7 @@
         nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED);
         nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
         nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED);
-        nc.setNetworkSpecifier(new StringNetworkSpecifier(iface));
+        nc.setNetworkSpecifier(new TestNetworkSpecifier(iface));
         nc.setAdministratorUids(administratorUids);
         if (!isMetered) {
             nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
diff --git a/services/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java
index ad2f524..cd3892d 100644
--- a/services/core/java/com/android/server/VcnManagementService.java
+++ b/services/core/java/com/android/server/VcnManagementService.java
@@ -16,6 +16,9 @@
 
 package com.android.server;
 
+import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE;
+import static android.net.vcn.VcnManager.VCN_STATUS_CODE_INACTIVE;
+import static android.net.vcn.VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED;
 import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE;
 
 import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
@@ -37,6 +40,7 @@
 import android.net.vcn.VcnConfig;
 import android.net.vcn.VcnManager;
 import android.net.vcn.VcnManager.VcnErrorCode;
+import android.net.vcn.VcnManager.VcnStatusCode;
 import android.net.vcn.VcnUnderlyingNetworkPolicy;
 import android.net.wifi.WifiInfo;
 import android.os.Binder;
@@ -314,8 +318,7 @@
 
         /** Gets the subId indicated by the given {@link WifiInfo}. */
         public int getSubIdForWifiInfo(@NonNull WifiInfo wifiInfo) {
-            // TODO(b/178501049): use the subId indicated by WifiInfo#getSubscriptionId
-            return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+            return wifiInfo.getSubscriptionId();
         }
 
         /** Creates a new LocationPermissionChecker for the provided Context. */
@@ -421,6 +424,11 @@
                                 // Carrier App manually removing/adding a VcnConfig.
                                 if (mVcns.get(uuidToTeardown) == instanceToTeardown) {
                                     stopVcnLocked(uuidToTeardown);
+
+                                    // TODO(b/181789060): invoke asynchronously after Vcn notifies
+                                    // through VcnCallback
+                                    notifyAllPermissionedStatusCallbacksLocked(
+                                            uuidToTeardown, VCN_STATUS_CODE_INACTIVE);
                                 }
                             }
                         }, instanceToTeardown, CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS);
@@ -455,6 +463,17 @@
     }
 
     @GuardedBy("mLock")
+    private void notifyAllPermissionedStatusCallbacksLocked(
+            @NonNull ParcelUuid subGroup, @VcnStatusCode int statusCode) {
+        for (final VcnStatusCallbackInfo cbInfo : mRegisteredStatusCallbacks.values()) {
+            if (isCallbackPermissioned(cbInfo, subGroup)) {
+                Binder.withCleanCallingIdentity(
+                        () -> cbInfo.mCallback.onVcnStatusChanged(statusCode));
+            }
+        }
+    }
+
+    @GuardedBy("mLock")
     private void startVcnLocked(@NonNull ParcelUuid subscriptionGroup, @NonNull VcnConfig config) {
         Slog.v(TAG, "Starting VCN config for subGrp: " + subscriptionGroup);
 
@@ -470,6 +489,9 @@
         // Now that a new VCN has started, notify all registered listeners to refresh their
         // UnderlyingNetworkPolicy.
         notifyAllPolicyListenersLocked();
+
+        // TODO(b/181789060): invoke asynchronously after Vcn notifies through VcnCallback
+        notifyAllPermissionedStatusCallbacksLocked(subscriptionGroup, VCN_STATUS_CODE_ACTIVE);
     }
 
     @GuardedBy("mLock")
@@ -478,7 +500,16 @@
         Slog.v(TAG, "Starting or updating VCN config for subGrp: " + subscriptionGroup);
 
         if (mVcns.containsKey(subscriptionGroup)) {
-            mVcns.get(subscriptionGroup).updateConfig(config);
+            final Vcn vcn = mVcns.get(subscriptionGroup);
+            final boolean isActive = vcn.isActive();
+            vcn.updateConfig(config);
+
+            // Only notify VcnStatusCallbacks if this VCN was previously in Safe Mode
+            if (!isActive) {
+                // TODO(b/181789060): invoke asynchronously after Vcn notifies through VcnCallback
+                notifyAllPermissionedStatusCallbacksLocked(
+                        subscriptionGroup, VCN_STATUS_CODE_ACTIVE);
+            }
         } else {
             startVcnLocked(subscriptionGroup, config);
         }
@@ -531,9 +562,17 @@
         Binder.withCleanCallingIdentity(() -> {
             synchronized (mLock) {
                 mConfigs.remove(subscriptionGroup);
+                final boolean vcnExists = mVcns.containsKey(subscriptionGroup);
 
                 stopVcnLocked(subscriptionGroup);
 
+                if (vcnExists) {
+                    // TODO(b/181789060): invoke asynchronously after Vcn notifies through
+                    // VcnCallback
+                    notifyAllPermissionedStatusCallbacksLocked(
+                            subscriptionGroup, VCN_STATUS_CODE_NOT_CONFIGURED);
+                }
+
                 writeConfigsToDiskLocked();
             }
         });
@@ -604,18 +643,20 @@
                 android.Manifest.permission.NETWORK_FACTORY,
                 "Must have permission NETWORK_FACTORY to register a policy listener");
 
-        PolicyListenerBinderDeath listenerBinderDeath = new PolicyListenerBinderDeath(listener);
+        Binder.withCleanCallingIdentity(() -> {
+            PolicyListenerBinderDeath listenerBinderDeath = new PolicyListenerBinderDeath(listener);
 
-        synchronized (mLock) {
-            mRegisteredPolicyListeners.put(listener.asBinder(), listenerBinderDeath);
+            synchronized (mLock) {
+                mRegisteredPolicyListeners.put(listener.asBinder(), listenerBinderDeath);
 
-            try {
-                listener.asBinder().linkToDeath(listenerBinderDeath, 0 /* flags */);
-            } catch (RemoteException e) {
-                // Remote binder already died - cleanup registered Listener
-                listenerBinderDeath.binderDied();
+                try {
+                    listener.asBinder().linkToDeath(listenerBinderDeath, 0 /* flags */);
+                } catch (RemoteException e) {
+                    // Remote binder already died - cleanup registered Listener
+                    listenerBinderDeath.binderDied();
+                }
             }
-        }
+        });
     }
 
     /** Removes the provided listener from receiving VcnUnderlyingNetworkPolicy updates. */
@@ -625,14 +666,31 @@
             @NonNull IVcnUnderlyingNetworkPolicyListener listener) {
         requireNonNull(listener, "listener was null");
 
-        synchronized (mLock) {
-            PolicyListenerBinderDeath listenerBinderDeath =
-                    mRegisteredPolicyListeners.remove(listener.asBinder());
+        Binder.withCleanCallingIdentity(() -> {
+            synchronized (mLock) {
+                PolicyListenerBinderDeath listenerBinderDeath =
+                        mRegisteredPolicyListeners.remove(listener.asBinder());
 
-            if (listenerBinderDeath != null) {
-                listener.asBinder().unlinkToDeath(listenerBinderDeath, 0 /* flags */);
+                if (listenerBinderDeath != null) {
+                    listener.asBinder().unlinkToDeath(listenerBinderDeath, 0 /* flags */);
+                }
             }
+        });
+    }
+
+    private int getSubIdForNetworkCapabilities(@NonNull NetworkCapabilities networkCapabilities) {
+        if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)
+                && networkCapabilities.getNetworkSpecifier() instanceof TelephonyNetworkSpecifier) {
+            TelephonyNetworkSpecifier telephonyNetworkSpecifier =
+                    (TelephonyNetworkSpecifier) networkCapabilities.getNetworkSpecifier();
+            return telephonyNetworkSpecifier.getSubscriptionId();
+        } else if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
+                && networkCapabilities.getTransportInfo() instanceof WifiInfo) {
+            WifiInfo wifiInfo = (WifiInfo) networkCapabilities.getTransportInfo();
+            return mDeps.getSubIdForWifiInfo(wifiInfo);
         }
+
+        return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
     }
 
     /**
@@ -652,51 +710,47 @@
                 "Must have permission NETWORK_FACTORY or be the SystemServer to get underlying"
                         + " Network policies");
 
-        // Defensive copy in case this call is in-process and the given NetworkCapabilities mutates
-        networkCapabilities = new NetworkCapabilities(networkCapabilities);
+        return Binder.withCleanCallingIdentity(() -> {
+            // Defensive copy in case this call is in-process and the given NetworkCapabilities
+            // mutates
+            final NetworkCapabilities ncCopy = new NetworkCapabilities(networkCapabilities);
 
-        int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
-        if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)
-                && networkCapabilities.getNetworkSpecifier() instanceof TelephonyNetworkSpecifier) {
-            TelephonyNetworkSpecifier telephonyNetworkSpecifier =
-                    (TelephonyNetworkSpecifier) networkCapabilities.getNetworkSpecifier();
-            subId = telephonyNetworkSpecifier.getSubscriptionId();
-        } else if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
-                && networkCapabilities.getTransportInfo() instanceof WifiInfo) {
-            WifiInfo wifiInfo = (WifiInfo) networkCapabilities.getTransportInfo();
-            subId = mDeps.getSubIdForWifiInfo(wifiInfo);
-        }
+            final int subId = getSubIdForNetworkCapabilities(ncCopy);
+            boolean isVcnManagedNetwork = false;
+            boolean isRestrictedCarrierWifi = false;
+            if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+                synchronized (mLock) {
+                    ParcelUuid subGroup = mLastSnapshot.getGroupForSubId(subId);
 
-        boolean isVcnManagedNetwork = false;
-        boolean isRestrictedCarrierWifi = false;
-        if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
-            synchronized (mLock) {
-                ParcelUuid subGroup = mLastSnapshot.getGroupForSubId(subId);
+                    final Vcn vcn = mVcns.get(subGroup);
+                    if (vcn != null) {
+                        if (vcn.isActive()) {
+                            isVcnManagedNetwork = true;
+                        }
 
-                Vcn vcn = mVcns.get(subGroup);
-                if (vcn != null) {
-                    if (vcn.isActive()) {
-                        isVcnManagedNetwork = true;
-                    }
-
-                    if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
-                        // Carrier WiFi always restricted if VCN exists (even in safe mode).
-                        isRestrictedCarrierWifi = true;
+                        if (ncCopy.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
+                            // Carrier WiFi always restricted if VCN exists (even in safe mode).
+                            isRestrictedCarrierWifi = true;
+                        }
                     }
                 }
             }
-        }
 
-        if (isVcnManagedNetwork) {
-            networkCapabilities.removeCapability(
-                    NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED);
-        }
+            final NetworkCapabilities.Builder ncBuilder = new NetworkCapabilities.Builder(ncCopy);
 
-        if (isRestrictedCarrierWifi) {
-            networkCapabilities.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
-        }
+            if (isVcnManagedNetwork) {
+                ncBuilder.removeCapability(
+                        NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED);
+            }
 
-        return new VcnUnderlyingNetworkPolicy(false /* isTearDownRequested */, networkCapabilities);
+            if (isRestrictedCarrierWifi) {
+                ncBuilder.removeCapability(
+                        NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
+            }
+
+            return new VcnUnderlyingNetworkPolicy(
+                    false /* isTearDownRequested */, ncBuilder.build());
+        });
     }
 
     /** Binder death recipient used to remove registered VcnStatusCallbacks. */
@@ -857,16 +911,7 @@
                 }
 
                 notifyAllPolicyListenersLocked();
-
-                // Notify all registered StatusCallbacks for this subGroup
-                for (VcnStatusCallbackInfo cbInfo : mRegisteredStatusCallbacks.values()) {
-                    if (isCallbackPermissioned(cbInfo, mSubGroup)) {
-                        Binder.withCleanCallingIdentity(
-                                () ->
-                                        cbInfo.mCallback.onVcnStatusChanged(
-                                                VCN_STATUS_CODE_SAFE_MODE));
-                    }
-                }
+                notifyAllPermissionedStatusCallbacksLocked(mSubGroup, VCN_STATUS_CODE_SAFE_MODE);
             }
         }
 
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index 5b50431..9636641 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -75,7 +75,8 @@
     //         can trigger the watchdog.
     // Note 2: The debug value is already below the wait time in ZygoteConnection. Wrapped
     //         applications may not work with a debug build. CTS will fail.
-    private static final long DEFAULT_TIMEOUT = DB ? 10 * 1000 : 60 * 1000;
+    private static final long DEFAULT_TIMEOUT =
+            (DB ? 10 * 1000 : 60 * 1000) * Build.HW_TIMEOUT_MULTIPLIER;
     private static final long CHECK_INTERVAL = DEFAULT_TIMEOUT / 2;
 
     // These are temporally ordered: larger values as lateness increases
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 277cb8c..f768db1 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -178,14 +178,14 @@
     private static final boolean SHOW_DUNGEON_NOTIFICATION = false;
 
     // How long we wait for a service to finish executing.
-    static final int SERVICE_TIMEOUT = 20*1000;
+    static final int SERVICE_TIMEOUT = 20 * 1000 * Build.HW_TIMEOUT_MULTIPLIER;
 
     // 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;
+    static final int SERVICE_START_FOREGROUND_TIMEOUT = 10 * 1000 * Build.HW_TIMEOUT_MULTIPLIER;
 
     final ActivityManagerService mAm;
 
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 9e5d7e4..8ea6194 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -44,7 +44,7 @@
 import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.os.FactoryTest.FACTORY_TEST_OFF;
-import static android.os.IInputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
+import static android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
 import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL;
 import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_HIGH;
 import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL;
@@ -67,6 +67,7 @@
 import static android.os.Process.SIGNAL_USR1;
 import static android.os.Process.SYSTEM_UID;
 import static android.os.Process.THREAD_PRIORITY_FOREGROUND;
+import static android.os.Process.THREAD_PRIORITY_TOP_APP_BOOST;
 import static android.os.Process.ZYGOTE_POLICY_FLAG_BATCH_LAUNCH;
 import static android.os.Process.ZYGOTE_POLICY_FLAG_EMPTY;
 import static android.os.Process.ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE;
@@ -408,10 +409,6 @@
 public class ActivityManagerService extends IActivityManager.Stub
         implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback, ActivityManagerGlobalLock {
 
-    /**
-     * Priority we boost main thread and RT of top app to.
-     */
-    public static final int TOP_APP_PRIORITY_BOOST = -10;
     private static final String SYSTEM_PROPERTY_DEVICE_PROVISIONED =
             "persist.sys.device_provisioned";
 
@@ -452,7 +449,7 @@
 
     // How long we wait for a launched process to attach to the activity manager
     // before we decide it's never going to come up for real.
-    static final int PROC_START_TIMEOUT = 10*1000;
+    static final int PROC_START_TIMEOUT = 10 * 1000 * Build.HW_TIMEOUT_MULTIPLIER;
     // How long we wait to kill an application zygote, after the last process using
     // it has gone away.
     static final int KILL_APP_ZYGOTE_DELAY_MS = 5 * 1000;
@@ -464,8 +461,8 @@
     static final int PROC_START_TIMEOUT_WITH_WRAPPER = 1200*1000;
 
     // How long we allow a receiver to run before giving up on it.
-    static final int BROADCAST_FG_TIMEOUT = 10*1000;
-    static final int BROADCAST_BG_TIMEOUT = 60*1000;
+    static final int BROADCAST_FG_TIMEOUT = 10 * 1000 * Build.HW_TIMEOUT_MULTIPLIER;
+    static final int BROADCAST_BG_TIMEOUT = 60 * 1000 * Build.HW_TIMEOUT_MULTIPLIER;
 
     public static final int MY_PID = myPid();
 
@@ -513,7 +510,8 @@
     private static final int MAX_BUGREPORT_TITLE_SIZE = 50;
     private static final int MAX_BUGREPORT_DESCRIPTION_SIZE = 150;
 
-    private static final int NATIVE_DUMP_TIMEOUT_MS = 2000; // 2 seconds;
+    private static final int NATIVE_DUMP_TIMEOUT_MS =
+            2000 * Build.HW_TIMEOUT_MULTIPLIER; // 2 seconds;
     private static final int JAVA_DUMP_MINIMUM_SIZE = 100; // 100 bytes.
 
     OomAdjuster mOomAdjuster;
@@ -6762,7 +6760,7 @@
                         setThreadScheduler(proc.getRenderThreadTid(),
                                 SCHED_FIFO | SCHED_RESET_ON_FORK, 1);
                     } else {
-                        setThreadPriority(proc.getRenderThreadTid(), TOP_APP_PRIORITY_BOOST);
+                        setThreadPriority(proc.getRenderThreadTid(), THREAD_PRIORITY_TOP_APP_BOOST);
                     }
                 }
             } else {
@@ -9238,6 +9236,8 @@
                     pw.print(ptw.callingUid);
                 }
             }
+            pw.println("  mFgsStartTempAllowList:");
+            mFgsStartTempAllowList.dump(pw);
         }
         if (mDebugApp != null || mOrigDebugApp != null || mDebugTransient
                 || mOrigWaitForDebugger) {
@@ -16652,7 +16652,7 @@
             throw new SecurityException("Calling uid " + callingUid + " cannot set locusId"
                     + "for package " + activity.getPackageName());
         }
-
+        mActivityTaskManager.setLocusId(locusId, appToken);
         if (mUsageStatsService != null) {
             mUsageStatsService.reportLocusUpdate(activity, userId, locusId, appToken);
         }
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 5ad77a3..b8e06ee 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -1705,7 +1705,14 @@
 
         pw.println("Hanging the system...");
         pw.flush();
-        mInterface.hang(new Binder(), allowRestart);
+        try {
+            mInterface.hang(getShellCallback().getShellCallbackBinder(), allowRestart);
+        } catch (NullPointerException e) {
+            pw.println("Hanging failed, since caller " + Binder.getCallingPid() +
+                    " did not provide a ShellCallback!");
+            pw.flush();
+            return 1;
+        }
         return 0;
     }
 
diff --git a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
index fc28bfb..e2086b0 100644
--- a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
+++ b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
@@ -194,6 +194,11 @@
         final WifiManager wm = mInjector.getSystemService(WifiManager.class);
         final TelephonyManager tm = mInjector.getSystemService(TelephonyManager.class);
         final PowerStatsInternal psi = mInjector.getLocalService(PowerStatsInternal.class);
+        final int voltageMv;
+        synchronized (mStats) {
+            voltageMv = mStats.getBatteryVoltageMvLocked();
+        }
+
         synchronized (mWorkerLock) {
             mWifiManager = wm;
             mTelephony = tm;
@@ -212,7 +217,7 @@
                         // According to spec, initialEcrs will include 0s for consumers that haven't
                         // used any energy yet, as long as they are supported; however,
                         // attributed uid energies will be absent if their energy is 0.
-                        mMeasuredEnergySnapshot.updateAndGetDelta(initialEcrs);
+                        mMeasuredEnergySnapshot.updateAndGetDelta(initialEcrs, voltageMv);
                     } catch (TimeoutException | InterruptedException e) {
                         Slog.w(TAG, "timeout or interrupt reading initial getEnergyConsumedAsync: "
                                 + e);
@@ -584,10 +589,15 @@
             Slog.w(TAG, "exception reading modem stats: " + e.getCause());
         }
 
-        final MeasuredEnergySnapshot.MeasuredEnergyDeltaData measuredEnergyDeltas;
+        final MeasuredEnergySnapshot.MeasuredEnergyDeltaData measuredEnergyDelta;
         if (mMeasuredEnergySnapshot == null || futureECRs == null) {
-            measuredEnergyDeltas = null;
+            measuredEnergyDelta = null;
         } else {
+            final int voltageMv;
+            synchronized (mStats) {
+                voltageMv = mStats.getBatteryVoltageMvLocked();
+            }
+
             EnergyConsumerResult[] ecrs;
             try {
                 ecrs = futureECRs.get(EXTERNAL_STATS_SYNC_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
@@ -599,7 +609,8 @@
                 Slog.wtf(TAG, "exception reading getEnergyConsumedAsync: " + e.getCause());
                 ecrs = null;
             }
-            measuredEnergyDeltas = mMeasuredEnergySnapshot.updateAndGetDelta(ecrs);
+
+            measuredEnergyDelta = mMeasuredEnergySnapshot.updateAndGetDelta(ecrs, voltageMv);
         }
 
         final long elapsedRealtime = SystemClock.elapsedRealtime();
@@ -620,7 +631,14 @@
                     onBattery = mStats.isOnBatteryLocked();
                     onBatteryScreenOff = mStats.isOnBatteryScreenOffLocked();
                 }
-                mStats.updateCpuTimeLocked(onBattery, onBatteryScreenOff);
+
+                final long[] cpuClusterChargeUC;
+                if (measuredEnergyDelta == null) {
+                    cpuClusterChargeUC = null;
+                } else {
+                    cpuClusterChargeUC = measuredEnergyDelta.cpuClusterChargeUC;
+                }
+                mStats.updateCpuTimeLocked(onBattery, onBatteryScreenOff, cpuClusterChargeUC);
             }
 
             if (updateFlags == UPDATE_ALL) {
@@ -633,20 +651,22 @@
             }
 
             // Inform mStats about each applicable measured energy.
-            if (measuredEnergyDeltas != null) {
-                final long displayEnergy = measuredEnergyDeltas.displayEnergyUJ;
-                if (displayEnergy != MeasuredEnergySnapshot.UNAVAILABLE) {
+            if (measuredEnergyDelta != null) {
+                final long displayChargeUC = measuredEnergyDelta.displayChargeUC;
+                if (displayChargeUC != MeasuredEnergySnapshot.UNAVAILABLE) {
                     // If updating, pass in what BatteryExternalStatsWorker thinks screenState is.
-                    mStats.updateDisplayEnergyLocked(displayEnergy, screenState, elapsedRealtime);
+                    mStats.updateDisplayMeasuredEnergyStatsLocked(displayChargeUC, screenState,
+                            elapsedRealtime);
                 }
             }
             // Inform mStats about each applicable custom energy bucket.
-            if (measuredEnergyDeltas != null && measuredEnergyDeltas.otherTotalEnergyUJ != null) {
+            if (measuredEnergyDelta != null
+                    && measuredEnergyDelta.otherTotalChargeUC != null) {
                 // Iterate over the custom (EnergyConsumerType.OTHER) ordinals.
-                for (int ord = 0; ord < measuredEnergyDeltas.otherTotalEnergyUJ.length; ord++) {
-                    long totalEnergy = measuredEnergyDeltas.otherTotalEnergyUJ[ord];
-                    SparseLongArray uidEnergies = measuredEnergyDeltas.otherUidEnergiesUJ[ord];
-                    mStats.updateCustomMeasuredEnergyDataLocked(ord, totalEnergy, uidEnergies);
+                for (int ord = 0; ord < measuredEnergyDelta.otherTotalChargeUC.length; ord++) {
+                    long totalEnergy = measuredEnergyDelta.otherTotalChargeUC[ord];
+                    SparseLongArray uidEnergies = measuredEnergyDelta.otherUidChargesUC[ord];
+                    mStats.updateCustomMeasuredEnergyStatsLocked(ord, totalEnergy, uidEnergies);
                 }
             }
 
@@ -664,7 +684,7 @@
 
         if (wifiInfo != null) {
             if (wifiInfo.isValid()) {
-                // TODO: wifiEnergyDelta = measuredEnergyDeltas.consumerTypeEnergyUJ
+                // TODO: wifiEnergyDelta = measuredEnergyDelta.consumerTypeEnergyUJ
                 //               .get(EnergyConsumerType.WIFI, MeasuredEnergySnapshot.UNAVAILABLE)
                 mStats.updateWifiState(extractDeltaLocked(wifiInfo)
                         /*, TODO: wifiEnergyDelta */, elapsedRealtime, uptime);
@@ -785,7 +805,7 @@
 
     /**
      * Map the {@link EnergyConsumerType}s in the given energyArray to
-     * their corresponding {@link MeasuredEnergyStats.StandardEnergyBucket}s.
+     * their corresponding {@link MeasuredEnergyStats.StandardPowerBucket}s.
      * Does not include custom energy buckets (which are always, by definition, supported).
      *
      * @return array with true for index i if standard energy bucket i is supported.
@@ -795,15 +815,18 @@
         if (idToConsumer == null) {
             return null;
         }
-        final boolean[] buckets = new boolean[MeasuredEnergyStats.NUMBER_STANDARD_ENERGY_BUCKETS];
+        final boolean[] buckets = new boolean[MeasuredEnergyStats.NUMBER_STANDARD_POWER_BUCKETS];
         final int size = idToConsumer.size();
         for (int idx = 0; idx < size; idx++) {
             final EnergyConsumer consumer = idToConsumer.valueAt(idx);
             switch (consumer.type) {
                 case EnergyConsumerType.DISPLAY:
-                    buckets[MeasuredEnergyStats.ENERGY_BUCKET_SCREEN_ON] = true;
-                    buckets[MeasuredEnergyStats.ENERGY_BUCKET_SCREEN_DOZE] = true;
-                    buckets[MeasuredEnergyStats.ENERGY_BUCKET_SCREEN_OTHER] = true;
+                    buckets[MeasuredEnergyStats.POWER_BUCKET_SCREEN_ON] = true;
+                    buckets[MeasuredEnergyStats.POWER_BUCKET_SCREEN_DOZE] = true;
+                    buckets[MeasuredEnergyStats.POWER_BUCKET_SCREEN_OTHER] = true;
+                    break;
+                case EnergyConsumerType.CPU_CLUSTER:
+                    buckets[MeasuredEnergyStats.POWER_BUCKET_CPU] = true;
                     break;
             }
         }
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 360e1b4..dbfa7f3 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -83,6 +83,7 @@
 import com.android.internal.util.ParseUtils;
 import com.android.internal.util.function.pooled.PooledLambda;
 import com.android.net.module.util.NetworkCapabilitiesUtils;
+import com.android.net.module.util.PermissionUtils;
 import com.android.server.LocalServices;
 import com.android.server.Watchdog;
 import com.android.server.net.BaseNetworkObserver;
@@ -1781,7 +1782,7 @@
 
     @Override
     public void noteNetworkInterfaceForTransports(final String iface, int[] transportTypes) {
-        enforceCallingPermission();
+        PermissionUtils.enforceNetworkStackPermission(mContext);
         synchronized (mLock) {
             mHandler.post(() -> {
                 mStats.noteNetworkInterfaceForTransports(iface, transportTypes);
diff --git a/services/core/java/com/android/server/am/BroadcastConstants.java b/services/core/java/com/android/server/am/BroadcastConstants.java
index 494f06e..e580327 100644
--- a/services/core/java/com/android/server/am/BroadcastConstants.java
+++ b/services/core/java/com/android/server/am/BroadcastConstants.java
@@ -18,6 +18,7 @@
 
 import android.content.ContentResolver;
 import android.database.ContentObserver;
+import android.os.Build;
 import android.os.Handler;
 import android.provider.Settings;
 import android.util.KeyValueListParser;
@@ -42,12 +43,13 @@
             "bcast_allow_bg_activity_start_timeout";
 
     // All time intervals are in milliseconds
-    private static final long DEFAULT_TIMEOUT = 10_000;
-    private static final long DEFAULT_SLOW_TIME = 5_000;
-    private static final long DEFAULT_DEFERRAL = 5_000;
+    private static final long DEFAULT_TIMEOUT = 10_000 * Build.HW_TIMEOUT_MULTIPLIER;
+    private static final long DEFAULT_SLOW_TIME = 5_000 * Build.HW_TIMEOUT_MULTIPLIER;
+    private static final long DEFAULT_DEFERRAL = 5_000 * Build.HW_TIMEOUT_MULTIPLIER;
     private static final float DEFAULT_DEFERRAL_DECAY_FACTOR = 0.75f;
     private static final long DEFAULT_DEFERRAL_FLOOR = 0;
-    private static final long DEFAULT_ALLOW_BG_ACTIVITY_START_TIMEOUT = 10_000;
+    private static final long DEFAULT_ALLOW_BG_ACTIVITY_START_TIMEOUT =
+            10_000 * Build.HW_TIMEOUT_MULTIPLIER;
 
     // All time constants are in milliseconds
 
diff --git a/services/core/java/com/android/server/am/FgsStartTempAllowList.java b/services/core/java/com/android/server/am/FgsStartTempAllowList.java
index 1f897b5..a844c2aa 100644
--- a/services/core/java/com/android/server/am/FgsStartTempAllowList.java
+++ b/services/core/java/com/android/server/am/FgsStartTempAllowList.java
@@ -19,10 +19,15 @@
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
 
 import android.annotation.Nullable;
+import android.os.PowerWhitelistManager;
 import android.os.PowerWhitelistManager.ReasonCode;
 import android.os.SystemClock;
+import android.os.UserHandle;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.util.TimeUtils;
+
+import java.io.PrintWriter;
 
 /**
  * List of uids that are temporarily allowed to start FGS from background.
@@ -113,4 +118,27 @@
     void remove(int uid) {
         mTempAllowListFgs.delete(uid);
     }
+
+    void dump(PrintWriter pw) {
+        final long currentTimeNow = System.currentTimeMillis();
+        final long elapsedRealtimeNow = SystemClock.elapsedRealtime();
+        for (int i = 0; i < mTempAllowListFgs.size(); i++) {
+            final int uid = mTempAllowListFgs.keyAt(i);
+            final TempFgsAllowListEntry entry = mTempAllowListFgs.valueAt(i);
+            pw.println(
+                    "    " + UserHandle.formatUid(uid) + ": " +
+                    " callingUid=" + UserHandle.formatUid(entry.mCallingUid) +
+                    " reasonCode=" + PowerWhitelistManager.reasonCodeToString(entry.mReasonCode) +
+                    " reason=" + entry.mReason);
+            pw.print("        duration=" + entry.mDuration +
+                    "ms expiration=");
+
+            // Convert entry.mExpirationTime, which is an elapsed time since boot,
+            // to a time since epoch (i.e. System.currentTimeMillis()-based time.)
+            final long expirationInCurrentTime =
+                    currentTimeNow - elapsedRealtimeNow + entry.mExpirationTime;
+            TimeUtils.dumpTimeWithDelta(pw, expirationInCurrentTime, currentTimeNow);
+            pw.println();
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/am/MeasuredEnergySnapshot.java b/services/core/java/com/android/server/am/MeasuredEnergySnapshot.java
index 9e0aa32..9b2ca13 100644
--- a/services/core/java/com/android/server/am/MeasuredEnergySnapshot.java
+++ b/services/core/java/com/android/server/am/MeasuredEnergySnapshot.java
@@ -25,6 +25,7 @@
 import android.hardware.power.stats.EnergyConsumerType;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.util.SparseIntArray;
 import android.util.SparseLongArray;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -38,11 +39,16 @@
 public class MeasuredEnergySnapshot {
     private static final String TAG = "MeasuredEnergySnapshot";
 
+    private static final int MILLIVOLTS_PER_VOLT = 1000;
+
     public static final long UNAVAILABLE = -1L;
 
     /** Map of {@link EnergyConsumer#id} to its corresponding {@link EnergyConsumer}. */
     private final SparseArray<EnergyConsumer> mEnergyConsumers;
 
+    /** Number of ordinals for {@link EnergyConsumerType#CPU_CLUSTER}. */
+    private final int mNumCpuClusterOrdinals;
+
     /** Number of ordinals for {@link EnergyConsumerType#OTHER}. */
     private final int mNumOtherOrdinals;
 
@@ -59,6 +65,14 @@
     private final SparseLongArray mMeasuredEnergySnapshots;
 
     /**
+     * Voltage snapshots, mapping {@link EnergyConsumer#id} to voltage (mV) from the last time
+     * each {@link EnergyConsumer} was updated.
+     *
+     * see {@link mMeasuredEnergySnapshots}.
+     */
+    private final SparseIntArray mVoltageSnapshots;
+
+    /**
      * Energy snapshots <b>per uid</b> from the last time each {@link EnergyConsumer} of type
      * {@link EnergyConsumerType#OTHER} was updated.
      * It maps each OTHER {@link EnergyConsumer#id} to a SparseLongArray, which itself maps each
@@ -77,8 +91,11 @@
     MeasuredEnergySnapshot(@NonNull SparseArray<EnergyConsumer> idToConsumerMap) {
         mEnergyConsumers = idToConsumerMap;
         mMeasuredEnergySnapshots = new SparseLongArray(mEnergyConsumers.size());
+        mVoltageSnapshots = new SparseIntArray(mEnergyConsumers.size());
 
-        mNumOtherOrdinals = calculateNumOtherOrdinals(idToConsumerMap);
+        mNumCpuClusterOrdinals = calculateNumOrdinals(EnergyConsumerType.CPU_CLUSTER,
+                idToConsumerMap);
+        mNumOtherOrdinals = calculateNumOrdinals(EnergyConsumerType.OTHER, idToConsumerMap);
         mAttributionSnapshots = new SparseArray<>(mNumOtherOrdinals);
     }
 
@@ -90,16 +107,19 @@
         return mNumOtherOrdinals;
     }
 
-    /** Class for returning measured energy delta data. */
+    /** Class for returning the relevant data calculated from the measured energy delta */
     static class MeasuredEnergyDeltaData {
-        /** The energyUJ for {@link EnergyConsumerType#DISPLAY}. */
-        public long displayEnergyUJ = UNAVAILABLE;
+        /** The chargeUC for {@link EnergyConsumerType#DISPLAY}. */
+        public long displayChargeUC = UNAVAILABLE;
 
-        /** Map of {@link EnergyConsumerType#OTHER} ordinals to their total energyUJ. */
-        public @Nullable long[] otherTotalEnergyUJ = null;
+        /** The chargeUC for {@link EnergyConsumerType#CPU_CLUSTER}s. */
+        public long[] cpuClusterChargeUC = null;
 
-        /** Map of {@link EnergyConsumerType#OTHER} ordinals to their {uid->energyUJ} maps. */
-        public @Nullable SparseLongArray[] otherUidEnergiesUJ = null;
+        /** Map of {@link EnergyConsumerType#OTHER} ordinals to their total chargeUC. */
+        public @Nullable long[] otherTotalChargeUC = null;
+
+        /** Map of {@link EnergyConsumerType#OTHER} ordinals to their {uid->chargeUC} maps. */
+        public @Nullable SparseLongArray[] otherUidChargesUC = null;
     }
 
     /**
@@ -108,19 +128,28 @@
      *
      * @param ecrs EnergyConsumerResults for some (possibly not all) {@link EnergyConsumer}s.
      *             Consumers that are not present are ignored (they are *not* treated as 0).
+     * @param voltageMV current voltage.
      *
      * @return a MeasuredEnergyDeltaData, containing maps from the updated consumers to
-     *         their corresponding energy deltas.
+     *         their corresponding charge deltas.
      *         Fields with no interesting data (consumers not present in ecrs or with no energy
      *         difference) will generally be left as their default values.
-     *         otherTotalEnergyUJ and otherUidEnergiesUJ are always either both null or both of
+     *         otherTotalChargeUC and otherUidChargesUC are always either both null or both of
      *         length {@link #getNumOtherOrdinals()}.
      *         Returns null, if ecrs is null or empty.
      */
-    public @Nullable MeasuredEnergyDeltaData updateAndGetDelta(EnergyConsumerResult[] ecrs) {
+    public @Nullable MeasuredEnergyDeltaData updateAndGetDelta(EnergyConsumerResult[] ecrs,
+            int voltageMV) {
         if (ecrs == null || ecrs.length == 0) {
             return null;
         }
+        if (voltageMV <= 0) {
+            Slog.wtf(TAG, "Unexpected battery voltage (" + voltageMV
+                    + " mV) when taking measured energy snapshot");
+            // TODO (b/181685156): consider adding the nominal voltage to power profile and
+            //  falling back to it if measured voltage is unavailable.
+            return null;
+        }
         final MeasuredEnergyDeltaData output = new MeasuredEnergyDeltaData();
 
         for (final EnergyConsumerResult ecr : ecrs) {
@@ -138,12 +167,15 @@
             final int type = consumer.type;
             final int ordinal = consumer.ordinal;
 
-            // Look up, and update, the old energy information about this consumer.
+            // Look up, and update, the old energy and voltage information about this consumer.
             final long oldEnergyUJ = mMeasuredEnergySnapshots.get(consumerId, UNAVAILABLE);
+            final int oldVoltageMV = mVoltageSnapshots.get(consumerId);
             mMeasuredEnergySnapshots.put(consumerId, newEnergyUJ);
-            final SparseLongArray otherUidEnergies
-                    = updateAndGetDeltaForTypeOther(consumer, newAttributions);
+            mVoltageSnapshots.put(consumerId, voltageMV);
 
+            final int avgVoltageMV = (oldVoltageMV + voltageMV + 1) / 2;
+            final SparseLongArray otherUidCharges =
+                    updateAndGetDeltaForTypeOther(consumer, newAttributions, avgVoltageMV);
             // Everything is fully done being updated. We now calculate the delta for returning.
 
             // NB: Since sum(attribution.energyUWs)<=energyUWs we assume that if deltaEnergy==0
@@ -152,24 +184,36 @@
 
             if (oldEnergyUJ < 0) continue; // Generally happens only on initialization.
             if (newEnergyUJ == oldEnergyUJ) continue;
+
             final long deltaUJ = newEnergyUJ - oldEnergyUJ;
-            if (deltaUJ < 0) {
-                Slog.e(TAG, "EnergyConsumer " + consumer.name + ": new energy (" + newEnergyUJ
-                        + ") < old energy (" + oldEnergyUJ + "). Skipping. ");
+            if (deltaUJ < 0 || oldVoltageMV <= 0) {
+                Slog.e(TAG, "Bad data! EnergyConsumer " + consumer.name
+                        + ": new energy (" + newEnergyUJ + ") < old energy (" + oldEnergyUJ
+                        + "), new voltage (" + voltageMV + "), old voltage (" + oldVoltageMV
+                        + "). Skipping. ");
                 continue;
             }
 
+            final long deltaChargeUC = calculateChargeConsumedUC(deltaUJ, avgVoltageMV);
             switch (type) {
                 case EnergyConsumerType.DISPLAY:
-                    output.displayEnergyUJ = deltaUJ;
+                    output.displayChargeUC = deltaChargeUC;
                     break;
-                case EnergyConsumerType.OTHER:
-                    if (output.otherTotalEnergyUJ == null) {
-                        output.otherTotalEnergyUJ = new long[getNumOtherOrdinals()];
-                        output.otherUidEnergiesUJ = new SparseLongArray[getNumOtherOrdinals()];
+
+                case EnergyConsumerType.CPU_CLUSTER:
+                    if (output.cpuClusterChargeUC == null) {
+                        output.cpuClusterChargeUC = new long[mNumCpuClusterOrdinals];
                     }
-                    output.otherTotalEnergyUJ[ordinal] = deltaUJ;
-                    output.otherUidEnergiesUJ[ordinal] = otherUidEnergies;
+                    output.cpuClusterChargeUC[ordinal] = deltaChargeUC;
+                    break;
+
+                case EnergyConsumerType.OTHER:
+                    if (output.otherTotalChargeUC == null) {
+                        output.otherTotalChargeUC = new long[getNumOtherOrdinals()];
+                        output.otherUidChargesUC = new SparseLongArray[getNumOtherOrdinals()];
+                    }
+                    output.otherTotalChargeUC[ordinal] = deltaChargeUC;
+                    output.otherUidChargesUC[ordinal] = otherUidCharges;
                     break;
                 default:
                     Slog.w(TAG, "Ignoring consumer " + consumer.name + " of unknown type " + type);
@@ -182,19 +226,21 @@
     /**
      * For a consumer of type {@link EnergyConsumerType#OTHER}, updates
      * {@link #mAttributionSnapshots} with freshly measured energies (per uid) and returns the
-     * difference (delta) between the previously stored values and the passed-in values.
+     * charge consumed (in microcouloumbs) between the previously stored values and the passed-in
+     * values.
      *
      * @param consumerInfo a consumer of type {@link EnergyConsumerType#OTHER}.
      * @param newAttributions Record of uids and their new energyUJ values.
      *                        Any uid not present is treated as having energy 0.
      *                        If null or empty, all uids are treated as having energy 0.
-     * @return A map (in the sense of {@link MeasuredEnergyDeltaData#otherUidEnergiesUJ} for this
-     *         consumer) of uid -> energyDelta, with all uids that have a non-zero energyDelta.
+     * @param avgVoltageMV The average voltage since the last snapshot.
+     * @return A map (in the sense of {@link MeasuredEnergyDeltaData#otherUidChargesUC} for this
+     *         consumer) of uid -> chargeDelta, with all uids that have a non-zero chargeDelta.
      *         Returns null if no delta available to calculate.
      */
     private @Nullable SparseLongArray updateAndGetDeltaForTypeOther(
             @NonNull EnergyConsumer consumerInfo,
-            @Nullable EnergyConsumerAttribution[] newAttributions) {
+            @Nullable EnergyConsumerAttribution[] newAttributions, int avgVoltageMV) {
 
         if (consumerInfo.type != EnergyConsumerType.OTHER) {
             return null;
@@ -217,8 +263,8 @@
             return null;
         }
 
-        // Map uid -> energyDelta. No initial capacity since many deltas might be 0.
-        final SparseLongArray uidEnergyDeltas = new SparseLongArray();
+        // Map uid -> chargeDelta. No initial capacity since many deltas might be 0.
+        final SparseLongArray uidChargeDeltas = new SparseLongArray();
 
         for (EnergyConsumerAttribution newAttribution : newAttributions) {
             final int uid = newAttribution.uid;
@@ -231,14 +277,17 @@
             if (oldEnergyUJ < 0) continue;
             if (newEnergyUJ == oldEnergyUJ) continue;
             final long deltaUJ = newEnergyUJ - oldEnergyUJ;
-            if (deltaUJ < 0) {
+            if (deltaUJ < 0 || avgVoltageMV <= 0) {
                 Slog.e(TAG, "EnergyConsumer " + consumerInfo.name + ": new energy (" + newEnergyUJ
-                        + ") but old energy (" + oldEnergyUJ + "). Skipping. ");
+                        + ") but old energy (" + oldEnergyUJ + "). Average voltage (" + avgVoltageMV
+                        + ")Skipping. ");
                 continue;
             }
-            uidEnergyDeltas.put(uid, deltaUJ);
+
+            final long deltaChargeUC = calculateChargeConsumedUC(deltaUJ, avgVoltageMV);
+            uidChargeDeltas.put(uid, deltaChargeUC);
         }
-        return uidEnergyDeltas;
+        return uidChargeDeltas;
     }
 
     /** Dump debug data. */
@@ -255,22 +304,33 @@
         for (int i = 0; i < mMeasuredEnergySnapshots.size(); i++) {
             final int id = mMeasuredEnergySnapshots.keyAt(i);
             final long energyUJ = mMeasuredEnergySnapshots.valueAt(i);
-            pw.println(String.format("    Consumer %d has energy %d uJ}", id, energyUJ));
+            final long voltageMV = mVoltageSnapshots.valueAt(i);
+            pw.println(String.format("    Consumer %d has energy %d uJ at %d mV", id, energyUJ,
+                    voltageMV));
         }
         pw.println("List of the " + mNumOtherOrdinals + " OTHER EnergyConsumers:");
         pw.println("    " + mAttributionSnapshots);
         pw.println();
     }
 
-    /** Determines the number of ordinals for {@link EnergyConsumerType#OTHER}. */
-    private static int calculateNumOtherOrdinals(SparseArray<EnergyConsumer> idToConsumer) {
+    /** Determines the number of ordinals for a given {@link EnergyConsumerType}. */
+    private static int calculateNumOrdinals(@EnergyConsumerType int type,
+            SparseArray<EnergyConsumer> idToConsumer) {
         if (idToConsumer == null) return 0;
-        int numOtherOrdinals = 0;
+        int numOrdinals = 0;
         final int size = idToConsumer.size();
         for (int idx = 0; idx < size; idx++) {
             final EnergyConsumer consumer = idToConsumer.valueAt(idx);
-            if (consumer.type == EnergyConsumerType.OTHER) numOtherOrdinals++;
+            if (consumer.type == type) numOrdinals++;
         }
-        return numOtherOrdinals;
+        return numOrdinals;
     }
+
+    /** Calculate charge consumption (in microcouloumbs) from a given energy and voltage */
+    private long calculateChargeConsumedUC(long deltaEnergyUJ, int avgVoltageMV) {
+        // To overflow, a 3.7V 10000mAh battery would need to completely drain 69244 times
+        // since the last snapshot. Round up to the nearest whole long.
+        return (deltaEnergyUJ * MILLIVOLTS_PER_VOLT + (avgVoltageMV + 1) / 2) / avgVoltageMV;
+    }
+
 }
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 06e879b..939d35f 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -49,6 +49,7 @@
 import static android.os.Process.THREAD_GROUP_RESTRICTED;
 import static android.os.Process.THREAD_GROUP_TOP_APP;
 import static android.os.Process.THREAD_PRIORITY_DISPLAY;
+import static android.os.Process.THREAD_PRIORITY_TOP_APP_BOOST;
 import static android.os.Process.setProcessGroup;
 import static android.os.Process.setThreadPriority;
 import static android.os.Process.setThreadScheduler;
@@ -68,7 +69,6 @@
 import static com.android.server.am.ActivityManagerService.TAG_LRU;
 import static com.android.server.am.ActivityManagerService.TAG_OOM_ADJ;
 import static com.android.server.am.ActivityManagerService.TAG_UID_OBSERVERS;
-import static com.android.server.am.ActivityManagerService.TOP_APP_PRIORITY_BOOST;
 import static com.android.server.am.AppProfiler.TAG_PSS;
 import static com.android.server.am.ProcessList.TAG_PROCESS_OBSERVERS;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH;
@@ -343,7 +343,7 @@
         // The process group is usually critical to the response time of foreground app, so the
         // setter should apply it as soon as possible.
         final ServiceThread adjusterThread =
-                new ServiceThread(TAG, TOP_APP_PRIORITY_BOOST, false /* allowIo */);
+                new ServiceThread(TAG, THREAD_PRIORITY_TOP_APP_BOOST, false /* allowIo */);
         adjusterThread.start();
         adjusterThread.getThreadHandler().post(() -> Process.setThreadGroupAndCpuset(
                 adjusterThread.getThreadId(), THREAD_GROUP_TOP_APP));
@@ -2647,11 +2647,11 @@
                                 }
                             } else {
                                 // Boost priority for top app UI and render threads
-                                setThreadPriority(app.getPid(), TOP_APP_PRIORITY_BOOST);
+                                setThreadPriority(app.getPid(), THREAD_PRIORITY_TOP_APP_BOOST);
                                 if (renderThreadTid != 0) {
                                     try {
                                         setThreadPriority(renderThreadTid,
-                                                TOP_APP_PRIORITY_BOOST);
+                                                THREAD_PRIORITY_TOP_APP_BOOST);
                                     } catch (IllegalArgumentException e) {
                                         // thread died, ignore
                                     }
@@ -2813,7 +2813,7 @@
                 // is not ready when attaching.
                 if (Process.getProcessGroup(app.getPid()) == THREAD_GROUP_TOP_APP) {
                     app.getWindowProcessController().onTopProcChanged();
-                    setThreadPriority(app.getPid(), TOP_APP_PRIORITY_BOOST);
+                    setThreadPriority(app.getPid(), THREAD_PRIORITY_TOP_APP_BOOST);
                 } else {
                     fallbackReason = "not expected top priority";
                 }
diff --git a/services/core/java/com/android/server/apphibernation/AppHibernationService.java b/services/core/java/com/android/server/apphibernation/AppHibernationService.java
index 968cf5f..2c0a589 100644
--- a/services/core/java/com/android/server/apphibernation/AppHibernationService.java
+++ b/services/core/java/com/android/server/apphibernation/AppHibernationService.java
@@ -314,17 +314,8 @@
     private void unhibernatePackageForUser(@NonNull String packageName, int userId,
             UserLevelState pkgState) {
         Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "unhibernatePackage");
-        final long caller = Binder.clearCallingIdentity();
-        try {
-            mIPackageManager.setPackageStoppedState(packageName, false, userId);
-            pkgState.hibernated = false;
-        } catch (RemoteException e) {
-            throw new IllegalStateException(
-                    "Failed to unhibernate due to manager not being available", e);
-        } finally {
-            Binder.restoreCallingIdentity(caller);
-            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
-        }
+        pkgState.hibernated = false;
+        Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
     }
 
     /**
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 4a12ff6..6614e06 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -5276,8 +5276,12 @@
         pw.println("    Limit output to data associated with the given package name.");
         pw.println("  --attributionTag [attributionTag]");
         pw.println("    Limit output to data associated with the given attribution tag.");
+        pw.println("  --include-discrete [n]");
+        pw.println("    Include discrete ops limited to n per dimension. Use zero for no limit.");
         pw.println("  --watchers");
         pw.println("    Only output the watcher sections.");
+        pw.println("  --history");
+        pw.println("    Only output history.");
     }
 
     private void dumpStatesLocked(@NonNull PrintWriter pw, @Nullable String filterAttributionTag,
@@ -5412,10 +5416,12 @@
         boolean dumpWatchers = false;
         // TODO ntmyren: Remove the dumpHistory and dumpFilter
         boolean dumpHistory = false;
+        boolean includeDiscreteOps = false;
+        int nDiscreteOps = 10;
         @HistoricalOpsRequestFilter int dumpFilter = 0;
 
         if (args != null) {
-            for (int i=0; i<args.length; i++) {
+            for (int i = 0; i < args.length; i++) {
                 String arg = args[i];
                 if ("-h".equals(arg)) {
                     dumpHelp(pw);
@@ -5473,7 +5479,22 @@
                     }
                 } else if ("--watchers".equals(arg)) {
                     dumpWatchers = true;
-                } else if (arg.length() > 0 && arg.charAt(0) == '-'){
+                } else if ("--include-discrete".equals(arg)) {
+                    i++;
+                    if (i >= args.length) {
+                        pw.println("No argument for --include-discrete option");
+                        return;
+                    }
+                    try {
+                        nDiscreteOps = Integer.valueOf(args[i]);
+                    } catch (NumberFormatException e) {
+                        pw.println("Wrong parameter: " + args[i]);
+                        return;
+                    }
+                    includeDiscreteOps = true;
+                } else if ("--history".equals(arg)) {
+                    dumpHistory = true;
+                } else if (arg.length() > 0 && arg.charAt(0) == '-') {
                     pw.println("Unknown option: " + arg);
                     return;
                 } else {
@@ -5483,6 +5504,8 @@
             }
         }
 
+        final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
+        final Date date = new Date();
         synchronized (this) {
             pw.println("Current AppOps Service state:");
             if (!dumpHistory && !dumpWatchers) {
@@ -5492,8 +5515,6 @@
             final long now = System.currentTimeMillis();
             final long nowElapsed = SystemClock.elapsedRealtime();
             final long nowUptime = SystemClock.uptimeMillis();
-            final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
-            final Date date = new Date();
             boolean needSep = false;
             if (dumpFilter == 0 && dumpMode < 0 && mProfileOwners != null && !dumpWatchers
                     && !dumpHistory) {
@@ -5961,6 +5982,11 @@
             mHistoricalRegistry.dump("  ", pw, dumpUid, dumpPackage, dumpAttributionTag, dumpOp,
                     dumpFilter);
         }
+        if (includeDiscreteOps) {
+            pw.println("Discrete accesses: ");
+            mHistoricalRegistry.dumpDiscreteData(pw, dumpUid, dumpPackage, dumpAttributionTag,
+                    dumpFilter, dumpOp, sdf, date, "  ", nDiscreteOps);
+        }
     }
 
     @Override
diff --git a/services/core/java/com/android/server/appop/DiscreteRegistry.java b/services/core/java/com/android/server/appop/DiscreteRegistry.java
index a99d908..ed62abc 100644
--- a/services/core/java/com/android/server/appop/DiscreteRegistry.java
+++ b/services/core/java/com/android/server/appop/DiscreteRegistry.java
@@ -23,9 +23,13 @@
 import static android.app.AppOpsManager.OP_CAMERA;
 import static android.app.AppOpsManager.OP_COARSE_LOCATION;
 import static android.app.AppOpsManager.OP_FINE_LOCATION;
+import static android.app.AppOpsManager.OP_FLAGS_ALL;
 import static android.app.AppOpsManager.OP_FLAG_SELF;
 import static android.app.AppOpsManager.OP_FLAG_TRUSTED_PROXIED;
+import static android.app.AppOpsManager.OP_NONE;
 import static android.app.AppOpsManager.OP_RECORD_AUDIO;
+import static android.app.AppOpsManager.flagsToString;
+import static android.app.AppOpsManager.getUidStateName;
 
 import static java.lang.Math.max;
 
@@ -45,15 +49,20 @@
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.XmlUtils;
 
+import libcore.util.EmptyArray;
+
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
+import java.io.PrintWriter;
+import java.text.SimpleDateFormat;
 import java.time.Duration;
 import java.time.Instant;
 import java.time.temporal.ChronoUnit;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
+import java.util.Date;
 import java.util.List;
 
 /**
@@ -237,6 +246,23 @@
         }
     }
 
+    void dump(@NonNull PrintWriter pw, int uidFilter, @Nullable String packageNameFilter,
+            @Nullable String attributionTagFilter,
+            @AppOpsManager.HistoricalOpsRequestFilter int filter, int dumpOp,
+            @NonNull SimpleDateFormat sdf, @NonNull Date date, @NonNull String prefix,
+            int nDiscreteOps) {
+        DiscreteOps discreteOps = new DiscreteOps();
+        synchronized (mOnDiskLock) {
+            writeAndClearAccessHistory();
+            String[] opNamesFilter = dumpOp == OP_NONE ? EmptyArray.STRING
+                    : new String[]{AppOpsManager.opToPublicName(dumpOp)};
+            readDiscreteOpsFromDisk(discreteOps, 0, Instant.now().toEpochMilli(), filter,
+                    uidFilter, packageNameFilter, opNamesFilter, attributionTagFilter,
+                    OP_FLAGS_ALL);
+        }
+        discreteOps.dump(pw, sdf, date, prefix, nDiscreteOps);
+    }
+
     public static boolean isDiscreteOp(int op, int uid, @AppOpsManager.OpFlags int flags) {
         if (!isDiscreteOp(op)) {
             return false;
@@ -306,6 +332,18 @@
             stream.close();
         }
 
+        private void dump(@NonNull PrintWriter pw, @NonNull SimpleDateFormat sdf,
+                @NonNull Date date, @NonNull String prefix, int nDiscreteOps) {
+            int nUids = mUids.size();
+            for (int i = 0; i < nUids; i++) {
+                pw.print(prefix);
+                pw.print("Uid: ");
+                pw.print(mUids.keyAt(i));
+                pw.println();
+                mUids.valueAt(i).dump(pw, sdf, date, prefix + "  ", nDiscreteOps);
+            }
+        }
+
         private DiscreteUidOps getOrCreateDiscreteUidOps(int uid) {
             DiscreteUidOps result = mUids.get(uid);
             if (result == null) {
@@ -395,6 +433,18 @@
             }
         }
 
+        private void dump(@NonNull PrintWriter pw, @NonNull SimpleDateFormat sdf,
+                @NonNull Date date, @NonNull String prefix, int nDiscreteOps) {
+            int nPackages = mPackages.size();
+            for (int i = 0; i < nPackages; i++) {
+                pw.print(prefix);
+                pw.print("Package: ");
+                pw.print(mPackages.keyAt(i));
+                pw.println();
+                mPackages.valueAt(i).dump(pw, sdf, date, prefix + "  ", nDiscreteOps);
+            }
+        }
+
         void deserialize(TypedXmlPullParser parser, long beginTimeMillis,
                 long endTimeMillis, @AppOpsManager.HistoricalOpsRequestFilter int filter,
                 @Nullable String packageNameFilter,
@@ -458,6 +508,17 @@
             }
         }
 
+        private void dump(@NonNull PrintWriter pw, @NonNull SimpleDateFormat sdf,
+                @NonNull Date date, @NonNull String prefix, int nDiscreteOps) {
+            int nOps = mPackageOps.size();
+            for (int i = 0; i < nOps; i++) {
+                pw.print(prefix);
+                pw.print(AppOpsManager.opToName(mPackageOps.keyAt(i)));
+                pw.println();
+                mPackageOps.valueAt(i).dump(pw, sdf, date, prefix + "  ", nDiscreteOps);
+            }
+        }
+
         void deserialize(TypedXmlPullParser parser, long beginTimeMillis, long endTimeMillis,
                 @AppOpsManager.HistoricalOpsRequestFilter int filter,
                 @Nullable String[] opNamesFilter, @Nullable String attributionTagFilter,
@@ -535,6 +596,24 @@
             }
         }
 
+        private void dump(@NonNull PrintWriter pw, @NonNull SimpleDateFormat sdf,
+                @NonNull Date date, @NonNull String prefix, int nDiscreteOps) {
+            int nAttributions = mAttributedOps.size();
+            for (int i = 0; i < nAttributions; i++) {
+                pw.print(prefix);
+                pw.print("Attribution: ");
+                pw.print(mAttributedOps.keyAt(i));
+                pw.println();
+                List<DiscreteOpEvent> ops = mAttributedOps.valueAt(i);
+                int nOps = ops.size();
+                int first = nDiscreteOps < 1 ? 0 : max(0, nOps - nDiscreteOps);
+                for (int j = first; j < nOps; j++) {
+                    ops.get(j).dump(pw, sdf, date, prefix + "  ");
+
+                }
+            }
+        }
+
         void serialize(TypedXmlSerializer out) throws Exception {
             int nAttributions = mAttributedOps.size();
             for (int i = 0; i < nAttributions; i++) {
@@ -609,6 +688,24 @@
             mOpFlag = opFlag;
         }
 
+        private void dump(@NonNull PrintWriter pw, @NonNull SimpleDateFormat sdf,
+                @NonNull Date date, @NonNull String prefix) {
+            pw.print(prefix);
+            pw.print("Access [");
+            pw.print(getUidStateName(mUidState));
+            pw.print("-");
+            pw.print(flagsToString(mOpFlag));
+            pw.print("] at ");
+            date.setTime(mNoteTime);
+            pw.print(sdf.format(date));
+            if (mNoteDuration != -1) {
+                pw.print(" for ");
+                pw.print(mNoteDuration);
+                pw.print(" milliseconds ");
+            }
+            pw.println();
+        }
+
         private void serialize(TypedXmlSerializer out) throws Exception {
             out.attributeLong(null, ATTR_NOTE_TIME, mNoteTime);
             if (mNoteDuration != -1) {
diff --git a/services/core/java/com/android/server/appop/HistoricalRegistry.java b/services/core/java/com/android/server/appop/HistoricalRegistry.java
index 0fcf5ee..22d628b 100644
--- a/services/core/java/com/android/server/appop/HistoricalRegistry.java
+++ b/services/core/java/com/android/server/appop/HistoricalRegistry.java
@@ -349,6 +349,15 @@
         }
     }
 
+    void dumpDiscreteData(@NonNull PrintWriter pw, int uidFilter,
+            @Nullable String packageNameFilter, @Nullable String attributionTagFilter,
+            @HistoricalOpsRequestFilter int filter, int dumpOp,
+            @NonNull SimpleDateFormat sdf, @NonNull Date date, @NonNull String prefix,
+            int nDiscreteOps) {
+        mDiscreteRegistry.dump(pw, uidFilter, packageNameFilter, attributionTagFilter, filter,
+                dumpOp, sdf, date, prefix, nDiscreteOps);
+    }
+
     @HistoricalMode int getMode() {
         synchronized (mInMemoryLock) {
             return mMode;
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 862627e..e4fc895 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -424,7 +424,7 @@
      * @return true if speakerphone is active, false otherwise.
      */
     /*package*/ boolean isSpeakerphoneOn() {
-        AudioDeviceAttributes device = getPreferredDeviceForComm();
+        AudioDeviceAttributes device = getPreferredCommunicationDevice();
         if (device == null) {
             return false;
         }
@@ -595,7 +595,7 @@
      * @return true if Bluetooth SCO is active , false otherwise.
      */
     /*package*/ boolean isBluetoothScoOn() {
-        AudioDeviceAttributes device = getPreferredDeviceForComm();
+        AudioDeviceAttributes device = getPreferredCommunicationDevice();
         if (device == null) {
             return false;
         }
@@ -1021,9 +1021,11 @@
 
         pw.println("\n" + prefix + "mPreferredCommunicationDevice: "
                 +  mPreferredCommunicationDevice);
+
         pw.println(prefix + "Selected Communication Device: "
                 +  ((getCommunicationDevice() == null) ? "None"
                         : new AudioDeviceAttributes(getCommunicationDevice())));
+
         pw.println(prefix + "mCommunicationStrategyId: "
                 +  mCommunicationStrategyId);
 
@@ -1213,11 +1215,9 @@
                 case MSG_I_SET_MODE_OWNER_PID:
                     synchronized (mSetModeLock) {
                         synchronized (mDeviceStateLock) {
-                            if (mModeOwnerPid != msg.arg1) {
-                                mModeOwnerPid = msg.arg1;
-                                if (msg.arg2 != AudioSystem.MODE_RINGTONE) {
-                                    onUpdateCommunicationRoute("setNewModeOwner");
-                                }
+                            mModeOwnerPid = msg.arg1;
+                            if (msg.arg2 != AudioSystem.MODE_RINGTONE) {
+                                onUpdateCommunicationRoute("setNewModeOwner");
                             }
                         }
                     }
@@ -1676,7 +1676,7 @@
      * @return selected forced usage for communication.
      */
     @GuardedBy("mDeviceStateLock")
-    @Nullable private AudioDeviceAttributes getPreferredDeviceForComm() {
+    @Nullable private AudioDeviceAttributes getPreferredCommunicationDevice() {
         boolean btSCoOn = mBluetoothScoOn && mBtHelper.isBluetoothScoOn();
         if (btSCoOn) {
             // Use the SCO device known to BtHelper so that it matches exactly
@@ -1704,11 +1704,14 @@
     // @GuardedBy("mSetModeLock")
     @GuardedBy("mDeviceStateLock")
     private void onUpdateCommunicationRoute(String eventSource) {
-        mPreferredCommunicationDevice = getPreferredDeviceForComm();
+        mPreferredCommunicationDevice = getPreferredCommunicationDevice();
         if (AudioService.DEBUG_COMM_RTE) {
             Log.v(TAG, "onUpdateCommunicationRoute, mPreferredCommunicationDevice: "
                     + mPreferredCommunicationDevice + " eventSource: " + eventSource);
         }
+        AudioService.sDeviceLogger.log((new AudioEventLogger.StringEvent(
+                "onUpdateCommunicationRoute, mPreferredCommunicationDevice: "
+                + mPreferredCommunicationDevice + " eventSource: " + eventSource)));
 
         if (mPreferredCommunicationDevice == null
                 || !AudioSystem.DEVICE_OUT_ALL_SCO_SET.contains(
diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
index 076cbff..9b88c9a 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
@@ -662,6 +662,11 @@
 
     /*package*/ int removePreferredDevicesForStrategySync(int strategy) {
         final long identity = Binder.clearCallingIdentity();
+
+        AudioService.sDeviceLogger.log((new AudioEventLogger.StringEvent(
+                "removePreferredDevicesForStrategySync, strategy: "
+                + strategy)).printLog(TAG));
+
         final int status = mAudioSystem.removeDevicesRoleForStrategy(
                 strategy, AudioSystem.DEVICE_ROLE_PREFERRED);
         Binder.restoreCallingIdentity(identity);
diff --git a/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java b/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java
index b3580fb..93fea90 100644
--- a/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java
@@ -80,6 +80,18 @@
         onErrorInternal(errorCode, vendorCode, true /* finish */);
     }
 
+    /**
+     * Notifies the caller that the operation was canceled by the user. Note that the actual
+     * operation still needs to wait for the HAL to send ERROR_CANCELED.
+     */
+    public void onUserCanceled() {
+        // Send USER_CANCELED, but do not finish. Wait for the HAL to respond with ERROR_CANCELED,
+        // which then finishes the AcquisitionClient's lifecycle.
+        onErrorInternal(BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED, 0 /* vendorCode */,
+                false /* finish */);
+        stopHalOperation();
+    }
+
     protected void onErrorInternal(int errorCode, int vendorCode, boolean finish) {
         // In some cases, the framework will send an error to the caller before a true terminal
         // case (success, failure, or error) is received from the HAL (e.g. versions of fingerprint
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/UdfpsHelper.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/UdfpsHelper.java
index 37f8e8c..f0e4597 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/UdfpsHelper.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/UdfpsHelper.java
@@ -22,9 +22,12 @@
 import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
 import android.hardware.fingerprint.FingerprintManager;
 import android.hardware.fingerprint.IUdfpsOverlayController;
+import android.hardware.fingerprint.IUdfpsOverlayControllerCallback;
 import android.os.RemoteException;
 import android.util.Slog;
 
+import com.android.server.biometrics.sensors.AcquisitionClient;
+
 /**
  * Contains helper methods for under-display fingerprint HIDL.
  */
@@ -77,12 +80,22 @@
     }
 
     public static void showUdfpsOverlay(int sensorId, int reason,
-            @Nullable IUdfpsOverlayController udfpsOverlayController) {
+            @Nullable IUdfpsOverlayController udfpsOverlayController,
+            @NonNull AcquisitionClient<?> client) {
         if (udfpsOverlayController == null) {
             return;
         }
+
+        final IUdfpsOverlayControllerCallback callback =
+                new IUdfpsOverlayControllerCallback.Stub() {
+                    @Override
+                    public void onUserCanceled() {
+                        client.onUserCanceled();
+                    }
+                };
+
         try {
-            udfpsOverlayController.showUdfpsOverlay(sensorId, reason);
+            udfpsOverlayController.showUdfpsOverlay(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/fingerprint/aidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
index f9527d9..e2743f6 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
@@ -89,7 +89,7 @@
     @Override
     protected void startHalOperation() {
         UdfpsHelper.showUdfpsOverlay(getSensorId(), Utils.getUdfpsAuthReason(this),
-                mUdfpsOverlayController);
+                mUdfpsOverlayController, this);
         try {
             mCancellationSignal = getFreshDaemon().authenticate(mSequentialId, mOperationId);
         } catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java
index bcd1b8b..620a9cf 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java
@@ -72,7 +72,7 @@
     protected void startHalOperation() {
         UdfpsHelper.showUdfpsOverlay(getSensorId(),
                 IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD,
-                mUdfpsOverlayController);
+                mUdfpsOverlayController, this);
         try {
             mCancellationSignal = getFreshDaemon().detectInteraction(mSequentialId);
         } catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
index ae64c77..63fa66c 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
@@ -121,7 +121,7 @@
     protected void startHalOperation() {
         UdfpsHelper.showUdfpsOverlay(getSensorId(),
                 UdfpsHelper.getReasonFromEnrollReason(mEnrollReason),
-                mUdfpsOverlayController);
+                mUdfpsOverlayController, this);
         try {
             mCancellationSignal = getFreshDaemon().enroll(mSequentialId,
                     HardwareAuthTokenUtils.toHardwareAuthToken(mHardwareAuthToken));
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java
index 83a3d94..db37112 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java
@@ -120,7 +120,7 @@
     @Override
     protected void startHalOperation() {
         UdfpsHelper.showUdfpsOverlay(getSensorId(), Utils.getUdfpsAuthReason(this),
-                mUdfpsOverlayController);
+                mUdfpsOverlayController, this);
         try {
             // GroupId was never used. In fact, groupId is always the same as userId.
             getFreshDaemon().authenticate(mOperationId, getTargetUserId());
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java
index 8acb284..db44aee 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java
@@ -85,7 +85,7 @@
     protected void startHalOperation() {
         UdfpsHelper.showUdfpsOverlay(getSensorId(),
                 IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD,
-                mUdfpsOverlayController);
+                mUdfpsOverlayController, this);
         try {
             getFreshDaemon().authenticate(0 /* operationId */, getTargetUserId());
         } catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java
index 33db64c..41d2308 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java
@@ -84,7 +84,7 @@
     protected void startHalOperation() {
         UdfpsHelper.showUdfpsOverlay(getSensorId(),
                 UdfpsHelper.getReasonFromEnrollReason(mEnrollReason),
-                mUdfpsOverlayController);
+                mUdfpsOverlayController, this);
         try {
             // GroupId was never used. In fact, groupId is always the same as userId.
             getFreshDaemon().enroll(mHardwareAuthToken, getTargetUserId(), mTimeoutSec);
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index ae0e001..df87012 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -17,6 +17,7 @@
 package com.android.server.content;
 
 import static android.os.PowerWhitelistManager.REASON_SYNC_MANAGER;
+import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED;
 
 import static com.android.server.content.SyncLogger.logSafe;
 
@@ -1672,6 +1673,7 @@
                 dic.addPowerSaveTempWhitelistApp(Process.SYSTEM_UID,
                         syncOperation.owningPackage,
                         mConstants.getKeyExemptionTempWhitelistDurationInSeconds() * 1000,
+                        TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED,
                         UserHandle.getUserId(syncOperation.owningUid),
                         /* sync=*/ false, REASON_SYNC_MANAGER, "sync by top app");
             }
diff --git a/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java b/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java
index 658d27f..217f1cd 100644
--- a/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java
+++ b/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java
@@ -78,9 +78,6 @@
 public final class DeviceStateManagerService extends SystemService {
     private static final String TAG = "DeviceStateManagerService";
     private static final boolean DEBUG = false;
-    // The device state to use as a placeholder before callback from the DeviceStateProvider occurs.
-    private static final DeviceState UNSPECIFIED_DEVICE_STATE =
-            new DeviceState(MINIMUM_DEVICE_STATE, "UNSPECIFIED");
 
     private final Object mLock = new Object();
     @NonNull
@@ -92,11 +89,11 @@
     @GuardedBy("mLock")
     private SparseArray<DeviceState> mDeviceStates = new SparseArray<>();
 
-    // The current committed device state. The default of UNSPECIFIED_DEVICE_STATE will be replaced
-    // by the current state after the initial callback from the DeviceStateProvider.
+    // The current committed device state. Will be empty until the first device state provided by
+    // the DeviceStateProvider is committed.
     @GuardedBy("mLock")
     @NonNull
-    private DeviceState mCommittedState = UNSPECIFIED_DEVICE_STATE;
+    private Optional<DeviceState> mCommittedState = Optional.empty();
     // The device state that is currently awaiting callback from the policy to be committed.
     @GuardedBy("mLock")
     @NonNull
@@ -105,10 +102,11 @@
     @GuardedBy("mLock")
     private boolean mIsPolicyWaitingForState = false;
 
-    // The device state that is set by the device state provider.
+    // The device state that is set by the DeviceStateProvider. Will be empty until the first
+    // callback from the provider and then will always contain the most recent value.
     @GuardedBy("mLock")
     @NonNull
-    private DeviceState mBaseState = UNSPECIFIED_DEVICE_STATE;
+    private Optional<DeviceState> mBaseState = Optional.empty();
 
     // List of processes registered to receive notifications about changes to device state and
     // request status indexed by process id.
@@ -142,11 +140,14 @@
     /**
      * Returns the current state the system is in. Note that the system may be in the process of
      * configuring a different state.
+     * <p>
+     * Note: This method will return {@link Optional#empty()} if called before the first state has
+     * been committed, otherwise it will return the last committed state.
      *
      * @see #getPendingState()
      */
     @NonNull
-    DeviceState getCommittedState() {
+    Optional<DeviceState> getCommittedState() {
         synchronized (mLock) {
             return mCommittedState;
         }
@@ -167,11 +168,15 @@
     /**
      * Returns the base state. The service will configure the device to match the base state when
      * there is no active request to override the base state.
+     * <p>
+     * Note: This method will return {@link Optional#empty()} if called before a base state is
+     * provided to the service by the {@link DeviceStateProvider}, otherwise it will return the
+     * most recent provided value.
      *
      * @see #getOverrideState()
      */
     @NonNull
-    DeviceState getBaseState() {
+    Optional<DeviceState> getBaseState() {
         synchronized (mLock) {
             return mBaseState;
         }
@@ -223,9 +228,14 @@
 
     @NonNull
     private DeviceStateInfo getDeviceStateInfoLocked() {
+        if (!mBaseState.isPresent() || !mCommittedState.isPresent()) {
+            throw new IllegalStateException("Trying to get the current DeviceStateInfo before the"
+                    + " initial state has been committed.");
+        }
+
         final int[] supportedStates = getSupportedStateIdentifiersLocked();
-        final int baseState = mBaseState.getIdentifier();
-        final int currentState = mCommittedState.getIdentifier();
+        final int baseState = mBaseState.get().getIdentifier();
+        final int currentState = mCommittedState.get().getIdentifier();
 
         return new DeviceStateInfo(supportedStates, baseState, currentState);
     }
@@ -237,6 +247,7 @@
 
     private void updateSupportedStates(DeviceState[] supportedDeviceStates) {
         boolean updatedPendingState;
+        boolean hasBaseState;
         synchronized (mLock) {
             final int[] oldStateIdentifiers = getSupportedStateIdentifiersLocked();
 
@@ -260,9 +271,10 @@
             }
 
             updatedPendingState = updatePendingStateLocked();
+            hasBaseState = mBaseState.isPresent();
         }
 
-        if (!updatedPendingState) {
+        if (hasBaseState && !updatedPendingState) {
             // If the change in the supported states didn't result in a change of the pending state
             // commitPendingState() will never be called and the callbacks will never be notified
             // of the change.
@@ -306,11 +318,11 @@
             }
 
             final DeviceState baseState = baseStateOptional.get();
-            if (mBaseState.equals(baseState)) {
+            if (mBaseState.isPresent() && mBaseState.get().equals(baseState)) {
                 // Base state hasn't changed. Nothing to do.
                 return;
             }
-            mBaseState = baseState;
+            mBaseState = Optional.of(baseState);
 
             final int requestSize = mRequestRecords.size();
             for (int i = 0; i < requestSize; i++) {
@@ -351,9 +363,10 @@
         final DeviceState stateToConfigure;
         if (!mRequestRecords.isEmpty()) {
             stateToConfigure = mRequestRecords.get(mRequestRecords.size() - 1).mRequestedState;
-        } else if (isSupportedStateLocked(mBaseState.getIdentifier())) {
+        } else if (mBaseState.isPresent()
+                && isSupportedStateLocked(mBaseState.get().getIdentifier())) {
             // Base state could have recently become unsupported after a change in supported states.
-            stateToConfigure = mBaseState;
+            stateToConfigure = mBaseState.get();
         } else {
             stateToConfigure = null;
         }
@@ -363,7 +376,7 @@
             return false;
         }
 
-        if (stateToConfigure.equals(mCommittedState)) {
+        if (mCommittedState.isPresent() && stateToConfigure.equals(mCommittedState.get())) {
             // The state requesting to be committed already matches the current committed state.
             return false;
         }
@@ -417,15 +430,15 @@
     private void commitPendingState() {
         // Update the current state.
         synchronized (mLock) {
+            final DeviceState newState = mPendingState.get();
             if (DEBUG) {
-                Slog.d(TAG, "Committing state: " + mPendingState);
+                Slog.d(TAG, "Committing state: " + newState);
             }
-            mCommittedState = mPendingState.get();
 
             if (!mRequestRecords.isEmpty()) {
                 final OverrideRequestRecord topRequest =
                         mRequestRecords.get(mRequestRecords.size() - 1);
-                if (topRequest.mRequestedState.getIdentifier() == mCommittedState.getIdentifier()) {
+                if (topRequest.mRequestedState.getIdentifier() == newState.getIdentifier()) {
                     // The top request could have come in while the service was awaiting callback
                     // from the policy. In that case we only set it to active if it matches the
                     // current committed state, otherwise it will be set to active when its
@@ -434,6 +447,7 @@
                 }
             }
 
+            mCommittedState = Optional.of(newState);
             mPendingState = Optional.empty();
             updatePendingStateLocked();
         }
@@ -503,19 +517,30 @@
     }
 
     private void registerProcess(int pid, IDeviceStateManagerCallback callback) {
+        DeviceStateInfo currentInfo;
+        ProcessRecord record;
+        // Grab the lock to register the callback and get the current state.
         synchronized (mLock) {
             if (mProcessRecords.contains(pid)) {
                 throw new SecurityException("The calling process has already registered an"
                         + " IDeviceStateManagerCallback.");
             }
 
-            ProcessRecord record = new ProcessRecord(callback, pid);
+            record = new ProcessRecord(callback, pid);
             try {
                 callback.asBinder().linkToDeath(record, 0);
             } catch (RemoteException ex) {
                 throw new RuntimeException(ex);
             }
             mProcessRecords.put(pid, record);
+
+            currentInfo = mCommittedState.isPresent() ? getDeviceStateInfoLocked() : null;
+        }
+
+        if (currentInfo != null) {
+            // If there is not a committed state we'll wait to notify the process of the initial
+            // value.
+            record.notifyDeviceStateInfoAsync(currentInfo);
         }
     }
 
diff --git a/services/core/java/com/android/server/devicestate/DeviceStateManagerShellCommand.java b/services/core/java/com/android/server/devicestate/DeviceStateManagerShellCommand.java
index f346600..56b68b7 100644
--- a/services/core/java/com/android/server/devicestate/DeviceStateManagerShellCommand.java
+++ b/services/core/java/com/android/server/devicestate/DeviceStateManagerShellCommand.java
@@ -18,6 +18,7 @@
 
 import static android.Manifest.permission.CONTROL_DEVICE_STATE;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
 import android.hardware.devicestate.DeviceStateManager;
@@ -63,14 +64,14 @@
     }
 
     private void printState(PrintWriter pw) {
-        DeviceState committedState = mService.getCommittedState();
-        DeviceState baseState = mService.getBaseState();
+        Optional<DeviceState> committedState = mService.getCommittedState();
+        Optional<DeviceState> baseState = mService.getBaseState();
         Optional<DeviceState> overrideState = mService.getOverrideState();
 
-        pw.println("Committed state: " + committedState);
+        pw.println("Committed state: " + toString(committedState));
         if (overrideState.isPresent()) {
             pw.println("----------------------");
-            pw.println("Base state: " + baseState);
+            pw.println("Base state: " + toString(baseState));
             pw.println("Override state: " + overrideState.get());
         }
     }
@@ -143,4 +144,8 @@
         pw.println("  print-states");
         pw.println("    Return list of currently supported device states.");
     }
+
+    private static String toString(@NonNull Optional<DeviceState> state) {
+        return state.isPresent() ? state.get().toString() : "(none)";
+    }
 }
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index a0d9365..d88896c 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -683,12 +683,7 @@
                                 setDisplayState(Display.STATE_ON);
                                 currentState = Display.STATE_ON;
                             } else {
-                                if (oldState == Display.STATE_UNKNOWN) {
-                                    // There's no guarantee about what the initial state is
-                                    // at startup, so we have to set it if previous was UNKNOWN.
-                                    setDisplayState(state);
-                                }
-                                return;
+                                return; // old state and new state is off
                             }
                         }
 
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 4e8fcf7..8285e32 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -1626,6 +1626,10 @@
             }
             mHandler.removeCallbacks(mUserSwitchHandlerTask);
         }
+        // Hide soft input before user switch task since switch task may block main handler a while
+        // and delayed the MSG_HIDE_SOFT_INPUT.
+        hideCurrentInputLocked(
+                mCurFocusedWindow, 0, null, SoftInputShowHideReason.HIDE_SWITCH_USER);
         final UserSwitchHandlerTask task = new UserSwitchHandlerTask(this, userId,
                 clientToBeReset);
         mUserSwitchHandlerTask = task;
@@ -1751,20 +1755,16 @@
         final boolean initialUserSwitch = TextUtils.isEmpty(defaultImiId);
         mLastSystemLocales = mRes.getConfiguration().getLocales();
 
-        // TODO: Is it really possible that switchUserLocked() happens before system ready?
-        if (mSystemReady) {
-            hideCurrentInputLocked(
-                    mCurFocusedWindow, 0, null, SoftInputShowHideReason.HIDE_SWITCH_USER);
-
-            resetCurrentMethodAndClient(UnbindReason.SWITCH_USER);
-            buildInputMethodListLocked(initialUserSwitch);
-            if (TextUtils.isEmpty(mSettings.getSelectedInputMethod())) {
-                // This is the first time of the user switch and
-                // set the current ime to the proper one.
-                resetDefaultImeLocked(mContext);
-            }
-            updateFromSettingsLocked(true);
+        // The mSystemReady flag is set during boot phase,
+        // and user switch would not happen at that time.
+        resetCurrentMethodAndClient(UnbindReason.SWITCH_USER);
+        buildInputMethodListLocked(initialUserSwitch);
+        if (TextUtils.isEmpty(mSettings.getSelectedInputMethod())) {
+            // This is the first time of the user switch and
+            // set the current ime to the proper one.
+            resetDefaultImeLocked(mContext);
         }
+        updateFromSettingsLocked(true);
 
         if (initialUserSwitch) {
             InputMethodUtils.setNonSelectedSystemImesDisabledUntilUsed(mIPackageManager,
diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
index 364aa2c..48382a9 100644
--- a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
+++ b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
@@ -207,7 +207,7 @@
         public void reportMetric(boolean success) {
             // TODO(b/179105110) design error code; and report the true value for other fields.
             FrameworkStatsLog.write(FrameworkStatsLog.REBOOT_ESCROW_RECOVERY_REPORTED, 0, 1, 1,
-                    -1, 0);
+                    -1, 0, -1);
         }
 
         public RebootEscrowEventLog getEventLog() {
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index e0f5346..7b376847 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -24,7 +24,6 @@
 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.ConnectivityManager.isNetworkTypeMobile;
 import static android.net.NetworkIdentity.SUBTYPE_COMBINED;
 import static android.net.NetworkStack.checkNetworkStackPermission;
 import static android.net.NetworkStats.DEFAULT_NETWORK_ALL;
@@ -71,6 +70,7 @@
 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.server.NetworkManagementService.LIMIT_GLOBAL_ALERT;
 import static com.android.server.NetworkManagementSocketTagger.resetKernelUidStats;
 import static com.android.server.NetworkManagementSocketTagger.setKernelCounterSet;
@@ -1291,7 +1291,9 @@
         final boolean combineSubtypeEnabled = mSettings.getCombineSubtypeEnabled();
         final ArraySet<String> mobileIfaces = new ArraySet<>();
         for (NetworkStateSnapshot snapshot : snapshots) {
-            final boolean isMobile = isNetworkTypeMobile(snapshot.legacyType);
+            final int displayTransport =
+                    getDisplayTransport(snapshot.networkCapabilities.getTransportTypes());
+            final boolean isMobile = (NetworkCapabilities.TRANSPORT_CELLULAR == displayTransport);
             final boolean isDefault = ArrayUtils.contains(mDefaultNetworks, snapshot.network);
             final int subType = combineSubtypeEnabled ? SUBTYPE_COMBINED
                     : getSubTypeForStateSnapshot(snapshot);
diff --git a/services/core/java/com/android/server/notification/NotificationDelegate.java b/services/core/java/com/android/server/notification/NotificationDelegate.java
index afb47e8..02f9ceb 100644
--- a/services/core/java/com/android/server/notification/NotificationDelegate.java
+++ b/services/core/java/com/android/server/notification/NotificationDelegate.java
@@ -55,9 +55,10 @@
     void onNotificationBubbleChanged(String key, boolean isBubble, int flags);
     /**
      * Called when the state of {@link Notification.BubbleMetadata#FLAG_SUPPRESS_NOTIFICATION}
-     * changes.
+     * or {@link Notification.BubbleMetadata#FLAG_SUPPRESS_BUBBLE} changes.
      */
-    void onBubbleNotificationSuppressionChanged(String key, boolean isSuppressed);
+    void onBubbleNotificationSuppressionChanged(String key, boolean isNotifSuppressed,
+            boolean isBubbleSuppressed);
 
     /**
      * Grant permission to read the specified URI to the package associated with the
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 73db705..6f39fea 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1269,7 +1269,7 @@
         }
 
         @Override
-        public void onNotificationBubbleChanged(String key, boolean isBubble, int flags) {
+        public void onNotificationBubbleChanged(String key, boolean isBubble, int bubbleFlags) {
             synchronized (mNotificationLock) {
                 NotificationRecord r = mNotificationsByKey.get(key);
                 if (r != null) {
@@ -1287,7 +1287,7 @@
                         r.getNotification().flags |= FLAG_ONLY_ALERT_ONCE;
                         r.setFlagBubbleRemoved(false);
                         if (r.getNotification().getBubbleMetadata() != null) {
-                            r.getNotification().getBubbleMetadata().setFlags(flags);
+                            r.getNotification().getBubbleMetadata().setFlags(bubbleFlags);
                         }
                         // Force isAppForeground true here, because for sysui's purposes we
                         // want to adjust the flag behaviour.
@@ -1299,7 +1299,8 @@
         }
 
         @Override
-        public void onBubbleNotificationSuppressionChanged(String key, boolean isSuppressed) {
+        public void onBubbleNotificationSuppressionChanged(String key, boolean isNotifSuppressed,
+                boolean isBubbleSuppressed) {
             synchronized (mNotificationLock) {
                 NotificationRecord r = mNotificationsByKey.get(key);
                 if (r != null) {
@@ -1308,26 +1309,36 @@
                         // No data, do nothing
                         return;
                     }
-                    boolean currentlySuppressed = data.isNotificationSuppressed();
-                    if (currentlySuppressed == isSuppressed) {
-                        // No changes, do nothing
-                        return;
-                    }
+
                     int flags = data.getFlags();
-                    if (isSuppressed) {
-                        flags |= Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION;
-                    } else {
-                        flags &= ~Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION;
+                    boolean flagChanged = false;
+                    if (data.isNotificationSuppressed() != isNotifSuppressed) {
+                        flagChanged = true;
+                        if (isNotifSuppressed) {
+                            flags |= Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION;
+                        } else {
+                            flags &= ~Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION;
+                        }
                     }
-                    data.setFlags(flags);
-                    r.getNotification().flags |= FLAG_ONLY_ALERT_ONCE;
-                    mHandler.post(new EnqueueNotificationRunnable(r.getUser().getIdentifier(), r,
-                            true /* isAppForeground */));
+                    if (data.isBubbleSuppressed() != isBubbleSuppressed) {
+                        flagChanged = true;
+                        if (isBubbleSuppressed) {
+                            flags |= Notification.BubbleMetadata.FLAG_SUPPRESS_BUBBLE;
+                        } else {
+                            flags &= ~Notification.BubbleMetadata.FLAG_SUPPRESS_BUBBLE;
+                        }
+                    }
+                    if (flagChanged) {
+                        data.setFlags(flags);
+                        r.getNotification().flags |= FLAG_ONLY_ALERT_ONCE;
+                        mHandler.post(
+                                new EnqueueNotificationRunnable(r.getUser().getIdentifier(), r,
+                                        true /* isAppForeground */));
+                    }
                 }
             }
         }
 
-        @Override
         /**
          * Grant permission to read the specified URI to the package specified in the
          * NotificationRecord associated with the given key. The callingUid represents the UID of
@@ -1337,6 +1348,7 @@
          * user associated with the NotificationRecord, and this grant will fail when trying
          * to grant URI permissions across users.
          */
+        @Override
         public void grantInlineReplyUriPermission(String key, Uri uri, UserHandle user,
                 String packageName, int callingUid) {
             synchronized (mNotificationLock) {
@@ -6117,18 +6129,27 @@
     }
 
     /**
-     * Some bubble specific flags only work if the app is foreground, this will strip those flags
-     * if the app wasn't foreground.
+     * Strips any flags from BubbleMetadata that wouldn't apply (e.g. app not foreground).
      */
     private void updateNotificationBubbleFlags(NotificationRecord r, boolean isAppForeground) {
-        // Remove any bubble specific flags that only work when foregrounded
         Notification notification = r.getNotification();
         Notification.BubbleMetadata metadata = notification.getBubbleMetadata();
-        if (!isAppForeground && metadata != null) {
+        if (metadata == null) {
+            // Nothing to update
+            return;
+        }
+        if (!isAppForeground) {
+            // Auto expand only works if foreground
             int flags = metadata.getFlags();
             flags &= ~Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE;
             metadata.setFlags(flags);
         }
+        if (!metadata.isBubbleSuppressable()) {
+            // If it's not suppressable remove the suppress flag
+            int flags = metadata.getFlags();
+            flags &= ~Notification.BubbleMetadata.FLAG_SUPPRESS_BUBBLE;
+            metadata.setFlags(flags);
+        }
     }
 
     private ShortcutHelper.ShortcutListener mShortcutListener =
@@ -6504,9 +6525,11 @@
                     }
 
                     if (mReason == REASON_LISTENER_CANCEL
-                        && (r.getNotification().flags & FLAG_BUBBLE) != 0) {
+                            && r.getNotification().isBubbleNotification()) {
+                        boolean isBubbleSuppressed = r.getNotification().getBubbleMetadata() != null
+                                && r.getNotification().getBubbleMetadata().isBubbleSuppressed();
                         mNotificationDelegate.onBubbleNotificationSuppressionChanged(
-                            r.getKey(), /* suppressed */ true);
+                                r.getKey(), true /* suppressed */, isBubbleSuppressed);
                         return;
                     }
 
diff --git a/services/core/java/com/android/server/om/OverlayManagerShellCommand.java b/services/core/java/com/android/server/om/OverlayManagerShellCommand.java
index 0b52c2e..ba1bf93 100644
--- a/services/core/java/com/android/server/om/OverlayManagerShellCommand.java
+++ b/services/core/java/com/android/server/om/OverlayManagerShellCommand.java
@@ -125,7 +125,7 @@
         out.println("    'lowest', change priority of PACKAGE to the lowest priority.");
         out.println("    If PARENT is the special keyword 'highest', change priority of");
         out.println("    PACKAGE to the highest priority.");
-        out.println("  lookup [--verbose] PACKAGE-TO-LOAD PACKAGE:TYPE/NAME");
+        out.println("  lookup [--user USER_ID] [--verbose] PACKAGE-TO-LOAD PACKAGE:TYPE/NAME");
         out.println("    Load a package and print the value of a given resource");
         out.println("    applying the current configuration and enabled overlays.");
         out.println("    For a more fine-grained alternative, use 'idmap2 lookup'.");
@@ -365,7 +365,22 @@
         final PrintWriter out = getOutPrintWriter();
         final PrintWriter err = getErrPrintWriter();
 
-        final boolean verbose = "--verbose".equals(getNextOption());
+        int userId = UserHandle.USER_SYSTEM;
+        boolean verbose = false;
+        String opt;
+        while ((opt = getNextOption()) != null) {
+            switch (opt) {
+                case "--user":
+                    userId = UserHandle.parseUserArg(getNextArgRequired());
+                    break;
+                case "--verbose":
+                    verbose = true;
+                    break;
+                default:
+                    err.println("Error: Unknown option: " + opt);
+                    return 1;
+            }
+        }
 
         final String packageToLoad = getNextArgRequired();
 
@@ -377,17 +392,15 @@
             return 1;
         }
 
-        final PackageManager pm = mContext.getPackageManager();
-        if (pm == null) {
-            err.println("Error: failed to get package manager");
-            return 1;
-        }
-
         final Resources res;
         try {
-            res = pm.getResourcesForApplication(packageToLoad);
+            res = mContext
+                .createContextAsUser(UserHandle.of(userId), /* flags */ 0)
+                .getPackageManager()
+                .getResourcesForApplication(packageToLoad);
         } catch (PackageManager.NameNotFoundException e) {
-            err.println("Error: failed to get resources for package " + packageToLoad);
+            err.println(String.format("Error: failed to get resources for package %s for user %d",
+                    packageToLoad, userId));
             return 1;
         }
         final AssetManager assets = res.getAssets();
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index b751503..a1da241 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -351,6 +351,7 @@
 import com.android.internal.policy.AttributeCache;
 import com.android.internal.telephony.CarrierAppUtils;
 import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.CollectionUtils;
 import com.android.internal.util.ConcurrentUtils;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.FrameworkStatsLog;
@@ -367,6 +368,7 @@
 import com.android.server.SystemConfig;
 import com.android.server.SystemServerInitThreadPool;
 import com.android.server.Watchdog;
+import com.android.server.apphibernation.AppHibernationManagerInternal;
 import com.android.server.compat.CompatChange;
 import com.android.server.compat.PlatformCompat;
 import com.android.server.net.NetworkPolicyManagerInternal;
@@ -1385,7 +1387,6 @@
         public @Nullable String systemTextClassifierPackage;
         public @Nullable String overlayConfigSignaturePackage;
         public ViewCompiler viewCompiler;
-        public @Nullable String wellbeingPackage;
         public @Nullable String retailDemoPackage;
         public @Nullable String recentsPackage;
         public ComponentName resolveComponentName;
@@ -1676,7 +1677,6 @@
     final @Nullable String mStorageManagerPackage;
     final @Nullable String mDefaultTextClassifierPackage;
     final @Nullable String mSystemTextClassifierPackageName;
-    final @Nullable String mWellbeingPackage;
     final @Nullable String mDocumenterPackage;
     final @Nullable String mConfiguratorPackage;
     final @Nullable String mAppPredictionServicePackage;
@@ -2654,13 +2654,10 @@
 
                 // If no apps are approved for the domain, resolve only to browsers
                 if (approvedInfos.isEmpty()) {
-                    // If the other profile has a result, include that and delegate to
-                    // ResolveActivity
+                    includeBrowser = true;
                     if (xpDomainInfo != null && xpDomainInfo.highestApprovalLevel
                             > DomainVerificationManagerInternal.APPROVAL_LEVEL_NONE) {
                         result.add(xpDomainInfo.resolveInfo);
-                    } else {
-                        includeBrowser = true;
                     }
                 } else {
                     result.addAll(approvedInfos);
@@ -2822,7 +2819,7 @@
 
                 result.highestApprovalLevel = Math.max(mDomainVerificationManager
                         .approvalLevelForDomain(ps, intent, resultTargetUser, flags,
-                                riTargetUser.targetUserId), result.highestApprovalLevel);
+                                parentUserId), result.highestApprovalLevel);
             }
             if (result != null && result.highestApprovalLevel
                     <= DomainVerificationManagerInternal.APPROVAL_LEVEL_NONE) {
@@ -4485,6 +4482,10 @@
                     break;
                 }
 
+                case DumpState.DUMP_PREFERRED:
+                    mSettings.dumpPreferred(pw, dumpState, packageName);
+                    break;
+
                 case DumpState.DUMP_PREFERRED_XML:
                 {
                     pw.flush();
@@ -6216,7 +6217,6 @@
         mStorageManagerPackage = testParams.storageManagerPackage;
         mDefaultTextClassifierPackage = testParams.defaultTextClassifierPackage;
         mSystemTextClassifierPackageName = testParams.systemTextClassifierPackage;
-        mWellbeingPackage = testParams.wellbeingPackage;
         mRetailDemoPackage = testParams.retailDemoPackage;
         mRecentsPackage = testParams.recentsPackage;
         mDocumenterPackage = testParams.documenterPackage;
@@ -6817,7 +6817,6 @@
 
             mDefaultTextClassifierPackage = getDefaultTextClassifierPackageName();
             mSystemTextClassifierPackageName = getSystemTextClassifierPackageName();
-            mWellbeingPackage = getWellbeingPackageName();
             mDocumenterPackage = getDocumenterPackageName();
             mConfiguratorPackage = getDeviceConfiguratorPackageName();
             mAppPredictionServicePackage = getAppPredictionServicePackageName();
@@ -9991,6 +9990,7 @@
                         false /*includeInstantApps*/,
                         isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, parent.id,
                                 resolvedType, 0));
+                flags |= PackageManager.MATCH_DEFAULT_ONLY;
                 CrossProfileDomainInfo xpDomainInfo = getCrossProfileDomainPreferredLpr(
                         intent, resolvedType, flags, sourceUserId, parent.id);
                 return xpDomainInfo != null;
@@ -22845,7 +22845,9 @@
 
     @Override
     public String getWellbeingPackageName() {
-        return ensureSystemPackageName(mContext.getString(R.string.config_defaultWellbeingPackage));
+        return CollectionUtils.firstOrNull(
+                mContext.getSystemService(RoleManager.class).getRoleHolders(
+                        RoleManager.ROLE_SYSTEM_WELLBEING));
     }
 
     @Override
@@ -23405,15 +23407,25 @@
         final boolean allowedByPermission = (permission == PackageManager.PERMISSION_GRANTED);
         enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */,
                 true /* checkShell */, "stop package");
+        boolean shouldUnhibernate = false;
         // writer
         synchronized (mLock) {
             final PackageSetting ps = mSettings.getPackageLPr(packageName);
+            if (ps.getStopped(userId) && !stopped) {
+                shouldUnhibernate = true;
+            }
             if (!shouldFilterApplicationLocked(ps, callingUid, userId)
                     && mSettings.setPackageStoppedStateLPw(this, packageName, stopped,
                             allowedByPermission, callingUid, userId)) {
                 scheduleWritePackageRestrictionsLocked(userId);
             }
         }
+        if (shouldUnhibernate) {
+            AppHibernationManagerInternal ah =
+                    mInjector.getLocalService(AppHibernationManagerInternal.class);
+            ah.setHibernatingForUser(packageName, userId, false);
+            ah.setHibernatingGlobally(packageName, false);
+        }
     }
 
     @Override
@@ -24133,11 +24145,7 @@
         }
 
         if (!checkin && dumpState.isDumping(DumpState.DUMP_PREFERRED)) {
-            // TODO: This cannot be moved to ComputerEngine since some variables with collections
-            //  types in IntentResolver such as mTypeToFilter do not have a copy of `F[]`.
-            synchronized (mLock) {
-                mSettings.dumpPreferred(pw, dumpState, packageName);
-            }
+            dump(DumpState.DUMP_PREFERRED, fd, pw, dumpState);
         }
 
         if (!checkin && dumpState.isDumping(DumpState.DUMP_PREFERRED_XML)) {
@@ -26363,8 +26371,6 @@
                             mDefaultTextClassifierPackage, mSystemTextClassifierPackageName);
                 case PackageManagerInternal.PACKAGE_PERMISSION_CONTROLLER:
                     return filterOnlySystemPackages(mRequiredPermissionControllerPackage);
-                case PackageManagerInternal.PACKAGE_WELLBEING:
-                    return filterOnlySystemPackages(mWellbeingPackage);
                 case PackageManagerInternal.PACKAGE_DOCUMENTER:
                     return filterOnlySystemPackages(mDocumenterPackage);
                 case PackageManagerInternal.PACKAGE_CONFIGURATOR:
diff --git a/services/core/java/com/android/server/pm/permission/Permission.java b/services/core/java/com/android/server/pm/permission/Permission.java
index ac50f29..b421cfc 100644
--- a/services/core/java/com/android/server/pm/permission/Permission.java
+++ b/services/core/java/com/android/server/pm/permission/Permission.java
@@ -304,10 +304,6 @@
                 & PermissionInfo.PROTECTION_FLAG_SYSTEM_TEXT_CLASSIFIER) != 0;
     }
 
-    public boolean isWellbeing() {
-        return (mPermissionInfo.protectionLevel & PermissionInfo.PROTECTION_FLAG_WELLBEING) != 0;
-    }
-
     public boolean isDocumenter() {
         return (mPermissionInfo.protectionLevel & PermissionInfo.PROTECTION_FLAG_DOCUMENTER) != 0;
     }
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 2dfb6ff..616058f 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -3471,13 +3471,6 @@
             // Special permissions for the device configurator.
             allowed = true;
         }
-        if (!allowed && bp.isWellbeing()
-                && ArrayUtils.contains(mPackageManagerInt.getKnownPackageNames(
-                        PackageManagerInternal.PACKAGE_WELLBEING, UserHandle.USER_SYSTEM),
-                pkg.getPackageName())) {
-            // Special permission granted only to the OEM specified wellbeing app
-            allowed = true;
-        }
         if (!allowed && bp.isDocumenter()
                 && ArrayUtils.contains(mPackageManagerInt.getKnownPackageNames(
                         PackageManagerInternal.PACKAGE_DOCUMENTER, UserHandle.USER_SYSTEM),
diff --git a/services/core/java/com/android/server/policy/DeviceStateProviderImpl.java b/services/core/java/com/android/server/policy/DeviceStateProviderImpl.java
index 4e1065a..cd7f685 100644
--- a/services/core/java/com/android/server/policy/DeviceStateProviderImpl.java
+++ b/services/core/java/com/android/server/policy/DeviceStateProviderImpl.java
@@ -161,7 +161,7 @@
     private int mLastReportedState = INVALID_DEVICE_STATE;
 
     @GuardedBy("mLock")
-    private boolean mIsLidOpen;
+    private Boolean mIsLidOpen;
     @GuardedBy("mLock")
     private final Map<Sensor, SensorEvent> mLatestSensorEvent = new ArrayMap<>();
 
@@ -299,7 +299,17 @@
             int newState = mOrderedStates[0].getIdentifier();
             for (int i = 0; i < mOrderedStates.length; i++) {
                 int state = mOrderedStates[i].getIdentifier();
-                if (mStateConditions.get(state).getAsBoolean()) {
+                boolean conditionSatisfied;
+                try {
+                    conditionSatisfied = mStateConditions.get(state).getAsBoolean();
+                } catch (IllegalStateException e) {
+                    // Failed to compute the current state based on current available data. Return
+                    // with the expectation that notifyDeviceStateChangedIfNeeded() will be called
+                    // when a callback with the missing data is triggered.
+                    return;
+                }
+
+                if (conditionSatisfied) {
                     newState = state;
                     break;
                 }
@@ -351,6 +361,10 @@
         @Override
         public boolean getAsBoolean() {
             synchronized (mLock) {
+                if (mIsLidOpen == null) {
+                    throw new IllegalStateException("Have not received lid switch value.");
+                }
+
                 return mIsLidOpen == mExpectedOpen;
             }
         }
@@ -377,13 +391,11 @@
             synchronized (mLock) {
                 SensorEvent latestEvent = mLatestSensorEvent.get(mSensor);
                 if (latestEvent == null) {
-                    // Default to returning false if we have not yet received a sensor event for the
-                    // sensor.
-                    return false;
+                    throw new IllegalStateException("Have not received sensor event.");
                 }
 
                 if (latestEvent.values.length != mExpectedValues.size()) {
-                    throw new IllegalStateException("Number of supplied numeric range(s) does not "
+                    throw new RuntimeException("Number of supplied numeric range(s) does not "
                             + "match the number of values in the latest sensor event for sensor: "
                             + mSensor);
                 }
diff --git a/services/core/java/com/android/server/powerstats/PowerStatsHALWrapper.java b/services/core/java/com/android/server/powerstats/PowerStatsHALWrapper.java
index f382d10..8ea2919 100644
--- a/services/core/java/com/android/server/powerstats/PowerStatsHALWrapper.java
+++ b/services/core/java/com/android/server/powerstats/PowerStatsHALWrapper.java
@@ -166,7 +166,7 @@
                 try {
                     powerEntityHAL = sVintfPowerStats.get().getPowerEntityInfo();
                 } catch (RemoteException e) {
-                    if (DEBUG) Slog.d(TAG, "Failed to get power entity info from PowerStats HAL");
+                    Slog.w(TAG, "Failed to get power entity info: ", e);
                 }
             }
 
@@ -183,7 +183,7 @@
                     stateResidencyResultHAL =
                         sVintfPowerStats.get().getStateResidency(powerEntityIds);
                 } catch (RemoteException e) {
-                    if (DEBUG) Slog.d(TAG, "Failed to get state residency from PowerStats HAL");
+                    Slog.w(TAG, "Failed to get state residency: ", e);
                 }
             }
 
@@ -198,9 +198,7 @@
                 try {
                     energyConsumerHAL = sVintfPowerStats.get().getEnergyConsumerInfo();
                 } catch (RemoteException e) {
-                    if (DEBUG) {
-                        Slog.d(TAG, "Failed to get energy consumer info from PowerStats HAL");
-                    }
+                    Slog.w(TAG, "Failed to get energy consumer info: ", e);
                 }
             }
 
@@ -217,9 +215,7 @@
                     energyConsumedHAL =
                         sVintfPowerStats.get().getEnergyConsumed(energyConsumerIds);
                 } catch (RemoteException e) {
-                    if (DEBUG) {
-                        Slog.d(TAG, "Failed to get energy consumer results from PowerStats HAL");
-                    }
+                    Slog.w(TAG, "Failed to get energy consumer results: ", e);
                 }
             }
 
@@ -234,7 +230,7 @@
                 try {
                     energyMeterInfoHAL = sVintfPowerStats.get().getEnergyMeterInfo();
                 } catch (RemoteException e) {
-                    if (DEBUG) Slog.d(TAG, "Failed to get energy meter info from PowerStats HAL");
+                    Slog.w(TAG, "Failed to get energy meter info: ", e);
                 }
             }
 
@@ -250,7 +246,7 @@
                     energyMeasurementHAL =
                         sVintfPowerStats.get().readEnergyMeter(channelIds);
                 } catch (RemoteException e) {
-                    if (DEBUG) Slog.d(TAG, "Failed to get energy measurements from PowerStats HAL");
+                    Slog.w(TAG, "Failed to get energy measurements: ", e);
                 }
             }
 
@@ -367,6 +363,7 @@
 
         @Override
         public synchronized void binderDied() {
+            Slog.w(TAG, "PowerStats HAL died");
             mInstance = null;
         }
     }
diff --git a/services/core/java/com/android/server/powerstats/ProtoStreamUtils.java b/services/core/java/com/android/server/powerstats/ProtoStreamUtils.java
index 746a098..688f0bf 100644
--- a/services/core/java/com/android/server/powerstats/ProtoStreamUtils.java
+++ b/services/core/java/com/android/server/powerstats/ProtoStreamUtils.java
@@ -111,6 +111,8 @@
     static class StateResidencyResultUtils {
         public static void adjustTimeSinceBootToEpoch(StateResidencyResult[] stateResidencyResult,
                 long startWallTime) {
+            if (stateResidencyResult == null) return;
+
             for (int i = 0; i < stateResidencyResult.length; i++) {
                 final int stateLength = stateResidencyResult[i].stateResidencyData.length;
                 for (int j = 0; j < stateLength; j++) {
@@ -320,6 +322,8 @@
     static class EnergyMeasurementUtils {
         public static void adjustTimeSinceBootToEpoch(EnergyMeasurement[] energyMeasurement,
                 long startWallTime) {
+            if (energyMeasurement == null) return;
+
             for (int i = 0; i < energyMeasurement.length; i++) {
                 energyMeasurement[i].timestampMs += startWallTime;
             }
@@ -539,6 +543,8 @@
     static class EnergyConsumerResultUtils {
         public static void adjustTimeSinceBootToEpoch(EnergyConsumerResult[] energyConsumerResult,
                 long startWallTime) {
+            if (energyConsumerResult == null) return;
+
             for (int i = 0; i < energyConsumerResult.length; i++) {
                 energyConsumerResult[i].timestampMs += startWallTime;
             }
diff --git a/services/core/java/com/android/server/rotationresolver/RemoteRotationResolverService.java b/services/core/java/com/android/server/rotationresolver/RemoteRotationResolverService.java
index b995b19..cfb4c27 100644
--- a/services/core/java/com/android/server/rotationresolver/RemoteRotationResolverService.java
+++ b/services/core/java/com/android/server/rotationresolver/RemoteRotationResolverService.java
@@ -87,6 +87,7 @@
             synchronized (request.mLock) {
                 if (!request.mIsFulfilled) {
                     request.mCallbackInternal.onFailure(ROTATION_RESULT_FAILURE_TIMED_OUT);
+                    Slog.d(TAG, "Trying to cancel the remote request. Reason: Timed out.");
                     request.cancelInternal();
                 }
             }
@@ -139,7 +140,6 @@
         void cancelInternal() {
             synchronized (mLock) {
                 if (mIsFulfilled) {
-                    Slog.v(TAG, "Trying to cancel the request that has been already fulfilled.");
                     return;
                 }
                 mIsFulfilled = true;
@@ -187,6 +187,8 @@
                             SystemClock.elapsedRealtime() - request.mRequestStartTimeMillis;
                     logRotationStats(request.mProposedRotation, request.mCurrentRotation, rotation,
                             timeToCalculate);
+                    Slog.d(TAG, "onSuccess:" + rotation);
+                    Slog.d(TAG, "timeToCalculate:" + timeToCalculate);
                 }
             }
 
@@ -204,6 +206,8 @@
                             SystemClock.elapsedRealtime() - request.mRequestStartTimeMillis;
                     logRotationStats(request.mProposedRotation, request.mCurrentRotation,
                             RESOLUTION_FAILURE, timeToCalculate);
+                    Slog.d(TAG, "onFailure:" + error);
+                    Slog.d(TAG, "timeToCalculate:" + timeToCalculate);
                 }
             }
 
diff --git a/services/core/java/com/android/server/rotationresolver/RotationResolverManagerPerUserService.java b/services/core/java/com/android/server/rotationresolver/RotationResolverManagerPerUserService.java
index 0cd0458..13f8d61 100644
--- a/services/core/java/com/android/server/rotationresolver/RotationResolverManagerPerUserService.java
+++ b/services/core/java/com/android/server/rotationresolver/RotationResolverManagerPerUserService.java
@@ -82,6 +82,7 @@
         if (mCurrentRequest == null) {
             return;
         }
+        Slog.d(TAG, "Trying to cancel the remote request. Reason: Service destroyed.");
         cancelLocked();
 
         if (mRemoteService != null) {
@@ -118,8 +119,10 @@
 
         cancellationSignalInternal.setOnCancelListener(() -> {
             synchronized (mLock) {
-                Slog.i(TAG, "Trying to cancel current request.");
-                mCurrentRequest.cancelInternal();
+                if (mCurrentRequest != null && !mCurrentRequest.mIsFulfilled) {
+                    Slog.d(TAG, "Trying to cancel the remote request. Reason: Client cancelled.");
+                    mCurrentRequest.cancelInternal();
+                }
             }
         });
 
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 8ffbb0a..546e420 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -1453,11 +1453,13 @@
     }
 
     @Override
-    public void onBubbleNotificationSuppressionChanged(String key, boolean isNotifSuppressed) {
+    public void onBubbleNotificationSuppressionChanged(String key, boolean isNotifSuppressed,
+            boolean isBubbleSuppressed) {
         enforceStatusBarService();
         final long identity = Binder.clearCallingIdentity();
         try {
-            mNotificationDelegate.onBubbleNotificationSuppressionChanged(key, isNotifSuppressed);
+            mNotificationDelegate.onBubbleNotificationSuppressionChanged(key, isNotifSuppressed,
+                    isBubbleSuppressed);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
diff --git a/services/core/java/com/android/server/vcn/Vcn.java b/services/core/java/com/android/server/vcn/Vcn.java
index 9d39c67..c55913e 100644
--- a/services/core/java/com/android/server/vcn/Vcn.java
+++ b/services/core/java/com/android/server/vcn/Vcn.java
@@ -128,7 +128,6 @@
      * from VcnManagementService, and therefore cannot rely on guarantees of running on the VCN
      * Looper.
      */
-    // TODO(b/179429339): update when exiting safemode (when a new VcnConfig is provided)
     private final AtomicBoolean mIsActive = new AtomicBoolean(true);
 
     public Vcn(
@@ -203,7 +202,8 @@
 
     @Override
     public void handleMessage(@NonNull Message msg) {
-        if (!isActive()) {
+        // Ignore if this Vcn is not active and we're not receiving new configs
+        if (!isActive() && msg.what != MSG_EVENT_CONFIG_UPDATED) {
             return;
         }
 
@@ -237,7 +237,13 @@
 
         mConfig = config;
 
-        // TODO: Reevaluate active VcnGatewayConnection(s)
+        // TODO(b/181815405): Reevaluate active VcnGatewayConnection(s)
+
+        if (!mIsActive.getAndSet(true)) {
+            // If this VCN was not previously active, it is exiting Safe Mode. Re-register the
+            // request listener to get NetworkRequests again (and all cached requests).
+            mVcnContext.getVcnNetworkProvider().registerListener(mRequestListener);
+        }
     }
 
     private void handleTeardown() {
@@ -253,6 +259,8 @@
     private void handleEnterSafeMode() {
         handleTeardown();
 
+        mVcnGatewayConnections.clear();
+
         mVcnCallback.onEnteredSafeMode();
     }
 
diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
index 6bc9978..15429f4 100644
--- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
+++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
@@ -979,7 +979,7 @@
         // IkeSessionCallback.onClosedExceptionally(), which calls sessionClosed()
         if (exception != null) {
             mGatewayStatusCallback.onGatewayConnectionError(
-                    mConnectionConfig.getRequiredUnderlyingCapabilities(),
+                    mConnectionConfig.getExposedCapabilities(),
                     VCN_ERROR_CODE_INTERNAL_ERROR,
                     RuntimeException.class.getName(),
                     "Received "
@@ -1016,7 +1016,7 @@
         }
 
         mGatewayStatusCallback.onGatewayConnectionError(
-                mConnectionConfig.getRequiredUnderlyingCapabilities(),
+                mConnectionConfig.getExposedCapabilities(),
                 errorCode,
                 exceptionClass,
                 exceptionMessage);
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 298128a..5446a39 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -253,6 +253,7 @@
 import android.app.usage.UsageEvents.Event;
 import android.content.ComponentName;
 import android.content.Intent;
+import android.content.LocusId;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.res.CompatibilityInfo;
@@ -551,6 +552,9 @@
 
     TaskDescription taskDescription; // the recents information for this activity
 
+    // The locusId associated with this activity, if set.
+    private LocusId mLocusId;
+
     // These configurations are collected from application's resources based on size-sensitive
     // qualifiers. For example, layout-w800dp will be added to mHorizontalSizeConfigurations as 800
     // and drawable-sw400dp will be added to both as 400.
@@ -6114,6 +6118,17 @@
         getTask().updateTaskDescription();
     }
 
+    void setLocusId(LocusId locusId) {
+        if (Objects.equals(locusId, mLocusId)) return;
+        mLocusId = locusId;
+        final Task task = getTask();
+        if (task != null) getTask().dispatchTaskInfoChangedIfNeeded(false /* force */);
+    }
+
+    LocusId getLocusId() {
+        return mLocusId;
+    }
+
     void setVoiceSessionLocked(IVoiceInteractionSession session) {
         voiceSession = session;
         pendingVoiceInteractionStart = false;
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 6ce9048..c6cece3 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -48,6 +48,7 @@
 import static android.content.pm.ActivityInfo.DOCUMENT_LAUNCH_ALWAYS;
 import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
 import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE;
+import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE_PER_TASK;
 import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK;
 import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TOP;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
@@ -1572,7 +1573,7 @@
                 }
             } else {
                 if (!mAvoidMoveToFront && mDoResume
-                        && mRootWindowContainer.hasVisibleWindowAboveNotificationShade(
+                        && 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
@@ -2093,7 +2094,8 @@
             mAddingToTask = true;
         } else if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0
                 || isDocumentLaunchesIntoExisting(mLaunchFlags)
-                || isLaunchModeOneOf(LAUNCH_SINGLE_INSTANCE, LAUNCH_SINGLE_TASK)) {
+                || isLaunchModeOneOf(LAUNCH_SINGLE_INSTANCE, LAUNCH_SINGLE_TASK,
+                        LAUNCH_SINGLE_INSTANCE_PER_TASK)) {
             // In this situation we want to remove all activities from the task up to the one
             // being started. In most cases this means we are resetting the task to its initial
             // state.
@@ -2261,6 +2263,12 @@
                 && !isLaunchModeOneOf(LAUNCH_SINGLE_TASK, LAUNCH_SINGLE_INSTANCE)
                 && (mLaunchFlags & FLAG_ACTIVITY_NEW_DOCUMENT) != 0;
 
+        if (mLaunchMode == LAUNCH_SINGLE_INSTANCE_PER_TASK) {
+            // Adding NEW_TASK flag for singleInstancePerTask launch mode activity, so that the
+            // activity won't be launched in source record's task.
+            mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
+        }
+
         sendNewTaskResultRequestIfNeeded();
 
         if ((mLaunchFlags & FLAG_ACTIVITY_NEW_DOCUMENT) != 0 && r.resultTo == null) {
@@ -2529,6 +2537,14 @@
             }
         }
 
+        if (intentActivity != null && mLaunchMode == LAUNCH_SINGLE_INSTANCE_PER_TASK
+                && !intentActivity.getTask().getRootActivity().mActivityComponent.equals(
+                mStartActivity.mActivityComponent)) {
+            // The task could be selected due to same task affinity. Do not reuse the task while
+            // starting the singleInstancePerTask activity if it is not the task root activity.
+            intentActivity = null;
+        }
+
         if (intentActivity != null
                 && (mStartActivity.isActivityTypeHome() || intentActivity.isActivityTypeHome())
                 && intentActivity.getDisplayArea() != mPreferredTaskDisplayArea) {
@@ -2715,6 +2731,10 @@
         return mode1 == mLaunchMode || mode2 == mLaunchMode;
     }
 
+    private boolean isLaunchModeOneOf(int mode1, int mode2, int mode3) {
+        return mode1 == mLaunchMode || mode2 == mLaunchMode || mode3 == mLaunchMode;
+    }
+
     static boolean isDocumentLaunchesIntoExisting(int flags) {
         return (flags & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) != 0 &&
                 (flags & Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0;
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 0c77d9f..d4eedf1 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -52,7 +52,7 @@
 import static android.os.FactoryTest.FACTORY_TEST_HIGH_LEVEL;
 import static android.os.FactoryTest.FACTORY_TEST_LOW_LEVEL;
 import static android.os.FactoryTest.FACTORY_TEST_OFF;
-import static android.os.IInputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
+import static android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
 import static android.os.Process.FIRST_APPLICATION_UID;
 import static android.os.Process.SYSTEM_UID;
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
@@ -160,6 +160,7 @@
 import android.content.DialogInterface;
 import android.content.IIntentSender;
 import android.content.Intent;
+import android.content.LocusId;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.ConfigurationInfo;
@@ -1942,6 +1943,21 @@
         }
     }
 
+    /**
+     * Sets the locusId for a particular activity.
+     *
+     * @param locusId the locusId to set.
+     * @param appToken the ActivityRecord's appToken.
+     */
+    public void setLocusId(LocusId locusId, IBinder appToken) {
+        synchronized (mGlobalLock) {
+            final ActivityRecord r = ActivityRecord.isInRootTaskLocked(appToken);
+            if (r != null) {
+                r.setLocusId(locusId);
+            }
+        }
+    }
+
     NeededUriGrants collectGrants(Intent intent, ActivityRecord target) {
         if (target != null) {
             return mUgmInternal.checkGrantUriPermissionFromIntent(intent,
@@ -2946,7 +2962,9 @@
         // startActivity() for these apps.
         if (!CompatChanges.isChangeEnabled(LOCK_DOWN_CLOSE_SYSTEM_DIALOGS, uid)) {
             synchronized (mGlobalLock) {
-                if (mRootWindowContainer.hasVisibleWindowAboveNotificationShade(uid)) {
+                // It's ok that the owner of the shade is not allowed *per this rule* because it has
+                // BROADCAST_CLOSE_SYSTEM_DIALOGS (SystemUI), so it would fall into that rule.
+                if (mRootWindowContainer.hasVisibleWindowAboveButDoesNotOwnNotificationShade(uid)) {
                     return true;
                 }
             }
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index db751e9..bfbc10a 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -109,6 +109,7 @@
 import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Debug;
 import android.os.Handler;
@@ -165,13 +166,13 @@
     static final String TAG_TASKS = TAG + POSTFIX_TASKS;
 
     /** How long we wait until giving up on the last activity telling us it is idle. */
-    private static final int IDLE_TIMEOUT = 10 * 1000;
+    private static final int IDLE_TIMEOUT = 10 * 1000 * Build.HW_TIMEOUT_MULTIPLIER;
 
     /** How long we can hold the sleep wake lock before giving up. */
-    private static final int SLEEP_TIMEOUT = 5 * 1000;
+    private static final int SLEEP_TIMEOUT = 5 * 1000 * Build.HW_TIMEOUT_MULTIPLIER;
 
     // How long we can hold the launch wake lock before giving up.
-    private static final int LAUNCH_TIMEOUT = 10 * 1000;
+    private static final int LAUNCH_TIMEOUT = 10 * 1000 * Build.HW_TIMEOUT_MULTIPLIER;
 
     /** How long we wait until giving up on the activity telling us it released the top state. */
     private static final int TOP_RESUMED_STATE_LOSS_TIMEOUT = 500;
diff --git a/services/core/java/com/android/server/wm/CompatModePackages.java b/services/core/java/com/android/server/wm/CompatModePackages.java
index a725dd3..28a509b 100644
--- a/services/core/java/com/android/server/wm/CompatModePackages.java
+++ b/services/core/java/com/android/server/wm/CompatModePackages.java
@@ -27,16 +27,20 @@
 import android.app.compat.CompatChanges;
 import android.compat.annotation.ChangeId;
 import android.compat.annotation.Disabled;
+import android.compat.annotation.EnabledSince;
+import android.compat.annotation.Overridable;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
 import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
+import android.os.Build;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.util.AtomicFile;
+import android.util.DisplayMetrics;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.TypedXmlPullParser;
@@ -119,6 +123,17 @@
     @Disabled
     private static final long DOWNSCALE_50 = 176926741L;
 
+    /**
+     * On Android TV applications that target pre-S are not expecting to receive a Window larger
+     * than 1080p, so if needed we are downscaling their Windows to 1080p.
+     * However, applications that target S and greater release version are expected to be able to
+     * handle any Window size, so we should not downscale their Windows.
+     */
+    @ChangeId
+    @Overridable
+    @EnabledSince(targetSdkVersion = Build.VERSION_CODES.S)
+    private static final long DO_NOT_DOWNSCALE_TO_1080P_ON_TV = 157629738L; // This is a Bug ID.
+
     private final HashMap<String, Integer> mPackages = new HashMap<String, Integer>();
 
     private static final int MSG_WRITE = 300;
@@ -138,7 +153,7 @@
                     break;
             }
         }
-    };
+    }
 
     public CompatModePackages(ActivityTaskManagerService service, File systemDir, Handler handler) {
         mService = service;
@@ -247,55 +262,53 @@
         mHandler.sendMessageDelayed(msg, 10000);
     }
 
+    public CompatibilityInfo compatibilityInfoForPackageLocked(ApplicationInfo ai) {
+        final boolean forceCompat = getPackageCompatModeEnabledLocked(ai);
+        final float compatScale = getCompatScale(ai.packageName, ai.uid);
+        final Configuration config = mService.getGlobalConfiguration();
+        return new CompatibilityInfo(ai, config.screenLayout, config.smallestScreenWidthDp,
+                forceCompat, compatScale);
+    }
+
     float getCompatScale(String packageName, int uid) {
-        if (!CompatChanges.isChangeEnabled(
-                DOWNSCALED, packageName, UserHandle.getUserHandleForUid(uid))) {
-            return 1f;
+        final UserHandle userHandle = UserHandle.getUserHandleForUid(uid);
+        if (CompatChanges.isChangeEnabled(DOWNSCALED, packageName, userHandle)) {
+            if (CompatChanges.isChangeEnabled(DOWNSCALE_87_5, packageName, userHandle)) {
+                return 8f / 7f; // 1.14285714286
+            }
+            if (CompatChanges.isChangeEnabled(DOWNSCALE_75, packageName, userHandle)) {
+                return 4f / 3f; // 1.333333333
+            }
+            if (CompatChanges.isChangeEnabled(DOWNSCALE_62_5, packageName, userHandle)) {
+                return /* 1 / 0.625 */ 1.6f;
+            }
+            if (CompatChanges.isChangeEnabled(DOWNSCALE_50, packageName, userHandle)) {
+                return /* 1 / 0.5 */ 2f;
+            }
         }
-        if (CompatChanges.isChangeEnabled(
-                DOWNSCALE_87_5, packageName, UserHandle.getUserHandleForUid(uid))) {
-            // 8/7 == (1 / 0.875) ~= 1.14285714286
-            return 8f / 7f;
+
+        if (mService.mHasLeanbackFeature) {
+            final Configuration config = mService.getGlobalConfiguration();
+            final float density = config.densityDpi / (float) DisplayMetrics.DENSITY_DEFAULT;
+            final int smallestScreenWidthPx = (int) (config.smallestScreenWidthDp * density + .5f);
+            if (smallestScreenWidthPx > 1080 && !CompatChanges.isChangeEnabled(
+                    DO_NOT_DOWNSCALE_TO_1080P_ON_TV, packageName, userHandle)) {
+                return smallestScreenWidthPx / 1080f;
+            }
         }
-        if (CompatChanges.isChangeEnabled(
-                DOWNSCALE_75, packageName, UserHandle.getUserHandleForUid(uid))) {
-            // 4/3 == (1 / 0.75) ~= 1.333333333
-            return 4f / 3f;
-        }
-        if (CompatChanges.isChangeEnabled(
-                DOWNSCALE_62_5, packageName, UserHandle.getUserHandleForUid(uid))) {
-            // (1 / 0.625) == 1.6
-            return 1.6f;
-        }
-        if (CompatChanges.isChangeEnabled(
-                DOWNSCALE_50, packageName, UserHandle.getUserHandleForUid(uid))) {
-            return 2f;
-        }
+
         return 1f;
     }
 
-    public CompatibilityInfo compatibilityInfoForPackageLocked(ApplicationInfo ai) {
-        final Configuration globalConfig = mService.getGlobalConfiguration();
-        final float requestedScale = getCompatScale(ai.packageName, ai.uid);
-        CompatibilityInfo ci = new CompatibilityInfo(ai, globalConfig.screenLayout,
-                globalConfig.smallestScreenWidthDp,
-                (getPackageFlags(ai.packageName) & COMPAT_FLAG_ENABLED) != 0, requestedScale);
-        //Slog.i(TAG, "*********** COMPAT FOR PKG " + ai.packageName + ": " + ci);
-        return ci;
-    }
-
     public int computeCompatModeLocked(ApplicationInfo ai) {
-        final boolean enabled = (getPackageFlags(ai.packageName)&COMPAT_FLAG_ENABLED) != 0;
-        final Configuration globalConfig = mService.getGlobalConfiguration();
-        final CompatibilityInfo info = new CompatibilityInfo(ai, globalConfig.screenLayout,
-                globalConfig.smallestScreenWidthDp, enabled);
+        final CompatibilityInfo info = compatibilityInfoForPackageLocked(ai);
         if (info.alwaysSupportsScreen()) {
             return ActivityManager.COMPAT_MODE_NEVER;
         }
         if (info.neverSupportsScreen()) {
             return ActivityManager.COMPAT_MODE_ALWAYS;
         }
-        return enabled ? ActivityManager.COMPAT_MODE_ENABLED
+        return getPackageCompatModeEnabledLocked(ai) ? ActivityManager.COMPAT_MODE_ENABLED
                 : ActivityManager.COMPAT_MODE_DISABLED;
     }
 
@@ -307,6 +320,10 @@
         setPackageFlagLocked(packageName, COMPAT_FLAG_DONT_ASK, ask);
     }
 
+    private boolean getPackageCompatModeEnabledLocked(ApplicationInfo ai) {
+        return (getPackageFlags(ai.packageName) & COMPAT_FLAG_ENABLED) != 0;
+    }
+
     private void setPackageFlagLocked(String packageName, int flag, boolean set) {
         final int curFlags = getPackageFlags(packageName);
         final int newFlags = set ? (curFlags & ~flag) : (curFlags | flag);
@@ -443,9 +460,6 @@
             out.startTag(null, "compat-packages");
 
             final IPackageManager pm = AppGlobals.getPackageManager();
-            final Configuration globalConfig = mService.getGlobalConfiguration();
-            final int screenLayout = globalConfig.screenLayout;
-            final int smallestScreenWidthDp = globalConfig.smallestScreenWidthDp;
             final Iterator<Map.Entry<String, Integer>> it = pkgs.entrySet().iterator();
             while (it.hasNext()) {
                 Map.Entry<String, Integer> entry = it.next();
@@ -462,8 +476,7 @@
                 if (ai == null) {
                     continue;
                 }
-                CompatibilityInfo info = new CompatibilityInfo(ai, screenLayout,
-                        smallestScreenWidthDp, false);
+                final CompatibilityInfo info = compatibilityInfoForPackageLocked(ai);
                 if (info.alwaysSupportsScreen()) {
                     continue;
                 }
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 119ffb7..1d45c6e 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -3856,6 +3856,9 @@
         if (newParent != null && newParent != mInputMethodSurfaceParent) {
             mInputMethodSurfaceParent = newParent;
             getPendingTransaction().reparent(mImeWindowsContainer.mSurfaceControl, newParent);
+            // When surface parent is removed, the relative layer will also be removed. We need to
+            // do a force update to make sure there is a layer set for the new parent.
+            assignRelativeLayerForIme(getPendingTransaction(), true /* forceUpdate */);
             scheduleAnimation();
         }
     }
@@ -4537,11 +4540,12 @@
         }
 
         @Override
-        void assignRelativeLayer(Transaction t, SurfaceControl relativeTo, int layer) {
+        void assignRelativeLayer(Transaction t, SurfaceControl relativeTo, int layer,
+                boolean forceUpdate) {
             if (!mNeedsLayer) {
                 return;
             }
-            super.assignRelativeLayer(t, relativeTo, layer);
+            super.assignRelativeLayer(t, relativeTo, layer, forceUpdate);
             mNeedsLayer = false;
         }
     }
@@ -4631,6 +4635,11 @@
 
     @Override
     void assignChildLayers(SurfaceControl.Transaction t) {
+        assignRelativeLayerForIme(t, false /* forceUpdate */);
+        super.assignChildLayers(t);
+    }
+
+    private void assignRelativeLayerForIme(SurfaceControl.Transaction t, boolean forceUpdate) {
         mImeWindowsContainer.setNeedsLayer();
         final WindowState imeTarget = mImeLayeringTarget;
         // In the case where we have an IME target that is not in split-screen mode IME
@@ -4657,14 +4666,13 @@
             mImeWindowsContainer.assignRelativeLayer(t, imeTarget.getSurfaceControl(),
                     // TODO: We need to use an extra level on the app surface to ensure
                     // this is always above SurfaceView but always below attached window.
-                    1);
+                    1, forceUpdate);
         } else if (mInputMethodSurfaceParent != null) {
             // The IME surface parent may not be its window parent's surface
             // (@see #computeImeParent), so set relative layer here instead of letting the window
             // parent to assign layer.
-            mImeWindowsContainer.assignRelativeLayer(t, mInputMethodSurfaceParent, 1);
+            mImeWindowsContainer.assignRelativeLayer(t, mInputMethodSurfaceParent, 1, forceUpdate);
         }
-        super.assignChildLayers(t);
     }
 
     /**
@@ -4677,7 +4685,6 @@
      * with {@link WindowState#assignLayer}
      */
     void assignRelativeLayerForImeTargetChild(SurfaceControl.Transaction t, WindowContainer child) {
-        mImeWindowsContainer.setNeedsLayer();
         child.assignRelativeLayer(t, mImeWindowsContainer.getSurfaceControl(), 1);
     }
 
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index af9cdeb..32152ec 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -69,7 +69,6 @@
 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
 import static android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE;
-import static android.view.WindowManager.LayoutParams.TYPE_POINTER;
 import static android.view.WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL;
@@ -243,7 +242,7 @@
         }
     }
 
-    private SystemGesturesPointerEventListener mSystemGestures;
+    private final SystemGesturesPointerEventListener mSystemGestures;
 
     private volatile int mLidState = LID_ABSENT;
     private volatile int mDockMode = Intent.EXTRA_DOCK_STATE_UNDOCKED;
@@ -385,7 +384,7 @@
     private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS = 0;
     private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_NAVIGATION = 1;
 
-    private GestureNavigationSettingsObserver mGestureNavigationSettingsObserver;
+    private final GestureNavigationSettingsObserver mGestureNavigationSettingsObserver;
 
     private final WindowManagerInternal.AppTransitionListener mAppTransitionListener;
 
@@ -449,6 +448,119 @@
 
         final Looper looper = UiThread.getHandler().getLooper();
         mHandler = new PolicyHandler(looper);
+        mSystemGestures = new SystemGesturesPointerEventListener(mContext, mHandler,
+                new SystemGesturesPointerEventListener.Callbacks() {
+                    @Override
+                    public void onSwipeFromTop() {
+                        synchronized (mLock) {
+                            if (mStatusBar != null) {
+                                requestTransientBars(mStatusBar);
+                            }
+                            checkAltBarSwipeForTransientBars(ALT_BAR_TOP);
+                        }
+                    }
+
+                    @Override
+                    public void onSwipeFromBottom() {
+                        synchronized (mLock) {
+                            if (mNavigationBar != null
+                                    && mNavigationBarPosition == NAV_BAR_BOTTOM) {
+                                requestTransientBars(mNavigationBar);
+                            }
+                            checkAltBarSwipeForTransientBars(ALT_BAR_BOTTOM);
+                        }
+                    }
+
+                    @Override
+                    public void onSwipeFromRight() {
+                        final Region excludedRegion = Region.obtain();
+                        synchronized (mLock) {
+                            mDisplayContent.calculateSystemGestureExclusion(
+                                    excludedRegion, null /* outUnrestricted */);
+                            final boolean excluded =
+                                    mSystemGestures.currentGestureStartedInRegion(excludedRegion);
+                            if (mNavigationBar != null && (mNavigationBarPosition == NAV_BAR_RIGHT
+                                    || !excluded && mNavigationBarAlwaysShowOnSideGesture)) {
+                                requestTransientBars(mNavigationBar);
+                            }
+                            checkAltBarSwipeForTransientBars(ALT_BAR_RIGHT);
+                        }
+                        excludedRegion.recycle();
+                    }
+
+                    @Override
+                    public void onSwipeFromLeft() {
+                        final Region excludedRegion = Region.obtain();
+                        synchronized (mLock) {
+                            mDisplayContent.calculateSystemGestureExclusion(
+                                    excludedRegion, null /* outUnrestricted */);
+                            final boolean excluded =
+                                    mSystemGestures.currentGestureStartedInRegion(excludedRegion);
+                            if (mNavigationBar != null && (mNavigationBarPosition == NAV_BAR_LEFT
+                                    || !excluded && mNavigationBarAlwaysShowOnSideGesture)) {
+                                requestTransientBars(mNavigationBar);
+                            }
+                            checkAltBarSwipeForTransientBars(ALT_BAR_LEFT);
+                        }
+                        excludedRegion.recycle();
+                    }
+
+                    @Override
+                    public void onFling(int duration) {
+                        if (mService.mPowerManagerInternal != null) {
+                            mService.mPowerManagerInternal.setPowerBoost(
+                                    Boost.INTERACTION, duration);
+                        }
+                    }
+
+                    @Override
+                    public void onDebug() {
+                        // no-op
+                    }
+
+                    private WindowOrientationListener getOrientationListener() {
+                        final DisplayRotation rotation = mDisplayContent.getDisplayRotation();
+                        return rotation != null ? rotation.getOrientationListener() : null;
+                    }
+
+                    @Override
+                    public void onDown() {
+                        final WindowOrientationListener listener = getOrientationListener();
+                        if (listener != null) {
+                            listener.onTouchStart();
+                        }
+                    }
+
+                    @Override
+                    public void onUpOrCancel() {
+                        final WindowOrientationListener listener = getOrientationListener();
+                        if (listener != null) {
+                            listener.onTouchEnd();
+                        }
+                    }
+
+                    @Override
+                    public void onMouseHoverAtTop() {
+                        mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
+                        Message msg = mHandler.obtainMessage(MSG_REQUEST_TRANSIENT_BARS);
+                        msg.arg1 = MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS;
+                        mHandler.sendMessageDelayed(msg, 500 /* delayMillis */);
+                    }
+
+                    @Override
+                    public void onMouseHoverAtBottom() {
+                        mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
+                        Message msg = mHandler.obtainMessage(MSG_REQUEST_TRANSIENT_BARS);
+                        msg.arg1 = MSG_REQUEST_TRANSIENT_BARS_ARG_NAVIGATION;
+                        mHandler.sendMessageDelayed(msg, 500 /* delayMillis */);
+                    }
+
+                    @Override
+                    public void onMouseLeaveFromEdge() {
+                        mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
+                    }
+                });
+        displayContent.registerPointerEventListener(mSystemGestures);
         mAppTransitionListener = new WindowManagerInternal.AppTransitionListener() {
 
             private Runnable mAppTransitionPending = () -> {
@@ -504,7 +616,7 @@
         mImmersiveModeConfirmation = new ImmersiveModeConfirmation(mContext, looper,
                 mService.mVrModeEnabled);
 
-        // TODO(b/180986447): Make it can take screenshot on external display
+        // TODO: Make it can take screenshot on external display
         mScreenshotHelper = displayContent.isDefaultDisplay
                 ? new ScreenshotHelper(mContext) : null;
 
@@ -528,6 +640,16 @@
         mRefreshRatePolicy = new RefreshRatePolicy(mService,
                 mDisplayContent.getDisplayInfo(),
                 mService.mHighRefreshRateDenylist);
+
+        mGestureNavigationSettingsObserver = new GestureNavigationSettingsObserver(mHandler,
+                mContext, () -> {
+            synchronized (mLock) {
+                onConfigurationChanged();
+                mSystemGestures.onConfigurationChanged();
+                mDisplayContent.updateSystemGestureExclusion();
+            }
+        });
+        mHandler.post(mGestureNavigationSettingsObserver::register);
     }
 
     private void checkAltBarSwipeForTransientBars(@WindowManagerPolicy.AltBarPosition int pos) {
@@ -546,154 +668,12 @@
     }
 
     void systemReady() {
+        mSystemGestures.systemReady();
         if (mService.mPointerLocationEnabled) {
             setPointerLocationEnabled(true);
         }
     }
 
-    @NonNull
-    private GestureNavigationSettingsObserver getGestureNavigationSettingsObserver() {
-        if (mGestureNavigationSettingsObserver == null) {
-            mGestureNavigationSettingsObserver = new GestureNavigationSettingsObserver(mHandler,
-                    mContext, () -> {
-                synchronized (mLock) {
-                    onConfigurationChanged();
-                    getSystemGestures().onConfigurationChanged();
-                    mDisplayContent.updateSystemGestureExclusion();
-                }
-            });
-            mHandler.post(mGestureNavigationSettingsObserver::register);
-        }
-        return mGestureNavigationSettingsObserver;
-    }
-
-    @NonNull
-    private SystemGesturesPointerEventListener getSystemGestures() {
-        if (mSystemGestures == null) {
-            final Context gestureContext = mUiContext.createWindowContext(
-                    mDisplayContent.getDisplay(), TYPE_POINTER, null /* options */);
-            mSystemGestures = new SystemGesturesPointerEventListener(gestureContext, mHandler,
-                    new SystemGesturesPointerEventListener.Callbacks() {
-                        @Override
-                        public void onSwipeFromTop() {
-                            synchronized (mLock) {
-                                if (mStatusBar != null) {
-                                    requestTransientBars(mStatusBar);
-                                }
-                                checkAltBarSwipeForTransientBars(ALT_BAR_TOP);
-                            }
-                        }
-
-                        @Override
-                        public void onSwipeFromBottom() {
-                            synchronized (mLock) {
-                                if (mNavigationBar != null
-                                        && mNavigationBarPosition == NAV_BAR_BOTTOM) {
-                                    requestTransientBars(mNavigationBar);
-                                }
-                                checkAltBarSwipeForTransientBars(ALT_BAR_BOTTOM);
-                            }
-                        }
-
-                        @Override
-                        public void onSwipeFromRight() {
-                            final Region excludedRegion = Region.obtain();
-                            synchronized (mLock) {
-                                mDisplayContent.calculateSystemGestureExclusion(
-                                        excludedRegion, null /* outUnrestricted */);
-                                final boolean excluded = mSystemGestures
-                                        .currentGestureStartedInRegion(excludedRegion);
-                                if (mNavigationBar != null
-                                        && (mNavigationBarPosition == NAV_BAR_RIGHT
-                                        || !excluded && mNavigationBarAlwaysShowOnSideGesture)) {
-                                    requestTransientBars(mNavigationBar);
-                                }
-                                checkAltBarSwipeForTransientBars(ALT_BAR_RIGHT);
-                            }
-                            excludedRegion.recycle();
-                        }
-
-                        @Override
-                        public void onSwipeFromLeft() {
-                            final Region excludedRegion = Region.obtain();
-                            synchronized (mLock) {
-                                mDisplayContent.calculateSystemGestureExclusion(
-                                        excludedRegion, null /* outUnrestricted */);
-                                final boolean excluded = mSystemGestures
-                                        .currentGestureStartedInRegion(excludedRegion);
-                                if (mNavigationBar != null
-                                        && (mNavigationBarPosition == NAV_BAR_LEFT
-                                        || !excluded && mNavigationBarAlwaysShowOnSideGesture)) {
-                                    requestTransientBars(mNavigationBar);
-                                }
-                                checkAltBarSwipeForTransientBars(ALT_BAR_LEFT);
-                            }
-                            excludedRegion.recycle();
-                        }
-
-                        @Override
-                        public void onFling(int duration) {
-                            if (mService.mPowerManagerInternal != null) {
-                                mService.mPowerManagerInternal.setPowerBoost(
-                                        Boost.INTERACTION, duration);
-                            }
-                        }
-
-                        @Override
-                        public void onDebug() {
-                            // no-op
-                        }
-
-                        private WindowOrientationListener getOrientationListener() {
-                            final DisplayRotation rotation = mDisplayContent.getDisplayRotation();
-                            return rotation != null ? rotation.getOrientationListener() : null;
-                        }
-
-                        @Override
-                        public void onDown() {
-                            final WindowOrientationListener listener = getOrientationListener();
-                            if (listener != null) {
-                                listener.onTouchStart();
-                            }
-                        }
-
-                        @Override
-                        public void onUpOrCancel() {
-                            final WindowOrientationListener listener = getOrientationListener();
-                            if (listener != null) {
-                                listener.onTouchEnd();
-                            }
-                        }
-
-                        @Override
-                        public void onMouseHoverAtTop() {
-                            mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
-                            Message msg = mHandler.obtainMessage(MSG_REQUEST_TRANSIENT_BARS);
-                            msg.arg1 = MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS;
-                            mHandler.sendMessageDelayed(msg, 500 /* delayMillis */);
-                        }
-
-                        @Override
-                        public void onMouseHoverAtBottom() {
-                            mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
-                            Message msg = mHandler.obtainMessage(MSG_REQUEST_TRANSIENT_BARS);
-                            msg.arg1 = MSG_REQUEST_TRANSIENT_BARS_ARG_NAVIGATION;
-                            mHandler.sendMessageDelayed(msg, 500 /* delayMillis */);
-                        }
-
-                        @Override
-                        public void onMouseLeaveFromEdge() {
-                            mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
-                        }
-                    });
-            mDisplayContent.registerPointerEventListener(getSystemGestures());
-            if (mService.mSystemReady) {
-                mSystemGestures.systemReady();
-            }
-        }
-        return mSystemGestures;
-    }
-
     private int getDisplayId() {
         return mDisplayContent.getDisplayId();
     }
@@ -1475,7 +1455,8 @@
     }
 
     void onDisplayInfoChanged(DisplayInfo info) {
-        getSystemGestures().onDisplayInfoChanged(info);
+        mSystemGestures.screenWidth = info.logicalWidth;
+        mSystemGestures.screenHeight = info.logicalHeight;
     }
 
     private void layoutStatusBar(DisplayFrames displayFrames, Rect contentFrame) {
@@ -1988,7 +1969,7 @@
     public void onOverlayChangedLw() {
         updateCurrentUserResources();
         onConfigurationChanged();
-        getSystemGestures().onConfigurationChanged();
+        mSystemGestures.onConfigurationChanged();
     }
 
     /**
@@ -2059,10 +2040,10 @@
         }
 
         mNavBarOpacityMode = res.getInteger(R.integer.config_navBarOpacityMode);
-        final GestureNavigationSettingsObserver observer = getGestureNavigationSettingsObserver();
-        mLeftGestureInset = observer.getLeftSensitivity(res);
-        mRightGestureInset = observer.getRightSensitivity(res);
-        mNavButtonForcedVisible = observer.areNavigationButtonForcedVisible();
+        mLeftGestureInset = mGestureNavigationSettingsObserver.getLeftSensitivity(res);
+        mRightGestureInset = mGestureNavigationSettingsObserver.getRightSensitivity(res);
+        mNavButtonForcedVisible =
+                mGestureNavigationSettingsObserver.areNavigationButtonForcedVisible();
         mNavigationBarLetsThroughTaps = res.getBoolean(R.bool.config_navBarTapThrough);
         mNavigationBarAlwaysShowOnSideGesture =
                 res.getBoolean(R.bool.config_navBarAlwaysShowOnSideEdgeGesture);
@@ -3075,7 +3056,7 @@
     }
 
     void release() {
-        mHandler.post(getGestureNavigationSettingsObserver()::unregister);
+        mHandler.post(mGestureNavigationSettingsObserver::unregister);
     }
 
     @VisibleForTesting
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index 86518ea..0b3c065 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -16,7 +16,7 @@
 
 package com.android.server.wm;
 
-import static android.os.IInputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
+import static android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP;
 
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION;
diff --git a/services/core/java/com/android/server/wm/InputConsumerImpl.java b/services/core/java/com/android/server/wm/InputConsumerImpl.java
index 4d0c75c..cbd5646 100644
--- a/services/core/java/com/android/server/wm/InputConsumerImpl.java
+++ b/services/core/java/com/android/server/wm/InputConsumerImpl.java
@@ -16,7 +16,7 @@
 
 package com.android.server.wm;
 
-import static android.os.IInputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
+import static android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
 
 import android.graphics.Point;
 import android.graphics.Rect;
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index 57f2638..b31c2e4 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -16,6 +16,7 @@
 
 package com.android.server.wm;
 
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 import static android.view.Display.DEFAULT_DISPLAY;
@@ -524,40 +525,36 @@
 
             boolean occludedByActivity = false;
             final Task task = getRootTaskForControllingOccluding(display);
-            if (task != null) {
-                final ActivityRecord r = task.getTopNonFinishingActivity();
-                if (r != null) {
-                    final boolean showWhenLocked = r.canShowWhenLocked();
-                    if (r.containsDismissKeyguardWindow()) {
-                        mDismissingKeyguardActivity = r;
-                    }
-                    if (r.getTurnScreenOnFlag()
-                            && r.currentLaunchCanTurnScreenOn()) {
-                        mTopTurnScreenOnActivity = r;
-                    }
+            final ActivityRecord top = task != null ? task.getTopNonFinishingActivity() : null;
+            if (top != null) {
+                if (top.containsDismissKeyguardWindow()) {
+                    mDismissingKeyguardActivity = top;
+                }
+                if (top.getTurnScreenOnFlag() && top.currentLaunchCanTurnScreenOn()) {
+                    mTopTurnScreenOnActivity = top;
+                }
 
-                    if (showWhenLocked) {
-                        mTopOccludesActivity = r;
-                    }
+                final boolean showWhenLocked = top.canShowWhenLocked();
+                if (showWhenLocked) {
+                    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
-                            && task.topRunningActivity() == mDismissingKeyguardActivity
-                            && controller.canShowWhileOccluded(
-                                    true /* dismissKeyguard */, false /* showWhenLocked */));
-                    // FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD only apply for secondary display.
-                    if (mDisplayId != DEFAULT_DISPLAY && task.mDisplayContent != null) {
-                        occludedByActivity |=
-                                task.mDisplayContent.canShowWithInsecureKeyguard()
-                                && controller.canDismissKeyguard();
-                    }
+                // 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
+                        && task.topRunningActivity() == mDismissingKeyguardActivity
+                        && controller.canShowWhileOccluded(
+                                true /* dismissKeyguard */, false /* showWhenLocked */));
+                // FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD only apply for secondary display.
+                if (mDisplayId != DEFAULT_DISPLAY) {
+                    occludedByActivity |= display.canShowWithInsecureKeyguard()
+                            && controller.canDismissKeyguard();
                 }
             }
-            // TODO(b/123372519): isShowingDream can only works on default display.
-            mOccluded = occludedByActivity || (mDisplayId == DEFAULT_DISPLAY
-                    && mService.mRootWindowContainer.getDefaultDisplay()
-                    .getDisplayPolicy().isShowingDreamLw());
+
+            final boolean dreaming = display.getDisplayPolicy().isShowingDreamLw() && (top != null
+                    && top.getActivityType() == ACTIVITY_TYPE_DREAM);
+            mOccluded = dreaming || occludedByActivity;
             mRequestDismissKeyguard = lastDismissKeyguardActivity != mDismissingKeyguardActivity
                     && !mOccluded
                     && mDismissingKeyguardActivity != null
diff --git a/services/core/java/com/android/server/wm/Letterbox.java b/services/core/java/com/android/server/wm/Letterbox.java
index 99c9e79..377e498 100644
--- a/services/core/java/com/android/server/wm/Letterbox.java
+++ b/services/core/java/com/android/server/wm/Letterbox.java
@@ -16,7 +16,7 @@
 
 package com.android.server.wm;
 
-import static android.os.IInputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
+import static android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
 import static android.view.SurfaceControl.HIDDEN;
 
 import android.graphics.Color;
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 0e8cadb..1212302 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -3127,11 +3127,14 @@
     }
 
     /**
-     * Returns {@code true} if {@code uid} has a visible window that's above a window of type {@link
-     * WindowManager.LayoutParams#TYPE_NOTIFICATION_SHADE}. If there is no window with type {@link
-     * WindowManager.LayoutParams#TYPE_NOTIFICATION_SHADE}, it returns {@code false}.
+     * Returns {@code true} if {@code uid} has a visible window that's above the window of type
+     * {@link WindowManager.LayoutParams#TYPE_NOTIFICATION_SHADE} and {@code uid} is not owner of
+     * the window of type {@link WindowManager.LayoutParams#TYPE_NOTIFICATION_SHADE}.
+     *
+     * If there is no window with type {@link WindowManager.LayoutParams#TYPE_NOTIFICATION_SHADE},
+     * it returns {@code false}.
      */
-    boolean hasVisibleWindowAboveNotificationShade(int uid) {
+    boolean hasVisibleWindowAboveButDoesNotOwnNotificationShade(int uid) {
         boolean[] visibleWindowFound = {false};
         // We only return true if we found the notification shade (ie. window of type
         // TYPE_NOTIFICATION_SHADE). Usually, it should always be there, but if for some reason
@@ -3141,7 +3144,7 @@
                 visibleWindowFound[0] = true;
             }
             if (w.mAttrs.type == TYPE_NOTIFICATION_SHADE) {
-                return visibleWindowFound[0];
+                return visibleWindowFound[0] && w.mOwnerUid != uid;
             }
             return false;
         }, true /* traverseTopToBottom */);
diff --git a/services/core/java/com/android/server/wm/SystemGesturesPointerEventListener.java b/services/core/java/com/android/server/wm/SystemGesturesPointerEventListener.java
index a98a478..f3859b4 100644
--- a/services/core/java/com/android/server/wm/SystemGesturesPointerEventListener.java
+++ b/services/core/java/com/android/server/wm/SystemGesturesPointerEventListener.java
@@ -126,17 +126,11 @@
                 Slog.w(TAG, "Cannot create GestureDetector, display removed:" + displayId);
                 return;
             }
-            onDisplayInfoChanged(info);
             mGestureDetector = new GestureDetector(mContext, new FlingGestureDetector(), mHandler) {
             };
         });
     }
 
-    void onDisplayInfoChanged(DisplayInfo info) {
-        screenWidth = info.logicalWidth;
-        screenHeight = info.logicalHeight;
-    }
-
     @Override
     public void onPointerEvent(MotionEvent event) {
         if (mGestureDetector != null && event.isTouchEvent()) {
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 194350d..d992a45 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -4107,6 +4107,8 @@
                 : INVALID_TASK_ID;
         info.isFocused = isFocused();
         info.isVisible = hasVisibleChildren();
+        ActivityRecord topRecord = getTopNonFinishingActivity();
+        info.mTopActivityLocusId = topRecord != null ? topRecord.getLocusId() : null;
     }
 
     @Nullable PictureInPictureParams getPictureInPictureParams() {
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index 76869e5..ed92fd0 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -462,7 +462,7 @@
 
         mLastLeafTaskToFrontId = t.mTaskId;
         EventLogTags.writeWmTaskToFront(t.mUserId, t.mTaskId);
-        // Notifying only when a leak task moved to front. Or the listeners would be notified
+        // Notifying only when a leaf task moved to front. Or the listeners would be notified
         // couple times from the leaf task all the way up to the root task.
         mAtmService.getTaskChangeNotificationController().notifyTaskMovedToFront(t.getTaskInfo());
     }
diff --git a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
index ee5c1f01..dff621c 100644
--- a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
+++ b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
@@ -406,6 +406,12 @@
             }
         }
 
+        if (taskDisplayArea == null && source != null) {
+            final TaskDisplayArea sourceDisplayArea = source.getDisplayArea();
+            if (DEBUG) appendLog("display-area-from-source=" + sourceDisplayArea);
+            taskDisplayArea = sourceDisplayArea;
+        }
+
         Task rootTask = (taskDisplayArea == null && task != null)
                 ? task.getRootTask() : null;
         if (rootTask != null) {
@@ -413,12 +419,6 @@
             taskDisplayArea = rootTask.getDisplayArea();
         }
 
-        if (taskDisplayArea == null && source != null) {
-            final TaskDisplayArea sourceDisplayArea = source.getDisplayArea();
-            if (DEBUG) appendLog("display-area-from-source=" + sourceDisplayArea);
-            taskDisplayArea = sourceDisplayArea;
-        }
-
         if (taskDisplayArea == null && options != null) {
             final int callerDisplayId = options.getCallerDisplayId();
             final DisplayContent dc =
diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java
index 6f7f113..364246e 100644
--- a/services/core/java/com/android/server/wm/TaskPositioner.java
+++ b/services/core/java/com/android/server/wm/TaskPositioner.java
@@ -18,7 +18,7 @@
 
 import static android.app.ActivityTaskManager.RESIZE_MODE_USER;
 import static android.app.ActivityTaskManager.RESIZE_MODE_USER_FORCED;
-import static android.os.IInputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
+import static android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 
 import static com.android.internal.policy.TaskResizingAlgorithm.CTRL_BOTTOM;
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 0c4ff2f..8d85958 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -2241,15 +2241,20 @@
         }
     }
 
-    void assignRelativeLayer(Transaction t, SurfaceControl relativeTo, int layer) {
+    void assignRelativeLayer(Transaction t, SurfaceControl relativeTo, int layer,
+            boolean forceUpdate) {
         final boolean changed = layer != mLastLayer || mLastRelativeToLayer != relativeTo;
-        if (mSurfaceControl != null && changed) {
+        if (mSurfaceControl != null && (changed || forceUpdate)) {
             setRelativeLayer(t, relativeTo, layer);
             mLastLayer = layer;
             mLastRelativeToLayer = relativeTo;
         }
     }
 
+    void assignRelativeLayer(Transaction t, SurfaceControl relativeTo, int layer) {
+        assignRelativeLayer(t, relativeTo, layer, false /* forceUpdate */);
+    }
+
     protected void setLayer(Transaction t, int layer) {
 
         // Route through surface animator to accommodate that our surface control might be
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 04a560b..6f853c7 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -33,7 +33,7 @@
 import static android.content.pm.PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT;
 import static android.content.pm.PackageManager.FEATURE_PC;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-import static android.os.IInputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
+import static android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
 import static android.os.Process.SYSTEM_UID;
 import static android.os.Process.myPid;
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
diff --git a/services/core/java/com/android/server/wm/WindowManagerThreadPriorityBooster.java b/services/core/java/com/android/server/wm/WindowManagerThreadPriorityBooster.java
index dd89b3b..6f2930c 100644
--- a/services/core/java/com/android/server/wm/WindowManagerThreadPriorityBooster.java
+++ b/services/core/java/com/android/server/wm/WindowManagerThreadPriorityBooster.java
@@ -17,11 +17,11 @@
 package com.android.server.wm;
 
 import static android.os.Process.THREAD_PRIORITY_DISPLAY;
+import static android.os.Process.THREAD_PRIORITY_TOP_APP_BOOST;
 import static android.os.Process.myTid;
 import static android.os.Process.setThreadPriority;
 
-import static com.android.server.LockGuard.INDEX_WINDOW;
-import static com.android.server.am.ActivityManagerService.TOP_APP_PRIORITY_BOOST;
+import static com.android.server.LockGuard.INDEX_WINDOW;;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.server.AnimationThread;
@@ -93,7 +93,7 @@
     @GuardedBy("mLock")
     private void updatePriorityLocked() {
         int priority = (mAppTransitionRunning || mBoundsAnimationRunning)
-                ? TOP_APP_PRIORITY_BOOST : THREAD_PRIORITY_DISPLAY;
+                ? THREAD_PRIORITY_TOP_APP_BOOST : THREAD_PRIORITY_DISPLAY;
         setBoostToPriority(priority);
         setThreadPriority(mAnimationThreadId, priority);
         setThreadPriority(mSurfaceAnimationThreadId, priority);
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index c362023..c5e24a9 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -19,7 +19,7 @@
 import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
 import static android.os.Build.VERSION_CODES.Q;
-import static android.os.IInputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
+import static android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
 
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION;
 import static com.android.internal.util.Preconditions.checkArgument;
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 1830c07..d9b879f 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -26,7 +26,7 @@
 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
 import static android.graphics.GraphicsProtos.dumpPointProto;
 import static android.hardware.input.InputManager.BLOCK_UNTRUSTED_TOUCHES;
-import static android.os.IInputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
+import static android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
 import static android.os.PowerManager.DRAW_WAKE_LOCK;
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 import static android.view.InsetsState.ITYPE_IME;
diff --git a/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp b/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp
index 8c6d084..a4a74af 100644
--- a/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp
+++ b/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp
@@ -135,7 +135,7 @@
 static int compactProcess(int pid, VmaToAdviseFunc vmaToAdviseFunc) {
     ProcMemInfo meminfo(pid);
     std::vector<Vma> pageoutVmas, coldVmas;
-    auto vmaCollectorCb = [&](Vma vma) {
+    auto vmaCollectorCb = [&coldVmas,&pageoutVmas,&vmaToAdviseFunc](const Vma& vma) {
         int advice = vmaToAdviseFunc(vma);
         switch (advice) {
             case MADV_COLD:
@@ -146,7 +146,7 @@
                 break;
         }
     };
-    meminfo.ForEachVma(vmaCollectorCb);
+    meminfo.ForEachVmaFromMaps(vmaCollectorCb);
 
     int err = compactMemory(pageoutVmas, pid, MADV_PAGEOUT);
     if (!err) {
diff --git a/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp b/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp
index 8efbaf5..f0210ee 100644
--- a/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp
+++ b/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp
@@ -643,7 +643,7 @@
         }
 
         TracedRead last = {};
-        auto lastSerialNo = mLastSerialNo;
+        auto lastSerialNo = mLastSerialNo < 0 ? pageReads[0].serialNo : mLastSerialNo;
         for (auto&& read : pageReads) {
             const auto expectedSerialNo = lastSerialNo + last.count;
 #ifdef VERBOSE_READ_LOGS
@@ -676,8 +676,7 @@
 
             // Second, report missing reads, if any.
             if (read.serialNo != expectedSerialNo) {
-                const auto readsMissing = read.serialNo - expectedSerialNo;
-                traceMissingReads(readsMissing);
+                traceMissingReads(expectedSerialNo, read.serialNo);
             }
 
             last = TracedRead{
@@ -721,9 +720,13 @@
         ATRACE_END();
     }
 
-    void traceMissingReads(int64_t count) {
-        const auto trace = android::base::StringPrintf("missing_page_reads: count=%lld",
-                                                       static_cast<long long>(count));
+    void traceMissingReads(int64_t expectedSerialNo, int64_t readSerialNo) {
+        const auto readsMissing = readSerialNo - expectedSerialNo;
+        const auto trace =
+                android::base::StringPrintf("missing_page_reads: count=%lld, range [%lld,%lld)",
+                                            static_cast<long long>(readsMissing),
+                                            static_cast<long long>(expectedSerialNo),
+                                            static_cast<long long>(readSerialNo));
         ATRACE_BEGIN(trace.c_str());
         ATRACE_END();
     }
@@ -874,7 +877,7 @@
     std::atomic<bool> mStopReceiving = false;
     std::atomic<bool> mReadLogsEnabled = false;
     std::chrono::milliseconds mWaitOnEofInterval{WaitOnEofMinInterval};
-    int64_t mLastSerialNo{1};
+    int64_t mLastSerialNo{-1};
     /** Tracks which files have been requested */
     std::unordered_set<FileIdx> mRequestedFiles;
 };
diff --git a/services/core/jni/gnss/GnssMeasurementCallback.cpp b/services/core/jni/gnss/GnssMeasurementCallback.cpp
index 757381d..9456946 100644
--- a/services/core/jni/gnss/GnssMeasurementCallback.cpp
+++ b/services/core/jni/gnss/GnssMeasurementCallback.cpp
@@ -131,7 +131,7 @@
                              "([I)Landroid/location/CorrelationVector$Builder;");
     method_correlationVectorBuilderSetFrequencyOffsetMetersPerSecond =
             env->GetMethodID(class_correlationVectorBuilder, "setFrequencyOffsetMetersPerSecond",
-                             "(I)Landroid/location/CorrelationVector$Builder;");
+                             "(D)Landroid/location/CorrelationVector$Builder;");
     method_correlationVectorBuilderSetSamplingStartMeters =
             env->GetMethodID(class_correlationVectorBuilder, "setSamplingStartMeters",
                              "(D)Landroid/location/CorrelationVector$Builder;");
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 9d2503a..a3dadd8 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -1604,10 +1604,6 @@
         void setDevicePolicySafetyChecker(DevicePolicySafetyChecker safetyChecker) {
             mSafetyChecker = safetyChecker;
         }
-
-        void dumpPerUserData(IndentingPrintWriter pw, @UserIdInt int userId) {
-            PersonalAppsSuspensionHelper.forUser(mContext, userId).dump(pw);
-        }
     }
 
     /**
@@ -5774,6 +5770,7 @@
                 if (generationResult != KeyChain.KEY_GEN_SUCCESS) {
                     Log.e(LOG_TAG, String.format(
                             "KeyChain failed to generate a keypair, error %d.", generationResult));
+                    logGenerateKeyPairFailure(caller, isCredentialManagementApp);
                     switch (generationResult) {
                         case KeyChain.KEY_GEN_STRONGBOX_UNAVAILABLE:
                             throw new ServiceSpecificException(
@@ -5783,7 +5780,6 @@
                             throw new UnsupportedOperationException(
                                 "Device does not support Device ID attestation.");
                         default:
-                            logGenerateKeyPairFailure(caller, isCredentialManagementApp);
                             return false;
                     }
                 }
@@ -7679,15 +7675,15 @@
 
     private void sendActiveAdminCommand(String action, Bundle extras,
             @UserIdInt int userId, ComponentName receiverComponent) {
-        if (VERBOSE_LOG) {
-            Slog.v(LOG_TAG, "sending intent " + action + " to "
-                    + receiverComponent.flattenToShortString() + " on user " + userId);
-        }
         final Intent intent = new Intent(action);
         intent.setComponent(receiverComponent);
         if (extras != null) {
             intent.putExtras(extras);
         }
+        if (VERBOSE_LOG) {
+            Slog.v(LOG_TAG, "sendActiveAdminCommand(): broadcasting " + action + " to "
+                    + receiverComponent.flattenToShortString() + " on user " + userId);
+        }
         mContext.sendBroadcastAsUser(intent, UserHandle.of(userId));
     }
 
@@ -9251,15 +9247,23 @@
 
     private void dumpPerUserData(IndentingPrintWriter pw) {
         int userCount = mUserData.size();
-        for (int userId = 0; userId < userCount; userId++) {
-            DevicePolicyData policy = getUserData(mUserData.keyAt(userId));
+        for (int i = 0; i < userCount; i++) {
+            int userId = mUserData.keyAt(i);
+            DevicePolicyData policy = getUserData(userId);
             policy.dump(pw);
             pw.println();
 
-            pw.increaseIndent();
-            mInjector.dumpPerUserData(pw, userId);
-            pw.decreaseIndent();
-            pw.println();
+            if (userId == UserHandle.USER_SYSTEM) {
+                pw.increaseIndent();
+                PersonalAppsSuspensionHelper.forUser(mContext, userId).dump(pw);
+                pw.decreaseIndent();
+                pw.println();
+            } else {
+                // pm.getUnsuspendablePackages() will fail if it's called for a different user;
+                // as this dump is mostly useful for system user anyways, we can just ignore the
+                // others (rather than changing the permission check in the PM method)
+                Slog.d(LOG_TAG, "skipping PersonalAppsSuspensionHelper.dump() for user " + userId);
+            }
         }
     }
 
@@ -12541,10 +12545,12 @@
             extras.putBoolean(DeviceAdminReceiver.EXTRA_OPERATION_SAFETY_STATE, isSafe);
 
             if (mOwners.hasDeviceOwner()) {
+                if (VERBOSE_LOG) Slog.v(LOG_TAG, "Notifying DO");
                 sendDeviceOwnerCommand(DeviceAdminReceiver.ACTION_OPERATION_SAFETY_STATE_CHANGED,
                         extras);
             }
             for (int profileOwnerId : mOwners.getProfileOwnerKeys()) {
+                if (VERBOSE_LOG) Slog.v(LOG_TAG, "Notifying PO for user " + profileOwnerId);
                 sendProfileOwnerCommand(DeviceAdminReceiver.ACTION_OPERATION_SAFETY_STATE_CHANGED,
                         extras, profileOwnerId);
             }
@@ -13724,6 +13730,9 @@
         mInjector.binderWithCleanCallingIdentity(() -> {
             // Clear restriction as user.
             final UserHandle parentUser = mUserManager.getProfileParent(UserHandle.of(userId));
+            if (parentUser == null) {
+                throw new IllegalStateException(String.format("User %d is not a profile", userId));
+            }
             if (!parentUser.isSystem()) {
                 throw new IllegalStateException(
                         String.format("Only the profile owner of a managed profile on the"
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/OneTimeSafetyChecker.java b/services/devicepolicy/java/com/android/server/devicepolicy/OneTimeSafetyChecker.java
index 257fc64..86437a2 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/OneTimeSafetyChecker.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/OneTimeSafetyChecker.java
@@ -60,7 +60,7 @@
         mOperation = operation;
         mReason = reason;
         mRealSafetyChecker = service.getDevicePolicySafetyChecker();
-        Slog.i(TAG, "OneTimeSafetyChecker constructor: operation= " + operationToString(operation)
+        Slog.i(TAG, "OneTimeSafetyChecker constructor: operation=" + operationToString(operation)
                 + ", reason=" + operationSafetyReasonToString(reason)
                 + ", realChecker=" + mRealSafetyChecker
                 + ", maxDuration=" + SELF_DESTRUCT_TIMEOUT_MS + "ms");
diff --git a/services/incremental/BinderIncrementalService.cpp b/services/incremental/BinderIncrementalService.cpp
index 42360d8..8f12b2e 100644
--- a/services/incremental/BinderIncrementalService.cpp
+++ b/services/incremental/BinderIncrementalService.cpp
@@ -348,6 +348,12 @@
     return ok();
 }
 
+binder::Status BinderIncrementalService::getMetrics(int32_t storageId,
+                                                    android::os::PersistableBundle* _aidl_return) {
+    mImpl.getMetrics(storageId, _aidl_return);
+    return ok();
+}
+
 } // namespace android::os::incremental
 
 jlong Incremental_IncrementalService_Start(JNIEnv* env) {
diff --git a/services/incremental/BinderIncrementalService.h b/services/incremental/BinderIncrementalService.h
index 740c542..ebb23dc 100644
--- a/services/incremental/BinderIncrementalService.h
+++ b/services/incremental/BinderIncrementalService.h
@@ -18,6 +18,7 @@
 
 #include <binder/BinderService.h>
 #include <binder/IServiceManager.h>
+#include <binder/PersistableBundle.h>
 #include <jni.h>
 
 #include "IncrementalService.h"
@@ -97,6 +98,8 @@
             const ::android::os::incremental::StorageHealthCheckParams& healthCheckParams,
             const ::android::sp<IStorageHealthListener>& healthListener, bool* _aidl_return) final;
     binder::Status unregisterStorageHealthListener(int32_t storageId) final;
+    binder::Status getMetrics(int32_t storageId,
+                              android::os::PersistableBundle* _aidl_return) final;
 
 private:
     android::incremental::IncrementalService mImpl;
diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp
index ce6e6ab..1fcc284 100644
--- a/services/incremental/IncrementalService.cpp
+++ b/services/incremental/IncrementalService.cpp
@@ -2118,6 +2118,29 @@
     return true;
 }
 
+void IncrementalService::getMetrics(StorageId storageId, android::os::PersistableBundle* result) {
+    const auto duration = getMillsSinceOldestPendingRead(storageId);
+    if (duration >= 0) {
+        const auto kMetricsMillisSinceOldestPendingRead =
+                os::incremental::BnIncrementalService::METRICS_MILLIS_SINCE_OLDEST_PENDING_READ();
+        result->putLong(String16(kMetricsMillisSinceOldestPendingRead.data()), duration);
+    }
+}
+
+long IncrementalService::getMillsSinceOldestPendingRead(StorageId storageId) {
+    std::unique_lock l(mLock);
+    const auto ifs = getIfsLocked(storageId);
+    if (!ifs) {
+        LOG(ERROR) << "getMillsSinceOldestPendingRead failed, invalid storageId: " << storageId;
+        return -EINVAL;
+    }
+    if (!ifs->dataLoaderStub) {
+        LOG(ERROR) << "getMillsSinceOldestPendingRead failed, no data loader: " << storageId;
+        return -EINVAL;
+    }
+    return ifs->dataLoaderStub->elapsedMsSinceOldestPendingRead();
+}
+
 IncrementalService::DataLoaderStub::DataLoaderStub(IncrementalService& service, MountId id,
                                                    DataLoaderParamsParcel&& params,
                                                    FileSystemControlParcel&& control,
@@ -2516,9 +2539,7 @@
                 std::max(1000ms,
                          std::chrono::milliseconds(mHealthCheckParams.unhealthyMonitoringMs));
 
-        const auto kernelDeltaUs = kernelTsUs - mHealthBase.kernelTsUs;
-        const auto userTs = mHealthBase.userTs + std::chrono::microseconds(kernelDeltaUs);
-        const auto delta = std::chrono::duration_cast<std::chrono::milliseconds>(now - userTs);
+        const auto delta = elapsedMsSinceKernelTs(now, kernelTsUs);
 
         Milliseconds checkBackAfter;
         if (delta + kTolerance < blockedTimeout) {
@@ -2550,6 +2571,13 @@
     fsmStep();
 }
 
+Milliseconds IncrementalService::DataLoaderStub::elapsedMsSinceKernelTs(TimePoint now,
+                                                                        BootClockTsUs kernelTsUs) {
+    const auto kernelDeltaUs = kernelTsUs - mHealthBase.kernelTsUs;
+    const auto userTs = mHealthBase.userTs + std::chrono::microseconds(kernelDeltaUs);
+    return std::chrono::duration_cast<Milliseconds>(now - userTs);
+}
+
 const incfs::UniqueControl& IncrementalService::DataLoaderStub::initializeHealthControl() {
     if (mHealthPath.empty()) {
         resetHealthControl();
@@ -2581,16 +2609,15 @@
     if (mService.mIncFs->waitForPendingReads(control, 0ms, &mLastPendingReads) !=
                 android::incfs::WaitResult::HaveData ||
         mLastPendingReads.empty()) {
+        // Clear previous pending reads
+        mLastPendingReads.clear();
         return result;
     }
 
     LOG(DEBUG) << id() << ": pendingReads: " << control.pendingReads() << ", "
                << mLastPendingReads.size() << ": " << mLastPendingReads.front().bootClockTsUs;
 
-    for (auto&& pendingRead : mLastPendingReads) {
-        result = std::min(result, pendingRead.bootClockTsUs);
-    }
-    return result;
+    return getOldestTsFromLastPendingReads();
 }
 
 void IncrementalService::DataLoaderStub::registerForPendingReads() {
@@ -2612,6 +2639,22 @@
     mService.mLooper->wake();
 }
 
+BootClockTsUs IncrementalService::DataLoaderStub::getOldestTsFromLastPendingReads() {
+    auto result = kMaxBootClockTsUs;
+    for (auto&& pendingRead : mLastPendingReads) {
+        result = std::min(result, pendingRead.bootClockTsUs);
+    }
+    return result;
+}
+
+long IncrementalService::DataLoaderStub::elapsedMsSinceOldestPendingRead() {
+    const auto oldestPendingReadKernelTs = getOldestTsFromLastPendingReads();
+    if (oldestPendingReadKernelTs == kMaxBootClockTsUs) {
+        return 0;
+    }
+    return elapsedMsSinceKernelTs(Clock::now(), oldestPendingReadKernelTs).count();
+}
+
 void IncrementalService::DataLoaderStub::unregisterFromPendingReads() {
     const auto pendingReadsFd = mHealthControl.pendingReads();
     if (pendingReadsFd < 0) {
diff --git a/services/incremental/IncrementalService.h b/services/incremental/IncrementalService.h
index d8f2c91..14e5a77 100644
--- a/services/incremental/IncrementalService.h
+++ b/services/incremental/IncrementalService.h
@@ -20,12 +20,14 @@
 #include <android/content/pm/DataLoaderParamsParcel.h>
 #include <android/content/pm/FileSystemControlParcel.h>
 #include <android/content/pm/IDataLoaderStatusListener.h>
+#include <android/os/incremental/BnIncrementalService.h>
 #include <android/os/incremental/BnIncrementalServiceConnector.h>
 #include <android/os/incremental/BnStorageHealthListener.h>
 #include <android/os/incremental/BnStorageLoadingProgressListener.h>
 #include <android/os/incremental/PerUidReadTimeouts.h>
 #include <android/os/incremental/StorageHealthCheckParams.h>
 #include <binder/IAppOpsCallback.h>
+#include <binder/PersistableBundle.h>
 #include <utils/String16.h>
 #include <utils/StrongPointer.h>
 #include <ziparchive/zip_archive.h>
@@ -181,6 +183,8 @@
                                  bool extractNativeLibs);
     bool waitForNativeBinariesExtraction(StorageId storage);
 
+    void getMetrics(int32_t storageId, android::os::PersistableBundle* _aidl_return);
+
     class AppOpsListener : public android::BnAppOpsCallback {
     public:
         AppOpsListener(IncrementalService& incrementalService, std::string packageName)
@@ -229,6 +233,7 @@
         const content::pm::DataLoaderParamsParcel& params() const { return mParams; }
         void setHealthListener(StorageHealthCheckParams&& healthCheckParams,
                                const StorageHealthListener* healthListener);
+        long elapsedMsSinceOldestPendingRead();
 
     private:
         binder::Status onStatusChanged(MountId mount, int newStatus) final;
@@ -259,6 +264,8 @@
         void resetHealthControl();
 
         BootClockTsUs getOldestPendingReadTs();
+        BootClockTsUs getOldestTsFromLastPendingReads();
+        Milliseconds elapsedMsSinceKernelTs(TimePoint now, BootClockTsUs kernelTsUs);
 
         Milliseconds updateBindDelay();
 
@@ -424,6 +431,7 @@
     bool removeTimedJobs(TimedQueueWrapper& timedQueue, MountId id);
     bool updateLoadingProgress(int32_t storageId,
                                const StorageLoadingProgressListener& progressListener);
+    long getMillsSinceOldestPendingRead(StorageId storage);
 
 private:
     const std::unique_ptr<VoldServiceWrapper> mVold;
diff --git a/services/incremental/OWNERS b/services/incremental/OWNERS
index d825dfd..ad5eca7 100644
--- a/services/incremental/OWNERS
+++ b/services/incremental/OWNERS
@@ -1 +1,7 @@
+# Bug component: 554432
 include /services/core/java/com/android/server/pm/OWNERS
+
+alexbuy@google.com
+schfan@google.com
+toddke@google.com
+zyy@google.com
diff --git a/services/incremental/test/IncrementalServiceTest.cpp b/services/incremental/test/IncrementalServiceTest.cpp
index b00a84f..5236983 100644
--- a/services/incremental/test/IncrementalServiceTest.cpp
+++ b/services/incremental/test/IncrementalServiceTest.cpp
@@ -21,6 +21,7 @@
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 #include <utils/Log.h>
+#include <utils/String16.h>
 
 #include <chrono>
 #include <future>
@@ -701,6 +702,18 @@
         mDataLoaderManager->getDataLoaderSuccess();
     }
 
+    void checkMillisSinceOldestPendingRead(int storageId, long expected) {
+        android::os::PersistableBundle result{};
+        mIncrementalService->getMetrics(storageId, &result);
+        int64_t value = -1;
+        ASSERT_TRUE(result.getLong(String16(BnIncrementalService::
+                                                    METRICS_MILLIS_SINCE_OLDEST_PENDING_READ()
+                                                            .c_str()),
+                                   &value));
+        ASSERT_EQ(expected, value);
+        ASSERT_EQ(1, (int)result.size());
+    }
+
 protected:
     NiceMock<MockVoldService>* mVold = nullptr;
     NiceMock<MockIncFs>* mIncFs = nullptr;
@@ -995,6 +1008,7 @@
     ASSERT_NE(nullptr, mLooper->mCallbackData);
     ASSERT_EQ(storageId, listener->mStorageId);
     ASSERT_EQ(IStorageHealthListener::HEALTH_STATUS_OK, listener->mStatus);
+    checkMillisSinceOldestPendingRead(storageId, 0);
 
     // Looper/epoll callback.
     mIncFs->waitForPendingReadsSuccess(kFirstTimestampUs);
@@ -1020,6 +1034,8 @@
     ASSERT_EQ(nullptr, mLooper->mCallbackData);
     ASSERT_EQ(storageId, listener->mStorageId);
     ASSERT_EQ(IStorageHealthListener::HEALTH_STATUS_BLOCKED, listener->mStatus);
+    checkMillisSinceOldestPendingRead(storageId, params.blockedTimeoutMs);
+
     // Timed callback present.
     ASSERT_EQ(storageId, mTimedQueue->mId);
     ASSERT_GE(mTimedQueue->mAfter, 1000ms);
@@ -1035,6 +1051,8 @@
     ASSERT_EQ(nullptr, mLooper->mCallbackData);
     ASSERT_EQ(storageId, listener->mStorageId);
     ASSERT_EQ(IStorageHealthListener::HEALTH_STATUS_UNHEALTHY, listener->mStatus);
+    checkMillisSinceOldestPendingRead(storageId, params.unhealthyTimeoutMs);
+
     // Timed callback present.
     ASSERT_EQ(storageId, mTimedQueue->mId);
     ASSERT_GE(mTimedQueue->mAfter, unhealthyMonitoring);
@@ -1050,6 +1068,8 @@
     ASSERT_EQ(nullptr, mLooper->mCallbackData);
     ASSERT_EQ(storageId, listener->mStorageId);
     ASSERT_EQ(IStorageHealthListener::HEALTH_STATUS_UNHEALTHY, listener->mStatus);
+    checkMillisSinceOldestPendingRead(storageId, params.unhealthyTimeoutMs);
+
     // Timed callback present.
     ASSERT_EQ(storageId, mTimedQueue->mId);
     ASSERT_GE(mTimedQueue->mAfter, unhealthyMonitoring);
@@ -1065,6 +1085,7 @@
     ASSERT_NE(nullptr, mLooper->mCallbackData);
     ASSERT_EQ(storageId, listener->mStorageId);
     ASSERT_EQ(IStorageHealthListener::HEALTH_STATUS_OK, listener->mStatus);
+    checkMillisSinceOldestPendingRead(storageId, 0);
 }
 
 TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsSuccess) {
@@ -1581,4 +1602,52 @@
     ASSERT_EQ(mTimedQueue->mAfter, Milliseconds());
 }
 
+TEST_F(IncrementalServiceTest, testInvalidMetricsQuery) {
+    const auto invalidStorageId = 100;
+    android::os::PersistableBundle result{};
+    mIncrementalService->getMetrics(invalidStorageId, &result);
+    int64_t expected = -1, value = -1;
+    ASSERT_FALSE(
+            result.getLong(String16(BnIncrementalService::METRICS_MILLIS_SINCE_OLDEST_PENDING_READ()
+                                            .c_str()),
+                           &value));
+    ASSERT_EQ(expected, value);
+    ASSERT_TRUE(result.empty());
+}
+
+TEST_F(IncrementalServiceTest, testNoMetrics) {
+    mVold->setIncFsMountOptionsSuccess();
+    TemporaryDir tempDir;
+    int storageId =
+            mIncrementalService->createStorage(tempDir.path, mDataLoaderParcel,
+                                               IncrementalService::CreateOptions::CreateNew);
+    ASSERT_GE(storageId, 0);
+    android::os::PersistableBundle result{};
+    mIncrementalService->getMetrics(storageId, &result);
+    int64_t expected = -1, value = -1;
+    ASSERT_FALSE(
+            result.getLong(String16(BnIncrementalService::METRICS_MILLIS_SINCE_OLDEST_PENDING_READ()
+                                            .c_str()),
+                           &value));
+    ASSERT_EQ(expected, value);
+    ASSERT_EQ(0, (int)result.size());
+}
+
+TEST_F(IncrementalServiceTest, testInvalidMetricsKeys) {
+    mVold->setIncFsMountOptionsSuccess();
+    TemporaryDir tempDir;
+    int storageId =
+            mIncrementalService->createStorage(tempDir.path, mDataLoaderParcel,
+                                               IncrementalService::CreateOptions::CreateNew);
+    ASSERT_GE(storageId, 0);
+    ASSERT_TRUE(mIncrementalService->startLoading(storageId, std::move(mDataLoaderParcel), {}, {},
+                                                  {}, {}));
+    android::os::PersistableBundle result{};
+    mIncrementalService->getMetrics(storageId, &result);
+    int64_t expected = -1, value = -1;
+    ASSERT_FALSE(result.getLong(String16("invalid"), &value));
+    ASSERT_EQ(expected, value);
+    ASSERT_EQ(1, (int)result.size());
+}
+
 } // namespace android::os::incremental
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 51c9b0d..f2e85a7 100644
--- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
@@ -49,8 +49,10 @@
 import static com.android.server.alarm.AlarmManagerService.AlarmHandler.CHARGING_STATUS_CHANGED;
 import static com.android.server.alarm.AlarmManagerService.AlarmHandler.REMOVE_FOR_CANCELED;
 import static com.android.server.alarm.AlarmManagerService.Constants.KEY_ALLOW_WHILE_IDLE_COMPAT_QUOTA;
+import static com.android.server.alarm.AlarmManagerService.Constants.KEY_ALLOW_WHILE_IDLE_COMPAT_WINDOW;
 import static com.android.server.alarm.AlarmManagerService.Constants.KEY_ALLOW_WHILE_IDLE_QUOTA;
 import static com.android.server.alarm.AlarmManagerService.Constants.KEY_ALLOW_WHILE_IDLE_WHITELIST_DURATION;
+import static com.android.server.alarm.AlarmManagerService.Constants.KEY_ALLOW_WHILE_IDLE_WINDOW;
 import static com.android.server.alarm.AlarmManagerService.Constants.KEY_LAZY_BATCHING;
 import static com.android.server.alarm.AlarmManagerService.Constants.KEY_LISTENER_TIMEOUT;
 import static com.android.server.alarm.AlarmManagerService.Constants.KEY_MAX_INTERVAL;
@@ -566,17 +568,23 @@
         setDeviceConfigLong(KEY_MAX_INTERVAL, 15);
         setDeviceConfigInt(KEY_ALLOW_WHILE_IDLE_QUOTA, 20);
         setDeviceConfigInt(KEY_ALLOW_WHILE_IDLE_COMPAT_QUOTA, 25);
-        setDeviceConfigLong(KEY_ALLOW_WHILE_IDLE_WHITELIST_DURATION, 30);
-        setDeviceConfigLong(KEY_LISTENER_TIMEOUT, 35);
+        setDeviceConfigLong(KEY_ALLOW_WHILE_IDLE_WINDOW, 30);
+        setDeviceConfigLong(KEY_ALLOW_WHILE_IDLE_COMPAT_WINDOW, 35);
+        setDeviceConfigLong(KEY_ALLOW_WHILE_IDLE_WHITELIST_DURATION, 40);
+        setDeviceConfigLong(KEY_LISTENER_TIMEOUT, 45);
         assertEquals(5, mService.mConstants.MIN_FUTURITY);
         assertEquals(10, mService.mConstants.MIN_INTERVAL);
         assertEquals(15, mService.mConstants.MAX_INTERVAL);
         assertEquals(20, mService.mConstants.ALLOW_WHILE_IDLE_QUOTA);
         assertEquals(25, mService.mConstants.ALLOW_WHILE_IDLE_COMPAT_QUOTA);
-        assertEquals(30, mService.mConstants.ALLOW_WHILE_IDLE_WHITELIST_DURATION);
-        assertEquals(35, mService.mConstants.LISTENER_TIMEOUT);
+        assertEquals(30, mService.mConstants.ALLOW_WHILE_IDLE_WINDOW);
+        assertEquals(35, mService.mConstants.ALLOW_WHILE_IDLE_COMPAT_WINDOW);
+        assertEquals(40, mService.mConstants.ALLOW_WHILE_IDLE_WHITELIST_DURATION);
+        assertEquals(45, mService.mConstants.LISTENER_TIMEOUT);
+    }
 
-        // Test safeguards.
+    @Test
+    public void positiveWhileIdleQuotas() {
         setDeviceConfigInt(KEY_ALLOW_WHILE_IDLE_QUOTA, -3);
         assertEquals(1, mService.mConstants.ALLOW_WHILE_IDLE_QUOTA);
         setDeviceConfigInt(KEY_ALLOW_WHILE_IDLE_QUOTA, 0);
@@ -589,6 +597,21 @@
     }
 
     @Test
+    public void whileIdleWindowsDontExceedAnHour() {
+        setDeviceConfigLong(KEY_ALLOW_WHILE_IDLE_WINDOW, AlarmManager.INTERVAL_DAY);
+        assertEquals(AlarmManager.INTERVAL_HOUR, mService.mConstants.ALLOW_WHILE_IDLE_WINDOW);
+        setDeviceConfigLong(KEY_ALLOW_WHILE_IDLE_WINDOW, AlarmManager.INTERVAL_HOUR + 1);
+        assertEquals(AlarmManager.INTERVAL_HOUR, mService.mConstants.ALLOW_WHILE_IDLE_WINDOW);
+
+        setDeviceConfigLong(KEY_ALLOW_WHILE_IDLE_COMPAT_WINDOW, AlarmManager.INTERVAL_DAY);
+        assertEquals(AlarmManager.INTERVAL_HOUR,
+                mService.mConstants.ALLOW_WHILE_IDLE_COMPAT_WINDOW);
+        setDeviceConfigLong(KEY_ALLOW_WHILE_IDLE_COMPAT_WINDOW, AlarmManager.INTERVAL_HOUR + 1);
+        assertEquals(AlarmManager.INTERVAL_HOUR,
+                mService.mConstants.ALLOW_WHILE_IDLE_COMPAT_WINDOW);
+    }
+
+    @Test
     public void testMinFuturity() {
         setDeviceConfigLong(KEY_MIN_FUTURITY, 10L);
         assertEquals(10, mService.mConstants.MIN_FUTURITY);
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
index 6e27b3a..e853fd3 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
@@ -287,6 +287,7 @@
         whenever(mocks.settings.internalVersion).thenReturn(DEFAULT_VERSION_INFO)
         whenever(mocks.settings.keySetManagerService).thenReturn(mocks.keySetManagerService)
         whenever(mocks.settings.keySetManagerService).thenReturn(mocks.keySetManagerService)
+        whenever(mocks.settings.snapshot()).thenReturn(mocks.settings)
         whenever(mocks.packageAbiHelper.derivePackageAbi(
                 any(AndroidPackage::class.java), anyBoolean(), nullable(), any(File::class.java))) {
             android.util.Pair(PackageAbiHelper.Abis("", ""),
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceHibernationTests.kt b/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceHibernationTests.kt
new file mode 100644
index 0000000..a0e208f
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceHibernationTests.kt
@@ -0,0 +1,81 @@
+/*
+ * 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.os.Build
+import com.android.server.apphibernation.AppHibernationManagerInternal
+import com.android.server.testutils.whenever
+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.Mock
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@RunWith(JUnit4::class)
+class PackageManagerServiceHibernationTests {
+
+    companion object {
+        val TEST_PACKAGE_NAME = "test.package"
+        val TEST_USER_ID = 0
+    }
+
+    @Rule
+    @JvmField
+    val rule = MockSystemRule()
+
+    @Mock
+    lateinit var appHibernationManager: AppHibernationManagerInternal
+
+    @Before
+    @Throws(Exception::class)
+    fun setup() {
+        MockitoAnnotations.initMocks(this)
+        rule.system().stageNominalSystemState()
+        whenever(rule.mocks().injector.getLocalService(AppHibernationManagerInternal::class.java))
+            .thenReturn(appHibernationManager)
+    }
+
+    @Test
+    fun testExitForceStopExitsHibernation() {
+        rule.system().stageScanExistingPackage(
+            TEST_PACKAGE_NAME,
+            1L,
+            rule.system().dataAppDirectory)
+        val pm = createPackageManagerService()
+        rule.system().validateFinalState()
+        val ps = pm.getPackageSetting(TEST_PACKAGE_NAME)
+        ps!!.setStopped(true, TEST_USER_ID)
+
+        pm.setPackageStoppedState(TEST_PACKAGE_NAME, false, TEST_USER_ID)
+        verify(appHibernationManager).setHibernatingForUser(TEST_PACKAGE_NAME, TEST_USER_ID, false)
+        verify(appHibernationManager).setHibernatingGlobally(TEST_PACKAGE_NAME, false)
+    }
+
+    private fun createPackageManagerService(): PackageManagerService {
+        return 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)
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInteractionControllerNodeRequestsTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInteractionControllerNodeRequestsTest.java
deleted file mode 100644
index 170f561..0000000
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInteractionControllerNodeRequestsTest.java
+++ /dev/null
@@ -1,581 +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.accessibility;
-
-
-import static android.view.accessibility.AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS;
-import static android.view.accessibility.AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS;
-import static android.view.accessibility.AccessibilityNodeInfo.FLAG_PREFETCH_SIBLINGS;
-import static android.view.accessibility.AccessibilityNodeInfo.ROOT_NODE_ID;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyList;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-import android.app.Instrumentation;
-import android.content.Context;
-import android.os.RemoteException;
-import android.view.AccessibilityInteractionController;
-import android.view.View;
-import android.view.ViewRootImpl;
-import android.view.WindowManager;
-import android.view.accessibility.AccessibilityNodeIdManager;
-import android.view.accessibility.AccessibilityNodeInfo;
-import android.view.accessibility.AccessibilityNodeProvider;
-import android.view.accessibility.IAccessibilityInteractionConnectionCallback;
-import android.widget.FrameLayout;
-import android.widget.TextView;
-
-import androidx.test.platform.app.InstrumentationRegistry;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Captor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Tests that verify expected node and prefetched node results when finding a view by node id. We
- * send some requests to the controller via View methods to control message timing.
- */
-@RunWith(AndroidJUnit4.class)
-public class AccessibilityInteractionControllerNodeRequestsTest {
-    private AccessibilityInteractionController mAccessibilityInteractionController;
-    @Mock
-    private IAccessibilityInteractionConnectionCallback mMockClientCallback1;
-    @Mock
-    private IAccessibilityInteractionConnectionCallback mMockClientCallback2;
-
-    @Captor
-    private ArgumentCaptor<AccessibilityNodeInfo> mFindInfoCaptor;
-    @Captor private ArgumentCaptor<List<AccessibilityNodeInfo>> mPrefetchInfoListCaptor;
-
-    private final Instrumentation mInstrumentation = InstrumentationRegistry.getInstrumentation();
-    private static final int MOCK_CLIENT_1_THREAD_AND_PROCESS_ID = 1;
-    private static final int MOCK_CLIENT_2_THREAD_AND_PROCESS_ID = 2;
-
-    private static final String FRAME_LAYOUT_DESCRIPTION = "frameLayout";
-    private static final String TEXT_VIEW_1_DESCRIPTION = "textView1";
-    private static final String TEXT_VIEW_2_DESCRIPTION = "textView2";
-
-    private TestFrameLayout mFrameLayout;
-    private TestTextView mTextView1;
-    private TestTextView2 mTextView2;
-
-    private boolean mSendClient1RequestForTextAfterTextPrefetched;
-    private boolean mSendClient2RequestForTextAfterTextPrefetched;
-    private boolean mSendRequestForTextAndIncludeUnImportantViews;
-    private int mMockClient1InteractionId;
-    private int mMockClient2InteractionId;
-
-    @Before
-    public void setUp() throws Throwable {
-        MockitoAnnotations.initMocks(this);
-
-        mInstrumentation.runOnMainSync(() -> {
-            final Context context = mInstrumentation.getTargetContext();
-            final ViewRootImpl viewRootImpl = new ViewRootImpl(context, context.getDisplay());
-
-            mFrameLayout = new TestFrameLayout(context);
-            mTextView1 = new TestTextView(context);
-            mTextView2 = new TestTextView2(context);
-
-            mFrameLayout.addView(mTextView1);
-            mFrameLayout.addView(mTextView2);
-
-            // The controller retrieves views through this manager, and registration happens on
-            // when attached to a window, which we don't have. We can simply reference FrameLayout
-            // with ROOT_NODE_ID
-            AccessibilityNodeIdManager.getInstance().registerViewWithId(
-                    mTextView1, mTextView1.getAccessibilityViewId());
-            AccessibilityNodeIdManager.getInstance().registerViewWithId(
-                    mTextView2, mTextView2.getAccessibilityViewId());
-
-            try {
-                viewRootImpl.setView(mFrameLayout, new WindowManager.LayoutParams(), null);
-
-            } catch (WindowManager.BadTokenException e) {
-                // activity isn't running, we will ignore BadTokenException.
-            }
-
-            mAccessibilityInteractionController =
-                    new AccessibilityInteractionController(viewRootImpl);
-        });
-
-    }
-
-    @After
-    public void tearDown() throws Throwable {
-        AccessibilityNodeIdManager.getInstance().unregisterViewWithId(
-                mTextView1.getAccessibilityViewId());
-        AccessibilityNodeIdManager.getInstance().unregisterViewWithId(
-                mTextView2.getAccessibilityViewId());
-    }
-
-    /**
-     * Tests a basic request for the root node with prefetch flag
-     * {@link AccessibilityNodeInfo#FLAG_PREFETCH_DESCENDANTS}
-     *
-     * @throws RemoteException
-     */
-    @Test
-    public void testFindRootView_withOneClient_shouldReturnRootNodeAndPrefetchDescendants()
-            throws RemoteException {
-        // Request for our FrameLayout
-        sendNodeRequestToController(ROOT_NODE_ID, mMockClientCallback1,
-                mMockClient1InteractionId, FLAG_PREFETCH_DESCENDANTS);
-        mInstrumentation.waitForIdleSync();
-
-        // Verify we get FrameLayout
-        verify(mMockClientCallback1).setFindAccessibilityNodeInfoResult(
-                mFindInfoCaptor.capture(), eq(mMockClient1InteractionId));
-        AccessibilityNodeInfo infoSentToService = mFindInfoCaptor.getValue();
-        assertEquals(FRAME_LAYOUT_DESCRIPTION, infoSentToService.getContentDescription());
-
-        verify(mMockClientCallback1).setPrefetchAccessibilityNodeInfoResult(
-                mPrefetchInfoListCaptor.capture(), eq(mMockClient1InteractionId));
-        // The descendants are our two TextViews
-        List<AccessibilityNodeInfo> prefetchedNodes = mPrefetchInfoListCaptor.getValue();
-        assertEquals(2, prefetchedNodes.size());
-        assertEquals(TEXT_VIEW_1_DESCRIPTION, prefetchedNodes.get(0).getContentDescription());
-        assertEquals(TEXT_VIEW_2_DESCRIPTION, prefetchedNodes.get(1).getContentDescription());
-
-    }
-
-    /**
-     * Tests a basic request for TestTextView1's node with prefetch flag
-     * {@link AccessibilityNodeInfo#FLAG_PREFETCH_SIBLINGS}
-     *
-     * @throws RemoteException
-     */
-    @Test
-    public void testFindTextView_withOneClient_shouldReturnNodeAndPrefetchedSiblings()
-            throws RemoteException {
-        // Request for TextView1
-        sendNodeRequestToController(AccessibilityNodeInfo.makeNodeId(
-                mTextView1.getAccessibilityViewId(), AccessibilityNodeProvider.HOST_VIEW_ID),
-                mMockClientCallback1, mMockClient1InteractionId, FLAG_PREFETCH_SIBLINGS);
-        mInstrumentation.waitForIdleSync();
-
-        // Verify we get TextView1
-        verify(mMockClientCallback1).setFindAccessibilityNodeInfoResult(
-                mFindInfoCaptor.capture(), eq(mMockClient1InteractionId));
-        AccessibilityNodeInfo infoSentToService = mFindInfoCaptor.getValue();
-        assertEquals(TEXT_VIEW_1_DESCRIPTION, infoSentToService.getContentDescription());
-
-        // Verify the prefetched sibling of TextView1 is TextView2
-        verify(mMockClientCallback1).setPrefetchAccessibilityNodeInfoResult(
-                mPrefetchInfoListCaptor.capture(), eq(mMockClient1InteractionId));
-        // TextView2 is the prefetched sibling
-        List<AccessibilityNodeInfo> prefetchedNodes = mPrefetchInfoListCaptor.getValue();
-        assertEquals(1, prefetchedNodes.size());
-        assertEquals(TEXT_VIEW_2_DESCRIPTION, prefetchedNodes.get(0).getContentDescription());
-    }
-
-    /**
-     * Tests a series of controller requests to prevent prefetching.
-     *     Request 1: Client 1 requests the root node
-     *     Request 2: When the root node is initialized in
-     *     {@link TestFrameLayout#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)},
-     *     Client 2 requests TestTextView1's node
-     *
-     * Request 2 on the queue prevents prefetching for Request 1.
-     *
-     * @throws RemoteException
-     */
-    @Test
-    public void testFindRootAndTextNodes_withTwoClients_shouldPreventClient1Prefetch()
-            throws RemoteException {
-        mFrameLayout.setAccessibilityDelegate(new View.AccessibilityDelegate() {
-            @Override
-            public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
-                super.onInitializeAccessibilityNodeInfo(host, info);
-                final long nodeId = AccessibilityNodeInfo.makeNodeId(
-                        mTextView1.getAccessibilityViewId(),
-                        AccessibilityNodeProvider.HOST_VIEW_ID);
-
-                    // Enqueue a request when this node is found from a different service for
-                    // TextView1
-                    sendNodeRequestToController(nodeId, mMockClientCallback2,
-                            mMockClient2InteractionId, FLAG_PREFETCH_SIBLINGS);
-            }
-        });
-        // Client 1 request for FrameLayout
-        sendNodeRequestToController(ROOT_NODE_ID, mMockClientCallback1,
-                mMockClient1InteractionId, FLAG_PREFETCH_DESCENDANTS);
-
-        mInstrumentation.waitForIdleSync();
-
-        // Verify client 1 gets FrameLayout
-        verify(mMockClientCallback1).setFindAccessibilityNodeInfoResult(
-                mFindInfoCaptor.capture(), eq(mMockClient1InteractionId));
-        AccessibilityNodeInfo infoSentToService = mFindInfoCaptor.getValue();
-        assertEquals(FRAME_LAYOUT_DESCRIPTION, infoSentToService.getContentDescription());
-
-        // The second request is put in the queue in the FrameLayout's onInitializeA11yNodeInfo,
-        // meaning prefetching is interrupted and does not even begin for the first request
-        verify(mMockClientCallback1, never())
-                .setPrefetchAccessibilityNodeInfoResult(anyList(), anyInt());
-
-        // Verify client 2 gets TextView1
-        verify(mMockClientCallback2).setFindAccessibilityNodeInfoResult(
-                mFindInfoCaptor.capture(), eq(mMockClient2InteractionId));
-        infoSentToService = mFindInfoCaptor.getValue();
-        assertEquals(TEXT_VIEW_1_DESCRIPTION, infoSentToService.getContentDescription());
-
-        // Verify the prefetched sibling of TextView1 is TextView2 (FLAG_PREFETCH_SIBLINGS)
-        verify(mMockClientCallback2).setPrefetchAccessibilityNodeInfoResult(
-                mPrefetchInfoListCaptor.capture(), eq(mMockClient2InteractionId));
-        List<AccessibilityNodeInfo> prefetchedNodes = mPrefetchInfoListCaptor.getValue();
-        assertEquals(1, prefetchedNodes.size());
-        assertEquals(TEXT_VIEW_2_DESCRIPTION, prefetchedNodes.get(0).getContentDescription());
-    }
-
-    /**
-     * Tests a series of controller same-service requests to interrupt prefetching and satisfy a
-     * pending node request.
-     *     Request 1: Request the root node
-     *     Request 2: When TextTextView1's node is initialized as part of Request 1's prefetching,
-     *     request TestTextView1's node
-     *
-     * Request 1 prefetches TestTextView1's node, is interrupted by a pending request, and checks
-     * if its prefetched nodes satisfy any pending requests. It satisfies Request 2's request for
-     * TestTextView1's node. Request 2 is fulfilled, so it is removed from queue and does not
-     * prefetch.
-     *
-     * @throws RemoteException
-     */
-    @Test
-    public void testFindRootAndTextNode_withOneClient_shouldInterruptPrefetchAndSatisfyPendingMsg()
-            throws RemoteException {
-        mSendClient1RequestForTextAfterTextPrefetched = true;
-
-        mTextView1.setAccessibilityDelegate(new View.AccessibilityDelegate(){
-            @Override
-            public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
-                super.onInitializeAccessibilityNodeInfo(host, info);
-                info.setContentDescription(TEXT_VIEW_1_DESCRIPTION);
-                final long nodeId = AccessibilityNodeInfo.makeNodeId(
-                        mTextView1.getAccessibilityViewId(),
-                        AccessibilityNodeProvider.HOST_VIEW_ID);
-
-                if (mSendClient1RequestForTextAfterTextPrefetched) {
-                    // Prevent a loop when processing second request
-                    mSendClient1RequestForTextAfterTextPrefetched = false;
-                    // TextView1 is prefetched here after the FrameLayout is found. Now enqueue a
-                    // same-client request for TextView1
-                    sendNodeRequestToController(nodeId, mMockClientCallback1,
-                            ++mMockClient1InteractionId, FLAG_PREFETCH_SIBLINGS);
-
-                }
-            }
-        });
-        // Client 1 requests FrameLayout
-        sendNodeRequestToController(ROOT_NODE_ID, mMockClientCallback1,
-                mMockClient1InteractionId, FLAG_PREFETCH_DESCENDANTS);
-
-        // Flush out all messages
-        mInstrumentation.waitForIdleSync();
-
-        // When TextView1 is prefetched for FrameLayout, we put a message on the queue in
-        // TextView1's onInitializeA11yNodeInfo that requests for TextView1. The service thus get
-        // two node results for FrameLayout and TextView1.
-        verify(mMockClientCallback1, times(2))
-                .setFindAccessibilityNodeInfoResult(mFindInfoCaptor.capture(), anyInt());
-
-        List<AccessibilityNodeInfo> foundNodes = mFindInfoCaptor.getAllValues();
-        assertEquals(FRAME_LAYOUT_DESCRIPTION, foundNodes.get(0).getContentDescription());
-        assertEquals(TEXT_VIEW_1_DESCRIPTION, foundNodes.get(1).getContentDescription());
-
-        // The controller will look at FrameLayout's prefetched nodes and find matching nodes in
-        // pending requests. The prefetched TextView1 matches the second request. The second
-        // request was removed from queue and prefetching for this request never occurred.
-        verify(mMockClientCallback1, times(1))
-                .setPrefetchAccessibilityNodeInfoResult(mPrefetchInfoListCaptor.capture(),
-                        eq(mMockClient1InteractionId - 1));
-        List<AccessibilityNodeInfo> prefetchedNodes = mPrefetchInfoListCaptor.getValue();
-        assertEquals(1, prefetchedNodes.size());
-        assertEquals(TEXT_VIEW_1_DESCRIPTION, prefetchedNodes.get(0).getContentDescription());
-    }
-
-    /**
-     * Like above, but tests a series of controller requests from different services to interrupt
-     * prefetching and satisfy a pending node request.
-     *
-     * @throws RemoteException
-     */
-    @Test
-    public void testFindRootAndTextNode_withTwoClients_shouldInterruptPrefetchAndSatisfyPendingMsg()
-            throws RemoteException {
-        mSendClient2RequestForTextAfterTextPrefetched = true;
-        mTextView1.setAccessibilityDelegate(new View.AccessibilityDelegate(){
-            @Override
-            public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
-                super.onInitializeAccessibilityNodeInfo(host, info);
-                info.setContentDescription(TEXT_VIEW_1_DESCRIPTION);
-                final long nodeId = AccessibilityNodeInfo.makeNodeId(
-                        mTextView1.getAccessibilityViewId(),
-                        AccessibilityNodeProvider.HOST_VIEW_ID);
-
-                if (mSendClient2RequestForTextAfterTextPrefetched) {
-                    mSendClient2RequestForTextAfterTextPrefetched = false;
-                    // TextView1 is prefetched here. Now enqueue client 2's request for
-                    // TextView1
-                    sendNodeRequestToController(nodeId, mMockClientCallback2,
-                            mMockClient2InteractionId, FLAG_PREFETCH_SIBLINGS);
-                }
-            }
-        });
-        // Client 1 requests FrameLayout
-        sendNodeRequestToController(ROOT_NODE_ID, mMockClientCallback1,
-                mMockClient1InteractionId, FLAG_PREFETCH_DESCENDANTS);
-
-        mInstrumentation.waitForIdleSync();
-
-        // Verify client 1 gets FrameLayout
-        verify(mMockClientCallback1, times(1))
-                .setFindAccessibilityNodeInfoResult(mFindInfoCaptor.capture(), anyInt());
-        assertEquals(FRAME_LAYOUT_DESCRIPTION,
-                mFindInfoCaptor.getValue().getContentDescription());
-
-        // Verify client 1 has prefetched nodes
-        verify(mMockClientCallback1, times(1))
-                .setPrefetchAccessibilityNodeInfoResult(mPrefetchInfoListCaptor.capture(),
-                        eq(mMockClient1InteractionId));
-
-        // Verify client 1's only prefetched node is TextView1
-        List<AccessibilityNodeInfo> prefetchedNodes = mPrefetchInfoListCaptor.getValue();
-        assertEquals(1, prefetchedNodes.size());
-        assertEquals(TEXT_VIEW_1_DESCRIPTION, prefetchedNodes.get(0).getContentDescription());
-
-        // Verify client 2 gets TextView1
-        verify(mMockClientCallback2, times(1))
-                .setFindAccessibilityNodeInfoResult(mFindInfoCaptor.capture(), anyInt());
-
-        assertEquals(TEXT_VIEW_1_DESCRIPTION, mFindInfoCaptor.getValue().getContentDescription());
-
-        // The second request was removed from queue and prefetching for this client request never
-        // occurred as it was satisfied.
-        verify(mMockClientCallback2, never())
-                .setPrefetchAccessibilityNodeInfoResult(anyList(), anyInt());
-
-    }
-
-    @Test
-    public void testFindNodeById_withTwoDifferentPrefetchFlags_shouldNotSatisfyPendingRequest()
-            throws RemoteException {
-        mSendRequestForTextAndIncludeUnImportantViews = true;
-        mTextView1.setAccessibilityDelegate(new View.AccessibilityDelegate(){
-            @Override
-            public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
-                super.onInitializeAccessibilityNodeInfo(host, info);
-                info.setContentDescription(TEXT_VIEW_1_DESCRIPTION);
-                final long nodeId = AccessibilityNodeInfo.makeNodeId(
-                        mTextView1.getAccessibilityViewId(),
-                        AccessibilityNodeProvider.HOST_VIEW_ID);
-
-                if (mSendRequestForTextAndIncludeUnImportantViews) {
-                    mSendRequestForTextAndIncludeUnImportantViews = false;
-                    // TextView1 is prefetched here for client 1. Now enqueue a request from a
-                    // different client that holds different fetch flags for TextView1
-                    sendNodeRequestToController(nodeId, mMockClientCallback2,
-                            mMockClient2InteractionId,
-                            FLAG_PREFETCH_SIBLINGS | FLAG_INCLUDE_NOT_IMPORTANT_VIEWS);
-                }
-            }
-        });
-
-        // Mockito does not make copies of objects when called. It holds references, so
-        // the captor would point to client 2's results after all requests are processed. Verify
-        // prefetched node immediately
-        doAnswer(invocation -> {
-            List<AccessibilityNodeInfo> prefetched = invocation.getArgument(0);
-            assertEquals(TEXT_VIEW_1_DESCRIPTION, prefetched.get(0).getContentDescription());
-            return null;
-        }).when(mMockClientCallback1).setPrefetchAccessibilityNodeInfoResult(anyList(),
-                eq(mMockClient1InteractionId));
-
-        // Client 1 requests FrameLayout
-        sendNodeRequestToController(ROOT_NODE_ID, mMockClientCallback1,
-                mMockClient1InteractionId, FLAG_PREFETCH_DESCENDANTS);
-
-        mInstrumentation.waitForIdleSync();
-
-        // Verify client 1 gets FrameLayout
-        verify(mMockClientCallback1, times(1))
-                .setFindAccessibilityNodeInfoResult(mFindInfoCaptor.capture(),
-                        eq(mMockClient1InteractionId));
-
-        assertEquals(FRAME_LAYOUT_DESCRIPTION,
-                mFindInfoCaptor.getValue().getContentDescription());
-
-        // Verify client 1 has prefetched results. The only prefetched node is TextView1
-        // (from above doAnswer)
-        verify(mMockClientCallback1, times(1))
-                .setPrefetchAccessibilityNodeInfoResult(mPrefetchInfoListCaptor.capture(),
-                        eq(mMockClient1InteractionId));
-
-        // Verify client 2 gets TextView1
-        verify(mMockClientCallback2, times(1))
-                .setFindAccessibilityNodeInfoResult(mFindInfoCaptor.capture(),
-                        eq(mMockClient2InteractionId));
-        assertEquals(TEXT_VIEW_1_DESCRIPTION,
-                mFindInfoCaptor.getValue().getContentDescription());
-        // Verify client 2 has TextView2 as a prefetched node
-        verify(mMockClientCallback2, times(1))
-                .setPrefetchAccessibilityNodeInfoResult(mPrefetchInfoListCaptor.capture(),
-                        eq(mMockClient2InteractionId));
-        List<AccessibilityNodeInfo> prefetchedNode = mPrefetchInfoListCaptor.getValue();
-        assertEquals(1, prefetchedNode.size());
-        assertEquals(TEXT_VIEW_2_DESCRIPTION, prefetchedNode.get(0).getContentDescription());
-    }
-
-    private void sendNodeRequestToController(long requestedNodeId,
-            IAccessibilityInteractionConnectionCallback callback, int interactionId,
-            int prefetchFlags) {
-        final int processAndThreadId = callback == mMockClientCallback1
-                ? MOCK_CLIENT_1_THREAD_AND_PROCESS_ID
-                : MOCK_CLIENT_2_THREAD_AND_PROCESS_ID;
-
-        mAccessibilityInteractionController.findAccessibilityNodeInfoByAccessibilityIdClientThread(
-                requestedNodeId,
-                null, interactionId,
-                callback, prefetchFlags,
-                processAndThreadId,
-                processAndThreadId, null, null);
-
-    }
-
-    private class TestFrameLayout extends FrameLayout {
-
-        TestFrameLayout(Context context) {
-            super(context);
-        }
-
-        @Override
-        public int getWindowVisibility() {
-            // We aren't attached to a window so let's pretend
-            return VISIBLE;
-        }
-
-        @Override
-        public boolean isShown() {
-            // Controller check
-            return true;
-        }
-
-        @Override
-        public int getAccessibilityViewId() {
-            // static id doesn't reset after tests so return the same one
-            return 0;
-        }
-
-        @Override
-        public void addChildrenForAccessibility(ArrayList<View> outChildren) {
-            // ViewGroup#addChildrenForAccessbility sorting logic will switch these two
-            outChildren.add(mTextView1);
-            outChildren.add(mTextView2);
-        }
-
-        @Override
-        public boolean includeForAccessibility() {
-            return true;
-        }
-
-        @Override
-        public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-            super.onInitializeAccessibilityNodeInfo(info);
-            info.setContentDescription(FRAME_LAYOUT_DESCRIPTION);
-        }
-    }
-
-    private class TestTextView extends TextView {
-        TestTextView(Context context) {
-            super(context);
-        }
-
-        @Override
-        public int getWindowVisibility() {
-            return VISIBLE;
-        }
-
-        @Override
-        public boolean isShown() {
-            return true;
-        }
-
-        @Override
-        public int getAccessibilityViewId() {
-            return 1;
-        }
-
-        @Override
-        public boolean includeForAccessibility() {
-            return true;
-        }
-
-        @Override
-        public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-            super.onInitializeAccessibilityNodeInfo(info);
-            info.setContentDescription(TEXT_VIEW_1_DESCRIPTION);
-        }
-    }
-
-    private class TestTextView2 extends TextView {
-        TestTextView2(Context context) {
-            super(context);
-        }
-
-        @Override
-        public int getWindowVisibility() {
-            return VISIBLE;
-        }
-
-        @Override
-        public boolean isShown() {
-            return true;
-        }
-
-        @Override
-        public int getAccessibilityViewId() {
-            return 2;
-        }
-
-        @Override
-        public boolean includeForAccessibility() {
-            return true;
-        }
-
-        @Override
-        public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-            super.onInitializeAccessibilityNodeInfo(info);
-            info.setContentDescription(TEXT_VIEW_2_DESCRIPTION);
-        }
-    }
-}
diff --git a/services/tests/servicestests/src/com/android/server/am/MeasuredEnergySnapshotTest.java b/services/tests/servicestests/src/com/android/server/am/MeasuredEnergySnapshotTest.java
index 1efce39..3231f62 100644
--- a/services/tests/servicestests/src/com/android/server/am/MeasuredEnergySnapshotTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/MeasuredEnergySnapshotTest.java
@@ -57,45 +57,58 @@
     private static final SparseArray<EnergyConsumer> SOME_ID_CONSUMER_MAP = createIdToConsumerMap(
             CONSUMER_DISPLAY);
 
+    private static final int VOLTAGE_0 = 4_000;
+    private static final int VOLTAGE_1 = 3_500;
+    private static final int VOLTAGE_2 = 3_100;
+    private static final int VOLTAGE_3 = 3_000;
+    private static final int VOLTAGE_4 = 2_800;
+
     // Elements in each results are purposefully out of order.
-    private static final  EnergyConsumerResult[] RESULTS_0 = new EnergyConsumerResult[] {
-        createEnergyConsumerResult(CONSUMER_OTHER_0.id, 90, new int[] {47, 3}, new long[] {14, 13}),
-        createEnergyConsumerResult(CONSUMER_DISPLAY.id, 14, null, null),
-        createEnergyConsumerResult(CONSUMER_OTHER_1.id, 0, null, null),
-        // No CONSUMER_OTHER_2
+    private static final EnergyConsumerResult[] RESULTS_0 = new EnergyConsumerResult[]{
+            createEnergyConsumerResult(CONSUMER_OTHER_0.id, 90_000, new int[]{47, 3},
+                    new long[]{14_000, 13_000}),
+            createEnergyConsumerResult(CONSUMER_DISPLAY.id, 14_000, null, null),
+            createEnergyConsumerResult(CONSUMER_OTHER_1.id, 0, null, null),
+            // No CONSUMER_OTHER_2
     };
-    private static final  EnergyConsumerResult[] RESULTS_1 = new EnergyConsumerResult[] {
-        createEnergyConsumerResult(CONSUMER_DISPLAY.id, 24, null, null),
-        createEnergyConsumerResult(CONSUMER_OTHER_0.id, 90, new int[] {47, 3}, new long[] {14, 13}),
-        createEnergyConsumerResult(CONSUMER_OTHER_2.id, 12, new int[] {6}, new long[] {10}),
-        createEnergyConsumerResult(CONSUMER_OTHER_1.id, 12_000, null, null),
+    private static final EnergyConsumerResult[] RESULTS_1 = new EnergyConsumerResult[]{
+            createEnergyConsumerResult(CONSUMER_DISPLAY.id, 24_000, null, null),
+            createEnergyConsumerResult(CONSUMER_OTHER_0.id, 90_000, new int[]{47, 3},
+                    new long[]{14_000, 13_000}),
+            createEnergyConsumerResult(CONSUMER_OTHER_2.id, 12_000, new int[]{6},
+                    new long[]{10_000}),
+            createEnergyConsumerResult(CONSUMER_OTHER_1.id, 12_000_000, null, null),
     };
-    private static final  EnergyConsumerResult[] RESULTS_2 = new EnergyConsumerResult[] {
-        createEnergyConsumerResult(CONSUMER_DISPLAY.id, 36, null, null),
-        // No CONSUMER_OTHER_0
-        // No CONSUMER_OTHER_1
-        // No CONSUMER_OTHER_2
+    private static final EnergyConsumerResult[] RESULTS_2 = new EnergyConsumerResult[]{
+            createEnergyConsumerResult(CONSUMER_DISPLAY.id, 36_000, null, null),
+            // No CONSUMER_OTHER_0
+            // No CONSUMER_OTHER_1
+            // No CONSUMER_OTHER_2
     };
-    private static final  EnergyConsumerResult[] RESULTS_3 = new EnergyConsumerResult[] {
-        // No CONSUMER_DISPLAY
-        createEnergyConsumerResult(CONSUMER_OTHER_2.id, 13, new int[] {6}, new long[] {10}),
-        createEnergyConsumerResult(
-                CONSUMER_OTHER_0.id, 190, new int[] {2, 3, 47, 7}, new long[] {9, 18, 14, 6}),
-        createEnergyConsumerResult(CONSUMER_OTHER_1.id, 12_000, null, null),
+    private static final EnergyConsumerResult[] RESULTS_3 = new EnergyConsumerResult[]{
+            // No CONSUMER_DISPLAY
+            createEnergyConsumerResult(CONSUMER_OTHER_2.id, 13_000, new int[]{6},
+                    new long[]{10_000}),
+            createEnergyConsumerResult(
+                    CONSUMER_OTHER_0.id, 190_000, new int[]{2, 3, 47, 7},
+                    new long[]{9_000, 18_000, 14_000, 6_000}),
+            createEnergyConsumerResult(CONSUMER_OTHER_1.id, 12_000_000, null, null),
     };
-    private static final  EnergyConsumerResult[] RESULTS_4 = new EnergyConsumerResult[] {
-        createEnergyConsumerResult(CONSUMER_DISPLAY.id, 43, null, null),
-        createEnergyConsumerResult(
-                CONSUMER_OTHER_0.id, 290, new int[] {7, 47, 3, 2}, new long[] {6, 14, 18, 11}),
-        // No CONSUMER_OTHER_1
-        createEnergyConsumerResult(CONSUMER_OTHER_2.id, 165, new int[] {6, 47}, new long[] {10, 8}),
+    private static final EnergyConsumerResult[] RESULTS_4 = new EnergyConsumerResult[]{
+            createEnergyConsumerResult(CONSUMER_DISPLAY.id, 43_000, null, null),
+            createEnergyConsumerResult(
+                    CONSUMER_OTHER_0.id, 290_000, new int[]{7, 47, 3, 2},
+                    new long[]{6_000, 14_000, 18_000, 11_000}),
+            // No CONSUMER_OTHER_1
+            createEnergyConsumerResult(CONSUMER_OTHER_2.id, 165_000, new int[]{6, 47},
+                    new long[]{10_000, 8_000}),
     };
 
     @Test
     public void testUpdateAndGetDelta_empty() {
         final MeasuredEnergySnapshot snapshot = new MeasuredEnergySnapshot(ALL_ID_CONSUMER_MAP);
-        assertNull(snapshot.updateAndGetDelta(null));
-        assertNull(snapshot.updateAndGetDelta(new EnergyConsumerResult[0]));
+        assertNull(snapshot.updateAndGetDelta(null, VOLTAGE_0));
+        assertNull(snapshot.updateAndGetDelta(new EnergyConsumerResult[0], VOLTAGE_0));
     }
 
     @Test
@@ -103,69 +116,88 @@
         final MeasuredEnergySnapshot snapshot = new MeasuredEnergySnapshot(ALL_ID_CONSUMER_MAP);
 
         // results0
-        MeasuredEnergyDeltaData delta = snapshot.updateAndGetDelta(RESULTS_0);
+        MeasuredEnergyDeltaData delta = snapshot.updateAndGetDelta(RESULTS_0, VOLTAGE_0);
         if (delta != null) { // null is fine here. If non-null, it better be uninteresting though.
-            assertEquals(UNAVAILABLE, delta.displayEnergyUJ);
-            assertNull(delta.otherTotalEnergyUJ);
-            assertNull(delta.otherUidEnergiesUJ);
+            assertEquals(UNAVAILABLE, delta.displayChargeUC);
+            assertNull(delta.otherTotalChargeUC);
+            assertNull(delta.otherUidChargesUC);
         }
 
         // results1
-        delta = snapshot.updateAndGetDelta(RESULTS_1);
+        delta = snapshot.updateAndGetDelta(RESULTS_1, VOLTAGE_1);
         assertNotNull(delta);
-        assertEquals(24 - 14, delta.displayEnergyUJ);
+        long expectedChargeUC;
+        expectedChargeUC = calculateChargeConsumedUC(14_000, VOLTAGE_0, 24_000, VOLTAGE_1);
+        assertEquals(expectedChargeUC, delta.displayChargeUC);
 
-        assertNotNull(delta.otherTotalEnergyUJ);
-        assertEquals(90 - 90, delta.otherTotalEnergyUJ[0]);
-        assertEquals(12_000 - 0, delta.otherTotalEnergyUJ[1]);
-        assertEquals(0, delta.otherTotalEnergyUJ[2]); // First good pull. Treat delta as 0.
+        assertNotNull(delta.otherTotalChargeUC);
 
-        assertNotNull(delta.otherUidEnergiesUJ);
-        assertNullOrEmpty(delta.otherUidEnergiesUJ[0]); // No change in uid energies
-        assertNullOrEmpty(delta.otherUidEnergiesUJ[1]);
-        assertNullOrEmpty(delta.otherUidEnergiesUJ[2]);
+        expectedChargeUC = calculateChargeConsumedUC(90_000, VOLTAGE_0, 90_000, VOLTAGE_1);
+        assertEquals(expectedChargeUC, delta.otherTotalChargeUC[0]);
+        expectedChargeUC = calculateChargeConsumedUC(0, VOLTAGE_0, 12_000_000, VOLTAGE_1);
+        assertEquals(expectedChargeUC, delta.otherTotalChargeUC[1]);
+        assertEquals(0, delta.otherTotalChargeUC[2]); // First good pull. Treat delta as 0.
+
+        assertNotNull(delta.otherUidChargesUC);
+        assertNullOrEmpty(delta.otherUidChargesUC[0]); // No change in uid energies
+        assertNullOrEmpty(delta.otherUidChargesUC[1]);
+        assertNullOrEmpty(delta.otherUidChargesUC[2]);
 
         // results2
-        delta = snapshot.updateAndGetDelta(RESULTS_2);
+        delta = snapshot.updateAndGetDelta(RESULTS_2, VOLTAGE_2);
         assertNotNull(delta);
-        assertEquals(36 - 24, delta.displayEnergyUJ);
-        assertNull(delta.otherUidEnergiesUJ);
-        assertNull(delta.otherTotalEnergyUJ);
+        expectedChargeUC = calculateChargeConsumedUC(24_000, VOLTAGE_1, 36_000, VOLTAGE_2);
+        assertEquals(expectedChargeUC, delta.displayChargeUC);
+        assertNull(delta.otherUidChargesUC);
+        assertNull(delta.otherTotalChargeUC);
 
         // results3
-        delta = snapshot.updateAndGetDelta(RESULTS_3);
+        delta = snapshot.updateAndGetDelta(RESULTS_3, VOLTAGE_3);
         assertNotNull(delta);
-        assertEquals(UNAVAILABLE, delta.displayEnergyUJ);
+        assertEquals(UNAVAILABLE, delta.displayChargeUC);
 
-        assertNotNull(delta.otherTotalEnergyUJ);
-        assertEquals(190 - 90, delta.otherTotalEnergyUJ[0]);
-        assertEquals(12_000 - 12_000, delta.otherTotalEnergyUJ[1]);
-        assertEquals(13 - 12, delta.otherTotalEnergyUJ[2]);
+        assertNotNull(delta.otherTotalChargeUC);
 
-        assertNotNull(delta.otherUidEnergiesUJ);
-        assertEquals(3, delta.otherUidEnergiesUJ[0].size());
-        assertEquals(9 - 0, delta.otherUidEnergiesUJ[0].get(2));
-        assertEquals(18 - 13, delta.otherUidEnergiesUJ[0].get(3));
-        assertEquals(6 - 0, delta.otherUidEnergiesUJ[0].get(7));
-        assertNullOrEmpty(delta.otherUidEnergiesUJ[1]);
-        assertNullOrEmpty(delta.otherUidEnergiesUJ[2]);
+        expectedChargeUC = calculateChargeConsumedUC(90_000, VOLTAGE_1, 190_000, VOLTAGE_3);
+        assertEquals(expectedChargeUC, delta.otherTotalChargeUC[0]);
+        expectedChargeUC = calculateChargeConsumedUC(12_000_000, VOLTAGE_1, 12_000_000, VOLTAGE_3);
+        assertEquals(expectedChargeUC, delta.otherTotalChargeUC[1]);
+        expectedChargeUC = calculateChargeConsumedUC(12_000, VOLTAGE_1, 13_000, VOLTAGE_3);
+        assertEquals(expectedChargeUC, delta.otherTotalChargeUC[2]);
+
+        assertNotNull(delta.otherUidChargesUC);
+
+        assertEquals(3, delta.otherUidChargesUC[0].size());
+        expectedChargeUC = calculateChargeConsumedUC(0, VOLTAGE_1, 9_000, VOLTAGE_3);
+        assertEquals(expectedChargeUC, delta.otherUidChargesUC[0].get(2));
+        expectedChargeUC = calculateChargeConsumedUC(13_000, VOLTAGE_1, 18_000, VOLTAGE_3);
+        assertEquals(expectedChargeUC, delta.otherUidChargesUC[0].get(3));
+        expectedChargeUC = calculateChargeConsumedUC(0, VOLTAGE_1, 6_000, VOLTAGE_3);
+        assertEquals(expectedChargeUC, delta.otherUidChargesUC[0].get(7));
+        assertNullOrEmpty(delta.otherUidChargesUC[1]);
+        assertNullOrEmpty(delta.otherUidChargesUC[2]);
 
         // results4
-        delta = snapshot.updateAndGetDelta(RESULTS_4);
+        delta = snapshot.updateAndGetDelta(RESULTS_4, VOLTAGE_4);
         assertNotNull(delta);
-        assertEquals(43 - 36, delta.displayEnergyUJ);
+        expectedChargeUC = calculateChargeConsumedUC(36_000, VOLTAGE_2, 43_000, VOLTAGE_4);
+        assertEquals(expectedChargeUC, delta.displayChargeUC);
 
-        assertNotNull(delta.otherTotalEnergyUJ);
-        assertEquals(290 - 190, delta.otherTotalEnergyUJ[0]);
-        assertEquals(0, delta.otherTotalEnergyUJ[1]); // Not present (e.g. missing data)
-        assertEquals(165 - 13, delta.otherTotalEnergyUJ[2]);
+        assertNotNull(delta.otherTotalChargeUC);
+        expectedChargeUC = calculateChargeConsumedUC(190_000, VOLTAGE_3, 290_000, VOLTAGE_4);
+        assertEquals(expectedChargeUC, delta.otherTotalChargeUC[0]);
+        assertEquals(0, delta.otherTotalChargeUC[1]); // Not present (e.g. missing data)
+        expectedChargeUC = calculateChargeConsumedUC(13_000, VOLTAGE_3, 165_000, VOLTAGE_4);
+        assertEquals(expectedChargeUC, delta.otherTotalChargeUC[2]);
 
-        assertNotNull(delta.otherUidEnergiesUJ);
-        assertEquals(1, delta.otherUidEnergiesUJ[0].size());
-        assertEquals(11 - 9, delta.otherUidEnergiesUJ[0].get(2));
-        assertNullOrEmpty(delta.otherUidEnergiesUJ[1]); // Not present
-        assertEquals(1, delta.otherUidEnergiesUJ[2].size());
-        assertEquals(8, delta.otherUidEnergiesUJ[2].get(47));
+        assertNotNull(delta.otherUidChargesUC);
+        assertEquals(1, delta.otherUidChargesUC[0].size());
+        expectedChargeUC = calculateChargeConsumedUC(9_000, VOLTAGE_3, 11_000, VOLTAGE_4);
+        assertEquals(expectedChargeUC, delta.otherUidChargesUC[0].get(2));
+        assertNullOrEmpty(delta.otherUidChargesUC[1]); // Not present
+        assertEquals(1, delta.otherUidChargesUC[2].size());
+        expectedChargeUC = calculateChargeConsumedUC(0, VOLTAGE_3, 8_000, VOLTAGE_4);
+        assertEquals(expectedChargeUC, delta.otherUidChargesUC[2].get(47));
     }
 
     /** Test updateAndGetDelta() when the results have consumers absent from idToConsumerMap. */
@@ -174,19 +206,21 @@
         final MeasuredEnergySnapshot snapshot = new MeasuredEnergySnapshot(SOME_ID_CONSUMER_MAP);
 
         // results0
-        MeasuredEnergyDeltaData delta = snapshot.updateAndGetDelta(RESULTS_0);
+        MeasuredEnergyDeltaData delta = snapshot.updateAndGetDelta(RESULTS_0, VOLTAGE_0);
         if (delta != null) { // null is fine here. If non-null, it better be uninteresting though.
-            assertEquals(UNAVAILABLE, delta.displayEnergyUJ);
-            assertNull(delta.otherTotalEnergyUJ);
-            assertNull(delta.otherUidEnergiesUJ);
+            assertEquals(UNAVAILABLE, delta.displayChargeUC);
+            assertNull(delta.otherTotalChargeUC);
+            assertNull(delta.otherUidChargesUC);
         }
 
         // results1
-        delta = snapshot.updateAndGetDelta(RESULTS_1);
+        delta = snapshot.updateAndGetDelta(RESULTS_1, VOLTAGE_1);
         assertNotNull(delta);
-        assertEquals(24 - 14, delta.displayEnergyUJ);
-        assertNull(delta.otherTotalEnergyUJ); // Although in the results, they're not in the idMap
-        assertNull(delta.otherUidEnergiesUJ);
+        final long expectedChargeUC =
+                calculateChargeConsumedUC(14_000, VOLTAGE_0, 24_000, VOLTAGE_1);
+        assertEquals(expectedChargeUC, delta.displayChargeUC);
+        assertNull(delta.otherTotalChargeUC); // Although in the results, they're not in the idMap
+        assertNull(delta.otherUidChargesUC);
     }
 
     @Test
@@ -234,6 +268,15 @@
         return ecr;
     }
 
+    private static long calculateChargeConsumedUC(long energyUWs0, long voltageMv0, long energyUWs1,
+            long voltageMv1) {
+        final long deltaEnergyUWs = energyUWs1 - energyUWs0;
+        final long avgVoltageMv = (voltageMv1 + voltageMv0 + 1) / 2;
+
+        // Charge uC = Energy uWs * (1000 mV/V) / (voltage mV) + 0.5 (for rounding)
+        return (deltaEnergyUWs * 1000 + (avgVoltageMv / 2)) / avgVoltageMv;
+    }
+
     private void assertNullOrEmpty(SparseLongArray a) {
         if (a != null) assertEquals("Array should be null or empty", 0, a.size());
     }
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/AcquisitionClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/AcquisitionClientTest.java
new file mode 100644
index 0000000..46f9636
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/AcquisitionClientTest.java
@@ -0,0 +1,118 @@
+/*
+ * 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.biometrics.sensors;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+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.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+import android.content.Context;
+import android.hardware.biometrics.BiometricConstants;
+import android.os.IBinder;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.annotation.NonNull;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@Presubmit
+@SmallTest
+public class AcquisitionClientTest {
+
+    private static final int TEST_SENSOR_ID = 100;
+
+    @Mock
+    private Context mContext;
+    @Mock
+    private IBinder mToken;
+    @Mock
+    private ClientMonitorCallbackConverter mClientCallback;
+    @Mock
+    private BaseClientMonitor.Callback mSchedulerCallback;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+    }
+
+    @Test
+    public void testUserCanceled() throws Exception {
+        // Start an AcquisitionClient
+        final TestAcquisitionClient client = new TestAcquisitionClient(mContext, Object::new,
+                mToken, mClientCallback);
+        client.start(mSchedulerCallback);
+        assertTrue(client.mHalOperationRunning);
+        verify(mSchedulerCallback).onClientStarted(eq(client));
+
+        // Pretend that it got canceled by the user.
+        client.onUserCanceled();
+        verify(mSchedulerCallback, never()).onClientFinished(any(), anyBoolean());
+        verify(mClientCallback).onError(eq(TEST_SENSOR_ID),
+                anyInt(),
+                eq(BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED),
+                eq(0) /* vendorCode */);
+        assertFalse(client.mHalOperationRunning);
+
+        // Pretend that the HAL responded with ERROR_CANCELED
+        client.onError(BiometricConstants.BIOMETRIC_ERROR_CANCELED, 0 /* vendorCode */);
+        verifyNoMoreInteractions(mClientCallback);
+        verify(mSchedulerCallback).onClientFinished(eq(client), anyBoolean());
+    }
+
+    private static class TestAcquisitionClient extends AcquisitionClient<Object> {
+        boolean mHalOperationRunning;
+
+        public TestAcquisitionClient(@NonNull Context context,
+                @NonNull LazyDaemon<Object> lazyDaemon, @NonNull IBinder token,
+                @NonNull ClientMonitorCallbackConverter callback) {
+            super(context, lazyDaemon, token, callback, 0 /* userId */, "Test", 0 /* cookie */,
+                    TEST_SENSOR_ID /* sensorId */, 0 /* statsModality */, 0 /* statsAction */,
+                    0 /* statsClient */);
+        }
+
+        @Override
+        public void start(@NonNull Callback callback) {
+            super.start(callback);
+            startHalOperation();
+        }
+
+        @Override
+        protected void stopHalOperation() {
+            mHalOperationRunning = false;
+        }
+
+        @Override
+        protected void startHalOperation() {
+            mHalOperationRunning = true;
+        }
+
+        @Override
+        public int getProtoEnum() {
+            return 0;
+        }
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java
index a97ea26..ff8fbda 100644
--- a/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java
@@ -73,16 +73,16 @@
 
     @Test
     public void baseStateChanged() {
-        assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
+        assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE));
         assertEquals(mService.getPendingState(), Optional.empty());
-        assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
+        assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE));
         assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
                 DEFAULT_DEVICE_STATE.getIdentifier());
 
         mProvider.setState(OTHER_DEVICE_STATE.getIdentifier());
-        assertEquals(mService.getCommittedState(), OTHER_DEVICE_STATE);
+        assertEquals(mService.getCommittedState(), Optional.of(OTHER_DEVICE_STATE));
         assertEquals(mService.getPendingState(), Optional.empty());
-        assertEquals(mService.getBaseState(), OTHER_DEVICE_STATE);
+        assertEquals(mService.getBaseState(), Optional.of(OTHER_DEVICE_STATE));
         assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
                 OTHER_DEVICE_STATE.getIdentifier());
     }
@@ -92,23 +92,23 @@
         mPolicy.blockConfigure();
 
         mProvider.setState(OTHER_DEVICE_STATE.getIdentifier());
-        assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
-        assertEquals(mService.getPendingState().get(), OTHER_DEVICE_STATE);
-        assertEquals(mService.getBaseState(), OTHER_DEVICE_STATE);
+        assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE));
+        assertEquals(mService.getPendingState(), Optional.of(OTHER_DEVICE_STATE));
+        assertEquals(mService.getBaseState(), Optional.of(OTHER_DEVICE_STATE));
         assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
                 OTHER_DEVICE_STATE.getIdentifier());
 
         mProvider.setState(DEFAULT_DEVICE_STATE.getIdentifier());
-        assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
-        assertEquals(mService.getPendingState().get(), OTHER_DEVICE_STATE);
-        assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
+        assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE));
+        assertEquals(mService.getPendingState(), Optional.of(OTHER_DEVICE_STATE));
+        assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE));
         assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
                 OTHER_DEVICE_STATE.getIdentifier());
 
         mPolicy.resumeConfigure();
-        assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
+        assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE));
         assertEquals(mService.getPendingState(), Optional.empty());
-        assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
+        assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE));
         assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
                 DEFAULT_DEVICE_STATE.getIdentifier());
     }
@@ -119,9 +119,9 @@
             mProvider.setState(UNSUPPORTED_DEVICE_STATE.getIdentifier());
         });
 
-        assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
+        assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE));
         assertEquals(mService.getPendingState(), Optional.empty());
-        assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
+        assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE));
         assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
                 DEFAULT_DEVICE_STATE.getIdentifier());
     }
@@ -132,9 +132,9 @@
             mProvider.setState(INVALID_DEVICE_STATE);
         });
 
-        assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
+        assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE));
         assertEquals(mService.getPendingState(), Optional.empty());
-        assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
+        assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE));
         assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
                 DEFAULT_DEVICE_STATE.getIdentifier());
     }
@@ -144,17 +144,17 @@
         TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
         mService.getBinderService().registerCallback(callback);
 
-        assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
+        assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE));
         assertEquals(mService.getPendingState(), Optional.empty());
-        assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
+        assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE));
 
         mProvider.notifySupportedDeviceStates(new DeviceState[]{ DEFAULT_DEVICE_STATE });
 
         // The current committed and requests states do not change because the current state remains
         // supported.
-        assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
+        assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE));
         assertEquals(mService.getPendingState(), Optional.empty());
-        assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
+        assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE));
 
         assertArrayEquals(callback.getLastNotifiedInfo().supportedStates,
                 new int[] { DEFAULT_DEVICE_STATE.getIdentifier() });
@@ -165,18 +165,21 @@
         TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
         mService.getBinderService().registerCallback(callback);
 
-        assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
+        // An initial callback will be triggered on registration, so we clear it here.
+        callback.clearLastNotifiedInfo();
+
+        assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE));
         assertEquals(mService.getPendingState(), Optional.empty());
-        assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
+        assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE));
 
         mProvider.notifySupportedDeviceStates(new DeviceState[]{ DEFAULT_DEVICE_STATE,
                 OTHER_DEVICE_STATE });
 
         // The current committed and requests states do not change because the current state remains
         // supported.
-        assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
+        assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE));
         assertEquals(mService.getPendingState(), Optional.empty());
-        assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
+        assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE));
 
         // The callback wasn't notified about a change in supported states as the states have not
         // changed.
@@ -230,6 +233,17 @@
     }
 
     @Test
+    public void registerCallback_emitsInitialValue() throws RemoteException {
+        TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
+        mService.getBinderService().registerCallback(callback);
+        assertNotNull(callback.getLastNotifiedInfo());
+        assertEquals(callback.getLastNotifiedInfo().baseState,
+                DEFAULT_DEVICE_STATE.getIdentifier());
+        assertEquals(callback.getLastNotifiedInfo().currentState,
+                DEFAULT_DEVICE_STATE.getIdentifier());
+    }
+
+    @Test
     public void requestState() throws RemoteException {
         TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
         mService.getBinderService().registerCallback(callback);
@@ -244,8 +258,8 @@
         assertEquals(callback.getLastNotifiedStatus(token),
                 TestDeviceStateManagerCallback.STATUS_ACTIVE);
         // Committed state changes as there is a requested override.
-        assertEquals(mService.getCommittedState(), OTHER_DEVICE_STATE);
-        assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
+        assertEquals(mService.getCommittedState(), Optional.of(OTHER_DEVICE_STATE));
+        assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE));
         assertEquals(mService.getOverrideState().get(), OTHER_DEVICE_STATE);
         assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
                 OTHER_DEVICE_STATE.getIdentifier());
@@ -261,8 +275,8 @@
         assertEquals(callback.getLastNotifiedStatus(token),
                 TestDeviceStateManagerCallback.STATUS_CANCELED);
         // Committed state is set back to the requested state once the override is cleared.
-        assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
-        assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
+        assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE));
+        assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE));
         assertFalse(mService.getOverrideState().isPresent());
         assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
                 DEFAULT_DEVICE_STATE.getIdentifier());
@@ -290,9 +304,9 @@
         mService.getBinderService().requestState(firstRequestToken,
                 OTHER_DEVICE_STATE.getIdentifier(), 0 /* flags */);
 
-        assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
-        assertEquals(mService.getPendingState().get(), OTHER_DEVICE_STATE);
-        assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
+        assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE));
+        assertEquals(mService.getPendingState(), Optional.of(OTHER_DEVICE_STATE));
+        assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE));
         assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
                 OTHER_DEVICE_STATE.getIdentifier());
 
@@ -309,17 +323,17 @@
         assertEquals(callback.getLastNotifiedStatus(secondRequestToken),
                 TestDeviceStateManagerCallback.STATUS_UNKNOWN);
 
-        assertEquals(mService.getCommittedState(), OTHER_DEVICE_STATE);
-        assertEquals(mService.getPendingState().get(), DEFAULT_DEVICE_STATE);
-        assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
+        assertEquals(mService.getCommittedState(), Optional.of(OTHER_DEVICE_STATE));
+        assertEquals(mService.getPendingState(), Optional.of(DEFAULT_DEVICE_STATE));
+        assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE));
         assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
                 DEFAULT_DEVICE_STATE.getIdentifier());
 
         mPolicy.resumeConfigure();
 
-        assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
+        assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE));
         assertEquals(mService.getPendingState(), Optional.empty());
-        assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
+        assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE));
         assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
                 DEFAULT_DEVICE_STATE.getIdentifier());
 
@@ -331,9 +345,9 @@
         assertEquals(callback.getLastNotifiedStatus(secondRequestToken),
                 TestDeviceStateManagerCallback.STATUS_CANCELED);
 
-        assertEquals(mService.getCommittedState(), OTHER_DEVICE_STATE);
+        assertEquals(mService.getCommittedState(), Optional.of(OTHER_DEVICE_STATE));
         assertEquals(mService.getPendingState(), Optional.empty());
-        assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
+        assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE));
         assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
                 OTHER_DEVICE_STATE.getIdentifier());
     }
@@ -370,8 +384,8 @@
                 TestDeviceStateManagerCallback.STATUS_ACTIVE);
 
         // Committed state changes as there is a requested override.
-        assertEquals(mService.getCommittedState(), OTHER_DEVICE_STATE);
-        assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
+        assertEquals(mService.getCommittedState(), Optional.of(OTHER_DEVICE_STATE));
+        assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE));
         assertEquals(mService.getOverrideState().get(), OTHER_DEVICE_STATE);
         assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
                 OTHER_DEVICE_STATE.getIdentifier());
@@ -382,8 +396,8 @@
         assertEquals(callback.getLastNotifiedStatus(token),
                 TestDeviceStateManagerCallback.STATUS_CANCELED);
         // Committed state is set back to the requested state once the override is cleared.
-        assertEquals(mService.getCommittedState(), OTHER_DEVICE_STATE);
-        assertEquals(mService.getBaseState(), OTHER_DEVICE_STATE);
+        assertEquals(mService.getCommittedState(), Optional.of(OTHER_DEVICE_STATE));
+        assertEquals(mService.getBaseState(), Optional.of(OTHER_DEVICE_STATE));
         assertFalse(mService.getOverrideState().isPresent());
         assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
                 OTHER_DEVICE_STATE.getIdentifier());
@@ -404,8 +418,8 @@
         assertEquals(callback.getLastNotifiedStatus(token),
                 TestDeviceStateManagerCallback.STATUS_ACTIVE);
         // Committed state changes as there is a requested override.
-        assertEquals(mService.getCommittedState(), OTHER_DEVICE_STATE);
-        assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
+        assertEquals(mService.getCommittedState(), Optional.of(OTHER_DEVICE_STATE));
+        assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE));
         assertEquals(mService.getOverrideState().get(), OTHER_DEVICE_STATE);
         assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
                 OTHER_DEVICE_STATE.getIdentifier());
@@ -417,8 +431,8 @@
                 TestDeviceStateManagerCallback.STATUS_CANCELED);
         // Committed state is set back to the requested state as the override state is no longer
         // supported.
-        assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
-        assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
+        assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE));
+        assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE));
         assertFalse(mService.getOverrideState().isPresent());
         assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
                 DEFAULT_DEVICE_STATE.getIdentifier());
@@ -551,7 +565,6 @@
 
         @Nullable
         private DeviceStateInfo mLastNotifiedInfo;
-        private boolean mNotifiedOfChangeInSupportedStates;
         private final HashMap<IBinder, Integer> mLastNotifiedStatus = new HashMap<>();
 
         @Override
@@ -579,6 +592,10 @@
             return mLastNotifiedInfo;
         }
 
+        void clearLastNotifiedInfo() {
+            mLastNotifiedInfo = null;
+        }
+
         int getLastNotifiedStatus(IBinder requestToken) {
             return mLastNotifiedStatus.getOrDefault(requestToken, STATUS_UNKNOWN);
         }
diff --git a/services/tests/servicestests/src/com/android/server/display/BrightnessTrackerTest.java b/services/tests/servicestests/src/com/android/server/display/BrightnessTrackerTest.java
index d362791..893ce9e 100644
--- a/services/tests/servicestests/src/com/android/server/display/BrightnessTrackerTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/BrightnessTrackerTest.java
@@ -38,6 +38,7 @@
 import android.hardware.display.AmbientBrightnessDayStats;
 import android.hardware.display.BrightnessChangeEvent;
 import android.hardware.display.BrightnessConfiguration;
+import android.hardware.display.ColorDisplayManager;
 import android.hardware.display.DisplayManager;
 import android.hardware.display.DisplayedContentSample;
 import android.hardware.display.DisplayedContentSamplingAttributes;
@@ -91,6 +92,7 @@
             new HandlerThread("brightness.test", android.os.Process.THREAD_PRIORITY_BACKGROUND);
 
     private int mDefaultNightModeColorTemperature;
+    private float mRbcOffsetFactor;
 
     private static Handler ensureHandler() {
         synchronized (sHandlerLock) {
@@ -111,6 +113,8 @@
         mDefaultNightModeColorTemperature =
                 InstrumentationRegistry.getContext().getResources().getInteger(
                 R.integer.config_nightDisplayColorTemperatureDefault);
+        mRbcOffsetFactor = InstrumentationRegistry.getContext()
+                .getSystemService(ColorDisplayManager.class).getReduceBrightColorsOffsetFactor();
     }
 
     @Test
@@ -314,6 +318,9 @@
         mInjector.mSecureIntSettings.put(Settings.Secure.NIGHT_DISPLAY_ACTIVATED, 1);
         mInjector.mSecureIntSettings.put(Settings.Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE, 3333);
 
+        mInjector.mSecureIntSettings.put(Settings.Secure.REDUCE_BRIGHT_COLORS_ACTIVATED, 1);
+        mInjector.mSecureIntSettings.put(Settings.Secure.REDUCE_BRIGHT_COLORS_LEVEL, 40);
+
         startTracker(mTracker, initialBrightness, DEFAULT_COLOR_SAMPLING_ENABLED);
         mInjector.mBroadcastReceiver.onReceive(InstrumentationRegistry.getContext(),
                 batteryChangeEvent(30, 60));
@@ -337,7 +344,7 @@
         assertEquals(3333, event.colorTemperature);
         assertTrue(event.reduceBrightColors);
         assertEquals(40, event.reduceBrightColorsStrength);
-        assertEquals(20f, event.reduceBrightColorsOffset, FLOAT_DELTA);
+        assertEquals(brightness * mRbcOffsetFactor, event.reduceBrightColorsOffset, FLOAT_DELTA);
         assertEquals("a.package", event.packageName);
         assertEquals(0, event.userId);
         assertArrayEquals(new long[] {1, 10, 100, 1000, 300, 30, 10, 1}, event.colorValueBuckets);
@@ -445,7 +452,9 @@
                 + Long.toString(someTimeAgo) + "\" packageName=\""
                 + "com.example.app\" user=\"10\" "
                 + "lastNits=\"32.333\" "
-                + "batteryLevel=\"1.0\" nightMode=\"false\" colorTemperature=\"0\"\n"
+                + "batteryLevel=\"1.0\" nightMode=\"false\" colorTemperature=\"0\" "
+                + "reduceBrightColors=\"false\" reduceBrightColorsStrength=\"40\" "
+                + "reduceBrightColorsOffset=\"0\"\n"
                 + "lux=\"32.2,31.1\" luxTimestamps=\""
                 + Long.toString(someTimeAgo) + "," + Long.toString(someTimeAgo) + "\""
                 + "defaultConfig=\"true\" powerSaveFactor=\"0.5\" userPoint=\"true\" />"
@@ -453,7 +462,9 @@
                 + Long.toString(someTimeAgo) + "\" packageName=\""
                 + "com.android.anapp\" user=\"11\" "
                 + "lastNits=\"32\" "
-                + "batteryLevel=\"0.5\" nightMode=\"true\" colorTemperature=\"3235\"\n"
+                + "batteryLevel=\"0.5\" nightMode=\"true\" colorTemperature=\"3235\" "
+                + "reduceBrightColors=\"true\" reduceBrightColorsStrength=\"40\" "
+                + "reduceBrightColorsOffset=\"0\"\n"
                 + "lux=\"132.2,131.1\" luxTimestamps=\""
                 + Long.toString(someTimeAgo) + "," + Long.toString(someTimeAgo) + "\""
                 + "colorSampleDuration=\"3456\" colorValueBuckets=\"123,598,23,19\"/>"
@@ -462,7 +473,9 @@
                 + Long.toString(twoMonthsAgo) + "\" packageName=\""
                 + "com.example.app\" user=\"10\" "
                 + "lastNits=\"32\" "
-                + "batteryLevel=\"1.0\" nightMode=\"false\" colorTemperature=\"0\"\n"
+                + "batteryLevel=\"1.0\" nightMode=\"false\" colorTemperature=\"0\" "
+                + "reduceBrightColors=\"false\" reduceBrightColorsStrength=\"40\" "
+                + "reduceBrightColorsOffset=\"0\"\n"
                 + "lux=\"32.2,31.1\" luxTimestamps=\""
                 + Long.toString(twoMonthsAgo) + "," + Long.toString(twoMonthsAgo) + "\"/>"
                 + "</events>";
@@ -477,6 +490,7 @@
         assertEquals(32.333, event.lastBrightness, FLOAT_DELTA);
         assertEquals(0, event.userId);
         assertFalse(event.nightMode);
+        assertFalse(event.reduceBrightColors);
         assertEquals(1.0f, event.batteryLevel, FLOAT_DELTA);
         assertEquals("com.example.app", event.packageName);
         assertTrue(event.isDefaultBrightnessConfig);
@@ -495,6 +509,7 @@
         assertEquals(1, event.userId);
         assertTrue(event.nightMode);
         assertEquals(3235, event.colorTemperature);
+        assertTrue(event.reduceBrightColors);
         assertEquals(0.5f, event.batteryLevel, FLOAT_DELTA);
         assertEquals("com.android.anapp", event.packageName);
         // Not present in the event so default to false.
@@ -600,7 +615,7 @@
         assertEquals(3339, event.colorTemperature);
         assertTrue(event.reduceBrightColors);
         assertEquals(40, event.reduceBrightColorsStrength);
-        assertEquals(20f, event.reduceBrightColorsOffset, FLOAT_DELTA);
+        assertEquals(brightness * mRbcOffsetFactor, event.reduceBrightColorsOffset, FLOAT_DELTA);
         assertEquals(0.5f, event.powerBrightnessFactor, FLOAT_DELTA);
         assertTrue(event.isUserSetBrightness);
         assertFalse(event.isDefaultBrightnessConfig);
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/ResumeOnRebootServiceProviderTests.java b/services/tests/servicestests/src/com/android/server/locksettings/ResumeOnRebootServiceProviderTests.java
index b9af82b..f3a38e6 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/ResumeOnRebootServiceProviderTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/ResumeOnRebootServiceProviderTests.java
@@ -19,12 +19,12 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.Manifest;
-import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
@@ -53,12 +53,9 @@
     Context mMockContext;
     @Mock
     PackageManager mMockPackageManager;
-    @Mock
-    ResolveInfo mMockResolvedInfo;
-    @Mock
-    ServiceInfo mMockServiceInfo;
-    @Mock
-    ComponentName mMockComponentName;
+
+    ResolveInfo mFakeResolvedInfo;
+    ServiceInfo mFakeServiceInfo;
     @Captor
     ArgumentCaptor<Intent> mIntentArgumentCaptor;
 
@@ -66,8 +63,13 @@
     public void setUp() {
         MockitoAnnotations.initMocks(this);
         when(mMockContext.getUserId()).thenReturn(0);
-        when(mMockResolvedInfo.serviceInfo).thenReturn(mMockServiceInfo);
-        when(mMockServiceInfo.getComponentName()).thenReturn(mMockComponentName);
+
+        mFakeServiceInfo = new ServiceInfo();
+        mFakeServiceInfo.packageName = "fakePackageName";
+        mFakeServiceInfo.name = "fakeName";
+
+        mFakeResolvedInfo = new ResolveInfo();
+        mFakeResolvedInfo.serviceInfo = mFakeServiceInfo;
     }
 
     @Test
@@ -82,10 +84,9 @@
     @Test
     public void serviceNotGuardedWithPermission() throws Exception {
         ArrayList<ResolveInfo> resultList = new ArrayList<>();
-        when(mMockServiceInfo.permission).thenReturn("");
-        resultList.add(mMockResolvedInfo);
-        when(mMockPackageManager.queryIntentServices(any(), any())).thenReturn(
-                resultList);
+        mFakeServiceInfo.permission = "";
+        resultList.add(mFakeResolvedInfo);
+        when(mMockPackageManager.queryIntentServices(any(), anyInt())).thenReturn(resultList);
         assertThat(new ResumeOnRebootServiceProvider(mMockContext,
                 mMockPackageManager).getServiceConnection()).isNull();
     }
@@ -93,18 +94,15 @@
     @Test
     public void serviceResolved() throws Exception {
         ArrayList<ResolveInfo> resultList = new ArrayList<>();
-        resultList.add(mMockResolvedInfo);
-        when(mMockServiceInfo.permission).thenReturn(
-                Manifest.permission.BIND_RESUME_ON_REBOOT_SERVICE);
-        when(mMockPackageManager.queryIntentServices(any(),
-                eq(PackageManager.MATCH_SYSTEM_ONLY))).thenReturn(
-                resultList);
+        resultList.add(mFakeResolvedInfo);
+        mFakeServiceInfo.permission = Manifest.permission.BIND_RESUME_ON_REBOOT_SERVICE;
+        when(mMockPackageManager.queryIntentServices(any(), anyInt())).thenReturn(resultList);
 
         assertThat(new ResumeOnRebootServiceProvider(mMockContext,
                 mMockPackageManager).getServiceConnection()).isNotNull();
 
         verify(mMockPackageManager).queryIntentServices(mIntentArgumentCaptor.capture(),
-                eq(PackageManager.MATCH_SYSTEM_ONLY));
+                eq(PackageManager.MATCH_SYSTEM_ONLY | PackageManager.GET_SERVICES));
         assertThat(mIntentArgumentCaptor.getValue().getAction()).isEqualTo(
                 ResumeOnRebootService.SERVICE_INTERFACE);
     }
diff --git a/services/tests/servicestests/src/com/android/server/policy/DeviceStateProviderImplTest.java b/services/tests/servicestests/src/com/android/server/policy/DeviceStateProviderImplTest.java
index 4f36c8a..d13687c 100644
--- a/services/tests/servicestests/src/com/android/server/policy/DeviceStateProviderImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/policy/DeviceStateProviderImplTest.java
@@ -150,8 +150,8 @@
         provider.setListener(listener);
 
         verify(listener).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture());
-        final DeviceState[] expectedStates = new DeviceState[]{ new DeviceState(1, null),
-                new DeviceState(2, null) };
+        final DeviceState[] expectedStates = new DeviceState[]{ new DeviceState(1, ""),
+                new DeviceState(2, "") };
         assertArrayEquals(expectedStates, mDeviceStateArrayCaptor.getValue());
 
         verify(listener).onStateChanged(mIntegerCaptor.capture());
@@ -187,16 +187,22 @@
         provider.setListener(listener);
 
         verify(listener).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture());
-        final DeviceState[] expectedStates = new DeviceState[]{ new DeviceState(1, null),
+        final DeviceState[] expectedStates = new DeviceState[]{ new DeviceState(1, ""),
                 new DeviceState(2, "CLOSED") };
         assertArrayEquals(expectedStates, mDeviceStateArrayCaptor.getValue());
 
+        // onStateChanged() should not be called because the provider has not yet been notified of
+        // the initial lid switch state.
+        verify(listener, never()).onStateChanged(mIntegerCaptor.capture());
+
+        provider.notifyLidSwitchChanged(0, false /* lidOpen */);
+
         verify(listener).onStateChanged(mIntegerCaptor.capture());
         assertEquals(2, mIntegerCaptor.getValue().intValue());
 
         Mockito.clearInvocations(listener);
 
-        provider.notifyLidSwitchChanged(0, true /* lidOpen */);
+        provider.notifyLidSwitchChanged(1, true /* lidOpen */);
         verify(listener, never()).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture());
         verify(listener).onStateChanged(mIntegerCaptor.capture());
         assertEquals(1, mIntegerCaptor.getValue().intValue());
@@ -260,9 +266,9 @@
         assertArrayEquals(
                 new DeviceState[]{ new DeviceState(1, "CLOSED"), new DeviceState(2, "HALF_OPENED"),
                         new DeviceState(3, "OPENED") }, mDeviceStateArrayCaptor.getValue());
-
-        verify(listener).onStateChanged(mIntegerCaptor.capture());
-        assertEquals(1, mIntegerCaptor.getValue().intValue());
+        // onStateChanged() should not be called because the provider has not yet been notified of
+        // the initial sensor state.
+        verify(listener, never()).onStateChanged(mIntegerCaptor.capture());
 
         Mockito.clearInvocations(listener);
 
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index cebdbbe..1905e2f 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -6207,7 +6207,8 @@
         reset(mListeners);
 
         // Test: update suppression to true
-        mService.mNotificationDelegate.onBubbleNotificationSuppressionChanged(nr.getKey(), true);
+        mService.mNotificationDelegate.onBubbleNotificationSuppressionChanged(nr.getKey(), true,
+                false);
         waitForIdle();
 
         // Check
@@ -6218,7 +6219,8 @@
         reset(mListeners);
 
         // Test: update suppression to false
-        mService.mNotificationDelegate.onBubbleNotificationSuppressionChanged(nr.getKey(), false);
+        mService.mNotificationDelegate.onBubbleNotificationSuppressionChanged(nr.getKey(), false,
+                false);
         waitForIdle();
 
         // Check
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 09a436c..f5d831b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -342,6 +342,25 @@
         verify(imeTarget.getRootDisplayArea()).placeImeContainer(imeContainer);
     }
 
+    @Test
+    public void testUpdateImeParent_forceUpdateRelativeLayer() {
+        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 SurfaceControl imeSurfaceParent = mock(SurfaceControl.class);
+        doReturn(imeSurfaceParent).when(mDisplayContent).computeImeParent();
+        spyOn(imeContainer);
+
+        mDisplayContent.updateImeParent();
+
+        // Force reassign the relative layer when the IME surface parent is changed.
+        verify(imeContainer).assignRelativeLayer(any(), eq(imeSurfaceParent), anyInt(), eq(true));
+    }
+
     /**
      * This tests stack movement between displays and proper stack's, task's and app token's display
      * container references updates.
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
index 074ef36..47cf53b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
@@ -323,16 +323,4 @@
         assertFalse(navBarSource.getFrame().isEmpty());
         assertTrue(imeSource.getFrame().contains(navBarSource.getFrame()));
     }
-
-    @UseTestDisplay
-    @Test
-    public void testDisplayPolicyNotCrash() {
-        final DisplayPolicy displayPolicy = mDisplayContent.getDisplayPolicy();
-
-        // Verify if modules initialized after DisplayContent ctr throws NPE.
-        displayPolicy.onDisplayInfoChanged(mDisplayInfo);
-        displayPolicy.onConfigurationChanged();
-        displayPolicy.onOverlayChangedLw();
-        displayPolicy.release();
-    }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
index 5239462..ed57294 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
@@ -195,7 +195,7 @@
     }
 
     @Test
-    public void testUsesTasksDisplayAreaIdPriorToSourceIfSet() {
+    public void testUsesSourcesDisplayAreaIdPriorToTaskIfSet() {
         final TestDisplayContent freeformDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FREEFORM);
         final TestDisplayContent fullscreenDisplay = createNewDisplayContent(
@@ -211,7 +211,7 @@
                         .setSource(source)
                         .calculate());
 
-        assertEquals(fullscreenDisplay.getDefaultTaskDisplayArea(),
+        assertEquals(freeformDisplay.getDefaultTaskDisplayArea(),
                 mResult.mPreferredTaskDisplayArea);
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
index bbb885eb..b88173d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
@@ -54,6 +54,7 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.clearInvocations;
 
 import android.content.pm.ActivityInfo;
 import android.content.res.Configuration;
@@ -1029,6 +1030,30 @@
         verify(win).clearFrozenInsetsState();
     }
 
+    @Test
+    public void testAssignRelativeLayer() {
+        final WindowContainer container = new WindowContainer(mWm);
+        container.mSurfaceControl = mock(SurfaceControl.class);
+        final SurfaceAnimator surfaceAnimator = container.mSurfaceAnimator;
+        final SurfaceControl relativeParent = mock(SurfaceControl.class);
+        final SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class);
+        spyOn(container);
+        spyOn(surfaceAnimator);
+
+        // Trigger for first relative layer call.
+        container.assignRelativeLayer(t, relativeParent, 1 /* layer */);
+        verify(surfaceAnimator).setRelativeLayer(t, relativeParent, 1 /* layer */);
+
+        // Not trigger for the same relative layer call.
+        clearInvocations(surfaceAnimator);
+        container.assignRelativeLayer(t, relativeParent, 1 /* layer */);
+        verify(surfaceAnimator, never()).setRelativeLayer(t, relativeParent, 1 /* layer */);
+
+        // Trigger for the same relative layer call if forceUpdate=true
+        container.assignRelativeLayer(t, relativeParent, 1 /* layer */, true /* forceUpdate */);
+        verify(surfaceAnimator).setRelativeLayer(t, relativeParent, 1 /* layer */);
+    }
+
     /* Used so we can gain access to some protected members of the {@link WindowContainer} class */
     private static class TestWindowContainer extends WindowContainer<TestWindowContainer> {
         private final int mLayer;
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 1f38f46..8d50a77 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -546,8 +546,9 @@
 
     /** Creates a {@link DisplayContent} and adds it to the system. */
     private DisplayContent createNewDisplay(DisplayInfo info, @DisplayImePolicy int imePolicy) {
-        final DisplayContent dc =
+        final DisplayContent display =
                 new TestDisplayContent.Builder(mAtm, info).build();
+        final DisplayContent dc = display.mDisplayContent;
         // this display can show IME.
         dc.mWmService.mDisplayWindowSettings.setDisplayImePolicy(dc, imePolicy);
         return dc;
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 9e419d4..0510b9c 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -2212,6 +2212,7 @@
         @Override
         public void reportLocusUpdate(@NonNull ComponentName activity, @UserIdInt int userId,
                 @Nullable LocusId locusId, @NonNull  IBinder appToken) {
+            if (locusId == null) return;
             Event event = new Event(LOCUS_ID_SET, SystemClock.elapsedRealtime());
             event.mLocusId = locusId.getId();
             event.mPackage = activity.getPackageName();
diff --git a/telephony/java/android/telephony/CellIdentity.java b/telephony/java/android/telephony/CellIdentity.java
index e8a51a9..15147da 100644
--- a/telephony/java/android/telephony/CellIdentity.java
+++ b/telephony/java/android/telephony/CellIdentity.java
@@ -37,7 +37,7 @@
 public abstract class CellIdentity implements Parcelable {
 
     /** @hide */
-    public static final int INVALID_CHANNEL_NUMBER = -1;
+    public static final int INVALID_CHANNEL_NUMBER = Integer.MAX_VALUE;
 
     /**
      * parameters for validation
diff --git a/telephony/java/android/telephony/PhysicalChannelConfig.java b/telephony/java/android/telephony/PhysicalChannelConfig.java
index fadf0e1..a012498 100644
--- a/telephony/java/android/telephony/PhysicalChannelConfig.java
+++ b/telephony/java/android/telephony/PhysicalChannelConfig.java
@@ -50,7 +50,7 @@
     public static final int CONNECTION_UNKNOWN = -1;
 
     /** Channel number is unknown. */
-    public static final int CHANNEL_NUMBER_UNKNOWN = -1;
+    public static final int CHANNEL_NUMBER_UNKNOWN = Integer.MAX_VALUE;
 
     /** Physical Cell Id is unknown. */
     public static final int PHYSICAL_CELL_ID_UNKNOWN = -1;
diff --git a/telephony/java/android/telephony/ims/ProvisioningManager.java b/telephony/java/android/telephony/ims/ProvisioningManager.java
index 8fb3b4d..85cd81b 100644
--- a/telephony/java/android/telephony/ims/ProvisioningManager.java
+++ b/telephony/java/android/telephony/ims/ProvisioningManager.java
@@ -1023,7 +1023,8 @@
          * server) or other operator defined triggers. If RCS provisioning is already
          * completed at the time of callback registration, then this method shall be
          * invoked with the current configuration
-         * @param configXml The RCS configurationXML received OTA.
+         * @param configXml The RCS configuration XML received by OTA. It is defined
+         * by GSMA RCC.07.
          */
         public void onConfigurationChanged(@NonNull byte[] configXml) {}
 
@@ -1390,7 +1391,9 @@
      * provisioning is done using autoconfiguration, then these parameters shall be
      * sent in the HTTP get request to fetch the RCS provisioning. RCS client
      * configuration must be provided by the application before registering for the
-     * provisioning status events {@link #registerRcsProvisioningChangedCallback}
+     * provisioning status events {@link #registerRcsProvisioningCallback()}
+     * When the IMS/RCS service receives the RCS client configuration, it will detect
+     * the change in the configuration, and trigger the auto-configuration as needed.
      * @param rcc RCS client configuration {@link RcsClientConfiguration}
      */
     @RequiresPermission(Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION)
@@ -1457,7 +1460,7 @@
     *
     * @param executor The {@link Executor} to call the callback methods on
     * @param callback The rcs provisioning callback to be registered.
-    * @see #unregisterRcsProvisioningChangedCallback(RcsProvisioningCallback)
+    * @see #unregisterRcsProvisioningCallback(RcsProvisioningCallback)
     * @see SubscriptionManager.OnSubscriptionsChangedListener
     * @throws IllegalArgumentException if the subscription associated with this
     * callback is not active (SIM is not inserted, ESIM inactive) or the
@@ -1473,12 +1476,12 @@
     */
     @RequiresPermission(anyOf = {Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
             Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION})
-    public void registerRcsProvisioningChangedCallback(
+    public void registerRcsProvisioningCallback(
             @NonNull @CallbackExecutor Executor executor,
             @NonNull RcsProvisioningCallback callback) throws ImsException {
         callback.setExecutor(executor);
         try {
-            getITelephony().registerRcsProvisioningChangedCallback(mSubId, callback.getBinder());
+            getITelephony().registerRcsProvisioningCallback(mSubId, callback.getBinder());
         } catch (ServiceSpecificException e) {
             throw new ImsException(e.getMessage(), e.errorCode);
         } catch (RemoteException | IllegalStateException e) {
@@ -1504,16 +1507,16 @@
      *
      * @param callback The existing {@link RcsProvisioningCallback} to be
      * removed.
-     * @see #registerRcsProvisioningChangedCallback
-     * @throws IllegalArgumentException if the subscription associated with this callback is
-     * invalid.
+     * @see #registerRcsProvisioningCallback(Executor, RcsProvisioningCallback)
+     * @throws IllegalArgumentException if the subscription associated with
+     * this callback is invalid.
      */
     @RequiresPermission(anyOf = {Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
             Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION})
-    public void unregisterRcsProvisioningChangedCallback(
+    public void unregisterRcsProvisioningCallback(
             @NonNull RcsProvisioningCallback callback) {
         try {
-            getITelephony().unregisterRcsProvisioningChangedCallback(
+            getITelephony().unregisterRcsProvisioningCallback(
                     mSubId, callback.getBinder());
         } catch (RemoteException e) {
             throw e.rethrowAsRuntimeException();
@@ -1523,6 +1526,14 @@
     /**
      * Reconfiguration triggered by the RCS application. Most likely cause
      * is the 403 forbidden to a HTTP request.
+     *
+     * <p>When this api is called, the RCS configuration for the associated
+     * subscription will be removed, and the application which has registered
+     * {@link RcsProvisioningCallback} may expect to receive
+     * {@link RcsProvisioningCallback#onConfigurationReset}, then
+     * {@link RcsProvisioningCallback#onConfigurationChanged} when the new
+     * RCS configuration is received and notified by
+     * {@link #notifyRcsAutoConfigurationReceived}
      */
     @RequiresPermission(Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION)
     public void triggerRcsReconfiguration() {
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 7e04baa..40b8696 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -2302,13 +2302,12 @@
     /**
      * Register RCS provisioning callback.
      */
-    void registerRcsProvisioningChangedCallback(int subId,
-            IRcsConfigCallback callback);
+    void registerRcsProvisioningCallback(int subId, IRcsConfigCallback callback);
 
     /**
      * Unregister RCS provisioning callback.
      */
-    void unregisterRcsProvisioningChangedCallback(int subId, IRcsConfigCallback callback);
+    void unregisterRcsProvisioningCallback(int subId, IRcsConfigCallback callback);
 
     /**
      * trigger RCS reconfiguration.
diff --git a/tests/DpiTest/src/com/google/android/test/dpi/DpiTestActivity.java b/tests/DpiTest/src/com/google/android/test/dpi/DpiTestActivity.java
index 01c1c70..cf501ae 100644
--- a/tests/DpiTest/src/com/google/android/test/dpi/DpiTestActivity.java
+++ b/tests/DpiTest/src/com/google/android/test/dpi/DpiTestActivity.java
@@ -19,23 +19,23 @@
 import android.app.Activity;
 import android.app.ActivityThread;
 import android.app.Application;
-import android.os.Bundle;
-import android.graphics.BitmapFactory;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-import android.widget.ScrollView;
-import android.view.LayoutInflater;
-import android.view.View;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.res.CompatibilityInfo;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
 import android.util.DisplayMetrics;
 import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.LinearLayout;
+import android.widget.ScrollView;
+import android.widget.TextView;
 
 public class DpiTestActivity extends Activity {
     public DpiTestActivity() {
@@ -64,7 +64,7 @@
                     | ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES;
                 app.getResources().setCompatibilityInfo(new CompatibilityInfo(ai,
                         getResources().getConfiguration().screenLayout,
-                        getResources().getConfiguration().smallestScreenWidthDp, false));
+                        getResources().getConfiguration().smallestScreenWidthDp, false, 1f));
             }
         } catch (PackageManager.NameNotFoundException e) {
             throw new RuntimeException("ouch", e);
diff --git a/tests/net/Android.bp b/tests/net/Android.bp
index 8122495..7f0318a 100644
--- a/tests/net/Android.bp
+++ b/tests/net/Android.bp
@@ -70,7 +70,7 @@
         "mockito-target-minus-junit4",
         "net-tests-utils",
         "platform-test-annotations",
-        "service-connectivity",
+        "service-connectivity-pre-jarjar",
         "services.core",
         "services.net",
     ],
diff --git a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
index 5d0e016..ddc31bf 100644
--- a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
+++ b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
@@ -211,7 +211,7 @@
         nc1 = new NetworkCapabilities().addTransportType(TRANSPORT_WIFI);
         nc2 = new NetworkCapabilities()
                 .addTransportType(TRANSPORT_WIFI)
-                .setNetworkSpecifier(new StringNetworkSpecifier("specs"));
+                .setNetworkSpecifier(new EthernetNetworkSpecifier("eth42"));
         assertNotEquals("", nc1.describeImmutableDifferences(nc2));
         assertEquals("", nc1.describeImmutableDifferences(nc1));
     }
@@ -671,7 +671,7 @@
         NetworkCapabilities nc1 = new NetworkCapabilities();
         nc1.addTransportType(TRANSPORT_CELLULAR).addTransportType(TRANSPORT_WIFI);
         try {
-            nc1.setNetworkSpecifier(new StringNetworkSpecifier("specs"));
+            nc1.setNetworkSpecifier(new EthernetNetworkSpecifier("eth0"));
             fail("Cannot set NetworkSpecifier on a NetworkCapability with multiple transports!");
         } catch (IllegalStateException expected) {
             // empty
@@ -680,7 +680,7 @@
         // Sequence 2: Transport + NetworkSpecifier + Transport
         NetworkCapabilities nc2 = new NetworkCapabilities();
         nc2.addTransportType(TRANSPORT_CELLULAR).setNetworkSpecifier(
-                new StringNetworkSpecifier("specs"));
+                new EthernetNetworkSpecifier("testtap3"));
         try {
             nc2.addTransportType(TRANSPORT_WIFI);
             fail("Cannot set a second TransportType of a network which has a NetworkSpecifier!");
diff --git a/tests/net/common/java/android/net/NetworkProviderTest.kt b/tests/net/common/java/android/net/NetworkProviderTest.kt
index bcc9072..71a7a7c 100644
--- a/tests/net/common/java/android/net/NetworkProviderTest.kt
+++ b/tests/net/common/java/android/net/NetworkProviderTest.kt
@@ -102,7 +102,7 @@
         mCm.registerNetworkProvider(provider)
         assertNotEquals(provider.getProviderId(), NetworkProvider.ID_NONE)
 
-        val specifier = StringNetworkSpecifier(UUID.randomUUID().toString())
+        val specifier = EthernetNetworkSpecifier(UUID.randomUUID().toString())
         val nr: NetworkRequest = NetworkRequest.Builder()
                 .addTransportType(TRANSPORT_TEST)
                 .setNetworkSpecifier(specifier)
@@ -183,7 +183,7 @@
 
         mCm.registerNetworkProvider(provider)
 
-        val specifier = StringNetworkSpecifier(UUID.randomUUID().toString())
+        val specifier = EthernetNetworkSpecifier(UUID.randomUUID().toString())
         val nr: NetworkRequest = NetworkRequest.Builder()
                 .addTransportType(TRANSPORT_TEST)
                 .setNetworkSpecifier(specifier)
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index d725171..2c6a21a 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -72,6 +72,7 @@
 import static android.net.NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_RCS;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_SUPL;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_WIFI_P2P;
@@ -5574,7 +5575,7 @@
         reset(mStatsManager);
 
         // Temp metered change shouldn't update ifaces
-        mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED);
+        mCellNetworkAgent.addCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED);
         waitForIdle();
         verify(mStatsManager, never()).notifyNetworkStatus(eq(Arrays.asList(onlyCell)),
                 any(List.class), eq(MOBILE_IFNAME), any(List.class));
@@ -7808,7 +7809,8 @@
         mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp);
         mCellNetworkAgent.connect(true);
         waitForIdle();
-        verify(mBatteryStatsService).noteNetworkInterfaceForTransports(cellLp.getInterfaceName(),
+        verify(mDeps).reportNetworkInterfaceForTransports(mServiceContext,
+                cellLp.getInterfaceName(),
                 new int[] { TRANSPORT_CELLULAR });
         reset(mBatteryStatsService);
 
@@ -7817,7 +7819,8 @@
         mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, wifiLp);
         mWiFiNetworkAgent.connect(true);
         waitForIdle();
-        verify(mBatteryStatsService).noteNetworkInterfaceForTransports(wifiLp.getInterfaceName(),
+        verify(mDeps).reportNetworkInterfaceForTransports(mServiceContext,
+                wifiLp.getInterfaceName(),
                 new int[] { TRANSPORT_WIFI });
         reset(mBatteryStatsService);
 
@@ -7828,7 +7831,8 @@
         mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp);
         mCellNetworkAgent.connect(true);
         waitForIdle();
-        verify(mBatteryStatsService).noteNetworkInterfaceForTransports(cellLp.getInterfaceName(),
+        verify(mDeps).reportNetworkInterfaceForTransports(mServiceContext,
+                cellLp.getInterfaceName(),
                 new int[] { TRANSPORT_CELLULAR });
         mCellNetworkAgent.disconnect();
     }
@@ -7912,7 +7916,8 @@
         assertRoutesAdded(cellNetId, ipv6Subnet, defaultRoute);
         verify(mMockDnsResolver, times(1)).createNetworkCache(eq(cellNetId));
         verify(mMockNetd, times(1)).networkAddInterface(cellNetId, MOBILE_IFNAME);
-        verify(mBatteryStatsService).noteNetworkInterfaceForTransports(cellLp.getInterfaceName(),
+        verify(mDeps).reportNetworkInterfaceForTransports(mServiceContext,
+                cellLp.getInterfaceName(),
                 new int[] { TRANSPORT_CELLULAR });
 
         networkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
@@ -7933,8 +7938,8 @@
         // Make sure BatteryStats was not told about any v4- interfaces, as none should have
         // come online yet.
         waitForIdle();
-        verify(mBatteryStatsService, never()).noteNetworkInterfaceForTransports(startsWith("v4-"),
-                any());
+        verify(mDeps, never())
+                .reportNetworkInterfaceForTransports(eq(mServiceContext), startsWith("v4-"), any());
 
         verifyNoMoreInteractions(mMockNetd);
         verifyNoMoreInteractions(mMockDnsResolver);
@@ -7986,8 +7991,9 @@
         assertTrue(ArrayUtils.contains(resolvrParams.servers, "8.8.8.8"));
 
         for (final LinkProperties stackedLp : stackedLpsAfterChange) {
-            verify(mBatteryStatsService).noteNetworkInterfaceForTransports(
-                    stackedLp.getInterfaceName(), new int[] { TRANSPORT_CELLULAR });
+            verify(mDeps).reportNetworkInterfaceForTransports(
+                    mServiceContext, stackedLp.getInterfaceName(),
+                    new int[] { TRANSPORT_CELLULAR });
         }
         reset(mMockNetd);
         when(mMockNetd.interfaceGetCfg(CLAT_PREFIX + MOBILE_IFNAME))
@@ -10647,7 +10653,7 @@
                 null,
                 null);
 
-        // default NCs will be unregistered in tearDown
+        // default callbacks will be unregistered in tearDown
     }
 
     /**
@@ -10704,7 +10710,7 @@
                 null,
                 mService.mNoServiceNetwork.network());
 
-        // default NCs will be unregistered in tearDown
+        // default callbacks will be unregistered in tearDown
     }
 
     /**
@@ -10763,7 +10769,7 @@
                 null,
                 mService.mNoServiceNetwork.network());
 
-        // default NCs will be unregistered in tearDown
+        // default callbacks will be unregistered in tearDown
     }
 
     /**
@@ -10822,7 +10828,28 @@
                 null,
                 mService.mNoServiceNetwork.network());
 
-        // default NCs will be unregistered in tearDown
+        // default callbacks will be unregistered in tearDown
+    }
+
+    @Test
+    public void testCapabilityWithOemNetworkPreference() throws Exception {
+        @OemNetworkPreferences.OemNetworkPreference final int networkPref =
+                OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY;
+        setupMultipleDefaultNetworksForOemNetworkPreferenceNotCurrentUidTest(networkPref);
+        registerDefaultNetworkCallbacks();
+
+        setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, true);
+
+        mSystemDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+        mDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+
+        mCellNetworkAgent.addCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED);
+        mSystemDefaultNetworkCallback.expectCapabilitiesThat(mCellNetworkAgent, nc ->
+                nc.hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED));
+        mDefaultNetworkCallback.expectCapabilitiesThat(mCellNetworkAgent, nc ->
+                nc.hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED));
+
+        // default callbacks will be unregistered in tearDown
     }
 
     @Test
diff --git a/tests/net/java/com/android/server/connectivity/MultipathPolicyTrackerTest.java b/tests/net/java/com/android/server/connectivity/MultipathPolicyTrackerTest.java
index 950d7163..38f6d7f 100644
--- a/tests/net/java/com/android/server/connectivity/MultipathPolicyTrackerTest.java
+++ b/tests/net/java/com/android/server/connectivity/MultipathPolicyTrackerTest.java
@@ -46,12 +46,12 @@
 import android.content.pm.ApplicationInfo;
 import android.content.res.Resources;
 import android.net.ConnectivityManager;
+import android.net.EthernetNetworkSpecifier;
 import android.net.Network;
 import android.net.NetworkCapabilities;
 import android.net.NetworkPolicy;
 import android.net.NetworkPolicyManager;
 import android.net.NetworkTemplate;
-import android.net.StringNetworkSpecifier;
 import android.net.TelephonyNetworkSpecifier;
 import android.os.Handler;
 import android.os.UserHandle;
@@ -240,7 +240,7 @@
         NetworkCapabilities capabilities = new NetworkCapabilities()
                 .addCapability(NET_CAPABILITY_INTERNET)
                 .addTransportType(TRANSPORT_CELLULAR)
-                .setNetworkSpecifier(new StringNetworkSpecifier("234"));
+                .setNetworkSpecifier(new EthernetNetworkSpecifier("eth234"));
         if (!roaming) {
             capabilities.addCapability(NET_CAPABILITY_NOT_ROAMING);
         }
diff --git a/tests/vcn/assets/client-end-cert.pem b/tests/vcn/assets/client-end-cert.pem
new file mode 100644
index 0000000..e82da85
--- /dev/null
+++ b/tests/vcn/assets/client-end-cert.pem
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDaDCCAlCgAwIBAgIIcorRI3n29E4wDQYJKoZIhvcNAQELBQAwQTELMAkGA1UE
+BhMCVVMxEDAOBgNVBAoTB0FuZHJvaWQxIDAeBgNVBAMTF3R3by5jYS50ZXN0LmFu
+ZHJvaWQubmV0MB4XDTIwMDQxNDA1MDM0OVoXDTIzMDQxNDA1MDM0OVowRTELMAkG
+A1UEBhMCVVMxEDAOBgNVBAoTB0FuZHJvaWQxJDAiBgNVBAMTG2NsaWVudC50ZXN0
+LmlrZS5hbmRyb2lkLm5ldDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
+AK/cK+sIaiQlJYvy5+Dq70sJbgR7PO1uS2qkLRP7Wb3z5SNvz94nQvZRrFn1AFIE
+CpfESh5kUF6gJe7t7NR3mpQ98iEosCRBMDJT8qB+EeHiL4wkrmCE9sYMTyvaApRc
+6Qzozn/9kKma7Qpj/25AvoPluTERqhZ6AQ77BJeb6FNOAoO1Aoe9GJuB1xmRxjRw
+D0mwusL+ciQ/7uKlsFP5VO5XqACcohXSerzO8jcD9necBvka3SDepqqzn1K0NPRC
+25fMmS5kSjddKtKOif7w2NI3OpVsmP3kHv66If73VURsy0lgXPYyKkq8lAMrtmXG
+R7svFGPbEl+Swkpr3b+dzF8CAwEAAaNgMF4wHwYDVR0jBBgwFoAUcqSu1uRYT/DL
+bLoDNUz38nGvCKQwJgYDVR0RBB8wHYIbY2xpZW50LnRlc3QuaWtlLmFuZHJvaWQu
+bmV0MBMGA1UdJQQMMAoGCCsGAQUFBwMCMA0GCSqGSIb3DQEBCwUAA4IBAQCa53tK
+I9RM9/MutZ5KNG2Gfs2cqaPyv8ZRhs90HDWZhkFVu7prywJAxOd2hxxHPsvgurio
+4bKAxnT4EXevgz5YoCbj2TPIL9TdFYh59zZ97XXMxk+SRdypgF70M6ETqKPs3hDP
+ZRMMoHvvYaqaPvp4StSBX9A44gSyjHxVYJkrjDZ0uffKg5lFL5IPvqfdmSRSpGab
+SyGTP4OLTy0QiNV3pBsJGdl0h5BzuTPR9OTl4xgeqqBQy2bDjmfJBuiYyCSCkPi7
+T3ohDYCymhuSkuktHPNG1aKllUJaw0tuZuNydlgdAveXPYfM36uvK0sfd9qr9pAy
+rmkYV2MAWguFeckh
+-----END CERTIFICATE-----
\ No newline at end of file
diff --git a/tests/vcn/assets/client-private-key.key b/tests/vcn/assets/client-private-key.key
new file mode 100644
index 0000000..22736e9
--- /dev/null
+++ b/tests/vcn/assets/client-private-key.key
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCv3CvrCGokJSWL
+8ufg6u9LCW4EezztbktqpC0T+1m98+Ujb8/eJ0L2UaxZ9QBSBAqXxEoeZFBeoCXu
+7ezUd5qUPfIhKLAkQTAyU/KgfhHh4i+MJK5ghPbGDE8r2gKUXOkM6M5//ZCpmu0K
+Y/9uQL6D5bkxEaoWegEO+wSXm+hTTgKDtQKHvRibgdcZkcY0cA9JsLrC/nIkP+7i
+pbBT+VTuV6gAnKIV0nq8zvI3A/Z3nAb5Gt0g3qaqs59StDT0QtuXzJkuZEo3XSrS
+jon+8NjSNzqVbJj95B7+uiH+91VEbMtJYFz2MipKvJQDK7Zlxke7LxRj2xJfksJK
+a92/ncxfAgMBAAECggEAQztaMvW5lm35J8LKsWs/5qEJRX9T8LWs8W0oqq36Riub
+G2wgvR6ndAIPcSjAYZqX7iOl7m6NZ0+0kN63HxdGqovwKIskpAekBGmhpYftED1n
+zh0r6UyMB3UnQ22KdOv8UOokIDxxdNX8728BdUYdT9Ggdkj5jLRB+VcwD0IUlNvo
+zzTpURV9HEd87uiLqd4AAHXSI0lIHI5U43z24HI/J6/YbYHT3Rlh6CIa/LuwO6vL
+gFkgqg0/oy6yJtjrHtzNVA67F0UaH62hR4YFgbC0d955SJnDidWOv/0j2DMpfdCc
+9kFAcPwUSyykvUSLnGIKWSG4D+6gzIeAeUx4oO7kMQKBgQDVNRkX8AGTHyLg+NXf
+spUWWcodwVioXl30Q7h6+4bt8OI61UbhQ7wX61wvJ1cySpa2KOYa2UdagQVhGhhL
+ADu363R77uXF/jZgzVfmjjyJ2nfDqRgHWRTlSkuq/jCOQCz7VIPHRZg5WL/9D4ms
+TAqMjpzqeMfFZI+w4/+xpcJIuQKBgQDTKBy+ZuerWrVT9icWKvLU58o5EVj/2yFy
+GJvKm+wRAAX2WzjNnR4HVd4DmMREVz1BPYby0j5gqjvtDsxYYu39+NT7JvMioLLK
+QPj+7k5geYgNqVgCxB1vP89RhY2X1RLrN9sTXOodgFPeXOQWNYITkGp3eQpx4nTJ
++K/al3oB1wKBgAjnc8nVIyuyxDEjE0OJYMKTM2a0uXAmqMPXxC+Wq5bqVXhhidlE
+i+lv0eTCPtkB1nN7F8kNQ/aaps/cWCFhvBy9P5shagUvzbOTP9WIIS0cq53HRRKh
+fMbqqGhWv05hjb9dUzeSR341n6cA7B3++v3Nwu3j52vt/DZF/1q68nc5AoGAS0SU
+ImbKE/GsizZGLoe2sZ/CHN+LKwCwhlwxRGKaHmE0vuE7eUeVSaYZEo0lAPtb8WJ+
+NRYueASWgeTxgFwbW5mUScZTirdfo+rPFwhZVdhcYApKPgosN9i2DOgfVcz1BnWN
+mPRY25U/0BaqkyQVruWeneG+kGPZn5kPDktKiVcCgYEAkzwU9vCGhm7ZVALvx/zR
+wARz2zsL9ImBc0P4DK1ld8g90FEnHrEgeI9JEwz0zFHOCMLwlk7kG0Xev7vfjZ7G
+xSqtQYOH33Qp6rtBOgdt8hSyDFvakvDl6bqhAw52gelO3MTpAB1+ZsfZ5gFx13Jf
+idNFcaIrC52PtZIH7QCzdDY=
+-----END PRIVATE KEY-----
\ No newline at end of file
diff --git a/tests/vcn/java/android/net/vcn/VcnControlPlaneIkeConfigTest.java b/tests/vcn/java/android/net/vcn/VcnControlPlaneIkeConfigTest.java
index 36f5e41..2333718 100644
--- a/tests/vcn/java/android/net/vcn/VcnControlPlaneIkeConfigTest.java
+++ b/tests/vcn/java/android/net/vcn/VcnControlPlaneIkeConfigTest.java
@@ -99,6 +99,13 @@
     }
 
     @Test
+    public void testPersistableBundle() {
+        final VcnControlPlaneIkeConfig config = buildTestConfig();
+
+        assertEquals(config, new VcnControlPlaneIkeConfig(config.toPersistableBundle()));
+    }
+
+    @Test
     public void testConstructConfigWithoutIkeParams() {
         try {
             new VcnControlPlaneIkeConfig(null, CHILD_PARAMS);
diff --git a/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java b/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java
new file mode 100644
index 0000000..546d957
--- /dev/null
+++ b/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java
@@ -0,0 +1,189 @@
+/*
+ * 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.vcn.persistablebundleutils;
+
+import static android.system.OsConstants.AF_INET;
+import static android.system.OsConstants.AF_INET6;
+import static android.telephony.TelephonyManager.APPTYPE_USIM;
+
+import static org.junit.Assert.assertEquals;
+
+import android.net.InetAddresses;
+import android.net.eap.EapSessionConfig;
+import android.net.ipsec.ike.IkeFqdnIdentification;
+import android.net.ipsec.ike.IkeSessionParams;
+import android.os.PersistableBundle;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.org.bouncycastle.util.io.pem.PemObject;
+import com.android.internal.org.bouncycastle.util.io.pem.PemReader;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.nio.charset.StandardCharsets;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.security.interfaces.RSAPrivateKey;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class IkeSessionParamsUtilsTest {
+    private static IkeSessionParams.Builder createBuilderMinimum() {
+        final InetAddress serverAddress = InetAddresses.parseNumericAddress("192.0.2.100");
+
+        return new IkeSessionParams.Builder()
+                .setServerHostname(serverAddress.getHostAddress())
+                .addSaProposal(SaProposalUtilsTest.buildTestIkeSaProposal())
+                .setLocalIdentification(new IkeFqdnIdentification("client.test.android.net"))
+                .setRemoteIdentification(new IkeFqdnIdentification("server.test.android.net"))
+                .setAuthPsk("psk".getBytes());
+    }
+
+    private static void verifyPersistableBundleEncodeDecodeIsLossless(IkeSessionParams params) {
+        final PersistableBundle bundle = IkeSessionParamsUtils.toPersistableBundle(params);
+        final IkeSessionParams result = IkeSessionParamsUtils.fromPersistableBundle(bundle);
+
+        assertEquals(result, params);
+    }
+
+    @Test
+    public void testEncodeRecodeParamsWithLifetimes() throws Exception {
+        final int hardLifetime = (int) TimeUnit.HOURS.toSeconds(20L);
+        final int softLifetime = (int) TimeUnit.HOURS.toSeconds(10L);
+        final IkeSessionParams params =
+                createBuilderMinimum().setLifetimeSeconds(hardLifetime, softLifetime).build();
+        verifyPersistableBundleEncodeDecodeIsLossless(params);
+    }
+
+    @Test
+    public void testEncodeRecodeParamsWithDpdDelay() throws Exception {
+        final int dpdDelay = (int) TimeUnit.MINUTES.toSeconds(10L);
+        final IkeSessionParams params = createBuilderMinimum().setDpdDelaySeconds(dpdDelay).build();
+
+        verifyPersistableBundleEncodeDecodeIsLossless(params);
+    }
+
+    @Test
+    public void testEncodeRecodeParamsWithNattKeepalive() throws Exception {
+        final int nattKeepAliveDelay = (int) TimeUnit.MINUTES.toSeconds(5L);
+        final IkeSessionParams params =
+                createBuilderMinimum().setNattKeepAliveDelaySeconds(nattKeepAliveDelay).build();
+
+        verifyPersistableBundleEncodeDecodeIsLossless(params);
+    }
+
+    @Test
+    public void testEncodeRecodeParamsWithRetransmissionTimeouts() throws Exception {
+        final int[] retransmissionTimeout = new int[] {500, 500, 500, 500, 500, 500};
+        final IkeSessionParams params =
+                createBuilderMinimum()
+                        .setRetransmissionTimeoutsMillis(retransmissionTimeout)
+                        .build();
+
+        verifyPersistableBundleEncodeDecodeIsLossless(params);
+    }
+
+    @Test
+    public void testEncodeRecodeParamsWithConfigRequests() throws Exception {
+        final Inet4Address ipv4Address =
+                (Inet4Address) InetAddresses.parseNumericAddress("192.0.2.100");
+        final Inet6Address ipv6Address =
+                (Inet6Address) InetAddresses.parseNumericAddress("2001:db8::1");
+
+        final IkeSessionParams params =
+                createBuilderMinimum()
+                        .addPcscfServerRequest(AF_INET)
+                        .addPcscfServerRequest(AF_INET6)
+                        .addPcscfServerRequest(ipv4Address)
+                        .addPcscfServerRequest(ipv6Address)
+                        .build();
+        verifyPersistableBundleEncodeDecodeIsLossless(params);
+    }
+
+    @Test
+    public void testEncodeRecodeParamsWithAuthPsk() throws Exception {
+        final IkeSessionParams params = createBuilderMinimum().setAuthPsk("psk".getBytes()).build();
+        verifyPersistableBundleEncodeDecodeIsLossless(params);
+    }
+
+    @Test
+    public void testEncodeRecodeParamsWithIkeOptions() throws Exception {
+        final IkeSessionParams params =
+                createBuilderMinimum()
+                        .addIkeOption(IkeSessionParams.IKE_OPTION_ACCEPT_ANY_REMOTE_ID)
+                        .addIkeOption(IkeSessionParams.IKE_OPTION_MOBIKE)
+                        .build();
+        verifyPersistableBundleEncodeDecodeIsLossless(params);
+    }
+
+    private static InputStream openAssetsFile(String fileName) throws Exception {
+        return InstrumentationRegistry.getContext().getResources().getAssets().open(fileName);
+    }
+
+    private static X509Certificate createCertFromPemFile(String fileName) throws Exception {
+        final CertificateFactory factory = CertificateFactory.getInstance("X.509");
+        return (X509Certificate) factory.generateCertificate(openAssetsFile(fileName));
+    }
+
+    private static RSAPrivateKey createRsaPrivateKeyFromKeyFile(String fileName) throws Exception {
+        final PemObject pemObject =
+                new PemReader(new InputStreamReader(openAssetsFile(fileName))).readPemObject();
+        return (RSAPrivateKey) CertUtils.privateKeyFromByteArray(pemObject.getContent());
+    }
+
+    @Test
+    public void testEncodeRecodeParamsWithDigitalSignAuth() throws Exception {
+        final X509Certificate serverCaCert = createCertFromPemFile("self-signed-ca.pem");
+        final X509Certificate clientEndCert = createCertFromPemFile("client-end-cert.pem");
+        final RSAPrivateKey clientPrivateKey =
+                createRsaPrivateKeyFromKeyFile("client-private-key.key");
+
+        final IkeSessionParams params =
+                createBuilderMinimum()
+                        .setAuthDigitalSignature(serverCaCert, clientEndCert, clientPrivateKey)
+                        .build();
+        verifyPersistableBundleEncodeDecodeIsLossless(params);
+    }
+
+    @Test
+    public void testEncodeRecodeParamsWithEapAuth() throws Exception {
+        final X509Certificate serverCaCert = createCertFromPemFile("self-signed-ca.pem");
+
+        final byte[] eapId = "test@android.net".getBytes(StandardCharsets.US_ASCII);
+        final int subId = 1;
+        final EapSessionConfig eapConfig =
+                new EapSessionConfig.Builder()
+                        .setEapIdentity(eapId)
+                        .setEapSimConfig(subId, APPTYPE_USIM)
+                        .setEapAkaConfig(subId, APPTYPE_USIM)
+                        .build();
+
+        final IkeSessionParams params =
+                createBuilderMinimum().setAuthEap(serverCaCert, eapConfig).build();
+        verifyPersistableBundleEncodeDecodeIsLossless(params);
+    }
+}
diff --git a/tests/vcn/java/android/net/vcn/persistablebundleutils/SaProposalUtilsTest.java b/tests/vcn/java/android/net/vcn/persistablebundleutils/SaProposalUtilsTest.java
index 8ae8692..664044a 100644
--- a/tests/vcn/java/android/net/vcn/persistablebundleutils/SaProposalUtilsTest.java
+++ b/tests/vcn/java/android/net/vcn/persistablebundleutils/SaProposalUtilsTest.java
@@ -32,21 +32,25 @@
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class SaProposalUtilsTest {
+    /** Package private so that IkeSessionParamsUtilsTest can use it */
+    static IkeSaProposal buildTestIkeSaProposal() {
+        return new IkeSaProposal.Builder()
+                .addEncryptionAlgorithm(
+                        SaProposal.ENCRYPTION_ALGORITHM_3DES, SaProposal.KEY_LEN_UNUSED)
+                .addEncryptionAlgorithm(
+                        SaProposal.ENCRYPTION_ALGORITHM_AES_CBC, SaProposal.KEY_LEN_AES_128)
+                .addIntegrityAlgorithm(SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96)
+                .addIntegrityAlgorithm(SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_256_128)
+                .addPseudorandomFunction(SaProposal.PSEUDORANDOM_FUNCTION_AES128_XCBC)
+                .addPseudorandomFunction(SaProposal.PSEUDORANDOM_FUNCTION_SHA2_256)
+                .addDhGroup(SaProposal.DH_GROUP_1024_BIT_MODP)
+                .addDhGroup(SaProposal.DH_GROUP_3072_BIT_MODP)
+                .build();
+    }
+
     @Test
     public void testPersistableBundleEncodeDecodeIsLosslessIkeProposal() throws Exception {
-        final IkeSaProposal proposal =
-                new IkeSaProposal.Builder()
-                        .addEncryptionAlgorithm(
-                                SaProposal.ENCRYPTION_ALGORITHM_3DES, SaProposal.KEY_LEN_UNUSED)
-                        .addEncryptionAlgorithm(
-                                SaProposal.ENCRYPTION_ALGORITHM_AES_CBC, SaProposal.KEY_LEN_AES_128)
-                        .addIntegrityAlgorithm(SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96)
-                        .addIntegrityAlgorithm(SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_256_128)
-                        .addPseudorandomFunction(SaProposal.PSEUDORANDOM_FUNCTION_AES128_XCBC)
-                        .addPseudorandomFunction(SaProposal.PSEUDORANDOM_FUNCTION_SHA2_256)
-                        .addDhGroup(SaProposal.DH_GROUP_1024_BIT_MODP)
-                        .addDhGroup(SaProposal.DH_GROUP_3072_BIT_MODP)
-                        .build();
+        final IkeSaProposal proposal = buildTestIkeSaProposal();
 
         final PersistableBundle bundle = IkeSaProposalUtils.toPersistableBundle(proposal);
         final SaProposal resultProposal = IkeSaProposalUtils.fromPersistableBundle(bundle);
diff --git a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
index 73a6b88..11498de 100644
--- a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
+++ b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
@@ -461,6 +461,34 @@
     }
 
     @Test
+    public void testSetVcnConfigNotifiesStatusCallback() throws Exception {
+        mVcnMgmtSvc.systemReady();
+        doReturn(true)
+                .when(mLocationPermissionChecker)
+                .checkLocationPermission(eq(TEST_PACKAGE_NAME), any(), eq(TEST_UID), any());
+        triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_2));
+
+        mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_2, mMockStatusCallback, TEST_PACKAGE_NAME);
+        verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED);
+
+        // Use a different UUID to simulate a new VCN config.
+        mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
+
+        verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_ACTIVE);
+    }
+
+    @Test
+    public void testSetVcnConfigInSafeModeNotifiesStatusCallback() throws Exception {
+        setupSubscriptionAndStartVcn(TEST_SUBSCRIPTION_ID, TEST_UUID_2, false /* isActive */);
+        mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_2, mMockStatusCallback, TEST_PACKAGE_NAME);
+        verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_SAFE_MODE);
+
+        mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
+
+        verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_ACTIVE);
+    }
+
+    @Test
     public void testClearVcnConfigRequiresNonSystemServer() throws Exception {
         doReturn(Process.SYSTEM_UID).when(mMockDeps).getBinderCallingUid();
 
@@ -503,6 +531,17 @@
     }
 
     @Test
+    public void testClearVcnConfigNotifiesStatusCallback() throws Exception {
+        setupSubscriptionAndStartVcn(TEST_SUBSCRIPTION_ID, TEST_UUID_2, true /* isActive */);
+        mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_2, mMockStatusCallback, TEST_PACKAGE_NAME);
+        verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_ACTIVE);
+
+        mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2);
+
+        verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED);
+    }
+
+    @Test
     public void testSetVcnConfigClearVcnConfigStartsUpdatesAndTeardsDownVcns() throws Exception {
         // Use a different UUID to simulate a new VCN config.
         mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
index 69b2fb1..4bf8491 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
@@ -241,7 +241,7 @@
 
         verify(mGatewayStatusCallback)
                 .onGatewayConnectionError(
-                        eq(mConfig.getRequiredUnderlyingCapabilities()),
+                        eq(mConfig.getExposedCapabilities()),
                         eq(VCN_ERROR_CODE_INTERNAL_ERROR),
                         any(),
                         any());
@@ -275,10 +275,7 @@
 
         verify(mGatewayStatusCallback)
                 .onGatewayConnectionError(
-                        eq(mConfig.getRequiredUnderlyingCapabilities()),
-                        eq(expectedErrorType),
-                        any(),
-                        any());
+                        eq(mConfig.getExposedCapabilities()), eq(expectedErrorType), any(), any());
     }
 
     @Test
diff --git a/tests/vcn/java/com/android/server/vcn/VcnTest.java b/tests/vcn/java/com/android/server/vcn/VcnTest.java
index 3dd710a..4fa63d4 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnTest.java
@@ -22,7 +22,9 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.argThat;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doReturn;
@@ -48,6 +50,7 @@
 import org.junit.Test;
 import org.mockito.ArgumentCaptor;
 
+import java.util.Arrays;
 import java.util.Set;
 import java.util.UUID;
 
@@ -58,7 +61,7 @@
     private static final int PROVIDER_ID = 5;
     private static final int[][] TEST_CAPS =
             new int[][] {
-                new int[] {NET_CAPABILITY_INTERNET, NET_CAPABILITY_MMS},
+                new int[] {NET_CAPABILITY_MMS, NET_CAPABILITY_INTERNET},
                 new int[] {NET_CAPABILITY_DUN}
             };
 
@@ -155,14 +158,6 @@
         }
     }
 
-    @Test
-    public void testGatewayEnteringSafeModeNotifiesVcn() {
-        final NetworkRequestListener requestListener = verifyAndGetRequestListener();
-        for (final int capability : VcnGatewayConnectionConfigTest.EXPOSED_CAPS) {
-            startVcnGatewayWithCapabilities(requestListener, capability);
-        }
-    }
-
     private void triggerVcnRequestListeners(NetworkRequestListener requestListener) {
         for (final int[] caps : TEST_CAPS) {
             startVcnGatewayWithCapabilities(requestListener, caps);
@@ -188,8 +183,20 @@
         return gatewayConnections;
     }
 
+    private void verifySafeMode(
+            NetworkRequestListener requestListener,
+            Set<VcnGatewayConnection> expectedGatewaysTornDown) {
+        assertFalse(mVcn.isActive());
+        assertTrue(mVcn.getVcnGatewayConnections().isEmpty());
+        for (final VcnGatewayConnection gatewayConnection : expectedGatewaysTornDown) {
+            verify(gatewayConnection).teardownAsynchronously();
+        }
+        verify(mVcnNetworkProvider).unregisterListener(requestListener);
+        verify(mVcnCallback).onEnteredSafeMode();
+    }
+
     @Test
-    public void testGatewayEnteringSafemodeNotifiesVcn() {
+    public void testGatewayEnteringSafeModeNotifiesVcn() {
         final NetworkRequestListener requestListener = verifyAndGetRequestListener();
         final Set<VcnGatewayConnection> gatewayConnections =
                 startGatewaysAndGetGatewayConnections(requestListener);
@@ -200,12 +207,7 @@
         statusCallback.onEnteredSafeMode();
         mTestLooper.dispatchAll();
 
-        assertFalse(mVcn.isActive());
-        for (final VcnGatewayConnection gatewayConnection : gatewayConnections) {
-            verify(gatewayConnection).teardownAsynchronously();
-        }
-        verify(mVcnNetworkProvider).unregisterListener(requestListener);
-        verify(mVcnCallback).onEnteredSafeMode();
+        verifySafeMode(requestListener, gatewayConnections);
     }
 
     @Test
@@ -234,4 +236,39 @@
                         any(),
                         mGatewayStatusCallbackCaptor.capture());
     }
+
+    @Test
+    public void testUpdateConfigExitsSafeMode() {
+        final NetworkRequestListener requestListener = verifyAndGetRequestListener();
+        final Set<VcnGatewayConnection> gatewayConnections =
+                new ArraySet<>(startGatewaysAndGetGatewayConnections(requestListener));
+
+        final VcnGatewayStatusCallback statusCallback = mGatewayStatusCallbackCaptor.getValue();
+        statusCallback.onEnteredSafeMode();
+        mTestLooper.dispatchAll();
+        verifySafeMode(requestListener, gatewayConnections);
+
+        doAnswer(invocation -> {
+            final NetworkRequestListener listener = invocation.getArgument(0);
+            triggerVcnRequestListeners(listener);
+            return null;
+        }).when(mVcnNetworkProvider).registerListener(eq(requestListener));
+
+        mVcn.updateConfig(mConfig);
+        mTestLooper.dispatchAll();
+
+        // Registered on start, then re-registered with new configs
+        verify(mVcnNetworkProvider, times(2)).registerListener(eq(requestListener));
+        assertTrue(mVcn.isActive());
+        for (final int[] caps : TEST_CAPS) {
+            // Expect each gateway connection created on initial startup, and again with new configs
+            verify(mDeps, times(2))
+                    .newVcnGatewayConnection(
+                            eq(mVcnContext),
+                            eq(TEST_SUB_GROUP),
+                            eq(mSubscriptionSnapshot),
+                            argThat(config -> Arrays.equals(caps, config.getExposedCapabilities())),
+                            any());
+        }
+    }
 }