Merge "Fix CDM association filtering" into sc-dev
diff --git a/Android.bp b/Android.bp
index 622b2c6..9690969 100644
--- a/Android.bp
+++ b/Android.bp
@@ -665,9 +665,8 @@
     ],
     required: [
         "framework-platform-compat-config",
-        // TODO: remove gps_debug, cec_config.xml and protolog.conf.json when the build system propagates "required" properly.
+        // TODO: remove gps_debug and protolog.conf.json when the build system propagates "required" properly.
         "gps_debug.conf",
-        "cec_config.xml",
         "icu4j-platform-compat-config",
         "libcore-platform-compat-config",
         "protolog.conf.json.gz",
diff --git a/apex/jobscheduler/framework/java/android/os/DeviceIdleManager.java b/apex/jobscheduler/framework/java/android/os/DeviceIdleManager.java
index 752c36e..6cdf585 100644
--- a/apex/jobscheduler/framework/java/android/os/DeviceIdleManager.java
+++ b/apex/jobscheduler/framework/java/android/os/DeviceIdleManager.java
@@ -65,7 +65,7 @@
      * @return package names the system has white-listed to opt out of power save restrictions,
      * except for device idle mode.
      *
-     * @hide Should be migrated to PowerWhitelistManager
+     * @hide Should be migrated to PowerExemptionManager
      */
     @TestApi
     public @NonNull String[] getSystemPowerWhitelistExceptIdle() {
@@ -80,7 +80,7 @@
      * @return package names the system has white-listed to opt out of power save restrictions for
      * all modes.
      *
-     * @hide Should be migrated to PowerWhitelistManager
+     * @hide Should be migrated to PowerExemptionManager
      */
     @TestApi
     public @NonNull String[] getSystemPowerWhitelist() {
diff --git a/apex/jobscheduler/framework/java/android/os/IDeviceIdleController.aidl b/apex/jobscheduler/framework/java/android/os/IDeviceIdleController.aidl
index 43d4873..9d18dfe 100644
--- a/apex/jobscheduler/framework/java/android/os/IDeviceIdleController.aidl
+++ b/apex/jobscheduler/framework/java/android/os/IDeviceIdleController.aidl
@@ -42,7 +42,7 @@
     boolean isPowerSaveWhitelistExceptIdleApp(String name);
     boolean isPowerSaveWhitelistApp(String name);
     @UnsupportedAppUsage(maxTargetSdk = 30,
-     publicAlternatives = "Use SystemApi {@code PowerWhitelistManager#whitelistAppTemporarily(String, int, String)}.")
+     publicAlternatives = "Use SystemApi {@code PowerExemptionManager#addToTemporaryAllowList(String, int, int, String)}.")
     void addPowerSaveTempWhitelistApp(String name, long duration, int userId, int reasonCode, String reason);
     long addPowerSaveTempWhitelistAppForMms(String name, int userId, int reasonCode, String reason);
     long addPowerSaveTempWhitelistAppForSms(String name, int userId, int reasonCode, String reason);
diff --git a/apex/jobscheduler/framework/java/android/os/PowerExemptionManager.java b/apex/jobscheduler/framework/java/android/os/PowerExemptionManager.java
index 8445335..d9a49aa 100644
--- a/apex/jobscheduler/framework/java/android/os/PowerExemptionManager.java
+++ b/apex/jobscheduler/framework/java/android/os/PowerExemptionManager.java
@@ -170,7 +170,7 @@
     /** @hide */
     public static final int REASON_EXEMPTED_PACKAGE = 64;
     /** @hide */
-    public static final int REASON_ALLOWLISTED_PACKAGE  = 65;
+    public static final int REASON_ALLOWLISTED_PACKAGE = 65;
     /** @hide */
     public static final int REASON_APPOP = 66;
 
@@ -193,6 +193,10 @@
      * Set temp-allow-list for activity recognition.
      */
     public static final int REASON_ACTIVITY_RECOGNITION = 103;
+    /**
+     * Set temp-allow-list for transferring accounts between users.
+     */
+    public static final int REASON_ACCOUNT_TRANSFER = 104;
 
     /* Reason code range 200-299 are reserved for broadcast actions */
     /**
@@ -216,7 +220,7 @@
      * Device idle system allow list, including EXCEPT-IDLE
      * @hide
      */
-    public static final int REASON_SYSTEM_ALLOW_LISTED  = 300;
+    public static final int REASON_SYSTEM_ALLOW_LISTED = 300;
     /** @hide */
     public static final int REASON_ALARM_MANAGER_ALARM_CLOCK = 301;
     /**
@@ -329,6 +333,7 @@
             REASON_PUSH_MESSAGING,
             REASON_PUSH_MESSAGING_OVER_QUOTA,
             REASON_ACTIVITY_RECOGNITION,
+            REASON_ACCOUNT_TRANSFER,
             REASON_BOOT_COMPLETED,
             REASON_PRE_BOOT_COMPLETED,
             REASON_LOCKED_BOOT_COMPLETED,
@@ -579,6 +584,8 @@
                 return "PUSH_MESSAGING_OVER_QUOTA";
             case REASON_ACTIVITY_RECOGNITION:
                 return "ACTIVITY_RECOGNITION";
+            case REASON_ACCOUNT_TRANSFER:
+                return "REASON_ACCOUNT_TRANSFER";
             case REASON_BOOT_COMPLETED:
                 return "BOOT_COMPLETED";
             case REASON_PRE_BOOT_COMPLETED:
diff --git a/apex/jobscheduler/framework/java/android/os/PowerWhitelistManager.java b/apex/jobscheduler/framework/java/android/os/PowerWhitelistManager.java
index b1b733a..eba39c7 100644
--- a/apex/jobscheduler/framework/java/android/os/PowerWhitelistManager.java
+++ b/apex/jobscheduler/framework/java/android/os/PowerWhitelistManager.java
@@ -16,13 +16,6 @@
 
 package android.os;
 
-import static android.app.ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
-import static android.app.ActivityManager.PROCESS_STATE_BOUND_TOP;
-import static android.app.ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
-import static android.app.ActivityManager.PROCESS_STATE_PERSISTENT;
-import static android.app.ActivityManager.PROCESS_STATE_PERSISTENT_UI;
-import static android.app.ActivityManager.PROCESS_STATE_TOP;
-
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -33,7 +26,6 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
-import java.util.Collections;
 import java.util.List;
 
 /**
@@ -43,9 +35,11 @@
  * placed on the temporary whitelist are removed from that whitelist after a predetermined amount of
  * time.
  *
+ * @deprecated Use {@link PowerExemptionManager} instead
  * @hide
  */
 @SystemApi
+@Deprecated
 @SystemService(Context.POWER_WHITELIST_MANAGER)
 public class PowerWhitelistManager {
     private final Context mContext;
@@ -53,21 +47,23 @@
     // TODO: migrate to PowerWhitelistController
     private final IDeviceIdleController mService;
 
+    private final PowerExemptionManager mPowerExemptionManager;
+
     /**
      * Indicates that an unforeseen event has occurred and the app should be whitelisted to handle
      * it.
      */
-    public static final int EVENT_UNSPECIFIED = 0;
+    public static final int EVENT_UNSPECIFIED = PowerExemptionManager.EVENT_UNSPECIFIED;
 
     /**
      * Indicates that an SMS event has occurred and the app should be whitelisted to handle it.
      */
-    public static final int EVENT_SMS = 1;
+    public static final int EVENT_SMS = PowerExemptionManager.EVENT_SMS;
 
     /**
      * Indicates that an MMS event has occurred and the app should be whitelisted to handle it.
      */
-    public static final int EVENT_MMS = 2;
+    public static final int EVENT_MMS = PowerExemptionManager.EVENT_MMS;
 
     /**
      * @hide
@@ -84,12 +80,14 @@
     /**
      * Allow the temp allowlist behavior, plus allow foreground service start from background.
      */
-    public static final int TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED = 0;
+    public static final int TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED =
+            PowerExemptionManager.TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
     /**
      * Only allow the temp allowlist behavior, not allow foreground service start from
      * background.
      */
-    public static final int TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED = 1;
+    public static final int TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED =
+            PowerExemptionManager.TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED;
 
     /**
      * The list of temp allowlist types.
@@ -107,73 +105,83 @@
      * BG-FGS-launch is denied.
      * @hide
      */
-    public static final int REASON_DENIED = -1;
+    public static final int REASON_DENIED = PowerExemptionManager.REASON_DENIED;
 
     /* Reason code range 0-9 are reserved for default reasons */
     /**
      * The default reason code if reason is unknown.
      */
-    public static final int REASON_UNKNOWN = 0;
+    public static final int REASON_UNKNOWN = PowerExemptionManager.REASON_UNKNOWN;
     /**
      * Use REASON_OTHER if there is no better choice.
      */
-    public static final int REASON_OTHER = 1;
+    public static final int REASON_OTHER = PowerExemptionManager.REASON_OTHER;
 
     /* Reason code range 10-49 are reserved for BG-FGS-launch allowed proc states */
     /** @hide */
-    public static final int REASON_PROC_STATE_PERSISTENT = 10;
+    public static final int REASON_PROC_STATE_PERSISTENT =
+            PowerExemptionManager.REASON_PROC_STATE_PERSISTENT;
     /** @hide */
-    public static final int REASON_PROC_STATE_PERSISTENT_UI = 11;
+    public static final int REASON_PROC_STATE_PERSISTENT_UI =
+            PowerExemptionManager.REASON_PROC_STATE_PERSISTENT_UI;
     /** @hide */
-    public static final int REASON_PROC_STATE_TOP = 12;
+    public static final int REASON_PROC_STATE_TOP = PowerExemptionManager.REASON_PROC_STATE_TOP;
     /** @hide */
-    public static final int REASON_PROC_STATE_BTOP = 13;
+    public static final int REASON_PROC_STATE_BTOP = PowerExemptionManager.REASON_PROC_STATE_BTOP;
     /** @hide */
-    public static final int REASON_PROC_STATE_FGS = 14;
+    public static final int REASON_PROC_STATE_FGS = PowerExemptionManager.REASON_PROC_STATE_FGS;
     /** @hide */
-    public static final int REASON_PROC_STATE_BFGS = 15;
+    public static final int REASON_PROC_STATE_BFGS = PowerExemptionManager.REASON_PROC_STATE_BFGS;
 
     /* Reason code range 50-99 are reserved for BG-FGS-launch allowed reasons */
     /** @hide */
-    public static final int REASON_UID_VISIBLE = 50;
+    public static final int REASON_UID_VISIBLE = PowerExemptionManager.REASON_UID_VISIBLE;
     /** @hide */
-    public static final int REASON_SYSTEM_UID = 51;
+    public static final int REASON_SYSTEM_UID = PowerExemptionManager.REASON_SYSTEM_UID;
     /** @hide */
-    public static final int REASON_ACTIVITY_STARTER = 52;
+    public static final int REASON_ACTIVITY_STARTER = PowerExemptionManager.REASON_ACTIVITY_STARTER;
     /** @hide */
-    public static final int REASON_START_ACTIVITY_FLAG = 53;
+    public static final int REASON_START_ACTIVITY_FLAG =
+            PowerExemptionManager.REASON_START_ACTIVITY_FLAG;
     /** @hide */
-    public static final int REASON_FGS_BINDING = 54;
+    public static final int REASON_FGS_BINDING = PowerExemptionManager.REASON_FGS_BINDING;
     /** @hide */
-    public static final int REASON_DEVICE_OWNER = 55;
+    public static final int REASON_DEVICE_OWNER = PowerExemptionManager.REASON_DEVICE_OWNER;
     /** @hide */
-    public static final int REASON_PROFILE_OWNER = 56;
+    public static final int REASON_PROFILE_OWNER = PowerExemptionManager.REASON_PROFILE_OWNER;
     /** @hide */
-    public static final int REASON_COMPANION_DEVICE_MANAGER = 57;
+    public static final int REASON_COMPANION_DEVICE_MANAGER =
+            PowerExemptionManager.REASON_COMPANION_DEVICE_MANAGER;
     /**
      * START_ACTIVITIES_FROM_BACKGROUND permission.
      * @hide
      */
-    public static final int REASON_BACKGROUND_ACTIVITY_PERMISSION = 58;
+    public static final int REASON_BACKGROUND_ACTIVITY_PERMISSION =
+            PowerExemptionManager.REASON_BACKGROUND_ACTIVITY_PERMISSION;
     /**
      * START_FOREGROUND_SERVICES_FROM_BACKGROUND permission.
      * @hide
      */
-    public static final int REASON_BACKGROUND_FGS_PERMISSION = 59;
+    public static final int REASON_BACKGROUND_FGS_PERMISSION =
+            PowerExemptionManager.REASON_BACKGROUND_FGS_PERMISSION;
     /** @hide */
-    public static final int REASON_INSTR_BACKGROUND_ACTIVITY_PERMISSION = 60;
+    public static final int REASON_INSTR_BACKGROUND_ACTIVITY_PERMISSION =
+            PowerExemptionManager.REASON_INSTR_BACKGROUND_ACTIVITY_PERMISSION;
     /** @hide */
-    public static final int REASON_INSTR_BACKGROUND_FGS_PERMISSION = 61;
+    public static final int REASON_INSTR_BACKGROUND_FGS_PERMISSION =
+            PowerExemptionManager.REASON_INSTR_BACKGROUND_FGS_PERMISSION;
     /** @hide */
-    public static final int REASON_SYSTEM_ALERT_WINDOW_PERMISSION = 62;
+    public static final int REASON_SYSTEM_ALERT_WINDOW_PERMISSION =
+            PowerExemptionManager.REASON_SYSTEM_ALERT_WINDOW_PERMISSION;
     /** @hide */
-    public static final int REASON_DEVICE_DEMO_MODE = 63;
+    public static final int REASON_DEVICE_DEMO_MODE = PowerExemptionManager.REASON_DEVICE_DEMO_MODE;
     /** @hide */
-    public static final int REASON_EXEMPTED_PACKAGE = 64;
+    public static final int REASON_EXEMPTED_PACKAGE = PowerExemptionManager.REASON_EXEMPTED_PACKAGE;
     /** @hide */
-    public static final int REASON_ALLOWLISTED_PACKAGE  = 65;
+    public static final int REASON_ALLOWLISTED_PACKAGE =
+            PowerExemptionManager.REASON_ALLOWLISTED_PACKAGE;
     /** @hide */
-    public static final int REASON_APPOP = 66;
+    public static final int REASON_APPOP = PowerExemptionManager.REASON_APPOP;
 
     /* BG-FGS-launch is allowed by temp-allowlist or system-allowlist.
        Reason code for temp and system allowlist starts here.
@@ -181,117 +189,128 @@
     /**
      * Set temp-allowlist for location geofence purpose.
      */
-    public static final int REASON_GEOFENCING = 100;
+    public static final int REASON_GEOFENCING = PowerExemptionManager.REASON_GEOFENCING;
     /**
      * Set temp-allowlist for server push messaging.
      */
-    public static final int REASON_PUSH_MESSAGING = 101;
+    public static final int REASON_PUSH_MESSAGING = PowerExemptionManager.REASON_PUSH_MESSAGING;
     /**
      * Set temp-allowlist for server push messaging over the quota.
      */
-    public static final int REASON_PUSH_MESSAGING_OVER_QUOTA = 102;
+    public static final int REASON_PUSH_MESSAGING_OVER_QUOTA =
+            PowerExemptionManager.REASON_PUSH_MESSAGING_OVER_QUOTA;
     /**
      * Set temp-allowlist for activity recognition.
      */
-    public static final int REASON_ACTIVITY_RECOGNITION = 103;
+    public static final int REASON_ACTIVITY_RECOGNITION =
+            PowerExemptionManager.REASON_ACTIVITY_RECOGNITION;
 
     /* Reason code range 200-299 are reserved for broadcast actions */
     /**
      * Broadcast ACTION_BOOT_COMPLETED.
      * @hide
      */
-    public static final int REASON_BOOT_COMPLETED = 200;
+    public static final int REASON_BOOT_COMPLETED = PowerExemptionManager.REASON_BOOT_COMPLETED;
     /**
      * Broadcast ACTION_PRE_BOOT_COMPLETED.
      * @hide
      */
-    public static final int REASON_PRE_BOOT_COMPLETED = 201;
+    public static final int REASON_PRE_BOOT_COMPLETED =
+            PowerExemptionManager.REASON_PRE_BOOT_COMPLETED;
     /**
      * Broadcast ACTION_LOCKED_BOOT_COMPLETED.
      * @hide
      */
-    public static final int REASON_LOCKED_BOOT_COMPLETED = 202;
+    public static final int REASON_LOCKED_BOOT_COMPLETED =
+            PowerExemptionManager.REASON_LOCKED_BOOT_COMPLETED;
 
     /* Reason code range 300-399 are reserved for other internal reasons */
     /**
      * Device idle system allowlist, including EXCEPT-IDLE
      * @hide
      */
-    public static final int REASON_SYSTEM_ALLOW_LISTED  = 300;
+    public static final int REASON_SYSTEM_ALLOW_LISTED =
+            PowerExemptionManager.REASON_SYSTEM_ALLOW_LISTED;
     /** @hide */
-    public static final int REASON_ALARM_MANAGER_ALARM_CLOCK = 301;
+    public static final int REASON_ALARM_MANAGER_ALARM_CLOCK =
+            PowerExemptionManager.REASON_ALARM_MANAGER_ALARM_CLOCK;
     /**
      * AlarmManagerService.
      * @hide
      */
-    public static final int REASON_ALARM_MANAGER_WHILE_IDLE = 302;
+    public static final int REASON_ALARM_MANAGER_WHILE_IDLE =
+            PowerExemptionManager.REASON_ALARM_MANAGER_WHILE_IDLE;
     /**
      * ActiveServices.
      * @hide
      */
-    public static final int REASON_SERVICE_LAUNCH = 303;
+    public static final int REASON_SERVICE_LAUNCH = PowerExemptionManager.REASON_SERVICE_LAUNCH;
     /**
      * KeyChainSystemService.
      * @hide
      */
-    public static final int REASON_KEY_CHAIN = 304;
+    public static final int REASON_KEY_CHAIN = PowerExemptionManager.REASON_KEY_CHAIN;
     /**
      * PackageManagerService.
      * @hide
      */
-    public static final int REASON_PACKAGE_VERIFIER = 305;
+    public static final int REASON_PACKAGE_VERIFIER = PowerExemptionManager.REASON_PACKAGE_VERIFIER;
     /**
      * SyncManager.
      * @hide
      */
-    public static final int REASON_SYNC_MANAGER = 306;
+    public static final int REASON_SYNC_MANAGER = PowerExemptionManager.REASON_SYNC_MANAGER;
     /**
      * DomainVerificationProxyV1.
      * @hide
      */
-    public static final int REASON_DOMAIN_VERIFICATION_V1 = 307;
+    public static final int REASON_DOMAIN_VERIFICATION_V1 =
+            PowerExemptionManager.REASON_DOMAIN_VERIFICATION_V1;
     /**
      * DomainVerificationProxyV2.
      * @hide
      */
-    public static final int REASON_DOMAIN_VERIFICATION_V2 = 308;
+    public static final int REASON_DOMAIN_VERIFICATION_V2 =
+            PowerExemptionManager.REASON_DOMAIN_VERIFICATION_V2;
     /** @hide */
     public static final int REASON_VPN = 309;
     /**
      * NotificationManagerService.
      * @hide
      */
-    public static final int REASON_NOTIFICATION_SERVICE = 310;
+    public static final int REASON_NOTIFICATION_SERVICE =
+            PowerExemptionManager.REASON_NOTIFICATION_SERVICE;
     /**
      * Broadcast ACTION_MY_PACKAGE_REPLACED.
      * @hide
      */
-    public static final int REASON_PACKAGE_REPLACED = 311;
+    public static final int REASON_PACKAGE_REPLACED = PowerExemptionManager.REASON_PACKAGE_REPLACED;
     /**
      * LocationProviderManager.
      * @hide
      */
-    public static final int REASON_LOCATION_PROVIDER = 312;
+    public static final int REASON_LOCATION_PROVIDER =
+            PowerExemptionManager.REASON_LOCATION_PROVIDER;
     /**
      * MediaButtonReceiver.
      * @hide
      */
-    public static final int REASON_MEDIA_BUTTON = 313;
+    public static final int REASON_MEDIA_BUTTON = PowerExemptionManager.REASON_MEDIA_BUTTON;
     /**
      * InboundSmsHandler.
      * @hide
      */
-    public static final int REASON_EVENT_SMS = 314;
+    public static final int REASON_EVENT_SMS = PowerExemptionManager.REASON_EVENT_SMS;
     /**
      * InboundSmsHandler.
      * @hide
      */
-    public static final int REASON_EVENT_MMS = 315;
+    public static final int REASON_EVENT_MMS = PowerExemptionManager.REASON_EVENT_MMS;
     /**
      * Shell app.
      * @hide
      */
-    public static final int REASON_SHELL = 316;
+    public static final int REASON_SHELL = PowerExemptionManager.REASON_SHELL;
 
     /**
      * The list of BG-FGS-Launch and temp-allowlist reason code.
@@ -360,26 +379,29 @@
     public PowerWhitelistManager(@NonNull Context context) {
         mContext = context;
         mService = context.getSystemService(DeviceIdleManager.class).getService();
+        mPowerExemptionManager = context.getSystemService(PowerExemptionManager.class);
     }
 
     /**
      * Add the specified package to the permanent power save whitelist.
+     *
+     * @deprecated Use {@link PowerExemptionManager#addToPermanentAllowList(String)} instead
      */
+    @Deprecated
     @RequiresPermission(android.Manifest.permission.DEVICE_POWER)
     public void addToWhitelist(@NonNull String packageName) {
-        addToWhitelist(Collections.singletonList(packageName));
+        mPowerExemptionManager.addToPermanentAllowList(packageName);
     }
 
     /**
      * Add the specified packages to the permanent power save whitelist.
+     *
+     * @deprecated Use {@link PowerExemptionManager#addToPermanentAllowList(List)} instead
      */
+    @Deprecated
     @RequiresPermission(android.Manifest.permission.DEVICE_POWER)
     public void addToWhitelist(@NonNull List<String> packageNames) {
-        try {
-            mService.addPowerSaveWhitelistApps(packageNames);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
+        mPowerExemptionManager.addToPermanentAllowList(packageNames);
     }
 
     /**
@@ -388,19 +410,13 @@
      *
      * @param includingIdle Set to true if the app should be whitelisted from device idle as well
      *                      as other power save restrictions
+     * @deprecated Use {@link PowerExemptionManager#getAllowListedAppIds(boolean)} instead
      * @hide
      */
+    @Deprecated
     @NonNull
     public int[] getWhitelistedAppIds(boolean includingIdle) {
-        try {
-            if (includingIdle) {
-                return mService.getAppIdWhitelist();
-            } else {
-                return mService.getAppIdWhitelistExceptIdle();
-            }
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
+        return mPowerExemptionManager.getAllowListedAppIds(includingIdle);
     }
 
     /**
@@ -409,18 +425,12 @@
      *
      * @param includingIdle Set to true if the app should be whitelisted from device
      *                      idle as well as other power save restrictions
+     * @deprecated Use {@link PowerExemptionManager#isAllowListed(String, boolean)} instead
      * @hide
      */
+    @Deprecated
     public boolean isWhitelisted(@NonNull String packageName, boolean includingIdle) {
-        try {
-            if (includingIdle) {
-                return mService.isPowerSaveWhitelistApp(packageName);
-            } else {
-                return mService.isPowerSaveWhitelistExceptIdleApp(packageName);
-            }
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
+        return mPowerExemptionManager.isAllowListed(packageName, includingIdle);
     }
 
     /**
@@ -429,14 +439,12 @@
      * whitelisted by default by the system cannot be removed.
      *
      * @param packageName The app to remove from the whitelist
+     * @deprecated Use {@link PowerExemptionManager#removeFromAllowList(String)} instead
      */
+    @Deprecated
     @RequiresPermission(android.Manifest.permission.DEVICE_POWER)
     public void removeFromWhitelist(@NonNull String packageName) {
-        try {
-            mService.removePowerSaveWhitelistApp(packageName);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
+        mPowerExemptionManager.removeFromAllowList(packageName);
     }
 
     /**
@@ -446,16 +454,14 @@
      * @param durationMs  How long to keep the app on the temp whitelist for (in milliseconds)
      * @param reasonCode one of {@link ReasonCode}, use {@link #REASON_UNKNOWN} if not sure.
      * @param reason a optional human readable reason string, could be null or empty string.
+     * @deprecated Use {@link PowerExemptionManager#addToTemporaryAllowList(
+     *             String, long, int, String)} instead
      */
+    @Deprecated
     @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST)
     public void whitelistAppTemporarily(@NonNull String packageName, long durationMs,
             @ReasonCode int reasonCode, @Nullable String reason) {
-        try {
-            mService.addPowerSaveTempWhitelistApp(packageName, durationMs, mContext.getUserId(),
-                    reasonCode, reason);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
+        mPowerExemptionManager.addToTemporaryAllowList(packageName, durationMs, reasonCode, reason);
     }
 
     /**
@@ -463,12 +469,14 @@
      *
      * @param packageName The package to add to the temp whitelist
      * @param durationMs  How long to keep the app on the temp whitelist for (in milliseconds)
-     * @deprecated Use {@link #whitelistAppTemporarily(String, long, int, String)} instead
+     * @deprecated Use {@link PowerExemptionManager#addToTemporaryAllowList(
+     *             String, long, int, String)} instead
      */
     @Deprecated
     @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST)
     public void whitelistAppTemporarily(@NonNull String packageName, long durationMs) {
-        whitelistAppTemporarily(packageName, durationMs, REASON_UNKNOWN, packageName);
+        mPowerExemptionManager.addToTemporaryAllowList(
+                packageName, durationMs, REASON_UNKNOWN, packageName);
     }
 
     /**
@@ -481,13 +489,15 @@
      * @param reason      A human-readable reason explaining why the app is temp whitelisted. Only
      *                    used for logging purposes. Could be null or empty string.
      * @return The duration (in milliseconds) that the app is whitelisted for
-     * @deprecated Use {@link #whitelistAppTemporarilyForEvent(String, int, int, String)} instead
+     * @deprecated Use {@link PowerExemptionManager#addToTemporaryAllowListForEvent(
+     *             String, int, int, String)} instead
      */
     @Deprecated
     @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST)
     public long whitelistAppTemporarilyForEvent(@NonNull String packageName,
             @WhitelistEvent int event, @Nullable String reason) {
-        return whitelistAppTemporarilyForEvent(packageName, event, REASON_UNKNOWN, reason);
+        return mPowerExemptionManager.addToTemporaryAllowListForEvent(
+                packageName, event, REASON_UNKNOWN, reason);
     }
 
     /**
@@ -501,47 +511,25 @@
      * @param reason      A human-readable reason explaining why the app is temp whitelisted. Only
      *                    used for logging purposes. Could be null or empty string.
      * @return The duration (in milliseconds) that the app is whitelisted for
+     * @deprecated Use {@link PowerExemptionManager#addToTemporaryAllowListForEvent(
+     *             String, int, int, String)} instead
      */
+    @Deprecated
     @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST)
     public long whitelistAppTemporarilyForEvent(@NonNull String packageName,
             @WhitelistEvent int event, @ReasonCode int reasonCode, @Nullable String reason) {
-        try {
-            switch (event) {
-                case EVENT_MMS:
-                    return mService.addPowerSaveTempWhitelistAppForMms(
-                            packageName, mContext.getUserId(), reasonCode, reason);
-                case EVENT_SMS:
-                    return mService.addPowerSaveTempWhitelistAppForSms(
-                            packageName, mContext.getUserId(), reasonCode, reason);
-                case EVENT_UNSPECIFIED:
-                default:
-                    return mService.whitelistAppTemporarily(
-                            packageName, mContext.getUserId(), reasonCode, reason);
-            }
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
+        return mPowerExemptionManager.addToTemporaryAllowListForEvent(
+                packageName, event, reasonCode, reason);
     }
 
     /**
      * @hide
+     *
+     * @deprecated Use {@link PowerExemptionManager#getReasonCodeFromProcState(int)} instead
      */
+    @Deprecated
     public static @ReasonCode int getReasonCodeFromProcState(int procState) {
-        if (procState <= PROCESS_STATE_PERSISTENT) {
-            return REASON_PROC_STATE_PERSISTENT;
-        } else if (procState <= PROCESS_STATE_PERSISTENT_UI) {
-            return REASON_PROC_STATE_PERSISTENT_UI;
-        } else if (procState <= PROCESS_STATE_TOP) {
-            return REASON_PROC_STATE_TOP;
-        } else if (procState <= PROCESS_STATE_BOUND_TOP) {
-            return REASON_PROC_STATE_BTOP;
-        } else if (procState <= PROCESS_STATE_FOREGROUND_SERVICE) {
-            return REASON_PROC_STATE_FGS;
-        } else if (procState <= PROCESS_STATE_BOUND_FOREGROUND_SERVICE) {
-            return REASON_PROC_STATE_BFGS;
-        } else {
-            return REASON_DENIED;
-        }
+        return PowerExemptionManager.getReasonCodeFromProcState(procState);
     }
 
     /**
@@ -549,111 +537,10 @@
      * @hide
      * @param reasonCode
      * @return string name of the reason code.
+     * @deprecated Use {@link PowerExemptionManager#reasonCodeToString(int)} instead
      */
+    @Deprecated
     public static String reasonCodeToString(@ReasonCode int reasonCode) {
-        switch (reasonCode) {
-            case REASON_DENIED:
-                return "DENIED";
-            case REASON_UNKNOWN:
-                return "UNKNOWN";
-            case REASON_OTHER:
-                return "OTHER";
-            case REASON_PROC_STATE_PERSISTENT:
-                return "PROC_STATE_PERSISTENT";
-            case REASON_PROC_STATE_PERSISTENT_UI:
-                return "PROC_STATE_PERSISTENT_UI";
-            case REASON_PROC_STATE_TOP:
-                return "PROC_STATE_TOP";
-            case REASON_PROC_STATE_BTOP:
-                return "PROC_STATE_BTOP";
-            case REASON_PROC_STATE_FGS:
-                return "PROC_STATE_FGS";
-            case REASON_PROC_STATE_BFGS:
-                return "PROC_STATE_BFGS";
-            case REASON_UID_VISIBLE:
-                return "UID_VISIBLE";
-            case REASON_SYSTEM_UID:
-                return "SYSTEM_UID";
-            case REASON_ACTIVITY_STARTER:
-                return "ACTIVITY_STARTER";
-            case REASON_START_ACTIVITY_FLAG:
-                return "START_ACTIVITY_FLAG";
-            case REASON_FGS_BINDING:
-                return "FGS_BINDING";
-            case REASON_DEVICE_OWNER:
-                return "DEVICE_OWNER";
-            case REASON_PROFILE_OWNER:
-                return "PROFILE_OWNER";
-            case REASON_COMPANION_DEVICE_MANAGER:
-                return "COMPANION_DEVICE_MANAGER";
-            case REASON_BACKGROUND_ACTIVITY_PERMISSION:
-                return "BACKGROUND_ACTIVITY_PERMISSION";
-            case REASON_BACKGROUND_FGS_PERMISSION:
-                return "BACKGROUND_FGS_PERMISSION";
-            case REASON_INSTR_BACKGROUND_ACTIVITY_PERMISSION:
-                return "INSTR_BACKGROUND_ACTIVITY_PERMISSION";
-            case REASON_INSTR_BACKGROUND_FGS_PERMISSION:
-                return "INSTR_BACKGROUND_FGS_PERMISSION";
-            case REASON_SYSTEM_ALERT_WINDOW_PERMISSION:
-                return "SYSTEM_ALERT_WINDOW_PERMISSION";
-            case REASON_DEVICE_DEMO_MODE:
-                return "DEVICE_DEMO_MODE";
-            case REASON_EXEMPTED_PACKAGE:
-                return "EXEMPTED_PACKAGE";
-            case REASON_ALLOWLISTED_PACKAGE:
-                return "ALLOWLISTED_PACKAGE";
-            case REASON_APPOP:
-                return "APPOP";
-            case REASON_GEOFENCING:
-                return "GEOFENCING";
-            case REASON_PUSH_MESSAGING:
-                return "PUSH_MESSAGING";
-            case REASON_PUSH_MESSAGING_OVER_QUOTA:
-                return "PUSH_MESSAGING_OVER_QUOTA";
-            case REASON_ACTIVITY_RECOGNITION:
-                return "ACTIVITY_RECOGNITION";
-            case REASON_BOOT_COMPLETED:
-                return "BOOT_COMPLETED";
-            case REASON_PRE_BOOT_COMPLETED:
-                return "PRE_BOOT_COMPLETED";
-            case REASON_LOCKED_BOOT_COMPLETED:
-                return "LOCKED_BOOT_COMPLETED";
-            case REASON_SYSTEM_ALLOW_LISTED:
-                return "SYSTEM_ALLOW_LISTED";
-            case REASON_ALARM_MANAGER_ALARM_CLOCK:
-                return "ALARM_MANAGER_ALARM_CLOCK";
-            case REASON_ALARM_MANAGER_WHILE_IDLE:
-                return "ALARM_MANAGER_WHILE_IDLE";
-            case REASON_SERVICE_LAUNCH:
-                return "SERVICE_LAUNCH";
-            case REASON_KEY_CHAIN:
-                return "KEY_CHAIN";
-            case REASON_PACKAGE_VERIFIER:
-                return "PACKAGE_VERIFIER";
-            case REASON_SYNC_MANAGER:
-                return "SYNC_MANAGER";
-            case REASON_DOMAIN_VERIFICATION_V1:
-                return "DOMAIN_VERIFICATION_V1";
-            case REASON_DOMAIN_VERIFICATION_V2:
-                return "DOMAIN_VERIFICATION_V2";
-            case REASON_VPN:
-                return "VPN";
-            case REASON_NOTIFICATION_SERVICE:
-                return "NOTIFICATION_SERVICE";
-            case REASON_PACKAGE_REPLACED:
-                return "PACKAGE_REPLACED";
-            case REASON_LOCATION_PROVIDER:
-                return "LOCATION_PROVIDER";
-            case REASON_MEDIA_BUTTON:
-                return "MEDIA_BUTTON";
-            case REASON_EVENT_SMS:
-                return "EVENT_SMS";
-            case REASON_EVENT_MMS:
-                return "EVENT_MMS";
-            case REASON_SHELL:
-                return "SHELL";
-            default:
-                return  "(unknown:" + reasonCode + ")";
-        }
+        return PowerExemptionManager.reasonCodeToString(reasonCode);
     }
 }
diff --git a/config/preloaded-classes b/config/preloaded-classes
index c6ec376..7c3fd8c 100644
--- a/config/preloaded-classes
+++ b/config/preloaded-classes
@@ -1844,11 +1844,9 @@
 android.ddm.DdmHandleAppName$Names
 android.ddm.DdmHandleAppName
 android.ddm.DdmHandleExit
-android.ddm.DdmHandleHeap
 android.ddm.DdmHandleHello
 android.ddm.DdmHandleNativeHeap
 android.ddm.DdmHandleProfiling
-android.ddm.DdmHandleThread
 android.ddm.DdmHandleViewDebug
 android.ddm.DdmRegister
 android.debug.AdbManager
diff --git a/core/api/current.txt b/core/api/current.txt
index bc25561..ef93f45 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -329,6 +329,7 @@
     field public static final int apiKey = 16843281; // 0x1010211
     field public static final int appCategory = 16844101; // 0x1010545
     field public static final int appComponentFactory = 16844154; // 0x101057a
+    field public static final int attributionTags = 16844353; // 0x1010641
     field public static final int author = 16843444; // 0x10102b4
     field public static final int authorities = 16842776; // 0x1010018
     field public static final int autoAdvanceViewId = 16843535; // 0x101030f
@@ -1393,6 +1394,7 @@
     field public static final int supportsRtl = 16843695; // 0x10103af
     field public static final int supportsSwitchingToNextInputMethod = 16843755; // 0x10103eb
     field public static final int supportsUploading = 16843419; // 0x101029b
+    field public static final int suppressesSpellChecker = 16844354; // 0x1010642
     field public static final int switchMinWidth = 16843632; // 0x1010370
     field public static final int switchPadding = 16843633; // 0x1010371
     field public static final int switchPreferenceStyle = 16843629; // 0x101036d
@@ -8490,7 +8492,7 @@
     field public static final int WIDGET_CATEGORY_HOME_SCREEN = 1; // 0x1
     field public static final int WIDGET_CATEGORY_KEYGUARD = 2; // 0x2
     field public static final int WIDGET_CATEGORY_SEARCHBOX = 4; // 0x4
-    field public static final int WIDGET_FEATURE_CONFIGURATION_OPTIONAL = 3; // 0x3
+    field public static final int WIDGET_FEATURE_CONFIGURATION_OPTIONAL = 4; // 0x4
     field public static final int WIDGET_FEATURE_HIDE_FROM_PICKER = 2; // 0x2
     field public static final int WIDGET_FEATURE_RECONFIGURABLE = 1; // 0x1
     field public int autoAdvanceViewId;
@@ -10500,6 +10502,7 @@
     field public static final String DEVICE_POLICY_SERVICE = "device_policy";
     field public static final String DISPLAY_HASH_SERVICE = "display_hash";
     field public static final String DISPLAY_SERVICE = "display";
+    field public static final String DOMAIN_VERIFICATION_SERVICE = "domain_verification";
     field public static final String DOWNLOAD_SERVICE = "download";
     field public static final String DROPBOX_SERVICE = "dropbox";
     field public static final String EUICC_SERVICE = "euicc";
@@ -26137,10 +26140,6 @@
     ctor public NetworkSpecifier();
   }
 
-  public class ParseException extends java.lang.RuntimeException {
-    field public String response;
-  }
-
   public abstract class PlatformVpnProfile {
     method public final int getType();
     method @NonNull public final String getTypeString();
@@ -30427,6 +30426,7 @@
     field public static final String BASE_OS;
     field public static final String CODENAME;
     field public static final String INCREMENTAL;
+    field public static final int MEDIA_PERFORMANCE_CLASS;
     field public static final int PREVIEW_SDK_INT;
     field public static final String RELEASE;
     field @NonNull public static final String RELEASE_OR_CODENAME;
@@ -40614,14 +40614,6 @@
   public static final class CarrierConfigManager.Iwlan {
     field public static final int AUTHENTICATION_METHOD_CERT = 1; // 0x1
     field public static final int AUTHENTICATION_METHOD_EAP_ONLY = 0; // 0x0
-    field public static final int DH_GROUP_1024_BIT_MODP = 2; // 0x2
-    field public static final int DH_GROUP_1536_BIT_MODP = 5; // 0x5
-    field public static final int DH_GROUP_2048_BIT_MODP = 14; // 0xe
-    field public static final int DH_GROUP_3072_BIT_MODP = 15; // 0xf
-    field public static final int DH_GROUP_4096_BIT_MODP = 16; // 0x10
-    field public static final int DH_GROUP_NONE = 0; // 0x0
-    field public static final int ENCRYPTION_ALGORITHM_AES_CBC = 12; // 0xc
-    field public static final int ENCRYPTION_ALGORITHM_AES_CTR = 13; // 0xd
     field public static final int EPDG_ADDRESS_CELLULAR_LOC = 3; // 0x3
     field public static final int EPDG_ADDRESS_PCO = 2; // 0x2
     field public static final int EPDG_ADDRESS_PLMN = 1; // 0x1
@@ -40629,12 +40621,6 @@
     field public static final int ID_TYPE_FQDN = 2; // 0x2
     field public static final int ID_TYPE_KEY_ID = 11; // 0xb
     field public static final int ID_TYPE_RFC822_ADDR = 3; // 0x3
-    field public static final int INTEGRITY_ALGORITHM_AES_XCBC_96 = 5; // 0x5
-    field public static final int INTEGRITY_ALGORITHM_HMAC_SHA1_96 = 2; // 0x2
-    field public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_256_128 = 12; // 0xc
-    field public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_384_192 = 13; // 0xd
-    field public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_512_256 = 14; // 0xe
-    field public static final int INTEGRITY_ALGORITHM_NONE = 0; // 0x0
     field public static final String KEY_ADD_KE_TO_CHILD_SESSION_REKEY_BOOL = "iwlan.add_ke_to_child_session_rekey_bool";
     field public static final String KEY_CHILD_SA_REKEY_HARD_TIMER_SEC_INT = "iwlan.child_sa_rekey_hard_timer_sec_int";
     field public static final String KEY_CHILD_SA_REKEY_SOFT_TIMER_SEC_INT = "iwlan.child_sa_rekey_soft_timer_sec_int";
@@ -40654,10 +40640,6 @@
     field public static final String KEY_IKE_REMOTE_ID_TYPE_INT = "iwlan.ike_remote_id_type_int";
     field public static final String KEY_IKE_SESSION_AES_CBC_KEY_SIZE_INT_ARRAY = "iwlan.ike_session_encryption_aes_cbc_key_size_int_array";
     field public static final String KEY_IKE_SESSION_AES_CTR_KEY_SIZE_INT_ARRAY = "iwlan.ike_session_encryption_aes_ctr_key_size_int_array";
-    field public static final int KEY_LEN_AES_128 = 128; // 0x80
-    field public static final int KEY_LEN_AES_192 = 192; // 0xc0
-    field public static final int KEY_LEN_AES_256 = 256; // 0x100
-    field public static final int KEY_LEN_UNUSED = 0; // 0x0
     field public static final String KEY_MAX_RETRIES_INT = "iwlan.max_retries_int";
     field public static final String KEY_MCC_MNCS_STRING_ARRAY = "iwlan.mcc_mncs_string_array";
     field public static final String KEY_NATT_KEEP_ALIVE_TIMER_SEC_INT = "iwlan.natt_keep_alive_timer_sec_int";
@@ -40667,11 +40649,6 @@
     field public static final String KEY_SUPPORTED_IKE_SESSION_ENCRYPTION_ALGORITHMS_INT_ARRAY = "iwlan.supported_ike_session_encryption_algorithms_int_array";
     field public static final String KEY_SUPPORTED_INTEGRITY_ALGORITHMS_INT_ARRAY = "iwlan.supported_integrity_algorithms_int_array";
     field public static final String KEY_SUPPORTED_PRF_ALGORITHMS_INT_ARRAY = "iwlan.supported_prf_algorithms_int_array";
-    field public static final int PSEUDORANDOM_FUNCTION_AES128_XCBC = 4; // 0x4
-    field public static final int PSEUDORANDOM_FUNCTION_HMAC_SHA1 = 2; // 0x2
-    field public static final int PSEUDORANDOM_FUNCTION_SHA2_256 = 5; // 0x5
-    field public static final int PSEUDORANDOM_FUNCTION_SHA2_384 = 6; // 0x6
-    field public static final int PSEUDORANDOM_FUNCTION_SHA2_512 = 7; // 0x7
   }
 
   public abstract class CellIdentity implements android.os.Parcelable {
@@ -42040,6 +42017,7 @@
     method public static int getDefaultSmsSubscriptionId();
     method public static int getDefaultSubscriptionId();
     method public static int getDefaultVoiceSubscriptionId();
+    method public int getDeviceToDeviceStatusSharing(int);
     method @NonNull @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public java.util.List<android.telephony.SubscriptionInfo> getOpportunisticSubscriptions();
     method public static int getSlotIndex(int);
     method @Nullable public int[] getSubscriptionIds(int);
@@ -42052,6 +42030,7 @@
     method public void removeOnOpportunisticSubscriptionsChangedListener(@NonNull android.telephony.SubscriptionManager.OnOpportunisticSubscriptionsChangedListener);
     method public void removeOnSubscriptionsChangedListener(android.telephony.SubscriptionManager.OnSubscriptionsChangedListener);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void removeSubscriptionsFromGroup(@NonNull java.util.List<java.lang.Integer>, @NonNull android.os.ParcelUuid);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDeviceToDeviceStatusSharing(int, int);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setOpportunistic(boolean, int);
     method public void setSubscriptionOverrideCongested(int, boolean, long);
     method public void setSubscriptionOverrideCongested(int, boolean, @NonNull int[], long);
@@ -42063,6 +42042,11 @@
     field public static final String ACTION_DEFAULT_SUBSCRIPTION_CHANGED = "android.telephony.action.DEFAULT_SUBSCRIPTION_CHANGED";
     field public static final String ACTION_MANAGE_SUBSCRIPTION_PLANS = "android.telephony.action.MANAGE_SUBSCRIPTION_PLANS";
     field public static final String ACTION_REFRESH_SUBSCRIPTION_PLANS = "android.telephony.action.REFRESH_SUBSCRIPTION_PLANS";
+    field public static final int D2D_SHARING_ALL = 3; // 0x3
+    field public static final int D2D_SHARING_ALL_CONTACTS = 1; // 0x1
+    field public static final int D2D_SHARING_DISABLED = 0; // 0x0
+    field public static final int D2D_SHARING_STARRED_CONTACTS = 2; // 0x2
+    field public static final String D2D_STATUS_SHARING = "d2d_sharing_status";
     field public static final int DATA_ROAMING_DISABLE = 0; // 0x0
     field public static final int DATA_ROAMING_ENABLE = 1; // 0x1
     field public static final int DEFAULT_SUBSCRIPTION_ID = 2147483647; // 0x7fffffff
@@ -49895,6 +49879,7 @@
 
   public interface WindowManager extends android.view.ViewManager {
     method public default void addCrossWindowBlurEnabledListener(@NonNull java.util.function.Consumer<java.lang.Boolean>);
+    method public default void addCrossWindowBlurEnabledListener(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
     method @NonNull public default android.view.WindowMetrics getCurrentWindowMetrics();
     method @Deprecated public android.view.Display getDefaultDisplay();
     method @NonNull public default android.view.WindowMetrics getMaximumWindowMetrics();
@@ -51476,7 +51461,6 @@
     method public int describeContents();
     method public void dump(android.util.Printer, String);
     method public android.content.ComponentName getComponent();
-    method public int getConfigChanges();
     method public String getId();
     method public int getIsDefaultResourceId();
     method public String getPackageName();
@@ -51487,6 +51471,7 @@
     method public int getSubtypeCount();
     method public android.graphics.drawable.Drawable loadIcon(android.content.pm.PackageManager);
     method public CharSequence loadLabel(android.content.pm.PackageManager);
+    method public boolean suppressesSpellChecker();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.view.inputmethod.InputMethodInfo> CREATOR;
   }
@@ -51508,6 +51493,7 @@
     method public boolean isActive(android.view.View);
     method public boolean isActive();
     method public boolean isFullscreenMode();
+    method public boolean isInputMethodSuppressingSpellChecker();
     method @Deprecated public boolean isWatchingCursor(android.view.View);
     method public void restartInput(android.view.View);
     method public void sendAppPrivateCommand(android.view.View, String, android.os.Bundle);
@@ -54983,6 +54969,7 @@
     ctor public RemoteViews(@NonNull java.util.Map<android.util.SizeF,android.widget.RemoteViews>);
     ctor public RemoteViews(android.widget.RemoteViews);
     ctor public RemoteViews(android.os.Parcel);
+    method public void addStableView(@IdRes int, @NonNull android.widget.RemoteViews, int);
     method public void addView(@IdRes int, android.widget.RemoteViews);
     method public android.view.View apply(android.content.Context, android.view.ViewGroup);
     method @Deprecated public android.widget.RemoteViews clone();
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index 057e16c..18b0a43 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -59,6 +59,10 @@
     method @NonNull public android.os.UserHandle getUser();
   }
 
+  public class Intent implements java.lang.Cloneable android.os.Parcelable {
+    field public static final String ACTION_CLEAR_DNS_CACHE = "android.intent.action.CLEAR_DNS_CACHE";
+  }
+
 }
 
 package android.content.pm {
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index eddf5a4..bfc205b 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -2162,7 +2162,6 @@
     field public static final int BIND_ALLOW_FOREGROUND_SERVICE_STARTS_FROM_BACKGROUND = 262144; // 0x40000
     field public static final String CONTENT_SUGGESTIONS_SERVICE = "content_suggestions";
     field public static final String CONTEXTHUB_SERVICE = "contexthub";
-    field public static final String DOMAIN_VERIFICATION_SERVICE = "domain_verification";
     field public static final String ETHERNET_SERVICE = "ethernet";
     field public static final String EUICC_CARD_SERVICE = "euicc_card";
     field public static final String FONT_SERVICE = "font";
@@ -2174,7 +2173,6 @@
     field public static final String OEM_LOCK_SERVICE = "oem_lock";
     field public static final String PERMISSION_SERVICE = "permission";
     field public static final String PERSISTENT_DATA_BLOCK_SERVICE = "persistent_data_block";
-    field public static final String POWER_EXEMPTION_SERVICE = "power_exemption";
     field public static final String REBOOT_READINESS_SERVICE = "reboot_readiness";
     field public static final String ROLLBACK_SERVICE = "rollback";
     field public static final String SEARCH_UI_SERVICE = "search_ui";
@@ -2241,6 +2239,7 @@
     field @RequiresPermission(android.Manifest.permission.REVIEW_ACCESSIBILITY_SERVICES) public static final String ACTION_REVIEW_ACCESSIBILITY_SERVICES = "android.intent.action.REVIEW_ACCESSIBILITY_SERVICES";
     field @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS) public static final String ACTION_REVIEW_ONGOING_PERMISSION_USAGE = "android.intent.action.REVIEW_ONGOING_PERMISSION_USAGE";
     field public static final String ACTION_REVIEW_PERMISSIONS = "android.intent.action.REVIEW_PERMISSIONS";
+    field @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS) public static final String ACTION_REVIEW_PERMISSION_HISTORY = "android.intent.action.REVIEW_PERMISSION_HISTORY";
     field @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS) public static final String ACTION_REVIEW_PERMISSION_USAGE = "android.intent.action.REVIEW_PERMISSION_USAGE";
     field public static final String ACTION_ROLLBACK_COMMITTED = "android.intent.action.ROLLBACK_COMMITTED";
     field public static final String ACTION_SHOW_SUSPENDED_APP_DETAILS = "android.intent.action.SHOW_SUSPENDED_APP_DETAILS";
@@ -2901,7 +2900,7 @@
   }
 
   public class FontManager {
-    method @NonNull public android.text.FontConfig getFontConfig();
+    method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_FONTS) public android.text.FontConfig getFontConfig();
     method @RequiresPermission(android.Manifest.permission.UPDATE_FONTS) public int updateFontFamily(@NonNull android.graphics.fonts.FontFamilyUpdateRequest, @IntRange(from=0) int);
     field public static final int RESULT_ERROR_DOWNGRADING = -5; // 0xfffffffb
     field public static final int RESULT_ERROR_FAILED_TO_WRITE_FONT_FILE = -1; // 0xffffffff
@@ -7521,12 +7520,12 @@
 package android.net.vcn {
 
   public class VcnManager {
-    method @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public void addVcnNetworkPolicyListener(@NonNull java.util.concurrent.Executor, @NonNull android.net.vcn.VcnManager.VcnNetworkPolicyListener);
+    method @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public void addVcnNetworkPolicyChangeListener(@NonNull java.util.concurrent.Executor, @NonNull android.net.vcn.VcnManager.VcnNetworkPolicyChangeListener);
     method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.vcn.VcnNetworkPolicyResult applyVcnNetworkPolicy(@NonNull android.net.NetworkCapabilities, @NonNull android.net.LinkProperties);
-    method public void removeVcnNetworkPolicyListener(@NonNull android.net.vcn.VcnManager.VcnNetworkPolicyListener);
+    method @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public void removeVcnNetworkPolicyChangeListener(@NonNull android.net.vcn.VcnManager.VcnNetworkPolicyChangeListener);
   }
 
-  public static interface VcnManager.VcnNetworkPolicyListener {
+  public static interface VcnManager.VcnNetworkPolicyChangeListener {
     method public void onPolicyChanged();
   }
 
@@ -8184,6 +8183,7 @@
     field public static final int EVENT_MMS = 2; // 0x2
     field public static final int EVENT_SMS = 1; // 0x1
     field public static final int EVENT_UNSPECIFIED = 0; // 0x0
+    field public static final int REASON_ACCOUNT_TRANSFER = 104; // 0x68
     field public static final int REASON_ACTIVITY_RECOGNITION = 103; // 0x67
     field public static final int REASON_GEOFENCING = 100; // 0x64
     field public static final int REASON_OTHER = 1; // 0x1
@@ -8224,25 +8224,25 @@
     field public static final int USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS = 1; // 0x1
   }
 
-  public class PowerWhitelistManager {
-    method @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void addToWhitelist(@NonNull String);
-    method @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void addToWhitelist(@NonNull java.util.List<java.lang.String>);
-    method @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void removeFromWhitelist(@NonNull String);
-    method @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST) public void whitelistAppTemporarily(@NonNull String, long, int, @Nullable String);
+  @Deprecated public class PowerWhitelistManager {
+    method @Deprecated @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void addToWhitelist(@NonNull String);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void addToWhitelist(@NonNull java.util.List<java.lang.String>);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void removeFromWhitelist(@NonNull String);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST) public void whitelistAppTemporarily(@NonNull String, long, int, @Nullable String);
     method @Deprecated @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST) public void whitelistAppTemporarily(@NonNull String, long);
     method @Deprecated @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST) public long whitelistAppTemporarilyForEvent(@NonNull String, int, @Nullable String);
-    method @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST) public long whitelistAppTemporarilyForEvent(@NonNull String, int, int, @Nullable String);
-    field public static final int EVENT_MMS = 2; // 0x2
-    field public static final int EVENT_SMS = 1; // 0x1
-    field public static final int EVENT_UNSPECIFIED = 0; // 0x0
-    field public static final int REASON_ACTIVITY_RECOGNITION = 103; // 0x67
-    field public static final int REASON_GEOFENCING = 100; // 0x64
-    field public static final int REASON_OTHER = 1; // 0x1
-    field public static final int REASON_PUSH_MESSAGING = 101; // 0x65
-    field public static final int REASON_PUSH_MESSAGING_OVER_QUOTA = 102; // 0x66
-    field public static final int REASON_UNKNOWN = 0; // 0x0
-    field public static final int TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED = 0; // 0x0
-    field public static final int TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED = 1; // 0x1
+    method @Deprecated @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST) public long whitelistAppTemporarilyForEvent(@NonNull String, int, int, @Nullable String);
+    field @Deprecated public static final int EVENT_MMS = 2; // 0x2
+    field @Deprecated public static final int EVENT_SMS = 1; // 0x1
+    field @Deprecated public static final int EVENT_UNSPECIFIED = 0; // 0x0
+    field @Deprecated public static final int REASON_ACTIVITY_RECOGNITION = 103; // 0x67
+    field @Deprecated public static final int REASON_GEOFENCING = 100; // 0x64
+    field @Deprecated public static final int REASON_OTHER = 1; // 0x1
+    field @Deprecated public static final int REASON_PUSH_MESSAGING = 101; // 0x65
+    field @Deprecated public static final int REASON_PUSH_MESSAGING_OVER_QUOTA = 102; // 0x66
+    field @Deprecated public static final int REASON_UNKNOWN = 0; // 0x0
+    field @Deprecated public static final int TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED = 0; // 0x0
+    field @Deprecated public static final int TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED = 1; // 0x1
   }
 
   public class RecoverySystem {
@@ -10363,6 +10363,7 @@
 
   public abstract class CallDiagnosticService extends android.app.Service {
     ctor public CallDiagnosticService();
+    method @NonNull public java.util.concurrent.Executor getExecutor();
     method @Nullable public android.os.IBinder onBind(@NonNull android.content.Intent);
     method public abstract void onBluetoothCallQualityReportReceived(@NonNull android.telecom.BluetoothCallQualityReport);
     method public abstract void onCallAudioStateChanged(@NonNull android.telecom.CallAudioState);
@@ -10435,16 +10436,12 @@
     ctor public DiagnosticCall();
     method public final void clearDiagnosticMessage(int);
     method public final void displayDiagnosticMessage(int, @NonNull CharSequence);
-    method @NonNull public android.telecom.Call.Details getCallDetails();
     method public abstract void onCallDetailsChanged(@NonNull android.telecom.Call.Details);
     method @Nullable public abstract CharSequence onCallDisconnected(int, int);
     method @Nullable public abstract CharSequence onCallDisconnected(@NonNull android.telephony.ims.ImsReasonInfo);
     method public abstract void onCallQualityReceived(@NonNull android.telephony.CallQuality);
     method public abstract void onReceiveDeviceToDeviceMessage(int, int);
     method public final void sendDeviceToDeviceMessage(int, int);
-    field public static final int AUDIO_CODEC_AMR_NB = 3; // 0x3
-    field public static final int AUDIO_CODEC_AMR_WB = 2; // 0x2
-    field public static final int AUDIO_CODEC_EVS = 1; // 0x1
     field public static final int BATTERY_STATE_CHARGING = 3; // 0x3
     field public static final int BATTERY_STATE_GOOD = 2; // 0x2
     field public static final int BATTERY_STATE_LOW = 1; // 0x1
@@ -10454,9 +10451,6 @@
     field public static final int MESSAGE_CALL_NETWORK_TYPE = 1; // 0x1
     field public static final int MESSAGE_DEVICE_BATTERY_STATE = 3; // 0x3
     field public static final int MESSAGE_DEVICE_NETWORK_COVERAGE = 4; // 0x4
-    field public static final int NETWORK_TYPE_IWLAN = 2; // 0x2
-    field public static final int NETWORK_TYPE_LTE = 1; // 0x1
-    field public static final int NETWORK_TYPE_NR = 3; // 0x3
   }
 
   public abstract class InCallService extends android.app.Service {
@@ -11478,7 +11472,7 @@
   }
 
   public static interface TelephonyCallback.AllowedNetworkTypesListener {
-    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void onAllowedNetworkTypesChanged(@NonNull java.util.Map<java.lang.Integer,java.lang.Long>);
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void onAllowedNetworkTypesChanged(int, long);
   }
 
   public static interface TelephonyCallback.CallAttributesListener {
@@ -11962,7 +11956,7 @@
     method @NonNull public android.telephony.data.DataCallResponse.Builder setMtuV4(int);
     method @NonNull public android.telephony.data.DataCallResponse.Builder setMtuV6(int);
     method @NonNull public android.telephony.data.DataCallResponse.Builder setPcscfAddresses(@NonNull java.util.List<java.net.InetAddress>);
-    method @NonNull public android.telephony.data.DataCallResponse.Builder setPduSessionId(int);
+    method @NonNull public android.telephony.data.DataCallResponse.Builder setPduSessionId(@IntRange(from=android.telephony.data.DataCallResponse.PDU_SESSION_ID_NOT_SET, to=15) int);
     method @NonNull public android.telephony.data.DataCallResponse.Builder setProtocolType(int);
     method @NonNull public android.telephony.data.DataCallResponse.Builder setRetryDurationMillis(long);
     method @NonNull public android.telephony.data.DataCallResponse.Builder setSliceInfo(@Nullable android.telephony.data.SliceInfo);
@@ -13039,6 +13033,7 @@
     method public void onAutoConfigurationErrorReceived(int, @NonNull String);
     method public void onConfigurationChanged(@NonNull byte[]);
     method public void onConfigurationReset();
+    method public void onPreProvisioningReceived(@NonNull byte[]);
     method public void onRemoved();
   }
 
@@ -13508,6 +13503,7 @@
     method public int getConfigInt(int);
     method public String getConfigString(int);
     method public final void notifyAutoConfigurationErrorReceived(int, @NonNull String);
+    method public final void notifyPreProvisioningReceived(@NonNull byte[]);
     method public final void notifyProvisionedValueChanged(int, int);
     method public final void notifyProvisionedValueChanged(int, String);
     method public void notifyRcsAutoConfigurationReceived(@NonNull byte[], boolean);
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 8fa4659..9fde791 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -414,6 +414,7 @@
     method public long getLastNetworkLogRetrievalTime();
     method public long getLastSecurityLogRetrievalTime();
     method public java.util.List<java.lang.String> getOwnerInstalledCaCerts(@NonNull android.os.UserHandle);
+    method @NonNull @RequiresPermission("android.permission.MANAGE_DEVICE_ADMINS") public java.util.Set<java.lang.String> getPolicyExemptApps();
     method public boolean isCurrentInputMethodSetByOwner();
     method public boolean isFactoryResetProtectionPolicySupported();
     method @RequiresPermission(anyOf={"android.permission.MARK_DEVICE_ORGANIZATION_OWNED", "android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS"}, conditional=true) public void markProfileOwnerOnOrganizationOwnedDevice(@NonNull android.content.ComponentName);
@@ -698,7 +699,8 @@
     field public static final String DEVICE_IDLE_CONTROLLER = "deviceidle";
     field public static final String DREAM_SERVICE = "dream";
     field public static final String FONT_SERVICE = "font";
-    field public static final String POWER_WHITELIST_MANAGER = "power_whitelist";
+    field public static final String POWER_EXEMPTION_SERVICE = "power_exemption";
+    field @Deprecated public static final String POWER_WHITELIST_MANAGER = "power_whitelist";
     field public static final String TEST_NETWORK_SERVICE = "test_network";
   }
 
@@ -706,6 +708,10 @@
     method public int getDisplayId();
   }
 
+  public class SyncAdapterType implements android.os.Parcelable {
+    method @Nullable public String getPackageName();
+  }
+
 }
 
 package android.content.integrity {
@@ -968,7 +974,7 @@
 package android.graphics.fonts {
 
   public class FontManager {
-    method @NonNull public android.text.FontConfig getFontConfig();
+    method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_FONTS) public android.text.FontConfig getFontConfig();
     method @RequiresPermission(android.Manifest.permission.UPDATE_FONTS) public int updateFontFamily(@NonNull android.graphics.fonts.FontFamilyUpdateRequest, @IntRange(from=0) int);
     field public static final int RESULT_ERROR_DOWNGRADING = -5; // 0xfffffffb
     field public static final int RESULT_ERROR_FAILED_TO_WRITE_FONT_FILE = -1; // 0xffffffff
@@ -1491,6 +1497,14 @@
 
 package android.os {
 
+  public final class BatteryStatsManager {
+    method @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void resetBattery(boolean);
+    method @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void setBatteryLevel(int, boolean);
+    method @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void setChargerAcOnline(boolean, boolean);
+    method @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void suspendBatteryInput();
+    method @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void unplugBattery(boolean);
+  }
+
   public class Build {
     method public static boolean is64BitAbi(String);
     field public static final boolean IS_EMULATOR;
@@ -2544,6 +2558,7 @@
     method public default int getDisplayImePolicy(int);
     method public default void holdLock(android.os.IBinder, int);
     method public default void setDisplayImePolicy(int, int);
+    method public default void setForceCrossWindowBlurDisabled(boolean);
     method public default void setShouldShowSystemDecors(int, boolean);
     method public default void setShouldShowWithInsecureKeyguard(int, boolean);
     method public default boolean shouldShowSystemDecors(int);
@@ -2719,10 +2734,6 @@
     method @NonNull public static android.view.inputmethod.InlineSuggestionsResponse newInlineSuggestionsResponse(@NonNull java.util.List<android.view.inputmethod.InlineSuggestion>);
   }
 
-  public final class InputMethodInfo implements android.os.Parcelable {
-    ctor public InputMethodInfo(@NonNull String, @NonNull String, @NonNull CharSequence, @NonNull String, int);
-  }
-
   public final class InputMethodManager {
     method public int getDisplayId();
     method public boolean hasActiveInputConnection(@Nullable android.view.View);
@@ -2921,7 +2932,7 @@
     method @BinderThread public void onTaskInfoChanged(@NonNull android.app.ActivityManager.RunningTaskInfo);
     method @BinderThread public void onTaskVanished(@NonNull android.app.ActivityManager.RunningTaskInfo);
     method @CallSuper @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public java.util.List<android.window.TaskAppearedInfo> registerOrganizer();
-    method @BinderThread public void removeStartingWindow(int);
+    method @BinderThread public void removeStartingWindow(int, @Nullable android.view.SurfaceControl, @Nullable android.graphics.Rect, boolean);
     method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void setInterceptBackPressedOnTaskRoot(@NonNull android.window.WindowContainerToken, boolean);
     method @CallSuper @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void unregisterOrganizer();
   }
diff --git a/core/java/android/app/ActivityTaskManager.java b/core/java/android/app/ActivityTaskManager.java
index 233f737..a24f871 100644
--- a/core/java/android/app/ActivityTaskManager.java
+++ b/core/java/android/app/ActivityTaskManager.java
@@ -394,6 +394,20 @@
     }
 
     /**
+     * Whether to allow non-resizable apps to be shown in multi-window. The app will be letterboxed
+     * if the request orientation is not met, and will be shown in size-compat mode if the container
+     * size has changed.
+     * @hide
+     */
+    public static boolean supportsNonResizableMultiWindow() {
+        try {
+            return ActivityTaskManager.getService().supportsNonResizableMultiWindow();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * @return whether the UI mode of the given config supports error dialogs (ANR, crash, etc).
      * @hide
      */
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index dd1bc7c..d310e8f 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -56,6 +56,7 @@
 import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.UserManager;
+import android.provider.DeviceConfig;
 import android.provider.Settings;
 import android.util.ArrayMap;
 import android.util.ArraySet;
@@ -200,9 +201,12 @@
     @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.R)
     public static final long SECURITY_EXCEPTION_ON_INVALID_ATTRIBUTION_TAG_CHANGE = 151105954L;
 
+    private static final String FULL_LOG = "privacy_attribution_tag_full_log_enabled";
 
     private static final int MAX_UNFORWARDED_OPS = 10;
 
+    private static Boolean sFullLog = null;
+
     final Context mContext;
 
     @UnsupportedAppUsage
@@ -6972,6 +6976,26 @@
     AppOpsManager(Context context, IAppOpsService service) {
         mContext = context;
         mService = service;
+
+        if (mContext != null) {
+            final PackageManager pm = mContext.getPackageManager();
+            try {
+                if (pm != null && pm.checkPermission(Manifest.permission.READ_DEVICE_CONFIG,
+                        mContext.getPackageName()) == PackageManager.PERMISSION_GRANTED) {
+                    DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_PRIVACY,
+                            mContext.getMainExecutor(), properties -> {
+                                if (properties.getKeyset().contains(FULL_LOG)) {
+                                    sFullLog = properties.getBoolean(FULL_LOG, false);
+                                }
+                            });
+                    return;
+                }
+            } catch (Exception e) {
+                // This manager was made before DeviceConfig is ready, so it's a low-level
+                // system app. We likely don't care about its logs.
+            }
+        }
+        sFullLog = false;
     }
 
     /**
@@ -9110,10 +9134,20 @@
 
         StringBuilder sb = new StringBuilder();
         for (int i = firstInteresting; i <= lastInteresting; i++) {
+            if (sFullLog == null) {
+                try {
+                    sFullLog = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
+                            FULL_LOG, false);
+                } catch (SecurityException e) {
+                    // This should not happen, but it may, in rare cases
+                    sFullLog = false;
+                }
+            }
+
             if (i != firstInteresting) {
                 sb.append('\n');
             }
-            if (sb.length() + trace[i].toString().length() > 600) {
+            if (!sFullLog && sb.length() + trace[i].toString().length() > 600) {
                 break;
             }
             sb.append(trace[i]);
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index 542f754..3bfddf7 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -289,6 +289,13 @@
     void setSplitScreenResizing(boolean resizing);
     boolean supportsLocalVoiceInteraction();
 
+    /**
+     * Whether to allow non-resizable apps to be shown in multi-window. The app will be letterboxed
+     * if the request orientation is not met, and will be shown in size-compat mode if the container
+     * size has changed.
+     */
+    boolean supportsNonResizableMultiWindow();
+
     // Get device configuration
     ConfigurationInfo getDeviceConfigurationInfo();
 
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 8e53b5b..7dbbc54 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -57,6 +57,7 @@
 import android.os.Build;
 import android.os.Bundle;
 import android.os.DeadSystemException;
+import android.os.Environment;
 import android.os.FileUtils;
 import android.os.Handler;
 import android.os.IBinder;
@@ -120,6 +121,8 @@
     /** {@hide} */
     private static final String VALUE_CMF_COLOR =
             android.os.SystemProperties.get("ro.boot.hardware.color");
+    /** {@hide} */
+    private static final String WALLPAPER_CMF_PATH = "/wallpaper/image/";
 
     /**
      * Activity Action: Show settings for choosing wallpaper. Do not use directly to construct
@@ -2066,22 +2069,17 @@
             return null;
         } else {
             whichProp = PROP_WALLPAPER;
-            final int defaultColorResId = context.getResources().getIdentifier(
-                    "default_wallpaper_" + VALUE_CMF_COLOR, "drawable", "android");
-            defaultResId =
-                    defaultColorResId == 0 ? com.android.internal.R.drawable.default_wallpaper
-                            : defaultColorResId;
+            defaultResId = com.android.internal.R.drawable.default_wallpaper;
         }
         final String path = SystemProperties.get(whichProp);
-        if (!TextUtils.isEmpty(path)) {
-            final File file = new File(path);
-            if (file.exists()) {
-                try {
-                    return new FileInputStream(file);
-                } catch (IOException e) {
-                    // Ignored, fall back to platform default below
-                }
-            }
+        final InputStream wallpaperInputStream = getWallpaperInputStream(path);
+        if (wallpaperInputStream != null) {
+            return wallpaperInputStream;
+        }
+        final String cmfPath = getCmfWallpaperPath();
+        final InputStream cmfWallpaperInputStream = getWallpaperInputStream(cmfPath);
+        if (cmfWallpaperInputStream != null) {
+            return cmfWallpaperInputStream;
         }
         try {
             return context.getResources().openRawResource(defaultResId);
@@ -2091,6 +2089,25 @@
         return null;
     }
 
+    private static InputStream getWallpaperInputStream(String path) {
+        if (!TextUtils.isEmpty(path)) {
+            final File file = new File(path);
+            if (file.exists()) {
+                try {
+                    return new FileInputStream(file);
+                } catch (IOException e) {
+                    // Ignored, fall back to platform default
+                }
+            }
+        }
+        return null;
+    }
+
+    private static String getCmfWallpaperPath() {
+        return Environment.getProductDirectory() + WALLPAPER_CMF_PATH + "default_wallpaper_"
+                + VALUE_CMF_COLOR;
+    }
+
     /**
      * Return {@link ComponentName} of the default live wallpaper, or
      * {@code null} if none is defined.
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 30fb858..930717b 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -13726,4 +13726,22 @@
             throw re.rethrowFromSystemServer();
         }
     }
+
+    /**
+     * Lists apps that are exempt from policies (such as
+     * {@link #setPackagesSuspended(ComponentName, String[], boolean)}).
+     *
+     * @hide
+     */
+    @TestApi
+    @RequiresPermission(value = android.Manifest.permission.MANAGE_DEVICE_ADMINS)
+    public @NonNull Set<String> getPolicyExemptApps() {
+        if (mService == null) return Collections.emptySet();
+
+        try {
+            return new HashSet<>(mService.listPolicyExemptApps());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
 }
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 25ca599..e98720c 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -177,6 +177,7 @@
 
     String[] setPackagesSuspended(in ComponentName admin, in String callerPackage, in String[] packageNames, boolean suspended);
     boolean isPackageSuspended(in ComponentName admin, in String callerPackage, String packageName);
+    List<String> listPolicyExemptApps();
 
     boolean installCaCert(in ComponentName admin, String callerPackage, in byte[] certBuffer);
     void uninstallCaCerts(in ComponentName admin, String callerPackage, in String[] aliases);
diff --git a/core/java/android/appwidget/AppWidgetProviderInfo.java b/core/java/android/appwidget/AppWidgetProviderInfo.java
index 6ac1c1a..1cbb2fb 100644
--- a/core/java/android/appwidget/AppWidgetProviderInfo.java
+++ b/core/java/android/appwidget/AppWidgetProviderInfo.java
@@ -121,7 +121,7 @@
      *
      * @see #widgetFeatures
      */
-    public static final int WIDGET_FEATURE_CONFIGURATION_OPTIONAL = 3;
+    public static final int WIDGET_FEATURE_CONFIGURATION_OPTIONAL = 4;
 
     /** @hide */
     @IntDef(flag = true, prefix = { "FLAG_" }, value = {
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 0509e3f..2523459 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3713,6 +3713,9 @@
      * usage statistics.
      * <dt> {@link #HARDWARE_PROPERTIES_SERVICE} ("hardware_properties")
      * <dd> A {@link android.os.HardwarePropertiesManager} for accessing hardware properties.
+     * <dt> {@link #DOMAIN_VERIFICATION_SERVICE} ("domain_verification")
+     * <dd> A {@link android.content.pm.verify.domain.DomainVerificationManager} for accessing
+     * web domain approval state.
      * </dl>
      *
      * <p>Note:  System services obtained via this API may be closely associated with
@@ -3794,6 +3797,8 @@
      * @see android.app.usage.NetworkStatsManager
      * @see android.os.HardwarePropertiesManager
      * @see #HARDWARE_PROPERTIES_SERVICE
+     * @see #DOMAIN_VERIFICATION_SERVICE
+     * @see android.content.pm.verify.domain.DomainVerificationManager
      */
     public abstract @Nullable Object getSystemService(@ServiceName @NonNull String name);
 
@@ -3813,7 +3818,8 @@
      * {@link android.view.inputmethod.InputMethodManager},
      * {@link android.app.UiModeManager}, {@link android.app.DownloadManager},
      * {@link android.os.BatteryManager}, {@link android.app.job.JobScheduler},
-     * {@link android.app.usage.NetworkStatsManager}.
+     * {@link android.app.usage.NetworkStatsManager},
+     * {@link android.content.pm.verify.domain.DomainVerificationManager}.
      * </p>
      *
      * <p>
@@ -4833,7 +4839,8 @@
      * @hide
      */
     @TestApi
-    @SuppressLint("ServiceName")  // TODO: This should be renamed to POWER_WHITELIST_SERVICE
+    @Deprecated
+    @SuppressLint("ServiceName")
     public static final String POWER_WHITELIST_MANAGER = "power_whitelist";
 
     /**
@@ -4842,7 +4849,7 @@
      * @see #getSystemService(String)
      * @hide
      */
-    @SystemApi
+    @TestApi
     public static final String POWER_EXEMPTION_SERVICE = "power_exemption";
 
     /**
@@ -5544,12 +5551,13 @@
     public static final String GAME_SERVICE = "game";
 
     /**
-     * Use with {@link #getSystemService(String)} to access domain verification service.
+     * Use with {@link #getSystemService(String)} to access
+     * {@link android.content.pm.verify.domain.DomainVerificationManager} to retrieve approval and
+     * user state for declared web domains.
      *
      * @see #getSystemService(String)
-     * @hide
+     * @see android.content.pm.verify.domain.DomainVerificationManager
      */
-    @SystemApi
     public static final String DOMAIN_VERIFICATION_SERVICE = "domain_verification";
 
     /**
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index de17fda..c601aab 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2172,6 +2172,29 @@
             "android.intent.action.REVIEW_PERMISSION_USAGE";
 
     /**
+     * Activity action: Launch UI to review the timeline history of permissions.
+     * <p>
+     * Input: {@link #EXTRA_PERMISSION_GROUP_NAME} specifies the permission group name
+     * that will be displayed by the launched UI.
+     * </p>
+     * <p>
+     * Output: Nothing.
+     * </p>
+     * <p class="note">
+     * This requires {@link android.Manifest.permission#GRANT_RUNTIME_PERMISSIONS} permission.
+     * </p>
+     *
+     * @see #EXTRA_PERMISSION_GROUP_NAME
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS)
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_REVIEW_PERMISSION_HISTORY =
+            "android.intent.action.REVIEW_PERMISSION_HISTORY";
+
+    /**
      * Activity action: Launch UI to review ongoing app uses of permissions.
      * <p>
      * Input: {@link #EXTRA_DURATION_MILLIS} specifies the minimum number of milliseconds of recent
@@ -2331,6 +2354,7 @@
      * @hide
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     public static final String ACTION_CLEAR_DNS_CACHE = "android.intent.action.CLEAR_DNS_CACHE";
     /**
      * Alarm Changed Action: This is broadcast when the AlarmClock
diff --git a/core/java/android/content/SyncAdapterType.java b/core/java/android/content/SyncAdapterType.java
index 1c21b2a..47c333c 100644
--- a/core/java/android/content/SyncAdapterType.java
+++ b/core/java/android/content/SyncAdapterType.java
@@ -17,6 +17,7 @@
 package android.content;
 
 import android.annotation.Nullable;
+import android.annotation.TestApi;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Build;
 import android.os.Parcel;
@@ -168,6 +169,7 @@
      *
      * @hide
      */
+    @TestApi
     public @Nullable String getPackageName() {
         return packageName;
     }
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 5a17753..58f83a7 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -1086,6 +1086,13 @@
      */
     public WindowLayout windowLayout;
 
+    /**
+     * Attribution tags for finer grained calls if a {@android.content.Context#sendBroadcast(Intent,
+     * String)} is used with a permission.
+     * @hide
+     */
+    public String[] attributionTags;
+
     public ActivityInfo() {
     }
 
@@ -1114,6 +1121,7 @@
         maxAspectRatio = orig.maxAspectRatio;
         minAspectRatio = orig.minAspectRatio;
         supportsSizeChanges = orig.supportsSizeChanges;
+        attributionTags = orig.attributionTags;
     }
 
     /**
@@ -1361,6 +1369,15 @@
         if (supportsSizeChanges) {
             pw.println(prefix + "supportsSizeChanges=true");
         }
+        if (attributionTags != null && attributionTags.length > 0) {
+            StringBuilder tags = new StringBuilder();
+            tags.append(attributionTags[0]);
+            for (int i = 1; i < attributionTags.length; i++) {
+                tags.append(", ");
+                tags.append(attributionTags[i]);
+            }
+            pw.println(prefix + "attributionTags=[" + tags + "]");
+        }
         super.dumpBack(pw, prefix, dumpFlags);
     }
 
@@ -1406,6 +1423,7 @@
         dest.writeFloat(maxAspectRatio);
         dest.writeFloat(minAspectRatio);
         dest.writeBoolean(supportsSizeChanges);
+        dest.writeString8Array(attributionTags);
     }
 
     /**
@@ -1525,6 +1543,7 @@
         maxAspectRatio = source.readFloat();
         minAspectRatio = source.readFloat();
         supportsSizeChanges = source.readBoolean();
+        attributionTags = source.createString8Array();
     }
 
     /**
diff --git a/core/java/android/content/pm/IDataLoaderStatusListener.aidl b/core/java/android/content/pm/IDataLoaderStatusListener.aidl
index 745c39b..79b70f2 100644
--- a/core/java/android/content/pm/IDataLoaderStatusListener.aidl
+++ b/core/java/android/content/pm/IDataLoaderStatusListener.aidl
@@ -23,32 +23,34 @@
 oneway interface IDataLoaderStatusListener {
     /** The DataLoader process died, binder disconnected or class destroyed. */
     const int DATA_LOADER_DESTROYED = 0;
+    /** The system is in process of binding to the DataLoader. */
+    const int DATA_LOADER_BINDING = 1;
     /** DataLoader process is running and bound to. */
-    const int DATA_LOADER_BOUND = 1;
+    const int DATA_LOADER_BOUND = 2;
     /** DataLoader has handled onCreate(). */
-    const int DATA_LOADER_CREATED = 2;
+    const int DATA_LOADER_CREATED = 3;
 
     /** DataLoader can receive missing pages and read pages notifications,
      *  and ready to provide data. */
-    const int DATA_LOADER_STARTED = 3;
+    const int DATA_LOADER_STARTED = 4;
     /** DataLoader no longer ready to provide data and is not receiving
     *   any notifications from IncFS. */
-    const int DATA_LOADER_STOPPED = 4;
+    const int DATA_LOADER_STOPPED = 5;
 
     /** DataLoader streamed everything necessary to continue installation. */
-    const int DATA_LOADER_IMAGE_READY = 5;
+    const int DATA_LOADER_IMAGE_READY = 6;
     /** Installation can't continue as DataLoader failed to stream necessary data. */
-    const int DATA_LOADER_IMAGE_NOT_READY = 6;
+    const int DATA_LOADER_IMAGE_NOT_READY = 7;
 
     /** DataLoader instance can't run at the moment, but might recover later.
      *  It's up to system to decide if the app is still usable. */
-    const int DATA_LOADER_UNAVAILABLE = 7;
+    const int DATA_LOADER_UNAVAILABLE = 8;
 
     /** DataLoader reports that this instance is invalid and can never be restored.
     *   Warning: this is a terminal status that data loader should use carefully and
     *            the system should almost never use - e.g. only if all recovery attempts
     *            fail and all retry limits are exceeded. */
-    const int DATA_LOADER_UNRECOVERABLE = 8;
+    const int DATA_LOADER_UNRECOVERABLE = 9;
 
     /** There are no known issues with the data stream. */
     const int STREAM_HEALTHY = 0;
diff --git a/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java b/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
index 9a84ded..b660a00 100644
--- a/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
+++ b/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
@@ -482,6 +482,7 @@
         ai.rotationAnimation = a.getRotationAnimation();
         ai.colorMode = a.getColorMode();
         ai.windowLayout = a.getWindowLayout();
+        ai.attributionTags = a.getAttributionTags();
         if ((flags & PackageManager.GET_META_DATA) != 0) {
             ai.metaData = a.getMetaData();
         }
diff --git a/core/java/android/content/pm/parsing/component/ParsedActivity.java b/core/java/android/content/pm/parsing/component/ParsedActivity.java
index 6f478ac..9285ccb 100644
--- a/core/java/android/content/pm/parsing/component/ParsedActivity.java
+++ b/core/java/android/content/pm/parsing/component/ParsedActivity.java
@@ -82,6 +82,9 @@
     @Nullable
     ActivityInfo.WindowLayout windowLayout;
 
+    @Nullable
+    String[] attributionTags;
+
     public ParsedActivity(ParsedActivity other) {
         super(other);
         this.theme = other.theme;
@@ -107,6 +110,7 @@
         this.rotationAnimation = other.rotationAnimation;
         this.colorMode = other.colorMode;
         this.windowLayout = other.windowLayout;
+        this.attributionTags = other.attributionTags;
     }
 
     /**
@@ -172,6 +176,7 @@
         alias.requestedVrComponent = target.requestedVrComponent;
         alias.directBootAware = target.directBootAware;
         alias.setProcessName(target.getProcessName());
+        alias.attributionTags = target.attributionTags;
         return alias;
 
         // Not all attributes from the target ParsedActivity are copied to the alias.
@@ -299,6 +304,7 @@
         } else {
             dest.writeBoolean(false);
         }
+        dest.writeString8Array(this.attributionTags);
     }
 
     public ParsedActivity() {
@@ -332,6 +338,7 @@
         if (in.readBoolean()) {
             windowLayout = new ActivityInfo.WindowLayout(in);
         }
+        this.attributionTags = in.createString8Array();
     }
 
     public static final Parcelable.Creator<ParsedActivity> CREATOR = new Creator<ParsedActivity>() {
@@ -445,4 +452,9 @@
     public ActivityInfo.WindowLayout getWindowLayout() {
         return windowLayout;
     }
+
+    @Nullable
+    public String[] getAttributionTags() {
+        return attributionTags;
+    }
 }
diff --git a/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java b/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java
index 0f4aa06..d99c410 100644
--- a/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java
+++ b/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java
@@ -210,6 +210,11 @@
                 pkg.setVisibleToInstantApps(true);
             }
 
+            String attributionTags = sa.getString(R.styleable.AndroidManifestActivity_attributionTags);
+            if (attributionTags != null) {
+                activity.attributionTags = attributionTags.split("\\|");
+            }
+
             return parseActivityOrAlias(activity, pkg, tag, parser, res, sa, receiver,
                     false /*isAlias*/, visibleToEphemeral, input,
                     R.styleable.AndroidManifestActivity_parentActivityName,
diff --git a/core/java/android/ddm/DdmHandleHeap.java b/core/java/android/ddm/DdmHandleHeap.java
index e24aeb2..8fa2352 100644
--- a/core/java/android/ddm/DdmHandleHeap.java
+++ b/core/java/android/ddm/DdmHandleHeap.java
@@ -30,15 +30,7 @@
  */
 public class DdmHandleHeap extends ChunkHandler {
 
-    public static final int CHUNK_HPIF = type("HPIF");
-    public static final int CHUNK_HPSG = type("HPSG");
-    public static final int CHUNK_HPDU = type("HPDU");
-    public static final int CHUNK_HPDS = type("HPDS");
-    public static final int CHUNK_NHSG = type("NHSG");
     public static final int CHUNK_HPGC = type("HPGC");
-    public static final int CHUNK_REAE = type("REAE");
-    public static final int CHUNK_REAQ = type("REAQ");
-    public static final int CHUNK_REAL = type("REAL");
 
     private static DdmHandleHeap mInstance = new DdmHandleHeap();
 
@@ -50,15 +42,7 @@
      * Register for the messages we're interested in.
      */
     public static void register() {
-        DdmServer.registerHandler(CHUNK_HPIF, mInstance);
-        DdmServer.registerHandler(CHUNK_HPSG, mInstance);
-        DdmServer.registerHandler(CHUNK_HPDU, mInstance);
-        DdmServer.registerHandler(CHUNK_HPDS, mInstance);
-        DdmServer.registerHandler(CHUNK_NHSG, mInstance);
         DdmServer.registerHandler(CHUNK_HPGC, mInstance);
-        DdmServer.registerHandler(CHUNK_REAE, mInstance);
-        DdmServer.registerHandler(CHUNK_REAQ, mInstance);
-        DdmServer.registerHandler(CHUNK_REAL, mInstance);
     }
 
     /**
@@ -81,24 +65,8 @@
             Log.v("ddm-heap", "Handling " + name(request.type) + " chunk");
         int type = request.type;
 
-        if (type == CHUNK_HPIF) {
-            return handleHPIF(request);
-        } else if (type == CHUNK_HPSG) {
-            return handleHPSGNHSG(request, false);
-        } else if (type == CHUNK_HPDU) {
-            return handleHPDU(request);
-        } else if (type == CHUNK_HPDS) {
-            return handleHPDS(request);
-        } else if (type == CHUNK_NHSG) {
-            return handleHPSGNHSG(request, true);
-        } else if (type == CHUNK_HPGC) {
+        if (type == CHUNK_HPGC) {
             return handleHPGC(request);
-        } else if (type == CHUNK_REAE) {
-            return handleREAE(request);
-        } else if (type == CHUNK_REAQ) {
-            return handleREAQ(request);
-        } else if (type == CHUNK_REAL) {
-            return handleREAL(request);
         } else {
             throw new RuntimeException("Unknown packet "
                 + ChunkHandler.name(type));
@@ -106,112 +74,6 @@
     }
 
     /*
-     * Handle a "HeaP InFo" request.
-     */
-    private Chunk handleHPIF(Chunk request) {
-        ByteBuffer in = wrapChunk(request);
-
-        int when = in.get();
-        if (false)
-            Log.v("ddm-heap", "Heap segment enable: when=" + when);
-
-        boolean ok = DdmVmInternal.heapInfoNotify(when);
-        if (!ok) {
-            return createFailChunk(1, "Unsupported HPIF what");
-        } else {
-            return null;        // empty response
-        }
-    }
-
-    /*
-     * Handle a "HeaP SeGment" or "Native Heap SeGment" request.
-     */
-    private Chunk handleHPSGNHSG(Chunk request, boolean isNative) {
-        ByteBuffer in = wrapChunk(request);
-
-        int when = in.get();
-        int what = in.get();
-        if (false)
-            Log.v("ddm-heap", "Heap segment enable: when=" + when
-                + ", what=" + what + ", isNative=" + isNative);
-
-        boolean ok = DdmVmInternal.heapSegmentNotify(when, what, isNative);
-        if (!ok) {
-            return createFailChunk(1, "Unsupported HPSG what/when");
-        } else {
-            // TODO: if "when" is non-zero and we want to see a dump
-            //       right away, initiate a GC.
-            return null;        // empty response
-        }
-    }
-
-    /*
-     * Handle a "HeaP DUmp" request.
-     *
-     * This currently just returns a result code.  We could pull up
-     * the entire contents of the file and return them, but hprof dump
-     * files can be a few megabytes.
-     */
-    private Chunk handleHPDU(Chunk request) {
-        ByteBuffer in = wrapChunk(request);
-        byte result;
-
-        /* get the filename for the output file */
-        int len = in.getInt();
-        String fileName = getString(in, len);
-        if (false)
-            Log.d("ddm-heap", "Heap dump: file='" + fileName + "'");
-
-        try {
-            Debug.dumpHprofData(fileName);
-            result = 0;
-        } catch (UnsupportedOperationException uoe) {
-            Log.w("ddm-heap", "hprof dumps not supported in this VM");
-            result = -1;
-        } catch (IOException ioe) {
-            result = -1;
-        } catch (RuntimeException re) {
-            result = -1;
-        }
-
-        /* create a non-empty reply so the handler fires on completion */
-        byte[] reply = { result };
-        return new Chunk(CHUNK_HPDU, reply, 0, reply.length);
-    }
-
-    /*
-     * Handle a "HeaP Dump Streaming" request.
-     *
-     * This tells the VM to create a heap dump and send it directly to
-     * DDMS.  The dumps are large enough that we don't want to copy the
-     * data into a byte[] and send it from here.
-     */
-    private Chunk handleHPDS(Chunk request) {
-        ByteBuffer in = wrapChunk(request);
-        byte result;
-
-        /* get the filename for the output file */
-        if (false)
-            Log.d("ddm-heap", "Heap dump: [DDMS]");
-
-        String failMsg = null;
-        try {
-            Debug.dumpHprofDataDdms();
-        } catch (UnsupportedOperationException uoe) {
-            failMsg = "hprof dumps not supported in this VM";
-        } catch (RuntimeException re) {
-            failMsg = "Exception: " + re.getMessage();
-        }
-
-        if (failMsg != null) {
-            Log.w("ddm-heap", failMsg);
-            return createFailChunk(1, failMsg);
-        } else {
-            return null;
-        }
-    }
-
-    /*
      * Handle a "HeaP Garbage Collection" request.
      */
     private Chunk handleHPGC(Chunk request) {
@@ -223,47 +85,4 @@
 
         return null;        // empty response
     }
-
-    /*
-     * Handle a "REcent Allocation Enable" request.
-     */
-    private Chunk handleREAE(Chunk request) {
-        ByteBuffer in = wrapChunk(request);
-        boolean enable;
-
-        enable = (in.get() != 0);
-
-        if (false)
-            Log.d("ddm-heap", "Recent allocation enable request: " + enable);
-
-        DdmVmInternal.enableRecentAllocations(enable);
-
-        return null;        // empty response
-    }
-
-    /*
-     * Handle a "REcent Allocation Query" request.
-     */
-    private Chunk handleREAQ(Chunk request) {
-        //ByteBuffer in = wrapChunk(request);
-
-        byte[] reply = new byte[1];
-        reply[0] = DdmVmInternal.getRecentAllocationStatus() ? (byte)1 :(byte)0;
-        return new Chunk(CHUNK_REAQ, reply, 0, reply.length);
-    }
-
-    /*
-     * Handle a "REcent ALlocations" request.
-     */
-    private Chunk handleREAL(Chunk request) {
-        //ByteBuffer in = wrapChunk(request);
-
-        if (false)
-            Log.d("ddm-heap", "Recent allocations request");
-
-        /* generate the reply in a ready-to-go format */
-        byte[] reply = DdmVmInternal.getRecentAllocations();
-        return new Chunk(CHUNK_REAL, reply, 0, reply.length);
-    }
 }
-
diff --git a/core/java/android/ddm/DdmHandleThread.java b/core/java/android/ddm/DdmHandleThread.java
deleted file mode 100644
index 613ab75..0000000
--- a/core/java/android/ddm/DdmHandleThread.java
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.ddm;
-
-import org.apache.harmony.dalvik.ddmc.Chunk;
-import org.apache.harmony.dalvik.ddmc.ChunkHandler;
-import org.apache.harmony.dalvik.ddmc.DdmServer;
-import org.apache.harmony.dalvik.ddmc.DdmVmInternal;
-import android.util.Log;
-import java.nio.ByteBuffer;
-
-/**
- * Handle thread-related traffic.
- */
-public class DdmHandleThread extends ChunkHandler {
-
-    public static final int CHUNK_THEN = type("THEN");
-    public static final int CHUNK_THCR = type("THCR");
-    public static final int CHUNK_THDE = type("THDE");
-    public static final int CHUNK_THST = type("THST");
-    public static final int CHUNK_STKL = type("STKL");
-
-    private static DdmHandleThread mInstance = new DdmHandleThread();
-
-
-    /* singleton, do not instantiate */
-    private DdmHandleThread() {}
-
-    /**
-     * Register for the messages we're interested in.
-     */
-    public static void register() {
-        DdmServer.registerHandler(CHUNK_THEN, mInstance);
-        DdmServer.registerHandler(CHUNK_THST, mInstance);
-        DdmServer.registerHandler(CHUNK_STKL, mInstance);
-    }
-
-    /**
-     * Called when the DDM server connects.  The handler is allowed to
-     * send messages to the server.
-     */
-    public void connected() {}
-
-    /**
-     * Called when the DDM server disconnects.  Can be used to disable
-     * periodic transmissions or clean up saved state.
-     */
-    public void disconnected() {}
-
-    /**
-     * Handle a chunk of data.
-     */
-    public Chunk handleChunk(Chunk request) {
-        if (false)
-            Log.v("ddm-thread", "Handling " + name(request.type) + " chunk");
-        int type = request.type;
-
-        if (type == CHUNK_THEN) {
-            return handleTHEN(request);
-        } else if (type == CHUNK_THST) {
-            return handleTHST(request);
-        } else if (type == CHUNK_STKL) {
-            return handleSTKL(request);
-        } else {
-            throw new RuntimeException("Unknown packet "
-                + ChunkHandler.name(type));
-        }
-    }
-
-    /*
-     * Handle a "THread notification ENable" request.
-     */
-    private Chunk handleTHEN(Chunk request) {
-        ByteBuffer in = wrapChunk(request);
-
-        boolean enable = (in.get() != 0);
-        //Log.i("ddm-thread", "Thread notify enable: " + enable);
-
-        DdmVmInternal.threadNotify(enable);
-        return null;        // empty response
-    }
-
-    /*
-     * Handle a "THread STatus" request.  This is constructed by the VM.
-     */
-    private Chunk handleTHST(Chunk request) {
-        ByteBuffer in = wrapChunk(request);
-        // currently nothing to read from "in"
-
-        //Log.d("ddm-thread", "Thread status request");
-
-        byte[] status = DdmVmInternal.getThreadStats();
-        if (status != null)
-            return new Chunk(CHUNK_THST, status, 0, status.length);
-        else
-            return createFailChunk(1, "Can't build THST chunk");
-    }
-
-    /*
-     * Handle a STacK List request.
-     *
-     * This is done by threadId, which isn't great since those are
-     * recycled.  We need a thread serial ID.  The Linux tid is an okay
-     * answer as it's unlikely to recycle at the exact wrong moment.
-     * However, we're using the short threadId in THST messages, so we
-     * use them here for consistency.  (One thought is to keep the current
-     * thread ID in the low 16 bits and somehow serialize the top 16 bits.)
-     */
-    private Chunk handleSTKL(Chunk request) {
-        ByteBuffer in = wrapChunk(request);
-        int threadId;
-
-        threadId = in.getInt();
-
-        //Log.d("ddm-thread", "Stack list request " + threadId);
-
-        StackTraceElement[] trace = DdmVmInternal.getStackTraceById(threadId);
-        if (trace == null) {
-            return createFailChunk(1, "Stack trace unavailable");
-        } else {
-            return createStackChunk(trace, threadId);
-        }
-    }
-
-    /*
-     * Serialize a StackTraceElement[] into an STKL chunk.
-     *
-     * We include the threadId in the response so the other side doesn't have
-     * to match up requests and responses as carefully.
-     */
-    private Chunk createStackChunk(StackTraceElement[] trace, int threadId) {
-        int bufferSize = 0;
-
-        bufferSize += 4;            // version, flags, whatever
-        bufferSize += 4;            // thread ID
-        bufferSize += 4;            // frame count
-        for (StackTraceElement elem : trace) {
-            bufferSize += 4 + elem.getClassName().length() * 2;
-            bufferSize += 4 + elem.getMethodName().length() * 2;
-            bufferSize += 4;
-            if (elem.getFileName() != null)
-                bufferSize += elem.getFileName().length() * 2;
-            bufferSize += 4;        // line number
-        }
-
-        ByteBuffer out = ByteBuffer.allocate(bufferSize);
-        out.putInt(0);
-        out.putInt(threadId);
-        out.putInt(trace.length);
-        for (StackTraceElement elem : trace) {
-            out.putInt(elem.getClassName().length());
-            putString(out, elem.getClassName());
-            out.putInt(elem.getMethodName().length());
-            putString(out, elem.getMethodName());
-            if (elem.getFileName() != null) {
-                out.putInt(elem.getFileName().length());
-                putString(out, elem.getFileName());
-            } else {
-                out.putInt(0);
-            }
-            out.putInt(elem.getLineNumber());
-        }
-
-        return new Chunk(CHUNK_STKL, out);
-    }
-}
-
diff --git a/core/java/android/ddm/DdmRegister.java b/core/java/android/ddm/DdmRegister.java
index e0faa51..ca10312 100644
--- a/core/java/android/ddm/DdmRegister.java
+++ b/core/java/android/ddm/DdmRegister.java
@@ -16,9 +16,10 @@
 
 package android.ddm;
 
-import org.apache.harmony.dalvik.ddmc.DdmServer;
 import android.util.Log;
 
+import org.apache.harmony.dalvik.ddmc.DdmServer;
+
 /**
  * Just a place to stick handler registrations, instead of scattering
  * them around.
@@ -46,7 +47,6 @@
         if (false)
             Log.v("ddm", "Registering DDM message handlers");
         DdmHandleHello.register();
-        DdmHandleThread.register();
         DdmHandleHeap.register();
         DdmHandleNativeHeap.register();
         DdmHandleProfiling.register();
diff --git a/core/java/android/graphics/fonts/FontManager.java b/core/java/android/graphics/fonts/FontManager.java
index 7bf692f..fa2ccbc 100644
--- a/core/java/android/graphics/fonts/FontManager.java
+++ b/core/java/android/graphics/fonts/FontManager.java
@@ -195,6 +195,7 @@
      * @return The current font configuration. null if failed to fetch information from the system
      *         service.
      */
+    @RequiresPermission(Manifest.permission.UPDATE_FONTS)
     public @NonNull FontConfig getFontConfig() {
         try {
             return mIFontManager.getFontConfig();
diff --git a/core/java/android/hardware/SystemSensorManager.java b/core/java/android/hardware/SystemSensorManager.java
index 788afe3..365dea6 100644
--- a/core/java/android/hardware/SystemSensorManager.java
+++ b/core/java/android/hardware/SystemSensorManager.java
@@ -65,7 +65,7 @@
     private static final int CAPPED_SAMPLING_RATE_LEVEL = SensorDirectChannel.RATE_NORMAL;
 
     private static final String HIGH_SAMPLING_RATE_SENSORS_PERMISSION =
-                                        "android.permisison.HIGH_SAMPLING_RATE_SENSORS";
+                                        "android.permission.HIGH_SAMPLING_RATE_SENSORS";
     /**
      * For apps targeting S and above, a SecurityException is thrown when they do not have
      * HIGH_SAMPLING_RATE_SENSORS permission, run in debug mode, and request sampling rates that
diff --git a/core/java/android/inputmethodservice/IInputMethodWrapper.java b/core/java/android/inputmethodservice/IInputMethodWrapper.java
index 9198eb7..5cfcd66 100644
--- a/core/java/android/inputmethodservice/IInputMethodWrapper.java
+++ b/core/java/android/inputmethodservice/IInputMethodWrapper.java
@@ -171,7 +171,7 @@
                 SomeArgs args = (SomeArgs) msg.obj;
                 try {
                     inputMethod.initializeInternal((IBinder) args.arg1, msg.arg1,
-                            (IInputMethodPrivilegedOperations) args.arg2, (int) args.arg3);
+                            (IInputMethodPrivilegedOperations) args.arg2);
                 } finally {
                     args.recycle();
                 }
@@ -280,10 +280,9 @@
     @BinderThread
     @Override
     public void initializeInternal(IBinder token, int displayId,
-            IInputMethodPrivilegedOperations privOps, int configChanges) {
+            IInputMethodPrivilegedOperations privOps) {
         mCaller.executeOrSendMessage(
-                mCaller.obtainMessageIOOO(DO_INITIALIZE_INTERNAL, displayId, token, privOps,
-                        configChanges));
+                mCaller.obtainMessageIOO(DO_INITIALIZE_INTERNAL, displayId, token, privOps));
     }
 
     @BinderThread
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 40a0fc4..7e2be01 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -70,7 +70,6 @@
 import android.compat.annotation.EnabledSince;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
-import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
 import android.content.res.Configuration;
 import android.content.res.Resources;
@@ -132,7 +131,6 @@
 import android.window.WindowMetricsHelper;
 
 import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.inputmethod.IInputContentUriToken;
 import com.android.internal.inputmethod.IInputMethodPrivilegedOperations;
 import com.android.internal.inputmethod.InputMethodPrivilegedOperations;
@@ -515,8 +513,6 @@
     private boolean mIsAutomotive;
     private Handler mHandler;
     private boolean mImeSurfaceScheduledForRemoval;
-    private Configuration mLastKnownConfig;
-    private int mHandledConfigChanges;
 
     /**
      * An opaque {@link Binder} token of window requesting {@link InputMethodImpl#showSoftInput}
@@ -592,13 +588,12 @@
         @MainThread
         @Override
         public final void initializeInternal(@NonNull IBinder token, int displayId,
-                IInputMethodPrivilegedOperations privilegedOperations, int configChanges) {
+                IInputMethodPrivilegedOperations privilegedOperations) {
             if (InputMethodPrivilegedOperationsRegistry.isRegistered(token)) {
                 Log.w(TAG, "The token has already registered, ignore this initialization.");
                 return;
             }
             Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.initializeInternal");
-            mHandledConfigChanges = configChanges;
             mPrivOps.set(privilegedOperations);
             InputMethodPrivilegedOperationsRegistry.put(token, mPrivOps);
             updateInputMethodDisplay(displayId);
@@ -826,9 +821,6 @@
                 setImeWindowStatus(mapToImeWindowStatus(), mBackDisposition);
             }
             final boolean isVisible = isInputViewShown();
-            if (isVisible && getResources() != null) {
-                mLastKnownConfig = new Configuration(getResources().getConfiguration());
-            }
             final boolean visibilityChanged = isVisible != wasVisible;
             if (resultReceiver != null) {
                 resultReceiver.send(visibilityChanged
@@ -1436,30 +1428,10 @@
      * state: {@link #onStartInput} if input is active, and
      * {@link #onCreateInputView} and {@link #onStartInputView} and related
      * appropriate functions if the UI is displayed.
-     * <p>Starting with {@link Build.VERSION_CODES#S}, IMEs can opt into handling configuration
-     * changes themselves instead of being restarted with
-     * {@link android.R.styleable#InputMethod_configChanges}.
      */
     @Override public void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
-        if (shouldImeRestartForConfig(newConfig)) {
-            resetStateForNewConfiguration();
-        }
-    }
-
-    /**
-     * @return {@code true} if {@link InputMethodService} needs to restart to handle
-     * .{@link #onConfigurationChanged(Configuration)}
-     */
-    @VisibleForTesting
-    boolean shouldImeRestartForConfig(@NonNull Configuration newConfig) {
-        if (mLastKnownConfig == null) {
-            return true;
-        }
-        // If the new config is the same as the config this Service is already running with,
-        // then don't bother calling resetStateForNewConfiguration.
-        int unhandledDiff = (mLastKnownConfig.diffPublicOnly(newConfig) & ~mHandledConfigChanges);
-        return unhandledDiff != 0;
+        resetStateForNewConfiguration();
     }
 
     private void resetStateForNewConfiguration() {
@@ -3209,17 +3181,7 @@
             requestHideSelf(InputMethodManager.HIDE_NOT_ALWAYS);
         }
     }
-
-    @VisibleForTesting
-    void setLastKnownConfig(@NonNull Configuration config) {
-        mLastKnownConfig = config;
-    }
-
-    @VisibleForTesting
-    void setHandledConfigChanges(int configChanges) {
-        mHandledConfigChanges = configChanges;
-    }
-
+    
     void startExtractingText(boolean inputChanged) {
         final ExtractEditText eet = mExtractEditText;
         if (eet != null && getCurrentInputStarted()
diff --git a/core/java/android/net/vcn/VcnManager.java b/core/java/android/net/vcn/VcnManager.java
index 8ebf757..062438c 100644
--- a/core/java/android/net/vcn/VcnManager.java
+++ b/core/java/android/net/vcn/VcnManager.java
@@ -73,7 +73,8 @@
 public class VcnManager {
     @NonNull private static final String TAG = VcnManager.class.getSimpleName();
 
-    private static final Map<VcnNetworkPolicyListener, VcnUnderlyingNetworkPolicyListenerBinder>
+    private static final Map<
+                    VcnNetworkPolicyChangeListener, VcnUnderlyingNetworkPolicyListenerBinder>
             REGISTERED_POLICY_LISTENERS = new ConcurrentHashMap<>();
 
     @NonNull private final Context mContext;
@@ -93,13 +94,13 @@
     }
 
     /**
-     * Get all currently registered VcnNetworkPolicyListeners for testing purposes.
+     * Get all currently registered VcnNetworkPolicyChangeListeners for testing purposes.
      *
      * @hide
      */
     @VisibleForTesting(visibility = Visibility.PRIVATE)
     @NonNull
-    public static Map<VcnNetworkPolicyListener, VcnUnderlyingNetworkPolicyListenerBinder>
+    public static Map<VcnNetworkPolicyChangeListener, VcnUnderlyingNetworkPolicyListenerBinder>
             getAllPolicyListeners() {
         return Collections.unmodifiableMap(REGISTERED_POLICY_LISTENERS);
     }
@@ -162,14 +163,14 @@
     }
 
     // TODO(b/180537630): remove all VcnUnderlyingNetworkPolicyListener refs once Telephony is using
-    // the new VcnNetworkPolicyListener API
+    // the new VcnNetworkPolicyChangeListener API
     /**
      * VcnUnderlyingNetworkPolicyListener is the interface through which internal system components
      * can register to receive updates for VCN-underlying Network policies from the System Server.
      *
      * @hide
      */
-    public interface VcnUnderlyingNetworkPolicyListener extends VcnNetworkPolicyListener {}
+    public interface VcnUnderlyingNetworkPolicyListener extends VcnNetworkPolicyChangeListener {}
 
     /**
      * Add a listener for VCN-underlying network policy updates.
@@ -185,7 +186,7 @@
     @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
     public void addVcnUnderlyingNetworkPolicyListener(
             @NonNull Executor executor, @NonNull VcnUnderlyingNetworkPolicyListener listener) {
-        addVcnNetworkPolicyListener(executor, listener);
+        addVcnNetworkPolicyChangeListener(executor, listener);
     }
 
     /**
@@ -198,7 +199,7 @@
      */
     public void removeVcnUnderlyingNetworkPolicyListener(
             @NonNull VcnUnderlyingNetworkPolicyListener listener) {
-        removeVcnNetworkPolicyListener(listener);
+        removeVcnNetworkPolicyChangeListener(listener);
     }
 
     /**
@@ -233,20 +234,20 @@
     }
 
     /**
-     * VcnNetworkPolicyListener is the interface through which internal system components (e.g.
-     * Network Factories) can register to receive updates for VCN-underlying Network policies from
-     * the System Server.
+     * VcnNetworkPolicyChangeListener is the interface through which internal system components
+     * (e.g. Network Factories) can register to receive updates for VCN-underlying Network policies
+     * from the System Server.
      *
      * <p>Any Network Factory that brings up Networks capable of being VCN-underlying Networks
-     * should register a VcnNetworkPolicyListener. VcnManager will then use this listener to notify
-     * the registrant when VCN Network policies change. Upon receiving this signal, the listener
-     * must check {@link VcnManager} for the current Network policy result for each of its Networks
-     * via {@link #applyVcnNetworkPolicy(NetworkCapabilities, LinkProperties)}.
+     * should register a VcnNetworkPolicyChangeListener. VcnManager will then use this listener to
+     * notify the registrant when VCN Network policies change. Upon receiving this signal, the
+     * listener must check {@link VcnManager} for the current Network policy result for each of its
+     * Networks via {@link #applyVcnNetworkPolicy(NetworkCapabilities, LinkProperties)}.
      *
      * @hide
      */
     @SystemApi
-    public interface VcnNetworkPolicyListener {
+    public interface VcnNetworkPolicyChangeListener {
         /**
          * Notifies the implementation that the VCN's underlying Network policy has changed.
          *
@@ -260,20 +261,21 @@
     /**
      * Add a listener for VCN-underlying Network policy updates.
      *
-     * <p>A {@link VcnNetworkPolicyListener} is eligible to begin receiving callbacks once it is
-     * registered. No callbacks are guaranteed upon registration.
+     * <p>A {@link VcnNetworkPolicyChangeListener} is eligible to begin receiving callbacks once it
+     * is registered. No callbacks are guaranteed upon registration.
      *
      * @param executor the Executor that will be used for invoking all calls to the specified
      *     Listener
-     * @param listener the VcnNetworkPolicyListener to be added
+     * @param listener the VcnNetworkPolicyChangeListener to be added
      * @throws SecurityException if the caller does not have permission NETWORK_FACTORY
-     * @throws IllegalStateException if the specified VcnNetworkPolicyListener is already registered
+     * @throws IllegalStateException if the specified VcnNetworkPolicyChangeListener is already
+     *     registered
      * @hide
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
-    public void addVcnNetworkPolicyListener(
-            @NonNull Executor executor, @NonNull VcnNetworkPolicyListener listener) {
+    public void addVcnNetworkPolicyChangeListener(
+            @NonNull Executor executor, @NonNull VcnNetworkPolicyChangeListener listener) {
         requireNonNull(executor, "executor must not be null");
         requireNonNull(listener, "listener must not be null");
 
@@ -292,15 +294,18 @@
     }
 
     /**
-     * Remove the specified VcnNetworkPolicyListener from VcnManager.
+     * Remove the specified VcnNetworkPolicyChangeListener from VcnManager.
      *
      * <p>If the specified listener is not currently registered, this is a no-op.
      *
-     * @param listener the VcnNetworkPolicyListener that will be removed
+     * @param listener the VcnNetworkPolicyChangeListener that will be removed
+     * @throws SecurityException if the caller does not have permission NETWORK_FACTORY
      * @hide
      */
     @SystemApi
-    public void removeVcnNetworkPolicyListener(@NonNull VcnNetworkPolicyListener listener) {
+    @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
+    public void removeVcnNetworkPolicyChangeListener(
+            @NonNull VcnNetworkPolicyChangeListener listener) {
         requireNonNull(listener, "listener must not be null");
 
         VcnUnderlyingNetworkPolicyListenerBinder binder =
@@ -320,8 +325,9 @@
      * Applies the network policy for a {@link android.net.Network} with the given parameters.
      *
      * <p>Prior to a new NetworkAgent being registered, or upon notification that Carrier VCN policy
-     * may have changed via {@link VcnNetworkPolicyListener#onPolicyChanged()}, a Network Provider
-     * MUST poll for the updated Network policy based on that Network's capabilities and properties.
+     * may have changed via {@link VcnNetworkPolicyChangeListener#onPolicyChanged()}, a Network
+     * Provider MUST poll for the updated Network policy based on that Network's capabilities and
+     * properties.
      *
      * @param networkCapabilities the NetworkCapabilities to be used in determining the Network
      *     policy result for this Network.
@@ -532,17 +538,18 @@
     }
 
     /**
-     * Binder wrapper for added VcnNetworkPolicyListeners to receive signals from System Server.
+     * Binder wrapper for added VcnNetworkPolicyChangeListeners to receive signals from System
+     * Server.
      *
      * @hide
      */
     private static class VcnUnderlyingNetworkPolicyListenerBinder
             extends IVcnUnderlyingNetworkPolicyListener.Stub {
         @NonNull private final Executor mExecutor;
-        @NonNull private final VcnNetworkPolicyListener mListener;
+        @NonNull private final VcnNetworkPolicyChangeListener mListener;
 
         private VcnUnderlyingNetworkPolicyListenerBinder(
-                Executor executor, VcnNetworkPolicyListener listener) {
+                Executor executor, VcnNetworkPolicyChangeListener listener) {
             mExecutor = executor;
             mListener = listener;
         }
diff --git a/core/java/android/os/BatteryManagerInternal.java b/core/java/android/os/BatteryManagerInternal.java
index a86237d..97ec594 100644
--- a/core/java/android/os/BatteryManagerInternal.java
+++ b/core/java/android/os/BatteryManagerInternal.java
@@ -83,4 +83,29 @@
      * wait on the battery service lock.
      */
     public abstract int getInvalidCharger();
+
+    /**
+     * Sets battery AC charger to enabled/disabled, and freezes the battery state.
+     */
+    public abstract void setChargerAcOnline(boolean online, boolean forceUpdate);
+
+    /**
+     * Sets battery level, and freezes the battery state.
+     */
+    public abstract void setBatteryLevel(int level, boolean forceUpdate);
+
+    /**
+     * Unplugs battery, and freezes the battery state.
+     */
+    public abstract void unplugBattery(boolean forceUpdate);
+
+    /**
+     * Unfreezes battery state, returning to current hardware values.
+     */
+    public abstract void resetBattery(boolean forceUpdate);
+
+    /**
+     * Suspend charging even if plugged in.
+     */
+    public abstract void suspendBatteryInput();
 }
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 66f7bd9..4c26e2f 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -995,6 +995,15 @@
         public abstract long getScreenOnMeasuredBatteryConsumptionUC();
 
         /**
+         * Returns the battery consumption (in microcoulombs) of the uid's cpu usage, derived from
+         * on device power measurement data.
+         * Will return {@link #POWER_DATA_UNAVAILABLE} if data is unavailable.
+         *
+         * {@hide}
+         */
+        public abstract long getCpuMeasuredBatteryConsumptionUC();
+
+        /**
          * 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}).
@@ -2521,6 +2530,15 @@
     public abstract long getScreenDozeMeasuredBatteryConsumptionUC();
 
     /**
+     * Returns the battery consumption (in microcoulombs) of the cpu, derived from on device power
+     * measurement data.
+     * Will return {@link #POWER_DATA_UNAVAILABLE} if data is unavailable.
+     *
+     * {@hide}
+     */
+    public abstract long getCpuMeasuredBatteryConsumptionUC();
+
+    /**
      * 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}) consumed.
diff --git a/core/java/android/os/BatteryStatsManager.java b/core/java/android/os/BatteryStatsManager.java
index 1905d70..e47478a 100644
--- a/core/java/android/os/BatteryStatsManager.java
+++ b/core/java/android/os/BatteryStatsManager.java
@@ -23,6 +23,7 @@
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
+import android.annotation.TestApi;
 import android.content.Context;
 import android.net.NetworkStack;
 import android.os.connectivity.CellularBatteryStats;
@@ -487,4 +488,74 @@
         return isActive ? DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH
                 : DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
     }
-}
+
+    /**
+     * Sets battery AC charger to enabled/disabled, and freezes the battery state.
+     * @hide
+     */
+    @TestApi
+    @RequiresPermission(android.Manifest.permission.DEVICE_POWER)
+    public void setChargerAcOnline(boolean online, boolean forceUpdate) {
+        try {
+            mBatteryStats.setChargerAcOnline(online, forceUpdate);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Sets battery level, and freezes the battery state.
+     * @hide
+     */
+    @TestApi
+    @RequiresPermission(android.Manifest.permission.DEVICE_POWER)
+    public void setBatteryLevel(int level, boolean forceUpdate) {
+        try {
+            mBatteryStats.setBatteryLevel(level, forceUpdate);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Unplugs battery, and freezes the battery state.
+     * @hide
+     */
+    @TestApi
+    @RequiresPermission(android.Manifest.permission.DEVICE_POWER)
+    public void unplugBattery(boolean forceUpdate) {
+        try {
+            mBatteryStats.unplugBattery(forceUpdate);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Unfreezes battery state, returning to current hardware values.
+     * @hide
+     */
+    @TestApi
+    @RequiresPermission(android.Manifest.permission.DEVICE_POWER)
+    public void resetBattery(boolean forceUpdate) {
+        try {
+            mBatteryStats.resetBattery(forceUpdate);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Suspend charging even if plugged in.
+     * @hide
+     */
+    @TestApi
+    @RequiresPermission(android.Manifest.permission.DEVICE_POWER)
+    public void suspendBatteryInput() {
+        try {
+            mBatteryStats.suspendBatteryInput();
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+}
\ No newline at end of file
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 83f78a5..0d9f715 100755
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -27,6 +27,7 @@
 import android.app.Application;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
+import android.sysprop.DeviceProperties;
 import android.sysprop.SocProperties;
 import android.sysprop.TelephonyProperties;
 import android.text.TextUtils;
@@ -298,6 +299,19 @@
                 "ro.build.version.security_patch", "");
 
         /**
+         * The media performance class of the device or 0 if none.
+         * <p>
+         * If this value is not <code>0</code>, the device conforms to the media performance class
+         * definition of the SDK version of this value. This value never changes while a device is
+         * booted, but it may increase when the hardware manufacturer provides an OTA update.
+         * <p>
+         * Possible non-zero values are defined in {@link Build.VERSION_CODES} starting with
+         * {@link Build.VERSION_CODES#S}.
+         */
+        public static final int MEDIA_PERFORMANCE_CLASS =
+                DeviceProperties.media_performance_class().orElse(0);
+
+        /**
          * The user-visible SDK version of the framework in its raw String
          * representation; use {@link #SDK_INT} instead.
          *
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index 124c0b0..21bf8b8 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -728,11 +728,11 @@
     /**
      * Standard directory in which to place any audio files that should be
      * in the regular list of music for the user.
-     * This may be combined with
+     * This may be combined with {@link #DIRECTORY_AUDIOBOOKS},
      * {@link #DIRECTORY_PODCASTS}, {@link #DIRECTORY_NOTIFICATIONS},
-     * {@link #DIRECTORY_ALARMS}, and {@link #DIRECTORY_RINGTONES} as a series
-     * of directories to categories a particular audio file as more than one
-     * type.
+     * {@link #DIRECTORY_ALARMS}, {@link #DIRECTORY_RINGTONES}, and
+     * {@link #DIRECTORY_RECORDINGS} as a series of directories to
+     * categorize a particular audio file as more than one type.
      */
     public static String DIRECTORY_MUSIC = "Music";
 
@@ -741,10 +741,10 @@
      * in the list of podcasts that the user can select (not as regular
      * music).
      * This may be combined with {@link #DIRECTORY_MUSIC},
-     * {@link #DIRECTORY_NOTIFICATIONS},
-     * {@link #DIRECTORY_ALARMS}, and {@link #DIRECTORY_RINGTONES} as a series
-     * of directories to categories a particular audio file as more than one
-     * type.
+     * {@link #DIRECTORY_AUDIOBOOKS}, {@link #DIRECTORY_NOTIFICATIONS},
+     * {@link #DIRECTORY_ALARMS}, {@link #DIRECTORY_RINGTONES}, and
+     * {@link #DIRECTORY_RECORDINGS} as a series of directories to
+     * categorize a particular audio file as more than one type.
      */
     public static String DIRECTORY_PODCASTS = "Podcasts";
 
@@ -753,10 +753,10 @@
      * in the list of ringtones that the user can select (not as regular
      * music).
      * This may be combined with {@link #DIRECTORY_MUSIC},
-     * {@link #DIRECTORY_PODCASTS}, {@link #DIRECTORY_NOTIFICATIONS}, and
-     * {@link #DIRECTORY_ALARMS} as a series
-     * of directories to categories a particular audio file as more than one
-     * type.
+     * {@link #DIRECTORY_AUDIOBOOKS}, {@link #DIRECTORY_PODCASTS},
+     * {@link #DIRECTORY_NOTIFICATIONS}, {@link #DIRECTORY_ALARMS},
+     * and {@link #DIRECTORY_RECORDINGS} as a series of directories
+     * to categorize a particular audio file as more than one type.
      */
     public static String DIRECTORY_RINGTONES = "Ringtones";
 
@@ -765,10 +765,10 @@
      * in the list of alarms that the user can select (not as regular
      * music).
      * This may be combined with {@link #DIRECTORY_MUSIC},
-     * {@link #DIRECTORY_PODCASTS}, {@link #DIRECTORY_NOTIFICATIONS},
-     * and {@link #DIRECTORY_RINGTONES} as a series
-     * of directories to categories a particular audio file as more than one
-     * type.
+     * {@link #DIRECTORY_AUDIOBOOKS}, {@link #DIRECTORY_PODCASTS},
+     * {@link #DIRECTORY_NOTIFICATIONS}, {@link #DIRECTORY_RINGTONES},
+     * and {@link #DIRECTORY_RECORDINGS} as a series of directories
+     * to categorize a particular audio file as more than one type.
      */
     public static String DIRECTORY_ALARMS = "Alarms";
 
@@ -777,10 +777,10 @@
      * in the list of notifications that the user can select (not as regular
      * music).
      * This may be combined with {@link #DIRECTORY_MUSIC},
-     * {@link #DIRECTORY_PODCASTS},
-     * {@link #DIRECTORY_ALARMS}, and {@link #DIRECTORY_RINGTONES} as a series
-     * of directories to categories a particular audio file as more than one
-     * type.
+     * {@link #DIRECTORY_AUDIOBOOKS}, {@link #DIRECTORY_PODCASTS},
+     * {@link #DIRECTORY_ALARMS}, {@link #DIRECTORY_RINGTONES}, and
+     * {@link #DIRECTORY_RECORDINGS} as a series of directories to
+     * categorize a particular audio file as more than one type.
      */
     public static String DIRECTORY_NOTIFICATIONS = "Notifications";
 
@@ -831,14 +831,26 @@
     public static String DIRECTORY_SCREENSHOTS = "Screenshots";
 
     /**
-     * Standard directory in which to place any audio files which are
-     * audiobooks.
+     * Standard directory in which to place any audio files that should be
+     * in the list of audiobooks that the user can select (not as regular
+     * music).
+     * This may be combined with {@link #DIRECTORY_MUSIC},
+     * {@link #DIRECTORY_PODCASTS}, {@link #DIRECTORY_NOTIFICATIONS},
+     * {@link #DIRECTORY_ALARMS}, {@link #DIRECTORY_RINGTONES},
+     * and {@link #DIRECTORY_RECORDINGS} as a series of directories
+     * to categorize a particular audio file as more than one type.
      */
     public static String DIRECTORY_AUDIOBOOKS = "Audiobooks";
 
     /**
-     * Standard directory in which to place any audio files which are
-     * recordings.
+     * Standard directory in which to place any audio files that should be
+     * in the list of voice recordings recorded by voice recorder apps that
+     * the user can select (not as regular music).
+     * This may be combined with {@link #DIRECTORY_MUSIC},
+     * {@link #DIRECTORY_AUDIOBOOKS}, {@link #DIRECTORY_PODCASTS},
+     * {@link #DIRECTORY_NOTIFICATIONS}, {@link #DIRECTORY_ALARMS},
+     * and {@link #DIRECTORY_RINGTONES} as a series of directories
+     * to categorize a particular audio file as more than one type.
      */
     @NonNull
     // The better way is that expose a static method getRecordingDirectories.
diff --git a/core/java/android/os/Vibrator.java b/core/java/android/os/Vibrator.java
index b003d23..b90d438 100644
--- a/core/java/android/os/Vibrator.java
+++ b/core/java/android/os/Vibrator.java
@@ -208,6 +208,28 @@
     public abstract boolean hasAmplitudeControl();
 
     /**
+     * Gets the resonant frequency of the vibrator.
+     *
+     * @return the resonant frequency of the vibrator, or {@link Float#NaN NaN} if it's unknown or
+     *         this vibrator is a composite of multiple physical devices.
+     * @hide
+     */
+    public float getResonantFrequency() {
+        return Float.NaN;
+    }
+
+    /**
+     * Gets the <a href="https://en.wikipedia.org/wiki/Q_factor">Q factor</a> of the vibrator.
+     *
+     * @return the Q factor of the vibrator, or {@link Float#NaN NaN} if it's unknown or
+     *         this vibrator is a composite of multiple physical devices.
+     * @hide
+     */
+    public float getQFactor() {
+        return Float.NaN;
+    }
+
+    /**
      * Configure an always-on haptics effect.
      *
      * @param alwaysOnId The board-specific always-on ID to configure.
diff --git a/core/java/android/os/VibratorInfo.java b/core/java/android/os/VibratorInfo.java
index 50d2de3..3121b95 100644
--- a/core/java/android/os/VibratorInfo.java
+++ b/core/java/android/os/VibratorInfo.java
@@ -42,21 +42,27 @@
     private final SparseBooleanArray mSupportedEffects;
     @Nullable
     private final SparseBooleanArray mSupportedPrimitives;
+    private final float mResonantFrequency;
+    private final float mQFactor;
 
     VibratorInfo(Parcel in) {
         mId = in.readInt();
         mCapabilities = in.readLong();
         mSupportedEffects = in.readSparseBooleanArray();
         mSupportedPrimitives = in.readSparseBooleanArray();
+        mResonantFrequency = in.readFloat();
+        mQFactor = in.readFloat();
     }
 
     /** @hide */
     public VibratorInfo(int id, long capabilities, int[] supportedEffects,
-            int[] supportedPrimitives) {
+            int[] supportedPrimitives, float resonantFrequency, float qFactor) {
         mId = id;
         mCapabilities = capabilities;
         mSupportedEffects = toSparseBooleanArray(supportedEffects);
         mSupportedPrimitives = toSparseBooleanArray(supportedPrimitives);
+        mResonantFrequency = resonantFrequency;
+        mQFactor = qFactor;
     }
 
     @Override
@@ -65,6 +71,8 @@
         dest.writeLong(mCapabilities);
         dest.writeSparseBooleanArray(mSupportedEffects);
         dest.writeSparseBooleanArray(mSupportedPrimitives);
+        dest.writeFloat(mResonantFrequency);
+        dest.writeFloat(mQFactor);
     }
 
     @Override
@@ -83,12 +91,15 @@
         VibratorInfo that = (VibratorInfo) o;
         return mId == that.mId && mCapabilities == that.mCapabilities
                 && Objects.equals(mSupportedEffects, that.mSupportedEffects)
-                && Objects.equals(mSupportedPrimitives, that.mSupportedPrimitives);
+                && Objects.equals(mSupportedPrimitives, that.mSupportedPrimitives)
+                && Objects.equals(mResonantFrequency, that.mResonantFrequency)
+                && Objects.equals(mQFactor, that.mQFactor);
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(mId, mCapabilities, mSupportedEffects, mSupportedPrimitives);
+        return Objects.hash(mId, mCapabilities, mSupportedEffects, mSupportedPrimitives,
+                mResonantFrequency, mQFactor);
     }
 
     @Override
@@ -99,6 +110,8 @@
                 + ", mCapabilities flags=" + Long.toBinaryString(mCapabilities)
                 + ", mSupportedEffects=" + Arrays.toString(getSupportedEffectsNames())
                 + ", mSupportedPrimitives=" + Arrays.toString(getSupportedPrimitivesNames())
+                + ", mResonantFrequency=" + mResonantFrequency
+                + ", mQFactor=" + mQFactor
                 + '}';
     }
 
@@ -156,6 +169,26 @@
         return (mCapabilities & capability) == capability;
     }
 
+    /**
+     * Gets the resonant frequency of the vibrator.
+     *
+     * @return the resonant frequency of the vibrator, or {@link Float#NaN NaN} if it's unknown or
+     *         this vibrator is a composite of multiple physical devices.
+     */
+    public float getResonantFrequency() {
+        return mResonantFrequency;
+    }
+
+    /**
+     * Gets the <a href="https://en.wikipedia.org/wiki/Q_factor">Q factor</a> of the vibrator.
+     *
+     * @return the Q factor of the vibrator, or {@link Float#NaN NaN} if it's unknown or
+     *         this vibrator is a composite of multiple physical devices.
+     */
+    public float getQFactor() {
+        return mQFactor;
+    }
+
     private String[] getCapabilitiesNames() {
         List<String> names = new ArrayList<>();
         if (hasCapability(IVibrator.CAP_ON_CALLBACK)) {
diff --git a/core/java/android/os/incremental/IncrementalManager.java b/core/java/android/os/incremental/IncrementalManager.java
index dc6f63a..047c05a 100644
--- a/core/java/android/os/incremental/IncrementalManager.java
+++ b/core/java/android/os/incremental/IncrementalManager.java
@@ -30,6 +30,7 @@
 import com.android.internal.annotations.GuardedBy;
 
 import java.io.File;
+import java.io.FileDescriptor;
 import java.io.IOException;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -265,6 +266,13 @@
     }
 
     /**
+     * Checks if an fd corresponds to a file on a mounted Incremental File System.
+     */
+    public static boolean isIncrementalFileFd(@NonNull FileDescriptor fd) {
+        return nativeIsIncrementalFd(fd.getInt$());
+    }
+
+    /**
      * Returns raw signature for file if it's on Incremental File System.
      * Unsafe, use only if you are sure what you are doing.
      */
@@ -421,9 +429,22 @@
         storage.unregisterStorageHealthListener();
     }
 
+    /**
+     * Returns the metrics of an Incremental Storage.
+     */
+    public IncrementalMetrics getMetrics(@NonNull String codePath) {
+        final IncrementalStorage storage = openStorage(codePath);
+        if (storage == null) {
+            // storage does not exist, package not installed
+            return null;
+        }
+        return new IncrementalMetrics(storage.getMetrics());
+    }
+
     /* Native methods */
     private static native boolean nativeIsEnabled();
     private static native boolean nativeIsV2Available();
     private static native boolean nativeIsIncrementalPath(@NonNull String path);
+    private static native boolean nativeIsIncrementalFd(@NonNull int fd);
     private static native byte[] nativeUnsafeGetFileSignature(@NonNull String path);
 }
diff --git a/core/java/android/os/incremental/IncrementalMetrics.java b/core/java/android/os/incremental/IncrementalMetrics.java
new file mode 100644
index 0000000..44dea1b
--- /dev/null
+++ b/core/java/android/os/incremental/IncrementalMetrics.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os.incremental;
+
+import android.annotation.NonNull;
+import android.os.PersistableBundle;
+
+/**
+ * Provides methods to access metrics about an app installed via Incremental
+ * @hide
+ */
+public class IncrementalMetrics {
+    @NonNull private final PersistableBundle mData;
+
+    public IncrementalMetrics(@NonNull PersistableBundle data) {
+        mData = data;
+    }
+
+    /**
+     * @return Milliseconds between now and when the oldest pending read happened
+     */
+    public long getMillisSinceOldestPendingRead() {
+        return mData.getLong(IIncrementalService.METRICS_MILLIS_SINCE_OLDEST_PENDING_READ, -1);
+    }
+}
diff --git a/core/java/android/os/incremental/IncrementalStorage.java b/core/java/android/os/incremental/IncrementalStorage.java
index e6ce8cd..7cf0144 100644
--- a/core/java/android/os/incremental/IncrementalStorage.java
+++ b/core/java/android/os/incremental/IncrementalStorage.java
@@ -20,6 +20,7 @@
 import android.annotation.Nullable;
 import android.content.pm.DataLoaderParams;
 import android.content.pm.IDataLoaderStatusListener;
+import android.os.PersistableBundle;
 import android.os.RemoteException;
 
 import java.io.File;
@@ -601,4 +602,17 @@
             return;
         }
     }
+
+    /**
+     * Returns the metrics of the current storage.
+     * {@see IIncrementalService} for metrics keys.
+     */
+    public PersistableBundle getMetrics() {
+        try {
+            return mService.getMetrics(mId);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+            return null;
+        }
+    }
 }
diff --git a/core/java/android/permission/PermissionUsageHelper.java b/core/java/android/permission/PermissionUsageHelper.java
index 4c9e77c..7e3a0f3 100644
--- a/core/java/android/permission/PermissionUsageHelper.java
+++ b/core/java/android/permission/PermissionUsageHelper.java
@@ -111,8 +111,7 @@
 
     private static boolean shouldShowLocationIndicator() {
         return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
-                PROPERTY_LOCATION_INDICATORS_ENABLED, false)
-                || shouldShowPermissionsHub();
+                PROPERTY_LOCATION_INDICATORS_ENABLED, false);
     }
 
     private static long getRecentThreshold(Long now) {
@@ -326,10 +325,10 @@
                     }
 
                     if (packageName.equals(SYSTEM_PKG)
-                            || (!isUserSensitive(packageName, user, op)
+                            || (!shouldShowPermissionsHub()
+                            && !isUserSensitive(packageName, user, op)
                             && !isLocationProvider(packageName, user)
-                            && !isAppPredictor(packageName, user))
-                            && !isSpeechRecognizerUsage(op, packageName)) {
+                            && !isSpeechRecognizerUsage(op, packageName))) {
                         continue;
                     }
 
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index 8a4812a..374de9c 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -5310,5 +5310,12 @@
          * @hide
          */
         public static final String COLUMN_VOIMS_OPT_IN_STATUS = "voims_opt_in_status";
+
+        /**
+         * TelephonyProvider column name for device to device sharing status.
+         *
+         * @hide
+         */
+        public static final String COLUMN_D2D_STATUS_SHARING = "d2d_sharing_status";
     }
 }
diff --git a/core/java/android/telephony/PhoneStateListener.java b/core/java/android/telephony/PhoneStateListener.java
index bbe887f..e9a79e7 100644
--- a/core/java/android/telephony/PhoneStateListener.java
+++ b/core/java/android/telephony/PhoneStateListener.java
@@ -20,7 +20,6 @@
 import android.annotation.NonNull;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
-import android.compat.annotation.ChangeId;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Binder;
 import android.os.Build;
@@ -1577,7 +1576,7 @@
             // default implementation empty
         }
 
-        public void onAllowedNetworkTypesChanged(Map allowedNetworkTypesList) {
+        public void onAllowedNetworkTypesChanged(int reason, long allowedNetworkType) {
             // default implementation empty
         }
     }
diff --git a/core/java/android/telephony/TelephonyCallback.java b/core/java/android/telephony/TelephonyCallback.java
index 2cadda2..e3d3dec 100644
--- a/core/java/android/telephony/TelephonyCallback.java
+++ b/core/java/android/telephony/TelephonyCallback.java
@@ -546,9 +546,6 @@
     /**
      * Event for changes to allowed network list based on all active subscriptions.
      *
-     * <p>Requires permission {@link android.Manifest.permission#READ_PHONE_STATE} or the calling
-     * app has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges}).
-     *
      * @hide
      * @see AllowedNetworkTypesListener#onAllowedNetworkTypesChanged
      */
@@ -1265,30 +1262,34 @@
     public interface AllowedNetworkTypesListener {
         /**
          * Callback invoked when the current allowed network type list has changed on the
-         * registered subscription.
+         * registered subscription for a specified reason.
          * Note, the registered subscription is associated with {@link TelephonyManager} object
-         * on which
-         * {@link TelephonyManager#registerTelephonyCallback(Executor, TelephonyCallback)}
+         * on which {@link TelephonyManager#registerTelephonyCallback(Executor, TelephonyCallback)}
          * was called.
          * If this TelephonyManager object was created with
          * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
          * given subscription ID. Otherwise, this callback applies to
          * {@link SubscriptionManager#getDefaultSubscriptionId()}.
          *
-         * @param allowedNetworkTypesList Map associating all allowed network type reasons
-         * ({@link TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_USER},
-         * {@link TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_POWER},
-         * {@link TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_CARRIER}, and
-         * {@link TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G}) with reason's allowed
-         * network type values.
+         * @param reason an allowed network type reasons.
+         * @see TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_USER
+         * @see TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_POWER
+         * @see TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_CARRIER
+         * @see TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G
+         *
+         * @param allowedNetworkType an allowed network type bitmask value. (for example,
+         * the long bitmask value is {{@link TelephonyManager#NETWORK_TYPE_BITMASK_NR}|
+         * {@link TelephonyManager#NETWORK_TYPE_BITMASK_LTE}})
+         *
          * For example:
-         * map{{TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_USER, long type value},
-         *     {TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_POWER, long type value},
-         *     {TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_CARRIER, long type value},
-         *     {TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G, long type value}}
+         * If the latest allowed network type is changed by user, then the system
+         * notifies the {@link TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_USER} and
+         * long type value}.
          */
         @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
-        void onAllowedNetworkTypesChanged(@NonNull Map<Integer, Long> allowedNetworkTypesList);
+        void onAllowedNetworkTypesChanged(
+                @TelephonyManager.AllowedNetworkTypesReason int reason,
+                @TelephonyManager.NetworkTypeBitMask long allowedNetworkType);
     }
 
     /**
@@ -1707,14 +1708,15 @@
                             enabled, reason)));
         }
 
-        public void onAllowedNetworkTypesChanged(Map allowedNetworkTypesList) {
+        public void onAllowedNetworkTypesChanged(int reason, long allowedNetworkType) {
             AllowedNetworkTypesListener listener =
                     (AllowedNetworkTypesListener) mTelephonyCallbackWeakRef.get();
             if (listener == null) return;
 
             Binder.withCleanCallingIdentity(
                     () -> mExecutor.execute(
-                            () -> listener.onAllowedNetworkTypesChanged(allowedNetworkTypesList)));
+                            () -> listener.onAllowedNetworkTypesChanged(reason,
+                                    allowedNetworkType)));
         }
     }
 }
diff --git a/core/java/android/telephony/TelephonyRegistryManager.java b/core/java/android/telephony/TelephonyRegistryManager.java
index 9cda4ae..3fa63d8 100644
--- a/core/java/android/telephony/TelephonyRegistryManager.java
+++ b/core/java/android/telephony/TelephonyRegistryManager.java
@@ -825,16 +825,18 @@
     }
 
     /**
-     * Notify emergency number list changed on certain subscription.
-     *
-     * @param slotIndex for which emergency number list changed. Can be derived from subId except
-     * when subId is invalid.
-     * @param subId for which emergency number list changed.
+     * Notify the allowed network types has changed for a specific subscription and the specific
+     * reason.
+     * @param slotIndex for which allowed network types changed.
+     * @param subId for which allowed network types changed.
+     * @param reason an allowed network type reasons.
+     * @param allowedNetworkType an allowed network type bitmask value.
      */
     public void notifyAllowedNetworkTypesChanged(int slotIndex, int subId,
-            Map<Integer, Long> allowedNetworkTypeList) {
+            int reason, long allowedNetworkType) {
         try {
-            sRegistry.notifyAllowedNetworkTypesChanged(slotIndex, subId, allowedNetworkTypeList);
+            sRegistry.notifyAllowedNetworkTypesChanged(slotIndex, subId, reason,
+                    allowedNetworkType);
         } catch (RemoteException ex) {
             // system process is dead
         }
diff --git a/core/java/android/util/Slog.java b/core/java/android/util/Slog.java
index 3880131..f61ab29 100644
--- a/core/java/android/util/Slog.java
+++ b/core/java/android/util/Slog.java
@@ -16,14 +16,26 @@
 
 package android.util;
 
+import android.annotation.Nullable;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Build;
 
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.Formatter;
+import java.util.Locale;
+
 /**
  * @hide
  */
 public final class Slog {
 
+    @GuardedBy("sMessageBuilder")
+    private static final StringBuilder sMessageBuilder = new StringBuilder();
+
+    @GuardedBy("sMessageBuilder")
+    private static final Formatter sFormatter = new Formatter(sMessageBuilder, Locale.ENGLISH);
+
     private Slog() {
     }
 
@@ -37,6 +49,15 @@
                 msg + '\n' + Log.getStackTraceString(tr));
     }
 
+    /**
+     * Logs a {@link Log.VERBOSE} message.
+     */
+    public static void v(String tag, String format, @Nullable Object... args) {
+        if (!Log.isLoggable(tag, Log.VERBOSE)) return;
+
+        v(tag, getMessage(format, args));
+    }
+
     @UnsupportedAppUsage
     public static int d(String tag, String msg) {
         return Log.println_native(Log.LOG_ID_SYSTEM, Log.DEBUG, tag, msg);
@@ -48,6 +69,15 @@
                 msg + '\n' + Log.getStackTraceString(tr));
     }
 
+    /**
+     * Logs a {@link Log.DEBUG} message.
+     */
+    public static void d(String tag, String format, @Nullable Object... args) {
+        if (!Log.isLoggable(tag, Log.DEBUG)) return;
+
+        d(tag, getMessage(format, args));
+    }
+
     @UnsupportedAppUsage
     public static int i(String tag, String msg) {
         return Log.println_native(Log.LOG_ID_SYSTEM, Log.INFO, tag, msg);
@@ -58,6 +88,15 @@
                 msg + '\n' + Log.getStackTraceString(tr));
     }
 
+    /**
+     * Logs a {@link Log.INFO} message.
+     */
+    public static void i(String tag, String format, @Nullable Object... args) {
+        if (!Log.isLoggable(tag, Log.INFO)) return;
+
+        i(tag, getMessage(format, args));
+    }
+
     @UnsupportedAppUsage
     public static int w(String tag, String msg) {
         return Log.println_native(Log.LOG_ID_SYSTEM, Log.WARN, tag, msg);
@@ -73,6 +112,24 @@
         return Log.println_native(Log.LOG_ID_SYSTEM, Log.WARN, tag, Log.getStackTraceString(tr));
     }
 
+    /**
+     * Logs a {@link Log.WARN} message.
+     */
+    public static void w(String tag, String format, @Nullable Object... args) {
+        if (!Log.isLoggable(tag, Log.WARN)) return;
+
+        w(tag, getMessage(format, args));
+    }
+
+    /**
+     * Logs a {@link Log.WARN} message with an exception
+     */
+    public static void w(String tag, Exception exception, String format, @Nullable Object... args) {
+        if (!Log.isLoggable(tag, Log.WARN)) return;
+
+        w(tag, getMessage(format, args), exception);
+    }
+
     @UnsupportedAppUsage
     public static int e(String tag, String msg) {
         return Log.println_native(Log.LOG_ID_SYSTEM, Log.ERROR, tag, msg);
@@ -85,6 +142,24 @@
     }
 
     /**
+     * Logs a {@link Log.ERROR} message.
+     */
+    public static void e(String tag, String format, @Nullable Object... args) {
+        if (!Log.isLoggable(tag, Log.ERROR)) return;
+
+        e(tag, getMessage(format, args));
+    }
+
+    /**
+     * Logs a {@link Log.ERROR} message with an exception
+     */
+    public static void e(String tag, Exception exception, String format, @Nullable Object... args) {
+        if (!Log.isLoggable(tag, Log.ERROR)) return;
+
+        e(tag, getMessage(format, args), exception);
+    }
+
+    /**
      * Like {@link Log#wtf(String, String)}, but will never cause the caller to crash, and
      * will always be handled asynchronously.  Primarily for use by coding running within
      * the system process.
@@ -95,6 +170,21 @@
     }
 
     /**
+     * Logs a {@code wtf} message.
+     */
+    public static void wtf(String tag, String format, @Nullable Object... args) {
+        wtf(tag, getMessage(format, args));
+    }
+
+    /**
+     * Logs a {@code wtf} message with an exception.
+     */
+    public static void wtf(String tag, Exception exception, String format,
+            @Nullable Object... args) {
+        wtf(tag, getMessage(format, args), exception);
+    }
+
+    /**
      * Like {@link #wtf(String, String)}, but does not output anything to the log.
      */
     public static void wtfQuiet(String tag, String msg) {
@@ -134,5 +224,13 @@
     public static int println(int priority, String tag, String msg) {
         return Log.println_native(Log.LOG_ID_SYSTEM, priority, tag, msg);
     }
-}
 
+    private static String getMessage(String format, @Nullable Object... args) {
+        synchronized (sMessageBuilder) {
+            sFormatter.format(format, args);
+            String message = sMessageBuilder.toString();
+            sMessageBuilder.setLength(0);
+            return message;
+        }
+    }
+}
diff --git a/core/java/android/util/apk/ApkSigningBlockUtils.java b/core/java/android/util/apk/ApkSigningBlockUtils.java
index c97c995..7e6175c 100644
--- a/core/java/android/util/apk/ApkSigningBlockUtils.java
+++ b/core/java/android/util/apk/ApkSigningBlockUtils.java
@@ -200,10 +200,9 @@
         // physical memory.
 
         DataSource beforeApkSigningBlock =
-                new MemoryMappedFileDataSource(apkFileDescriptor, 0,
-                        signatureInfo.apkSigningBlockOffset);
+                DataSource.create(apkFileDescriptor, 0, signatureInfo.apkSigningBlockOffset);
         DataSource centralDir =
-                new MemoryMappedFileDataSource(
+                DataSource.create(
                         apkFileDescriptor, signatureInfo.centralDirOffset,
                         signatureInfo.eocdOffset - signatureInfo.centralDirOffset);
 
diff --git a/core/java/android/util/apk/DataSource.java b/core/java/android/util/apk/DataSource.java
index 82f3800..dd6389d 100644
--- a/core/java/android/util/apk/DataSource.java
+++ b/core/java/android/util/apk/DataSource.java
@@ -16,6 +16,10 @@
 
 package android.util.apk;
 
+import android.annotation.NonNull;
+import android.os.incremental.IncrementalManager;
+
+import java.io.FileDescriptor;
 import java.io.IOException;
 import java.security.DigestException;
 
@@ -35,4 +39,22 @@
      */
     void feedIntoDataDigester(DataDigester md, long offset, int size)
             throws IOException, DigestException;
+
+    /**
+     * Creates a DataSource that can handle the passed fd in the most efficient and safe manner.
+     * @param fd file descriptor to read from
+     * @param pos starting offset
+     * @param size size of the region
+     * @return created DataSource object
+     */
+    static @NonNull DataSource create(@NonNull FileDescriptor fd, long pos, long size) {
+        if (IncrementalManager.isIncrementalFileFd(fd)) {
+            // IncFS-based files may have missing pages, and reading those via mmap() results
+            // in a SIGBUS signal. Java doesn't have a good way of catching it, ending up killing
+            // the process by default. Going back to read() is the safest option for these files.
+            return new ReadFileDataSource(fd, pos, size);
+        } else {
+            return new MemoryMappedFileDataSource(fd, pos, size);
+        }
+    }
 }
diff --git a/core/java/android/util/apk/MemoryMappedFileDataSource.java b/core/java/android/util/apk/MemoryMappedFileDataSource.java
index 8d2b1e32..69a526d 100644
--- a/core/java/android/util/apk/MemoryMappedFileDataSource.java
+++ b/core/java/android/util/apk/MemoryMappedFileDataSource.java
@@ -40,6 +40,7 @@
     /**
      * Constructs a new {@code MemoryMappedFileDataSource} for the specified region of the file.
      *
+     * @param fd file descriptor to read from.
      * @param position start position of the region in the file.
      * @param size size (in bytes) of the region.
      */
diff --git a/core/java/android/util/apk/ReadFileDataSource.java b/core/java/android/util/apk/ReadFileDataSource.java
new file mode 100644
index 0000000..d0e1140
--- /dev/null
+++ b/core/java/android/util/apk/ReadFileDataSource.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util.apk;
+
+import android.system.ErrnoException;
+import android.system.Os;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.security.DigestException;
+
+/**
+ * {@link DataSource} which provides data from a file descriptor by reading the sections
+ * of the file via raw read() syscall. This is slower than memory-mapping but safer.
+ */
+class ReadFileDataSource implements DataSource {
+    private final FileDescriptor mFd;
+    private final long mFilePosition;
+    private final long mSize;
+
+    private static final int CHUNK_SIZE = 1024 * 1024;
+
+    /**
+     * Constructs a new {@code ReadFileDataSource} for the specified region of the file.
+     *
+     * @param fd file descriptor to read from.
+     * @param position start position of the region in the file.
+     * @param size size (in bytes) of the region.
+     */
+    ReadFileDataSource(FileDescriptor fd, long position, long size) {
+        mFd = fd;
+        mFilePosition = position;
+        mSize = size;
+    }
+
+    @Override
+    public long size() {
+        return mSize;
+    }
+
+    @Override
+    public void feedIntoDataDigester(DataDigester md, long offset, int size)
+            throws IOException, DigestException {
+        try {
+            final byte[] buffer = new byte[Math.min(size, CHUNK_SIZE)];
+            final long start = mFilePosition + offset;
+            final long end = start + size;
+            for (long pos = start, curSize = Math.min(size, CHUNK_SIZE);
+                    pos < end; curSize = Math.min(end - pos, CHUNK_SIZE)) {
+                final int readSize = Os.pread(mFd, buffer, 0, (int) curSize, pos);
+                md.consume(ByteBuffer.wrap(buffer, 0, readSize));
+                pos += readSize;
+            }
+        } catch (ErrnoException e) {
+            throw new IOException(e);
+        }
+    }
+}
diff --git a/core/java/android/util/apk/TEST_MAPPING b/core/java/android/util/apk/TEST_MAPPING
index 8544e82..4598b4f 100644
--- a/core/java/android/util/apk/TEST_MAPPING
+++ b/core/java/android/util/apk/TEST_MAPPING
@@ -1,6 +1,17 @@
 {
   "presubmit": [
     {
+      "name": "CtsContentTestCases",
+      "options": [
+        {
+          "include-filter": "android.content.pm.cts.PackageManagerShellCommandIncrementalTest"
+        },
+        {
+          "include-filter": "android.content.pm.cts.PackageManagerShellCommandTest"
+        }
+      ]
+    },
+    {
       "name": "FrameworksCoreTests",
       "options": [
         {
diff --git a/core/java/android/util/apk/VerityBuilder.java b/core/java/android/util/apk/VerityBuilder.java
index 4596c6e..b0a5992 100644
--- a/core/java/android/util/apk/VerityBuilder.java
+++ b/core/java/android/util/apk/VerityBuilder.java
@@ -294,7 +294,7 @@
 
         // 1. Digest the whole file by chunks.
         consumeByChunk(digester,
-                new MemoryMappedFileDataSource(file.getFD(), 0, file.length()),
+                DataSource.create(file.getFD(), 0, file.length()),
                 MMAP_REGION_SIZE_BYTES);
 
         // 2. Pad 0s up to the nearest 4096-byte block before hashing.
@@ -315,7 +315,7 @@
 
         // 1. Digest from the beginning of the file, until APK Signing Block is reached.
         consumeByChunk(digester,
-                new MemoryMappedFileDataSource(apk.getFD(), 0, signatureInfo.apkSigningBlockOffset),
+                DataSource.create(apk.getFD(), 0, signatureInfo.apkSigningBlockOffset),
                 MMAP_REGION_SIZE_BYTES);
 
         // 2. Skip APK Signing Block and continue digesting, until the Central Directory offset
@@ -323,7 +323,7 @@
         long eocdCdOffsetFieldPosition =
                 signatureInfo.eocdOffset + ZIP_EOCD_CENTRAL_DIR_OFFSET_FIELD_OFFSET;
         consumeByChunk(digester,
-                new MemoryMappedFileDataSource(apk.getFD(), signatureInfo.centralDirOffset,
+                DataSource.create(apk.getFD(), signatureInfo.centralDirOffset,
                     eocdCdOffsetFieldPosition - signatureInfo.centralDirOffset),
                 MMAP_REGION_SIZE_BYTES);
 
@@ -338,7 +338,7 @@
         long offsetAfterEocdCdOffsetField =
                 eocdCdOffsetFieldPosition + ZIP_EOCD_CENTRAL_DIR_OFFSET_FIELD_SIZE;
         consumeByChunk(digester,
-                new MemoryMappedFileDataSource(apk.getFD(), offsetAfterEocdCdOffsetField,
+                DataSource.create(apk.getFD(), offsetAfterEocdCdOffsetField,
                     apk.length() - offsetAfterEocdCdOffsetField),
                 MMAP_REGION_SIZE_BYTES);
 
diff --git a/core/java/android/util/imetracing/ImeTracing.java b/core/java/android/util/imetracing/ImeTracing.java
index 49ff237..b28cfb8 100644
--- a/core/java/android/util/imetracing/ImeTracing.java
+++ b/core/java/android/util/imetracing/ImeTracing.java
@@ -23,7 +23,6 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.ServiceManager.ServiceNotFoundException;
-import android.os.ShellCommand;
 import android.util.Log;
 import android.util.proto.ProtoOutputStream;
 import android.view.inputmethod.InputMethodManager;
@@ -104,12 +103,6 @@
     public abstract void addToBuffer(ProtoOutputStream proto, int source);
 
     /**
-     * @param shell The shell command to process
-     * @return {@code 0} if the command was successfully processed, {@code -1} otherwise
-     */
-    public abstract int onShellCommand(ShellCommand shell);
-
-    /**
      * Starts a proto dump of the client side information.
      *
      * @param where Place where the trace was triggered.
diff --git a/core/java/android/util/imetracing/ImeTracingClientImpl.java b/core/java/android/util/imetracing/ImeTracingClientImpl.java
index 2c27639..35a81b7 100644
--- a/core/java/android/util/imetracing/ImeTracingClientImpl.java
+++ b/core/java/android/util/imetracing/ImeTracingClientImpl.java
@@ -20,7 +20,6 @@
 import android.inputmethodservice.AbstractInputMethodService;
 import android.os.RemoteException;
 import android.os.ServiceManager.ServiceNotFoundException;
-import android.os.ShellCommand;
 import android.util.Log;
 import android.util.proto.ProtoOutputStream;
 import android.view.inputmethod.InputMethodManager;
@@ -45,11 +44,6 @@
     }
 
     @Override
-    public int onShellCommand(ShellCommand shell) {
-        return -1;
-    }
-
-    @Override
     public void triggerClientDump(String where, @NonNull InputMethodManager immInstance,
             ProtoOutputStream icProto) {
         if (!isEnabled() || !isAvailable()) {
diff --git a/core/java/android/util/imetracing/ImeTracingServerImpl.java b/core/java/android/util/imetracing/ImeTracingServerImpl.java
index e793c28..77f017a 100644
--- a/core/java/android/util/imetracing/ImeTracingServerImpl.java
+++ b/core/java/android/util/imetracing/ImeTracingServerImpl.java
@@ -22,7 +22,6 @@
 import android.inputmethodservice.AbstractInputMethodService;
 import android.os.RemoteException;
 import android.os.ServiceManager.ServiceNotFoundException;
-import android.os.ShellCommand;
 import android.util.Log;
 import android.util.proto.ProtoOutputStream;
 import android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceFileProto;
@@ -106,32 +105,6 @@
         }
     }
 
-    /**
-     * Responds to a shell command of the format "adb shell cmd input_method ime tracing <command>"
-     *
-     * @param shell The shell command to process
-     * @return {@code 0} if the command was valid and successfully processed, {@code -1} otherwise
-     */
-    @Override
-    public int onShellCommand(ShellCommand shell) {
-        PrintWriter pw = shell.getOutPrintWriter();
-        String cmd = shell.getNextArgRequired();
-        switch (cmd) {
-            case "start":
-                startTrace(pw);
-                return 0;
-            case "stop":
-                stopTrace(pw);
-                return 0;
-            default:
-                pw.println("Unknown command: " + cmd);
-                pw.println("Input method trace options:");
-                pw.println("  start: Start tracing");
-                pw.println("  stop: Stop tracing");
-                return -1;
-        }
-    }
-
     @Override
     public void triggerClientDump(String where, InputMethodManager immInstance,
             ProtoOutputStream icProto) {
diff --git a/core/java/android/view/CrossWindowBlurListeners.java b/core/java/android/view/CrossWindowBlurListeners.java
index 5a1b850..55fc4f4 100644
--- a/core/java/android/view/CrossWindowBlurListeners.java
+++ b/core/java/android/view/CrossWindowBlurListeners.java
@@ -16,13 +16,19 @@
 
 package android.view;
 
+import android.annotation.CallbackExecutor;
+import android.annotation.NonNull;
+import android.os.Binder;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.RemoteException;
 import android.os.SystemProperties;
-import android.util.ArraySet;
+import android.util.ArrayMap;
 import android.util.Log;
 
+import com.android.internal.util.Preconditions;
+
+import java.util.concurrent.Executor;
 import java.util.function.Consumer;
 
 /**
@@ -42,7 +48,7 @@
     private static final Object sLock = new Object();
 
     private final BlurEnabledListenerInternal mListenerInternal = new BlurEnabledListenerInternal();
-    private final ArraySet<Consumer<Boolean>> mListeners = new ArraySet();
+    private final ArrayMap<Consumer<Boolean>, Executor> mListeners = new ArrayMap();
     private final Handler mMainHandler = new Handler(Looper.getMainLooper());
     private boolean mInternalListenerAttached = false;
     private boolean mCrossWindowBlurEnabled;
@@ -74,20 +80,22 @@
         }
     }
 
-    void addListener(Consumer<Boolean> listener) {
-        if (listener == null) return;
+    void addListener(@NonNull @CallbackExecutor Executor executor,
+            @NonNull Consumer<Boolean> listener) {
+        Preconditions.checkNotNull(listener, "listener cannot be null");
+        Preconditions.checkNotNull(executor, "executor cannot be null");
 
         synchronized (sLock) {
             attachInternalListenerIfNeededLocked();
 
-            mListeners.add(listener);
-            notifyListenerOnMain(listener, mCrossWindowBlurEnabled);
+            mListeners.put(listener, executor);
+            notifyListener(listener, executor, mCrossWindowBlurEnabled);
         }
     }
 
 
     void removeListener(Consumer<Boolean> listener) {
-        if (listener == null) return;
+        Preconditions.checkNotNull(listener, "listener cannot be null");
 
         synchronized (sLock) {
             mListeners.remove(listener);
@@ -116,10 +124,8 @@
         }
     }
 
-    private void notifyListenerOnMain(Consumer<Boolean> listener, boolean enabled) {
-        mMainHandler.post(() -> {
-            listener.accept(enabled);
-        });
+    private void notifyListener(Consumer<Boolean> listener, Executor executor, boolean enabled) {
+        executor.execute(() -> listener.accept(enabled));
     }
 
     private final class BlurEnabledListenerInternal extends ICrossWindowBlurEnabledListener.Stub {
@@ -128,8 +134,13 @@
             synchronized (sLock) {
                 mCrossWindowBlurEnabled = enabled;
 
-                for (int i = 0; i < mListeners.size(); i++) {
-                    notifyListenerOnMain(mListeners.valueAt(i), enabled);
+                final long token = Binder.clearCallingIdentity();
+                try {
+                    for (int i = 0; i < mListeners.size(); i++) {
+                        notifyListener(mListeners.keyAt(i), mListeners.valueAt(i), enabled);
+                    }
+                } finally {
+                    Binder.restoreCallingIdentity(token);
                 }
             }
         }
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index a8aaeb7..9aaf5c0 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -636,7 +636,9 @@
     public void getMaxBoundsMetrics(DisplayMetrics outMetrics, CompatibilityInfo compatInfo,
             Configuration configuration) {
         Rect bounds = configuration.windowConfiguration.getMaxBounds();
-        getMetricsWithSize(outMetrics, compatInfo, configuration, bounds.width(), bounds.height());
+        // Pass in null configuration to ensure width and height are not overridden to app bounds.
+        getMetricsWithSize(outMetrics, compatInfo, /* configuration= */ null,
+                bounds.width(), bounds.height());
     }
 
     public int getNaturalWidth() {
diff --git a/core/java/android/view/IRecentsAnimationController.aidl b/core/java/android/view/IRecentsAnimationController.aidl
index afbd249..ddb49786 100644
--- a/core/java/android/view/IRecentsAnimationController.aidl
+++ b/core/java/android/view/IRecentsAnimationController.aidl
@@ -142,7 +142,13 @@
      *
      * The system reparents the leash of navigation bar to the app when the recents animation starts
      * and Launcher should call this method to let system restore the navigation bar to its
-     * original position when the quick switch gesture is finished.
+     * original position when the quick switch gesture is finished and will run the fade-in
+     * animation If {@param moveHomeToTop} is {@code true}. Otherwise, restore the navigtation bar
+     * without animation.
+     *
+     * @param moveHomeToTop if {@code true}, the home activity should be moved to the top.
+     *                      Otherwise, the home activity is hidden and the user is returned to the
+     *                      app.
      */
-    void detachNavigationBarFromApp();
+    void detachNavigationBarFromApp(boolean moveHomeToTop);
 }
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 5477800..b345b2e 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -816,4 +816,6 @@
      * @param listener the listener to be unregistered
      */
     void unregisterCrossWindowBlurEnabledListener(ICrossWindowBlurEnabledListener listener);
+
+    void setForceCrossWindowBlurDisabled(boolean disable);
 }
diff --git a/core/java/android/view/KeyCharacterMap.java b/core/java/android/view/KeyCharacterMap.java
index 02a9788..aa1acc1 100644
--- a/core/java/android/view/KeyCharacterMap.java
+++ b/core/java/android/view/KeyCharacterMap.java
@@ -16,6 +16,7 @@
 
 package android.view;
 
+import android.annotation.Nullable;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.hardware.input.InputManager;
 import android.os.Build;
@@ -25,6 +26,8 @@
 import android.util.AndroidRuntimeException;
 import android.util.SparseIntArray;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 import java.text.Normalizer;
 
 /**
@@ -297,6 +300,8 @@
     private static native char nativeGetDisplayLabel(long ptr, int keyCode);
     private static native int nativeGetKeyboardType(long ptr);
     private static native KeyEvent[] nativeGetEvents(long ptr, char[] chars);
+    private static native KeyCharacterMap nativeObtainEmptyKeyCharacterMap(int deviceId);
+    private static native boolean nativeEquals(long ptr1, long ptr2);
 
     private KeyCharacterMap(Parcel in) {
         if (in == null) {
@@ -323,6 +328,18 @@
     }
 
     /**
+     * Obtain empty key character map
+     * @param deviceId The input device ID
+     * @return The KeyCharacterMap object
+     * @hide
+     */
+    @VisibleForTesting
+    @Nullable
+    public static KeyCharacterMap obtainEmptyMap(int deviceId) {
+        return nativeObtainEmptyKeyCharacterMap(deviceId);
+    }
+
+    /**
      * Loads the key character maps for the keyboard with the specified device id.
      *
      * @param deviceId The device id of the keyboard.
@@ -729,6 +746,18 @@
         return 0;
     }
 
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == null || !(obj instanceof KeyCharacterMap)) {
+            return false;
+        }
+        KeyCharacterMap peer = (KeyCharacterMap) obj;
+        if (mPtr == 0 || peer.mPtr == 0) {
+            return mPtr == peer.mPtr;
+        }
+        return nativeEquals(mPtr, peer.mPtr);
+    }
+
     /**
      * Thrown by {@link KeyCharacterMap#load} when a key character map could not be loaded.
      */
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 9fc415d..35726c0 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -8572,6 +8572,17 @@
         }
 
         @Override
+        public void onDragEvent(boolean isExiting, float x, float y) {
+            // force DRAG_EXITED_EVENT if appropriate
+            DragEvent event = DragEvent.obtain(
+                    isExiting ? DragEvent.ACTION_DRAG_EXITED : DragEvent.ACTION_DRAG_LOCATION,
+                    x, y, 0 /* offsetX */, 0 /* offsetY */, null/* localState */,
+                    null/* description */, null /* data */, null /* dragSurface */,
+                    null /* dragAndDropPermissions */, false /* result */);
+            dispatchDragEvent(event);
+        }
+
+        @Override
         public void dispose() {
             unscheduleConsumeBatchedInput();
             super.dispose();
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 7338c7d..04512c9 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -81,6 +81,7 @@
 import static android.view.WindowLayoutParamsProto.Y;
 
 import android.Manifest.permission;
+import android.annotation.CallbackExecutor;
 import android.annotation.IntDef;
 import android.annotation.IntRange;
 import android.annotation.NonNull;
@@ -121,6 +122,7 @@
 import java.util.Arrays;
 import java.util.List;
 import java.util.Objects;
+import java.util.concurrent.Executor;
 import java.util.function.Consumer;
 
 /**
@@ -864,6 +866,33 @@
     }
 
     /**
+     * Adds a listener, which will be called when cross-window blurs are enabled/disabled at
+     * runtime. This affects both window blur behind (see {@link LayoutParams#setBlurBehindRadius})
+     * and window background blur (see {@link Window#setBackgroundBlurRadius}).
+     *
+     * Cross-window blur might not be supported by some devices due to GPU limitations. It can also
+     * be disabled at runtime, e.g. during battery saving mode, when multimedia tunneling is used or
+     * when minimal post processing is requested. In such situations, no blur will be computed or
+     * drawn, so the blur target area will not be blurred. To handle this, the app might want to
+     * change its theme to one that does not use blurs.
+     *
+     * If the listener is added successfully, it will be called immediately with the current
+     * cross-window blur enabled state.
+     *
+     * @param executor {@link Executor} to handle the listener callback
+     * @param listener the listener to be added. It will be called back with a boolean parameter,
+     *                 which is true if cross-window blur is enabled and false if it is disabled
+     *
+     * @see #removeCrossWindowBlurEnabledListener
+     * @see #isCrossWindowBlurEnabled
+     * @see LayoutParams#setBlurBehindRadius
+     * @see Window#setBackgroundBlurRadius
+     */
+    default void addCrossWindowBlurEnabledListener(@NonNull @CallbackExecutor Executor executor,
+            @NonNull Consumer<Boolean> listener) {
+    }
+
+    /**
      * Removes a listener, previously added with {@link #addCrossWindowBlurEnabledListener}
      *
      * @param listener the listener to be removed
@@ -873,6 +902,20 @@
     default void removeCrossWindowBlurEnabledListener(@NonNull Consumer<Boolean> listener) {
     }
 
+    /**
+     * Disables cross-window blurs device-wide. This includes window blur behind
+     * (see {@link LayoutParams#setBlurBehindRadius}) and window background blur
+     * (see {@link Window#setBackgroundBlurRadius}).
+     *
+     * @param disable specifies whether to disable the blur. Note that calling this
+     *                with 'disable=false' will not enable blurs if there is something
+     *                else disabling blurs.
+     * @hide
+     */
+    @TestApi
+    default void setForceCrossWindowBlurDisabled(boolean disable) {
+    }
+
     public static class LayoutParams extends ViewGroup.LayoutParams implements Parcelable {
         /**
          * X position for this window.  With the default gravity it is ignored.
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index b398707..8dce852 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -23,6 +23,7 @@
 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
 
+import android.annotation.CallbackExecutor;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UiContext;
@@ -40,6 +41,7 @@
 import com.android.internal.os.IResultReceiver;
 
 import java.util.List;
+import java.util.concurrent.Executor;
 import java.util.function.Consumer;
 
 /**
@@ -310,11 +312,26 @@
 
     @Override
     public void addCrossWindowBlurEnabledListener(@NonNull Consumer<Boolean> listener) {
-        CrossWindowBlurListeners.getInstance().addListener(listener);
+        addCrossWindowBlurEnabledListener(mContext.getMainExecutor(), listener);
+    }
+
+    @Override
+    public void addCrossWindowBlurEnabledListener(@NonNull @CallbackExecutor Executor executor,
+            @NonNull Consumer<Boolean> listener) {
+        CrossWindowBlurListeners.getInstance().addListener(executor, listener);
     }
 
     @Override
     public void removeCrossWindowBlurEnabledListener(@NonNull Consumer<Boolean> listener) {
         CrossWindowBlurListeners.getInstance().removeListener(listener);
     }
+
+    @Override
+    public void setForceCrossWindowBlurDisabled(boolean disable) {
+        try {
+            WindowManagerGlobal.getWindowManagerService()
+                .setForceCrossWindowBlurDisabled(disable);
+        } catch (RemoteException e) {
+        }
+    }
 }
diff --git a/core/java/android/view/inputmethod/InputMethod.java b/core/java/android/view/inputmethod/InputMethod.java
index 6ade5e6..de4554b 100644
--- a/core/java/android/view/inputmethod/InputMethod.java
+++ b/core/java/android/view/inputmethod/InputMethod.java
@@ -105,7 +105,7 @@
      */
     @MainThread
     default void initializeInternal(IBinder token, int displayId,
-            IInputMethodPrivilegedOperations privilegedOperations, int configChanges) {
+            IInputMethodPrivilegedOperations privilegedOperations) {
         updateInputMethodDisplay(displayId);
         attachToken(token);
     }
diff --git a/core/java/android/view/inputmethod/InputMethodInfo.java b/core/java/android/view/inputmethod/InputMethodInfo.java
index 25712f8..cc533eb 100644
--- a/core/java/android/view/inputmethod/InputMethodInfo.java
+++ b/core/java/android/view/inputmethod/InputMethodInfo.java
@@ -18,23 +18,19 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.TestApi;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.Context;
-import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
-import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.content.res.Resources.NotFoundException;
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
 import android.graphics.drawable.Drawable;
-import android.inputmethodservice.InputMethodService;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.AttributeSet;
@@ -64,7 +60,7 @@
  * @attr ref android.R.styleable#InputMethod_isDefault
  * @attr ref android.R.styleable#InputMethod_supportsSwitchingToNextInputMethod
  * @attr ref android.R.styleable#InputMethod_supportsInlineSuggestions
- * @attr ref android.R.styleable#InputMethod_configChanges
+ * @attr ref android.R.styleable#InputMethod_suppressesSpellChecker
  */
 public final class InputMethodInfo implements Parcelable {
     static final String TAG = "InputMethodInfo";
@@ -123,10 +119,9 @@
     private final boolean mInlineSuggestionsEnabled;
 
     /**
-     * The flag for configurations IME assumes the responsibility for handling in
-     * {@link InputMethodService#onConfigurationChanged(Configuration)}}.
+     * The flag whether this IME suppresses spell checker.
      */
-    private final int mHandledConfigChanges;
+    private final boolean mSuppressesSpellChecker;
 
     /**
      * @param service the {@link ResolveInfo} corresponds in which the IME is implemented.
@@ -171,6 +166,7 @@
         boolean isAuxIme = true;
         boolean supportsSwitchingToNextInputMethod = false; // false as default
         boolean inlineSuggestionsEnabled = false; // false as default
+        boolean suppressesSpellChecker = false; // false as default
         mForceDefault = false;
 
         PackageManager pm = context.getPackageManager();
@@ -214,8 +210,8 @@
                     false);
             inlineSuggestionsEnabled = sa.getBoolean(
                     com.android.internal.R.styleable.InputMethod_supportsInlineSuggestions, false);
-            mHandledConfigChanges = sa.getInt(
-                    com.android.internal.R.styleable.InputMethod_configChanges, 0);
+            suppressesSpellChecker = sa.getBoolean(
+                    com.android.internal.R.styleable.InputMethod_suppressesSpellChecker, false);
             sa.recycle();
 
             final int depth = parser.getDepth();
@@ -287,6 +283,7 @@
         mIsAuxIme = isAuxIme;
         mSupportsSwitchingToNextInputMethod = supportsSwitchingToNextInputMethod;
         mInlineSuggestionsEnabled = inlineSuggestionsEnabled;
+        mSuppressesSpellChecker = suppressesSpellChecker;
         mIsVrOnly = isVrOnly;
     }
 
@@ -297,10 +294,10 @@
         mIsAuxIme = source.readInt() == 1;
         mSupportsSwitchingToNextInputMethod = source.readInt() == 1;
         mInlineSuggestionsEnabled = source.readInt() == 1;
+        mSuppressesSpellChecker = source.readBoolean();
         mIsVrOnly = source.readBoolean();
         mService = ResolveInfo.CREATOR.createFromParcel(source);
         mSubtypes = new InputMethodSubtypeArray(source);
-        mHandledConfigChanges = source.readInt();
         mForceDefault = false;
     }
 
@@ -312,22 +309,7 @@
         this(buildFakeResolveInfo(packageName, className, label), false /* isAuxIme */,
                 settingsActivity, null /* subtypes */, 0 /* isDefaultResId */,
                 false /* forceDefault */, true /* supportsSwitchingToNextInputMethod */,
-                false /* inlineSuggestionsEnabled */, false /* isVrOnly */,
-                0 /* handledConfigChanges */);
-    }
-
-    /**
-     * Temporary API for creating a built-in input method for test.
-     * @hide
-     */
-    @TestApi
-    public InputMethodInfo(@NonNull String packageName, @NonNull String className,
-            @NonNull CharSequence label, @NonNull String settingsActivity,
-            int handledConfigChanges) {
-        this(buildFakeResolveInfo(packageName, className, label), false /* isAuxIme */,
-                settingsActivity, null /* subtypes */, 0 /* isDefaultResId */,
-                false /* forceDefault */, true /* supportsSwitchingToNextInputMethod */,
-                false /* inlineSuggestionsEnabled */, false /* isVrOnly */, handledConfigChanges);
+                false /* inlineSuggestionsEnabled */, false /* isVrOnly */);
     }
 
     /**
@@ -339,7 +321,7 @@
             boolean forceDefault) {
         this(ri, isAuxIme, settingsActivity, subtypes, isDefaultResId, forceDefault,
                 true /* supportsSwitchingToNextInputMethod */, false /* inlineSuggestionsEnabled */,
-                false /* isVrOnly */, 0 /* handledconfigChanges */);
+                false /* isVrOnly */);
     }
 
     /**
@@ -350,8 +332,7 @@
             List<InputMethodSubtype> subtypes, int isDefaultResId, boolean forceDefault,
             boolean supportsSwitchingToNextInputMethod, boolean isVrOnly) {
         this(ri, isAuxIme, settingsActivity, subtypes, isDefaultResId, forceDefault,
-                supportsSwitchingToNextInputMethod, false /* inlineSuggestionsEnabled */, isVrOnly,
-                0 /* handledConfigChanges */);
+                supportsSwitchingToNextInputMethod, false /* inlineSuggestionsEnabled */, isVrOnly);
     }
 
     /**
@@ -361,7 +342,7 @@
     public InputMethodInfo(ResolveInfo ri, boolean isAuxIme, String settingsActivity,
             List<InputMethodSubtype> subtypes, int isDefaultResId, boolean forceDefault,
             boolean supportsSwitchingToNextInputMethod, boolean inlineSuggestionsEnabled,
-            boolean isVrOnly, int handledConfigChanges) {
+            boolean isVrOnly) {
         final ServiceInfo si = ri.serviceInfo;
         mService = ri;
         mId = new ComponentName(si.packageName, si.name).flattenToShortString();
@@ -372,8 +353,8 @@
         mForceDefault = forceDefault;
         mSupportsSwitchingToNextInputMethod = supportsSwitchingToNextInputMethod;
         mInlineSuggestionsEnabled = inlineSuggestionsEnabled;
+        mSuppressesSpellChecker = false;
         mIsVrOnly = isVrOnly;
-        mHandledConfigChanges = handledConfigChanges;
     }
 
     private static ResolveInfo buildFakeResolveInfo(String packageName, String className,
@@ -520,23 +501,13 @@
         }
     }
 
-    /**
-     * Returns the bit mask of kinds of configuration changes that this IME
-     * can handle itself (without being restarted by the system).
-     *
-     * @attr ref android.R.styleable#InputMethod_configChanges
-     */
-    @ActivityInfo.Config
-    public int getConfigChanges() {
-        return mHandledConfigChanges;
-    }
-
     public void dump(Printer pw, String prefix) {
         pw.println(prefix + "mId=" + mId
                 + " mSettingsActivityName=" + mSettingsActivityName
                 + " mIsVrOnly=" + mIsVrOnly
                 + " mSupportsSwitchingToNextInputMethod=" + mSupportsSwitchingToNextInputMethod
-                + " mInlineSuggestionsEnabled=" + mInlineSuggestionsEnabled);
+                + " mInlineSuggestionsEnabled=" + mInlineSuggestionsEnabled
+                + " mSuppressesSpellChecker=" + mSuppressesSpellChecker);
         pw.println(prefix + "mIsDefaultResId=0x"
                 + Integer.toHexString(mIsDefaultResId));
         pw.println(prefix + "Service:");
@@ -605,6 +576,13 @@
     }
 
     /**
+     * Return {@code true} if this input method suppresses spell checker.
+     */
+    public boolean suppressesSpellChecker() {
+        return mSuppressesSpellChecker;
+    }
+
+    /**
      * Used to package this object into a {@link Parcel}.
      *
      * @param dest The {@link Parcel} to be written.
@@ -618,10 +596,10 @@
         dest.writeInt(mIsAuxIme ? 1 : 0);
         dest.writeInt(mSupportsSwitchingToNextInputMethod ? 1 : 0);
         dest.writeInt(mInlineSuggestionsEnabled ? 1 : 0);
+        dest.writeBoolean(mSuppressesSpellChecker);
         dest.writeBoolean(mIsVrOnly);
         mService.writeToParcel(dest, flags);
         mSubtypes.writeToParcel(dest);
-        dest.writeInt(mHandledConfigChanges);
     }
 
     /**
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index a8fff8b..c6e5eee 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -106,7 +106,6 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
-import java.lang.ref.WeakReference;
 import java.lang.reflect.Proxy;
 import java.util.Arrays;
 import java.util.Collections;
@@ -413,7 +412,7 @@
      * The InputConnection that was last retrieved from the served view.
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
-    ControlledInputConnectionWrapper mServedInputConnectionWrapper;
+    IInputConnectionWrapper mServedInputConnectionWrapper;
     /**
      * The completions that were last provided by the served view.
      */
@@ -445,6 +444,13 @@
      */
     private Matrix mActivityViewToScreenMatrix = null;
 
+    /**
+     * As reported by {@link InputBindResult}. This value is determined by
+     * {@link com.android.internal.R.styleable#InputMethod_suppressesSpellChecking}.
+     */
+    @GuardedBy("mH")
+    private boolean mIsInputMethodSuppressingSpellChecker = false;
+
     // -----------------------------------------------------------
 
     /**
@@ -740,8 +746,7 @@
         /**
          * Checks whether the active input connection (if any) is for the given view.
          *
-         * TODO(b/160968797): Remove this method and move mServedInputConnectionWrapper to
-         *  ImeFocusController.
+         * TODO(b/182259171): Clean-up hasActiveConnection to simplify the logic.
          *
          * Note that this method is only intended for restarting input after focus gain
          * (e.g. b/160391516), DO NOT leverage this method to do another check.
@@ -755,7 +760,7 @@
 
                 return mServedInputConnectionWrapper != null
                         && mServedInputConnectionWrapper.isActive()
-                        && mServedInputConnectionWrapper.mServedView.get() == view;
+                        && mServedInputConnectionWrapper.getServedView() == view;
             }
         }
     }
@@ -860,6 +865,8 @@
                         mCurId = res.id;
                         mBindSequence = res.sequence;
                         mActivityViewToScreenMatrix = res.getActivityViewToScreenMatrix();
+                        mIsInputMethodSuppressingSpellChecker =
+                                res.isInputMethodSuppressingSpellChecker;
                     }
                     startInputInner(StartInputReason.BOUND_TO_IMMS, null, 0, 0, 0);
                     return;
@@ -1022,77 +1029,6 @@
         }
     }
 
-    private static class ControlledInputConnectionWrapper extends IInputConnectionWrapper {
-        private final InputMethodManager mParentInputMethodManager;
-        private final WeakReference<View> mServedView;
-
-        ControlledInputConnectionWrapper(Looper icLooper, InputConnection conn,
-                InputMethodManager inputMethodManager, View servedView) {
-            super(icLooper, conn);
-            mParentInputMethodManager = inputMethodManager;
-            mServedView = new WeakReference<>(servedView);
-        }
-
-        @Override
-        public boolean isActive() {
-            return mParentInputMethodManager.mActive && !isFinished();
-        }
-
-        @Override
-        public InputMethodManager getIMM() {
-            return mParentInputMethodManager;
-        }
-
-        void deactivate() {
-            if (isFinished()) {
-                // This is a small performance optimization.  Still only the 1st call of
-                // reportFinish() will take effect.
-                return;
-            }
-            closeConnection();
-
-            // Notify the app that the InputConnection was closed.
-            final View servedView = mServedView.get();
-            if (servedView != null) {
-                final Handler handler = servedView.getHandler();
-                // The handler is null if the view is already detached. When that's the case, for
-                // now, we simply don't dispatch this callback.
-                if (handler != null) {
-                    if (DEBUG) {
-                        Log.v(TAG, "Calling View.onInputConnectionClosed: view=" + servedView);
-                    }
-                    if (handler.getLooper().isCurrentThread()) {
-                        servedView.onInputConnectionClosedInternal();
-                    } else {
-                        handler.post(servedView::onInputConnectionClosedInternal);
-                    }
-                }
-            }
-        }
-
-        @Override
-        public String toString() {
-            return "ControlledInputConnectionWrapper{"
-                    + "connection=" + getInputConnection()
-                    + " finished=" + isFinished()
-                    + " mParentInputMethodManager.mActive=" + mParentInputMethodManager.mActive
-                    + " mServedView=" + mServedView.get()
-                    + "}";
-        }
-
-        void dumpDebug(ProtoOutputStream proto, long fieldId) {
-            // Check that the call is initiated in the main thread of the current InputConnection
-            // {@link InputConnection#getHandler} since the messages to IInputConnectionWrapper are
-            // executed on this thread. Otherwise the messages are dispatched to the correct thread
-            // in IInputConnectionWrapper, but this is not wanted while dumpng, for performance
-            // reasons.
-            if (getInputConnection() instanceof DumpableInputConnection && Looper.myLooper()
-                    == getLooper()) {
-                ((DumpableInputConnection) getInputConnection()).dumpDebug(proto, fieldId);
-            }
-        }
-    }
-
     final IInputMethodClient.Stub mClient = new IInputMethodClient.Stub() {
         @Override
         protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
@@ -1256,8 +1192,7 @@
         mMainLooper = looper;
         mH = new H(looper);
         mDisplayId = displayId;
-        mIInputContext = new ControlledInputConnectionWrapper(looper, mDummyInputConnection, this,
-                null);
+        mIInputContext = new IInputConnectionWrapper(looper, mDummyInputConnection, this, null);
     }
 
     /**
@@ -1544,6 +1479,15 @@
     }
 
     /**
+     * Return {@code true} if the input method is suppressing system spell checker.
+     */
+    public boolean isInputMethodSuppressingSpellChecker() {
+        synchronized (mH) {
+            return mIsInputMethodSuppressingSpellChecker;
+        }
+    }
+
+    /**
      * Reset all of the state associated with being bound to an input method.
      */
     void clearBindingLocked() {
@@ -1587,6 +1531,7 @@
     @UnsupportedAppUsage
     void finishInputLocked() {
         mActivityViewToScreenMatrix = null;
+        mIsInputMethodSuppressingSpellChecker = false;
         setNextServedViewLocked(null);
         if (getServedViewLocked() != null) {
             if (DEBUG) {
@@ -2063,7 +2008,7 @@
                 mServedInputConnectionWrapper.deactivate();
                 mServedInputConnectionWrapper = null;
             }
-            ControlledInputConnectionWrapper servedContext;
+            IInputConnectionWrapper servedContext;
             final int missingMethodFlags;
             if (ic != null) {
                 mCursorSelStart = tba.initialSelStart;
@@ -2080,7 +2025,7 @@
                 } else {
                     icHandler = ic.getHandler();
                 }
-                servedContext = new ControlledInputConnectionWrapper(
+                servedContext = new IInputConnectionWrapper(
                         icHandler != null ? icHandler.getLooper() : vh.getLooper(), ic, this, view);
             } else {
                 servedContext = null;
@@ -2111,6 +2056,7 @@
                     return false;
                 }
                 mActivityViewToScreenMatrix = res.getActivityViewToScreenMatrix();
+                mIsInputMethodSuppressingSpellChecker = res.isInputMethodSuppressingSpellChecker;
                 if (res.id != null) {
                     setInputChannelLocked(res.channel);
                     mBindSequence = res.sequence;
diff --git a/core/java/android/view/textservice/SpellCheckerSession.java b/core/java/android/view/textservice/SpellCheckerSession.java
index 35d8445..ba58b65 100644
--- a/core/java/android/view/textservice/SpellCheckerSession.java
+++ b/core/java/android/view/textservice/SpellCheckerSession.java
@@ -25,6 +25,7 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.util.Log;
+import android.view.inputmethod.InputMethodManager;
 
 import com.android.internal.textservice.ISpellCheckerSession;
 import com.android.internal.textservice.ISpellCheckerSessionListener;
@@ -176,6 +177,11 @@
      * @param suggestionsLimit the maximum number of suggestions that will be returned
      */
     public void getSentenceSuggestions(TextInfo[] textInfos, int suggestionsLimit) {
+        final InputMethodManager imm = mTextServicesManager.getInputMethodManager();
+        if (imm != null && imm.isInputMethodSuppressingSpellChecker()) {
+            handleOnGetSentenceSuggestionsMultiple(new SentenceSuggestionsInfo[0]);
+            return;
+        }
         mSpellCheckerSessionListenerImpl.getSentenceSuggestionsMultiple(
                 textInfos, suggestionsLimit);
     }
@@ -204,6 +210,11 @@
         if (DBG) {
             Log.w(TAG, "getSuggestions from " + mSpellCheckerInfo.getId());
         }
+        final InputMethodManager imm = mTextServicesManager.getInputMethodManager();
+        if (imm != null && imm.isInputMethodSuppressingSpellChecker()) {
+            handleOnGetSuggestionsMultiple(new SuggestionsInfo[0]);
+            return;
+        }
         mSpellCheckerSessionListenerImpl.getSuggestionsMultiple(
                 textInfos, suggestionsLimit, sequentialWords);
     }
diff --git a/core/java/android/view/textservice/TextServicesManager.java b/core/java/android/view/textservice/TextServicesManager.java
index 996757d..6fb01a3 100644
--- a/core/java/android/view/textservice/TextServicesManager.java
+++ b/core/java/android/view/textservice/TextServicesManager.java
@@ -30,6 +30,7 @@
 import android.os.ServiceManager.ServiceNotFoundException;
 import android.os.UserHandle;
 import android.util.Log;
+import android.view.inputmethod.InputMethodManager;
 import android.view.textservice.SpellCheckerSession.SpellCheckerSessionListener;
 
 import com.android.internal.textservice.ISpellCheckerSessionListener;
@@ -88,10 +89,15 @@
     @UserIdInt
     private final int mUserId;
 
-    private TextServicesManager(@UserIdInt int userId) throws ServiceNotFoundException {
+    @Nullable
+    private final InputMethodManager mInputMethodManager;
+
+    private TextServicesManager(@UserIdInt int userId,
+            @Nullable InputMethodManager inputMethodManager) throws ServiceNotFoundException {
         mService = ITextServicesManager.Stub.asInterface(
                 ServiceManager.getServiceOrThrow(Context.TEXT_SERVICES_MANAGER_SERVICE));
         mUserId = userId;
+        mInputMethodManager = inputMethodManager;
     }
 
     /**
@@ -105,7 +111,8 @@
     @NonNull
     public static TextServicesManager createInstance(@NonNull Context context)
             throws ServiceNotFoundException {
-        return new TextServicesManager(context.getUserId());
+        return new TextServicesManager(context.getUserId(), context.getSystemService(
+                InputMethodManager.class));
     }
 
     /**
@@ -118,7 +125,7 @@
         synchronized (TextServicesManager.class) {
             if (sInstance == null) {
                 try {
-                    sInstance = new TextServicesManager(UserHandle.myUserId());
+                    sInstance = new TextServicesManager(UserHandle.myUserId(), null);
                 } catch (ServiceNotFoundException e) {
                     throw new IllegalStateException(e);
                 }
@@ -127,6 +134,12 @@
         }
     }
 
+    /** @hide */
+    @Nullable
+    public InputMethodManager getInputMethodManager() {
+        return mInputMethodManager;
+    }
+
     /**
      * Returns the language component of a given locale string.
      */
diff --git a/core/java/android/widget/AnalogClock.java b/core/java/android/widget/AnalogClock.java
index 34fe51e..42d7535 100644
--- a/core/java/android/widget/AnalogClock.java
+++ b/core/java/android/widget/AnalogClock.java
@@ -200,6 +200,8 @@
         mTimeZone = toZoneId(a.getString(com.android.internal.R.styleable.AnalogClock_timeZone));
         createClock();
 
+        a.recycle();
+
         mDialWidth = mDial.getIntrinsicWidth();
         mDialHeight = mDial.getIntrinsicHeight();
     }
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 012352d..ca89677 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -988,6 +988,12 @@
 
         if (mTextView.isTextEditable() && mTextView.isSuggestionsEnabled()
                 && !(mTextView.isInExtractedMode())) {
+            final InputMethodManager imm = getInputMethodManager();
+            if (imm != null && imm.isInputMethodSuppressingSpellChecker()) {
+                // Do not close mSpellChecker here as it may be reused when the current IME has been
+                // changed.
+                return;
+            }
             if (mSpellChecker == null && createSpellChecker) {
                 mSpellChecker = new SpellChecker(mTextView);
             }
@@ -3790,7 +3796,7 @@
         }
 
         public SuggestionsPopupWindow() {
-            mCursorWasVisibleBeforeSuggestions = mCursorVisible;
+            mCursorWasVisibleBeforeSuggestions = mTextView.isCursorVisibleFromAttr();
         }
 
         @Override
@@ -3957,7 +3963,7 @@
             }
 
             if (updateSuggestions()) {
-                mCursorWasVisibleBeforeSuggestions = mCursorVisible;
+                mCursorWasVisibleBeforeSuggestions = mTextView.isCursorVisibleFromAttr();
                 mTextView.setCursorVisible(false);
                 mIsShowingUp = true;
                 super.show();
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 2328e58..d2f4cea 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -120,6 +120,7 @@
 import java.util.Stack;
 import java.util.concurrent.Executor;
 import java.util.function.Consumer;
+import java.util.function.Predicate;
 
 /**
  * A class that describes a view hierarchy that can be displayed in
@@ -1993,22 +1994,79 @@
         mIsRoot = false;
     }
 
+    private static boolean hasStableId(View view) {
+        Object tag = view.getTag(com.android.internal.R.id.remote_views_stable_id);
+        return tag != null;
+    }
+
+    private static int getStableId(View view) {
+        Integer id = (Integer) view.getTag(com.android.internal.R.id.remote_views_stable_id);
+        return id == null ? ViewGroupActionAdd.NO_ID : id;
+    }
+
+    private static void setStableId(View view, int stableId) {
+        view.setTagInternal(com.android.internal.R.id.remote_views_stable_id, stableId);
+    }
+
+    // Returns the next recyclable child of the view group, or -1 if there are none.
+    private static int getNextRecyclableChild(ViewGroup vg) {
+        Integer tag = (Integer) vg.getTag(com.android.internal.R.id.remote_views_next_child);
+        return tag == null ? -1 : tag;
+    }
+
+    private static int getViewLayoutId(View v) {
+        return (Integer) v.getTag(R.id.widget_frame);
+    }
+
+    private static void setNextRecyclableChild(ViewGroup vg, int nextChild, int numChildren) {
+        if (nextChild < 0 || nextChild >= numChildren) {
+            vg.setTagInternal(com.android.internal.R.id.remote_views_next_child, -1);
+        } else {
+            vg.setTagInternal(com.android.internal.R.id.remote_views_next_child, nextChild);
+        }
+    }
+
+    private void finalizeViewRecycling(ViewGroup root) {
+        // Remove any recyclable children that were not used. nextChild should either be -1 or point
+        // to the next recyclable child that hasn't been recycled.
+        int nextChild = getNextRecyclableChild(root);
+        if (nextChild >= 0 && nextChild < root.getChildCount()) {
+            root.removeViews(nextChild, root.getChildCount() - nextChild);
+        }
+        // Make sure on the next round, we don't try to recycle if removeAllViews is not called.
+        setNextRecyclableChild(root, -1, 0);
+        // Traverse the view tree.
+        for (int i = 0; i < root.getChildCount(); i++) {
+            View child = root.getChildAt(i);
+            if (child instanceof ViewGroup && !child.isRootNamespace()) {
+                finalizeViewRecycling((ViewGroup) child);
+            }
+        }
+    }
+
     /**
      * ViewGroup methods that are related to adding Views.
      */
     private class ViewGroupActionAdd extends Action {
+        static final int NO_ID = -1;
         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
         private RemoteViews mNestedViews;
         private int mIndex;
+        private int mStableId;
 
         ViewGroupActionAdd(@IdRes int viewId, RemoteViews nestedViews) {
-            this(viewId, nestedViews, -1 /* index */);
+            this(viewId, nestedViews, -1 /* index */, NO_ID /* nestedViewId */);
         }
 
         ViewGroupActionAdd(@IdRes int viewId, RemoteViews nestedViews, int index) {
+            this(viewId, nestedViews, index, NO_ID /* nestedViewId */);
+        }
+
+        ViewGroupActionAdd(@IdRes int viewId, RemoteViews nestedViews, int index, int stableId) {
             this.viewId = viewId;
             mNestedViews = nestedViews;
             mIndex = index;
+            mStableId = stableId;
             if (nestedViews != null) {
                 configureRemoteViewsAsChild(nestedViews);
             }
@@ -2018,6 +2076,7 @@
                 int depth, Map<Class, Object> classCookies) {
             viewId = parcel.readInt();
             mIndex = parcel.readInt();
+            mStableId = parcel.readInt();
             mNestedViews = new RemoteViews(parcel, bitmapCache, info, depth, classCookies);
             mNestedViews.addFlags(mApplyFlags);
         }
@@ -2025,6 +2084,7 @@
         public void writeToParcel(Parcel dest, int flags) {
             dest.writeInt(viewId);
             dest.writeInt(mIndex);
+            dest.writeInt(mStableId);
             mNestedViews.writeToParcel(dest, flags);
         }
 
@@ -2033,6 +2093,17 @@
             return mNestedViews.hasSameAppInfo(parentInfo);
         }
 
+        private int findViewIndexToRecycle(ViewGroup target, RemoteViews newContent) {
+            for (int nextChild = getNextRecyclableChild(target); nextChild < target.getChildCount();
+                    nextChild++) {
+                View child = target.getChildAt(nextChild);
+                if (getStableId(child) == mStableId) {
+                    return nextChild;
+                }
+            }
+            return -1;
+        }
+
         @Override
         public void apply(View root, ViewGroup rootParent, InteractionHandler handler,
                 ColorResources colorResources) {
@@ -2043,10 +2114,45 @@
                 return;
             }
 
+            // If removeAllViews was called, this returns the next potential recycled view.
+            // If there are no more views to recycle (or removeAllViews was not called), this
+            // will return -1.
+            final int nextChild = getNextRecyclableChild(target);
+            RemoteViews rvToApply = mNestedViews.getRemoteViewsToApply(context);
+            if (nextChild >= 0 && mStableId != NO_ID) {
+                // At that point, the views starting at index nextChild are the ones recyclable but
+                // not yet recycled. All views added on that round of application are placed before.
+                // Find the next view with the same stable id, or -1.
+                int recycledViewIndex = findViewIndexToRecycle(target, rvToApply);
+                if (recycledViewIndex >= 0) {
+                    View child = target.getChildAt(recycledViewIndex);
+                    if (getViewLayoutId(child) == rvToApply.getLayoutId()) {
+                        if (nextChild < recycledViewIndex) {
+                            target.removeViews(nextChild, recycledViewIndex - nextChild);
+                        }
+                        setNextRecyclableChild(target, nextChild + 1, target.getChildCount());
+                        rvToApply.reapply(context, child, handler, null /* size */, colorResources,
+                                false /* topLevel */);
+                        return;
+                    }
+                    // If we cannot recycle the views, we still remove all views in between to
+                    // avoid weird behaviors and insert the new view in place of the old one.
+                    target.removeViews(nextChild, recycledViewIndex - nextChild + 1);
+                }
+            }
+            // If we cannot recycle, insert the new view before the next recyclable child.
+
             // Inflate nested views and add as children
-            target.addView(
-                    mNestedViews.apply(context, target, handler, null /* size */, colorResources),
-                    mIndex);
+            View nestedView = rvToApply.apply(context, target, handler, null /* size */,
+                    colorResources);
+            if (mStableId != NO_ID) {
+                setStableId(nestedView, mStableId);
+            }
+            target.addView(nestedView, mIndex >= 0 ? mIndex : nextChild);
+            if (nextChild >= 0) {
+                // If we are at the end, there is no reason to try to recycle anymore
+                setNextRecyclableChild(target, nextChild + 1, target.getChildCount());
+            }
         }
 
         @Override
@@ -2063,24 +2169,91 @@
 
             // Inflate nested views and perform all the async tasks for the child remoteView.
             final Context context = root.mRoot.getContext();
-            final AsyncApplyTask task = mNestedViews.getAsyncApplyTask(context, targetVg,
-                    null /* listener */, handler, null /* size */, colorResources);
+
+            // If removeAllViews was called, this returns the next potential recycled view.
+            // If there are no more views to recycle (or removeAllViews was not called), this
+            // will return -1.
+            final int nextChild = getNextRecyclableChild(targetVg);
+            if (nextChild >= 0 && mStableId != NO_ID) {
+                RemoteViews rvToApply = mNestedViews.getRemoteViewsToApply(context);
+                final int recycledViewIndex = target.findChildIndex(nextChild,
+                        view -> getStableId(view) == mStableId);
+                if (recycledViewIndex >= 0) {
+                    // At that point, the views starting at index nextChild are the ones
+                    // recyclable but not yet recycled. All views added on that round of
+                    // application are placed before.
+                    ViewTree recycled = target.mChildren.get(recycledViewIndex);
+                    // We can only recycle the view if the layout id is the same.
+                    if (getViewLayoutId(recycled.mRoot) == rvToApply.getLayoutId()) {
+                        if (recycledViewIndex > nextChild) {
+                            target.removeChildren(nextChild, recycledViewIndex - nextChild);
+                        }
+                        setNextRecyclableChild(targetVg, nextChild + 1, target.mChildren.size());
+                        final AsyncApplyTask reapplyTask = rvToApply.getInternalAsyncApplyTask(
+                                context,
+                                targetVg, null /* listener */, handler, null /* size */,
+                                colorResources,
+                                recycled.mRoot);
+                        final ViewTree tree = reapplyTask.doInBackground();
+                        if (tree == null) {
+                            throw new ActionException(reapplyTask.mError);
+                        }
+                        return new RuntimeAction() {
+                            @Override
+                            public void apply(View root, ViewGroup rootParent,
+                                    InteractionHandler handler, ColorResources colorResources)
+                                    throws ActionException {
+                                reapplyTask.onPostExecute(tree);
+                                if (recycledViewIndex > nextChild) {
+                                    targetVg.removeViews(nextChild, recycledViewIndex - nextChild);
+                                }
+                            }
+                        };
+                    }
+                    // If the layout id is different, still remove the children as if we recycled
+                    // the view, to insert at the same place.
+                    target.removeChildren(nextChild, recycledViewIndex - nextChild + 1);
+                    return insertNewView(context, target, handler, colorResources,
+                            () -> targetVg.removeViews(nextChild,
+                                    recycledViewIndex - nextChild + 1));
+
+                }
+            }
+            // If we cannot recycle, simply add the view at the same available slot.
+            return insertNewView(context, target, handler, colorResources, () -> {});
+        }
+
+        private Action insertNewView(Context context, ViewTree target, InteractionHandler handler,
+                ColorResources colorResources, Runnable finalizeAction) {
+            ViewGroup targetVg = (ViewGroup) target.mRoot;
+            int nextChild = getNextRecyclableChild(targetVg);
+            final AsyncApplyTask task = mNestedViews.getInternalAsyncApplyTask(context, targetVg,
+                    null /* listener */, handler, null /* size */, colorResources,
+                    null /* result */);
             final ViewTree tree = task.doInBackground();
 
             if (tree == null) {
                 throw new ActionException(task.mError);
             }
+            if (mStableId != NO_ID) {
+                setStableId(task.mResult, mStableId);
+            }
 
             // Update the global view tree, so that next call to findViewTreeById
             // goes through the subtree as well.
-            target.addChild(tree, mIndex);
+            final int insertIndex = mIndex >= 0 ? mIndex : nextChild;
+            target.addChild(tree, insertIndex);
+            if (nextChild >= 0) {
+                setNextRecyclableChild(targetVg, nextChild + 1, target.mChildren.size());
+            }
 
             return new RuntimeAction() {
                 @Override
                 public void apply(View root, ViewGroup rootParent, InteractionHandler handler,
                         ColorResources colorResources) throws ActionException {
                     task.onPostExecute(tree);
-                    targetVg.addView(task.mResult, mIndex);
+                    finalizeAction.run();
+                    targetVg.addView(task.mResult, insertIndex);
                 }
             };
         }
@@ -2148,7 +2321,14 @@
             }
 
             if (mViewIdToKeep == REMOVE_ALL_VIEWS_ID) {
-                target.removeAllViews();
+                // Remote any view without a stable id
+                for (int i = target.getChildCount() - 1; i >= 0; i--) {
+                    if (!hasStableId(target.getChildAt(i))) {
+                        target.removeViewAt(i);
+                    }
+                }
+                // In the end, only children with a stable id (i.e. recyclable) are left.
+                setNextRecyclableChild(target, 0, target.getChildCount());
                 return;
             }
 
@@ -2170,8 +2350,8 @@
             final ViewGroup targetVg = (ViewGroup) target.mRoot;
 
             if (mViewIdToKeep == REMOVE_ALL_VIEWS_ID) {
-                // Clear all children when there's no excepted view
-                target.mChildren = null;
+                target.mChildren.removeIf(childTree -> !hasStableId(childTree.mRoot));
+                setNextRecyclableChild(targetVg, 0, target.mChildren.size());
             } else {
                 // Remove just the children which don't match the excepted view
                 target.mChildren.removeIf(childTree -> childTree.mRoot.getId() != mViewIdToKeep);
@@ -2184,7 +2364,11 @@
                 public void apply(View root, ViewGroup rootParent, InteractionHandler handler,
                         ColorResources colorResources) throws ActionException {
                     if (mViewIdToKeep == REMOVE_ALL_VIEWS_ID) {
-                        targetVg.removeAllViews();
+                        for (int i = targetVg.getChildCount() - 1; i >= 0; i--) {
+                            if (!hasStableId(targetVg.getChildAt(i))) {
+                                targetVg.removeViewAt(i);
+                            }
+                        }
                         return;
                     }
 
@@ -3084,6 +3268,7 @@
         }
         mApplication = portrait.mApplication;
         mLayoutId = portrait.mLayoutId;
+        mViewId = portrait.mViewId;
         mLightBackgroundLayoutId = portrait.mLightBackgroundLayoutId;
 
         mLandscape = landscape;
@@ -3136,6 +3321,7 @@
         RemoteViews smallestView = findSmallestRemoteView();
         mApplication = smallestView.mApplication;
         mLayoutId = smallestView.mLayoutId;
+        mViewId = smallestView.mViewId;
         mLightBackgroundLayoutId = smallestView.mLightBackgroundLayoutId;
     }
 
@@ -3253,6 +3439,7 @@
                     ApplicationInfo.CREATOR.createFromParcel(parcel);
             mIdealSize = parcel.readInt() == 0 ? null : SizeF.CREATOR.createFromParcel(parcel);
             mLayoutId = parcel.readInt();
+            mViewId = parcel.readInt();
             mLightBackgroundLayoutId = parcel.readInt();
 
             readActionsFromParcel(parcel, depth);
@@ -3273,6 +3460,7 @@
             RemoteViews smallestView = findSmallestRemoteView();
             mApplication = smallestView.mApplication;
             mLayoutId = smallestView.mLayoutId;
+            mViewId = smallestView.mViewId;
             mLightBackgroundLayoutId = smallestView.mLightBackgroundLayoutId;
         } else {
             // MODE_HAS_LANDSCAPE_AND_PORTRAIT
@@ -3281,6 +3469,7 @@
                     mClassCookies);
             mApplication = mPortrait.mApplication;
             mLayoutId = mPortrait.mLayoutId;
+            mViewId = mPortrait.mViewId;
             mLightBackgroundLayoutId = mPortrait.mLightBackgroundLayoutId;
         }
         mApplyFlags = parcel.readInt();
@@ -3458,6 +3647,29 @@
     }
 
     /**
+     * Equivalent to calling {@link ViewGroup#addView(View)} after inflating the given
+     * {@link RemoteViews}. If the {@link RemoteViews} may be re-inflated or updated,
+     * {@link #removeAllViews(int)} must be called on the same {@code viewId
+     * } before the first call to this method for the behavior of this method to be predictable.
+     *
+     * The {@code stableId} will be used to identify a potential view to recycled when the remote
+     * view is inflated. Views can be re-used if inserted in the same order, potentially with
+     * some views appearing / disappearing.
+     *
+     * Note: if a view is re-used, all the actions will be re-applied on it. However, its properties
+     * are not reset, so what was applied in previous round will have an effect. As a view may be
+     * re-created at any time by the host, the RemoteViews should not rely on keeping information
+     * from previous applications and always re-set all the properties they need.
+     *
+     * @param viewId The id of the parent {@link ViewGroup} to add child into.
+     * @param nestedView {@link RemoteViews} that describes the child.
+     * @param stableId An id that is stable across different versions of RemoteViews.
+     */
+    public void addStableView(@IdRes int viewId, @NonNull RemoteViews nestedView, int stableId) {
+        addAction(new ViewGroupActionAdd(viewId, nestedView, -1 /* index */, stableId));
+    }
+
+    /**
      * Equivalent to calling {@link ViewGroup#addView(View, int)} after inflating the
      * given {@link RemoteViews}.
      *
@@ -4870,23 +5082,24 @@
     public CancellationSignal applyAsync(Context context, ViewGroup parent,
             Executor executor, OnViewAppliedListener listener, InteractionHandler handler,
             SizeF size) {
-        return getAsyncApplyTask(context, parent, listener, handler, size, null /* themeColors */)
-                .startTaskOnExecutor(executor);
+        return applyAsync(context, parent, executor, listener, handler, size,
+                null /* themeColors */);
     }
 
     /** @hide */
     public CancellationSignal applyAsync(Context context, ViewGroup parent, Executor executor,
             OnViewAppliedListener listener, InteractionHandler handler, SizeF size,
             ColorResources colorResources) {
-        return getAsyncApplyTask(context, parent, listener, handler, size, colorResources)
-                .startTaskOnExecutor(executor);
+        return new AsyncApplyTask(getRemoteViewsToApply(context, size), parent, context, listener,
+                handler, colorResources, null /* result */,
+                true /* topLevel */).startTaskOnExecutor(executor);
     }
 
-    private AsyncApplyTask getAsyncApplyTask(Context context, ViewGroup parent,
+    private AsyncApplyTask getInternalAsyncApplyTask(Context context, ViewGroup parent,
             OnViewAppliedListener listener, InteractionHandler handler, SizeF size,
-            ColorResources colorResources) {
+            ColorResources colorResources, View result) {
         return new AsyncApplyTask(getRemoteViewsToApply(context, size), parent, context, listener,
-                handler, colorResources, null /* result */);
+                handler, colorResources, result, false /* topLevel */);
     }
 
     private class AsyncApplyTask extends AsyncTask<Void, Void, ViewTree>
@@ -4898,6 +5111,12 @@
         final OnViewAppliedListener mListener;
         final InteractionHandler mHandler;
         final ColorResources mColorResources;
+        /**
+         * Whether the remote view is the top-level one (i.e. not within an action).
+         *
+         * This is only used if the result is specified (i.e. the view is being recycled).
+         */
+        final boolean mTopLevel;
 
         private View mResult;
         private ViewTree mTree;
@@ -4906,13 +5125,15 @@
 
         private AsyncApplyTask(
                 RemoteViews rv, ViewGroup parent, Context context, OnViewAppliedListener listener,
-                InteractionHandler handler, ColorResources colorResources, View result) {
+                InteractionHandler handler, ColorResources colorResources,
+                View result, boolean topLevel) {
             mRV = rv;
             mParent = parent;
             mContext = context;
             mListener = listener;
             mColorResources = colorResources;
             mHandler = handler;
+            mTopLevel = topLevel;
 
             mResult = result;
         }
@@ -4959,6 +5180,10 @@
                             a.apply(viewTree.mRoot, mParent, handler, mColorResources);
                         }
                     }
+                    // If the parent of the view is has is a root, resolve the recycling.
+                    if (mTopLevel && mResult instanceof ViewGroup) {
+                        finalizeViewRecycling((ViewGroup) mResult);
+                    }
                 } catch (Exception e) {
                     mError = e;
                 }
@@ -5011,6 +5236,14 @@
     /** @hide */
     public void reapply(Context context, View v, InteractionHandler handler, SizeF size,
             ColorResources colorResources) {
+        reapply(context, v, handler, size, colorResources, true);
+    }
+
+    // Note: topLevel should be true only for calls on the topLevel RemoteViews, internal calls
+    // should set it to false.
+    private void reapply(Context context, View v, InteractionHandler handler, SizeF size,
+            ColorResources colorResources, boolean topLevel) {
+
         RemoteViews rvToApply = getRemoteViewsToApply(context, size);
 
         // In the case that a view has this RemoteViews applied in one orientation or size, is
@@ -5025,6 +5258,11 @@
         }
 
         rvToApply.performApply(v, (ViewGroup) v.getParent(), handler, colorResources);
+
+        // If the parent of the view is has is a root, resolve the recycling.
+        if (topLevel && v instanceof ViewGroup) {
+            finalizeViewRecycling((ViewGroup) v);
+        }
     }
 
     /**
@@ -5068,8 +5306,8 @@
         }
 
         return new AsyncApplyTask(rvToApply, (ViewGroup) v.getParent(),
-                context, listener, handler, colorResources, v).startTaskOnExecutor(
-                executor);
+                context, listener, handler, colorResources, v, true /* topLevel */)
+                .startTaskOnExecutor(executor);
     }
 
     private void performApply(View v, ViewGroup parent, InteractionHandler handler,
@@ -5282,6 +5520,7 @@
                 mIdealSize.writeToParcel(dest, flags);
             }
             dest.writeInt(mLayoutId);
+            dest.writeInt(mViewId);
             dest.writeInt(mLightBackgroundLayoutId);
             writeActionsToParcel(dest);
         } else if (hasSizedRemoteViews()) {
@@ -5470,6 +5709,14 @@
             mChildren.add(index, child);
         }
 
+        public void removeChildren(int start, int count) {
+            if (mChildren != null) {
+                for (int i = 0; i < count; i++) {
+                    mChildren.remove(start);
+                }
+            }
+        }
+
         private void addViewChild(View v) {
             // ViewTree only contains Views which can be found using findViewById.
             // If isRootNamespace is true, this view is skipped.
@@ -5500,6 +5747,28 @@
                 }
             }
         }
+
+        /** Find the first child for which the condition is true and return its index. */
+        public int findChildIndex(Predicate<View> condition) {
+            return findChildIndex(0, condition);
+        }
+
+        /**
+         * Find the first child, starting at {@code startIndex}, for which the condition is true and
+         * return its index.
+         */
+        public int findChildIndex(int startIndex, Predicate<View> condition) {
+            if (mChildren == null) {
+                return -1;
+            }
+
+            for (int i = startIndex; i < mChildren.size(); i++) {
+                if (condition.test(mChildren.get(i).mRoot)) {
+                    return i;
+                }
+            }
+            return -1;
+        }
     }
 
     /**
@@ -5758,9 +6027,9 @@
     }
 
     /**
-     *  Set the ID of the top-level view of the XML layout.
+     * Set the ID of the top-level view of the XML layout.
      *
-     *  Set to {@link View#NO_ID} to reset and simply keep the id defined in the XML layout.
+     * Set to {@link View#NO_ID} to reset and simply keep the id defined in the XML layout.
      *
      * @throws UnsupportedOperationException if the method is called on a RemoteViews defined in
      * term of other RemoteViews (e.g. {@link #RemoteViews(RemoteViews, RemoteViews)}).
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 177a9f1..dba7fa9 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -503,7 +503,7 @@
     private boolean mImeIsConsumingInput;
 
     // Whether cursor is visible without regard to {@link mImeConsumesInput}.
-    // {code true} is the default value.
+    // {@code true} is the default value.
     private boolean mCursorVisibleFromAttr = true;
 
     static class Drawables {
@@ -10571,6 +10571,17 @@
         return mEditor == null ? true : mEditor.mCursorVisible;
     }
 
+    /**
+     * @return whether cursor is visible without regard to {@code mImeIsConsumingInput}.
+     * {@code true} is the default value.
+     *
+     * @see #setCursorVisible(boolean)
+     * @hide
+     */
+    public boolean isCursorVisibleFromAttr() {
+        return mCursorVisibleFromAttr;
+    }
+
     private boolean canMarquee() {
         int width = mRight - mLeft - getCompoundPaddingLeft() - getCompoundPaddingRight();
         return width > 0 && (mLayout.getLineWidth(0) > width
diff --git a/core/java/android/window/ITaskOrganizer.aidl b/core/java/android/window/ITaskOrganizer.aidl
index 8f541d0..3eb35c2 100644
--- a/core/java/android/window/ITaskOrganizer.aidl
+++ b/core/java/android/window/ITaskOrganizer.aidl
@@ -18,6 +18,7 @@
 
 import android.view.SurfaceControl;
 import android.app.ActivityManager;
+import android.graphics.Rect;
 import android.window.StartingWindowInfo;
 import android.window.WindowContainerToken;
 
@@ -38,8 +39,12 @@
 
     /**
      * Called when the Task want to remove the starting window.
+     * @param leash A persistent leash for the top window in this task.
+     * @param frame Window frame of the top window.
+     * @param playRevealAnimation Play vanish animation.
      */
-    void removeStartingWindow(int taskId);
+    void removeStartingWindow(int taskId, in SurfaceControl leash, in Rect frame,
+            in boolean playRevealAnimation);
 
     /**
      * Called when the Task want to copy the splash screen.
diff --git a/core/java/android/window/SplashScreenView.java b/core/java/android/window/SplashScreenView.java
index 35ccfca..da445b8 100644
--- a/core/java/android/window/SplashScreenView.java
+++ b/core/java/android/window/SplashScreenView.java
@@ -46,6 +46,8 @@
 import com.android.internal.R;
 import com.android.internal.policy.DecorView;
 
+import java.util.function.Consumer;
+
 /**
  * <p>The view which allows an activity to customize its splash screen exit animation.</p>
  *
@@ -77,7 +79,8 @@
 
     private Animatable mAnimatableIcon;
     private ValueAnimator mAnimator;
-
+    private Runnable mAnimationFinishListener;
+    private Consumer<Canvas> mOnDrawCallback;
     // cache original window and status
     private Window mWindow;
     private boolean mDrawBarBackground;
@@ -85,7 +88,7 @@
     private int mNavigationBarColor;
 
     /**
-     * Internal builder to create a SplashScreenWindowView object.
+     * Internal builder to create a SplashScreenView object.
      * @hide
      */
     public static class Builder {
@@ -391,7 +394,7 @@
      * Get the initial background color of this view.
      * @hide
      */
-    @ColorInt int getInitBackgroundColor() {
+    public @ColorInt int getInitBackgroundColor() {
         return mInitBackgroundColor;
     }
 
diff --git a/core/java/android/window/StartingWindowInfo.java b/core/java/android/window/StartingWindowInfo.java
index d1c1e40..c7672dc 100644
--- a/core/java/android/window/StartingWindowInfo.java
+++ b/core/java/android/window/StartingWindowInfo.java
@@ -126,6 +126,12 @@
      */
     public int splashScreenThemeResId;
 
+    /**
+     * Is keyguard occluded on default display.
+     * @hide
+     */
+    public boolean isKeyguardOccluded = false;
+
     public StartingWindowInfo() {
 
     }
@@ -147,6 +153,7 @@
         dest.writeTypedObject(topOpaqueWindowLayoutParams, flags);
         dest.writeTypedObject(mainWindowLayoutParams, flags);
         dest.writeInt(splashScreenThemeResId);
+        dest.writeBoolean(isKeyguardOccluded);
     }
 
     void readFromParcel(@NonNull Parcel source) {
@@ -157,6 +164,7 @@
                 WindowManager.LayoutParams.CREATOR);
         mainWindowLayoutParams = source.readTypedObject(WindowManager.LayoutParams.CREATOR);
         splashScreenThemeResId = source.readInt();
+        isKeyguardOccluded = source.readBoolean();
     }
 
     @Override
diff --git a/core/java/android/window/TaskOrganizer.java b/core/java/android/window/TaskOrganizer.java
index 04020ec..3340cf4 100644
--- a/core/java/android/window/TaskOrganizer.java
+++ b/core/java/android/window/TaskOrganizer.java
@@ -24,6 +24,7 @@
 import android.annotation.SuppressLint;
 import android.annotation.TestApi;
 import android.app.ActivityManager;
+import android.graphics.Rect;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.view.SurfaceControl;
@@ -100,9 +101,14 @@
 
     /**
      * Called when the Task want to remove the starting window.
+     * @param leash A persistent leash for the top window in this task. Release it once exit
+     *              animation has finished.
+     * @param frame Window frame of the top window.
+     * @param playRevealAnimation Play vanish animation.
      */
     @BinderThread
-    public void removeStartingWindow(int taskId) {}
+    public void removeStartingWindow(int taskId, @Nullable SurfaceControl leash,
+            @Nullable Rect frame, boolean playRevealAnimation) {}
 
     /**
      * Called when the Task want to copy the splash screen.
@@ -217,15 +223,16 @@
 
     private final ITaskOrganizer mInterface = new ITaskOrganizer.Stub() {
         @Override
-
         public void addStartingWindow(StartingWindowInfo windowInfo,
                 IBinder appToken) {
             mExecutor.execute(() -> TaskOrganizer.this.addStartingWindow(windowInfo, appToken));
         }
 
         @Override
-        public void removeStartingWindow(int taskId) {
-            mExecutor.execute(() -> TaskOrganizer.this.removeStartingWindow(taskId));
+        public void removeStartingWindow(int taskId, SurfaceControl leash, Rect frame,
+                boolean playRevealAnimation) {
+            mExecutor.execute(() -> TaskOrganizer.this.removeStartingWindow(taskId, leash, frame,
+                    playRevealAnimation));
         }
 
         @Override
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index c1952c7..957e416 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -166,4 +166,15 @@
 
     /** {@hide} */
     boolean setChargingStateUpdateDelayMillis(int delay);
+
+    /** Exposed as a test API. */
+    void setChargerAcOnline(boolean online, boolean forceUpdate);
+    /** Exposed as a test API. */
+    void setBatteryLevel(int level, boolean forceUpdate);
+    /** Exposed as a test API. */
+    void unplugBattery(boolean forceUpdate);
+    /** Exposed as a test API. */
+    void resetBattery(boolean forceUpdate);
+    /** Exposed as a test API. */
+    void suspendBatteryInput();
 }
diff --git a/core/java/com/android/internal/compat/AndroidBuildClassifier.java b/core/java/com/android/internal/compat/AndroidBuildClassifier.java
index 0b937fa..364db06 100644
--- a/core/java/com/android/internal/compat/AndroidBuildClassifier.java
+++ b/core/java/com/android/internal/compat/AndroidBuildClassifier.java
@@ -31,4 +31,14 @@
     public boolean isFinalBuild() {
         return "REL".equals(Build.VERSION.CODENAME);
     }
+
+    /**
+     * The current platform SDK version.
+     */
+    public int platformTargetSdk() {
+        if (isFinalBuild()) {
+            return Build.VERSION.SDK_INT;
+        }
+        return Build.VERSION_CODES.CUR_DEVELOPMENT;
+    }
 }
diff --git a/core/java/com/android/internal/compat/OverrideAllowedState.java b/core/java/com/android/internal/compat/OverrideAllowedState.java
index c0bbe50..e408be2 100644
--- a/core/java/com/android/internal/compat/OverrideAllowedState.java
+++ b/core/java/com/android/internal/compat/OverrideAllowedState.java
@@ -34,7 +34,8 @@
             DISABLED_NON_TARGET_SDK,
             DISABLED_TARGET_SDK_TOO_HIGH,
             DEFERRED_VERIFICATION,
-            LOGGING_ONLY_CHANGE
+            LOGGING_ONLY_CHANGE,
+            PLATFORM_TOO_OLD
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface State {
@@ -65,6 +66,10 @@
      * Change is marked as logging only, and cannot be toggled.
      */
     public static final int LOGGING_ONLY_CHANGE = 5;
+    /**
+     * Change is gated by a target sdk version newer than the current platform sdk version.
+     */
+    public static final int PLATFORM_TOO_OLD = 6;
 
     @State
     public final int state;
@@ -123,6 +128,11 @@
                 throw new SecurityException(String.format(
                         "Cannot override %1$d because it is marked as a logging-only change.",
                         changeId));
+            case PLATFORM_TOO_OLD:
+                throw new SecurityException(String.format(
+                        "Cannot override %1$d for %2$s because the change's targetSdk threshold "
+                                + "(%3$d) is above the platform sdk.",
+                        changeId, packageName, changeIdTargetSdk));
         }
     }
 
@@ -170,6 +180,8 @@
                 return "DEFERRED_VERIFICATION";
             case LOGGING_ONLY_CHANGE:
                 return "LOGGING_ONLY_CHANGE";
+            case PLATFORM_TOO_OLD:
+                return "PLATFORM_TOO_OLD";
         }
         return "UNKNOWN";
     }
diff --git a/core/java/com/android/internal/graphics/palette/WSMeansQuantizer.java b/core/java/com/android/internal/graphics/palette/WSMeansQuantizer.java
index b4f216b..1d865c2 100644
--- a/core/java/com/android/internal/graphics/palette/WSMeansQuantizer.java
+++ b/core/java/com/android/internal/graphics/palette/WSMeansQuantizer.java
@@ -75,7 +75,7 @@
             // Note: they don't _have_ to be ignored, for example, we could instead turn them
             // opaque. Traditionally, including outside Android, quantizers ignore transparent
             // pixels, so that strategy was chosen.
-            int alpha = (pixel >> 24);
+            int alpha = (pixel >> 24) & 0xff;
             if (alpha < 255) {
                 continue;
             }
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 9ecb0ad..11466f4 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -6976,6 +6976,11 @@
         return getPowerBucketConsumptionUC(MeasuredEnergyStats.POWER_BUCKET_SCREEN_DOZE);
     }
 
+    @Override
+    public long getCpuMeasuredBatteryConsumptionUC() {
+        return getPowerBucketConsumptionUC(MeasuredEnergyStats.POWER_BUCKET_CPU);
+    }
+
     /**
      * Returns the consumption (in microcoulombs) that the given standard power bucket consumed.
      * Will return {@link #POWER_DATA_UNAVAILABLE} if data is unavailable
@@ -8482,6 +8487,11 @@
             return getMeasuredBatteryConsumptionUC(MeasuredEnergyStats.POWER_BUCKET_SCREEN_ON);
         }
 
+        @Override
+        public long getCpuMeasuredBatteryConsumptionUC() {
+            return getMeasuredBatteryConsumptionUC(MeasuredEnergyStats.POWER_BUCKET_CPU);
+        }
+
         void initNetworkActivityLocked() {
             detachIfNotNull(mNetworkByteActivityCounters);
             mNetworkByteActivityCounters = new LongSamplingCounter[NUM_NETWORK_ACTIVITY_TYPES];
diff --git a/core/java/com/android/internal/os/CpuPowerCalculator.java b/core/java/com/android/internal/os/CpuPowerCalculator.java
index 97f727b..b15543a 100644
--- a/core/java/com/android/internal/os/CpuPowerCalculator.java
+++ b/core/java/com/android/internal/os/CpuPowerCalculator.java
@@ -85,12 +85,14 @@
                 builder.getUidBatteryConsumerBuilders();
         for (int i = uidBatteryConsumerBuilders.size() - 1; i >= 0; i--) {
             final UidBatteryConsumer.Builder app = uidBatteryConsumerBuilders.valueAt(i);
-            calculateApp(app, app.getBatteryStatsUid(), result);
+            calculateApp(app, app.getBatteryStatsUid(), query, result);
         }
     }
 
-    private void calculateApp(UidBatteryConsumer.Builder app, BatteryStats.Uid u, Result result) {
-        calculatePowerAndDuration(u, BatteryStats.STATS_SINCE_CHARGED, result);
+    private void calculateApp(UidBatteryConsumer.Builder app, BatteryStats.Uid u,
+            BatteryUsageStatsQuery query, Result result) {
+        calculatePowerAndDuration(u, BatteryStats.STATS_SINCE_CHARGED,
+                query.shouldForceUsePowerProfileModel(), result);
 
         app.setConsumedPower(BatteryConsumer.POWER_COMPONENT_CPU, result.powerMah)
                 .setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_CPU, result.durationMs)
@@ -112,7 +114,7 @@
     }
 
     private void calculateApp(BatterySipper app, BatteryStats.Uid u, int statsType, Result result) {
-        calculatePowerAndDuration(u, statsType, result);
+        calculatePowerAndDuration(u, statsType, false, result);
 
         app.cpuPowerMah = result.powerMah;
         app.cpuTimeMs = result.durationMs;
@@ -120,46 +122,16 @@
         app.packageWithHighestDrain = result.packageWithHighestDrain;
     }
 
-    private void calculatePowerAndDuration(BatteryStats.Uid u, int statsType, Result result) {
+    private void calculatePowerAndDuration(BatteryStats.Uid u, int statsType,
+            boolean forceUsePowerProfileModel, Result result) {
         long durationMs = (u.getUserCpuTimeUs(statsType) + u.getSystemCpuTimeUs(statsType)) / 1000;
 
-        // Constant battery drain when CPU is active
-        double powerMah = calculateActiveCpuPowerMah(u.getCpuActiveTime());
-
-        // Additional per-cluster battery drain
-        long[] cpuClusterTimes = u.getCpuClusterTimes();
-        if (cpuClusterTimes != null) {
-            if (cpuClusterTimes.length == mNumCpuClusters) {
-                for (int cluster = 0; cluster < mNumCpuClusters; cluster++) {
-                    double power = calculatePerCpuClusterPowerMah(cluster,
-                            cpuClusterTimes[cluster]);
-                    powerMah += power;
-                    if (DEBUG) {
-                        Log.d(TAG, "UID " + u.getUid() + ": CPU cluster #" + cluster
-                                + " clusterTimeMs=" + cpuClusterTimes[cluster]
-                                + " power=" + formatCharge(power));
-                    }
-                }
-            } else {
-                Log.w(TAG, "UID " + u.getUid() + " CPU cluster # mismatch: Power Profile # "
-                        + mNumCpuClusters + " actual # " + cpuClusterTimes.length);
-            }
-        }
-
-        // Additional per-frequency battery drain
-        for (int cluster = 0; cluster < mNumCpuClusters; cluster++) {
-            final int speedsForCluster = mPerCpuFreqPowerEstimators[cluster].length;
-            for (int speed = 0; speed < speedsForCluster; speed++) {
-                final long timeUs = u.getTimeAtCpuSpeed(cluster, speed, statsType);
-                final double power = calculatePerCpuFreqPowerMah(cluster, speed,
-                        timeUs / 1000);
-                if (DEBUG) {
-                    Log.d(TAG, "UID " + u.getUid() + ": CPU cluster #" + cluster + " step #"
-                            + speed + " timeUs=" + timeUs + " power="
-                            + formatCharge(power));
-                }
-                powerMah += power;
-            }
+        final double powerMah;
+        final long consumptionUC = u.getCpuMeasuredBatteryConsumptionUC();
+        if (forceUsePowerProfileModel || consumptionUC == BatteryStats.POWER_DATA_UNAVAILABLE) {
+            powerMah = calculateUidModeledPowerMah(u, statsType);
+        } else {
+            powerMah = uCtoMah(consumptionUC);
         }
 
         if (DEBUG && (durationMs != 0 || powerMah != 0)) {
@@ -208,6 +180,48 @@
         result.packageWithHighestDrain = packageWithHighestDrain;
     }
 
+    private double calculateUidModeledPowerMah(BatteryStats.Uid u, int statsType) {
+        // Constant battery drain when CPU is active
+        double powerMah = calculateActiveCpuPowerMah(u.getCpuActiveTime());
+
+        // Additional per-cluster battery drain
+        long[] cpuClusterTimes = u.getCpuClusterTimes();
+        if (cpuClusterTimes != null) {
+            if (cpuClusterTimes.length == mNumCpuClusters) {
+                for (int cluster = 0; cluster < mNumCpuClusters; cluster++) {
+                    double power = calculatePerCpuClusterPowerMah(cluster,
+                            cpuClusterTimes[cluster]);
+                    powerMah += power;
+                    if (DEBUG) {
+                        Log.d(TAG, "UID " + u.getUid() + ": CPU cluster #" + cluster
+                                + " clusterTimeMs=" + cpuClusterTimes[cluster]
+                                + " power=" + formatCharge(power));
+                    }
+                }
+            } else {
+                Log.w(TAG, "UID " + u.getUid() + " CPU cluster # mismatch: Power Profile # "
+                        + mNumCpuClusters + " actual # " + cpuClusterTimes.length);
+            }
+        }
+
+        // Additional per-frequency battery drain
+        for (int cluster = 0; cluster < mNumCpuClusters; cluster++) {
+            final int speedsForCluster = mPerCpuFreqPowerEstimators[cluster].length;
+            for (int speed = 0; speed < speedsForCluster; speed++) {
+                final long timeUs = u.getTimeAtCpuSpeed(cluster, speed, statsType);
+                final double power = calculatePerCpuFreqPowerMah(cluster, speed,
+                        timeUs / 1000);
+                if (DEBUG) {
+                    Log.d(TAG, "UID " + u.getUid() + ": CPU cluster #" + cluster + " step #"
+                            + speed + " timeUs=" + timeUs + " power="
+                            + formatCharge(power));
+                }
+                powerMah += power;
+            }
+        }
+        return powerMah;
+    }
+
     /**
      * Calculates active CPU power consumption.
      *
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index 200e0dd..fea0751 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -257,4 +257,12 @@
      * file descriptor passed in.
      */
      void passThroughShellCommand(in String[] args, in ParcelFileDescriptor pfd);
+
+    /**
+     * Enables/disables the navigation bar luma sampling.
+     *
+     * @param displayId the id of the display to notify.
+     * @param enable {@code true} if enable, otherwise set to {@code false}.
+     */
+    void setNavigationBarLumaSamplingEnabled(int displayId, boolean enable);
 }
diff --git a/core/java/com/android/internal/telephony/IPhoneStateListener.aidl b/core/java/com/android/internal/telephony/IPhoneStateListener.aidl
index 85114e5..b57b4b9 100644
--- a/core/java/com/android/internal/telephony/IPhoneStateListener.aidl
+++ b/core/java/com/android/internal/telephony/IPhoneStateListener.aidl
@@ -72,5 +72,5 @@
     void onBarringInfoChanged(in BarringInfo barringInfo);
     void onPhysicalChannelConfigChanged(in List<PhysicalChannelConfig> configs);
     void onDataEnabledChanged(boolean enabled, int reason);
-    void onAllowedNetworkTypesChanged(in Map allowedNetworkTypeList);
+    void onAllowedNetworkTypesChanged(in int reason, in long allowedNetworkType);
 }
diff --git a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index 95e0a3b..83691ee 100644
--- a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -95,5 +95,5 @@
     void notifyPhysicalChannelConfigForSubscriber(in int subId,
             in List<PhysicalChannelConfig> configs);
     void notifyDataEnabled(in int phoneId, int subId, boolean enabled, int reason);
-    void notifyAllowedNetworkTypesChanged(in int phoneId, in int subId, in Map allowedNetworkTypeList);
+    void notifyAllowedNetworkTypesChanged(in int phoneId, in int subId, in int reason, in long allowedNetworkType);
 }
diff --git a/core/java/com/android/internal/view/IInputConnectionWrapper.java b/core/java/com/android/internal/view/IInputConnectionWrapper.java
index 19506a3..d0c807d 100644
--- a/core/java/com/android/internal/view/IInputConnectionWrapper.java
+++ b/core/java/com/android/internal/view/IInputConnectionWrapper.java
@@ -31,8 +31,10 @@
 import android.util.imetracing.InputConnectionHelper;
 import android.util.proto.ProtoOutputStream;
 import android.view.KeyEvent;
+import android.view.View;
 import android.view.inputmethod.CompletionInfo;
 import android.view.inputmethod.CorrectionInfo;
+import android.view.inputmethod.DumpableInputConnection;
 import android.view.inputmethod.ExtractedText;
 import android.view.inputmethod.ExtractedTextRequest;
 import android.view.inputmethod.InputConnection;
@@ -49,7 +51,9 @@
 import com.android.internal.inputmethod.ISurroundingTextResultCallback;
 import com.android.internal.os.SomeArgs;
 
-public abstract class IInputConnectionWrapper extends IInputContext.Stub {
+import java.lang.ref.WeakReference;
+
+public final class IInputConnectionWrapper extends IInputContext.Stub {
     private static final String TAG = "IInputConnectionWrapper";
     private static final boolean DEBUG = false;
 
@@ -90,10 +94,13 @@
     private Looper mMainLooper;
     private Handler mH;
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    private Object mLock = new Object();
+    private final Object mLock = new Object();
     @GuardedBy("mLock")
     private boolean mFinished = false;
 
+    private final InputMethodManager mParentInputMethodManager;
+    private final WeakReference<View> mServedView;
+
     class MyHandler extends Handler {
         MyHandler(Looper looper) {
             super(looper);
@@ -104,11 +111,15 @@
             executeMessage(msg);
         }
     }
-    
-    public IInputConnectionWrapper(Looper mainLooper, @NonNull InputConnection inputConnection) {
+
+    public IInputConnectionWrapper(@NonNull Looper mainLooper,
+            @NonNull InputConnection inputConnection,
+            @NonNull InputMethodManager inputMethodManager, @Nullable View servedView) {
         mInputConnection = inputConnection;
         mMainLooper = mainLooper;
         mH = new MyHandler(mMainLooper);
+        mParentInputMethodManager = inputMethodManager;
+        mServedView = new WeakReference<>(servedView);
     }
 
     @Nullable
@@ -118,21 +129,70 @@
         }
     }
 
-    protected Looper getLooper() {
-        synchronized (mMainLooper) {
-            return mMainLooper;
-        }
-    }
-
-    protected boolean isFinished() {
+    private boolean isFinished() {
         synchronized (mLock) {
             return mFinished;
         }
     }
 
-    protected abstract boolean isActive();
+    public boolean isActive() {
+        return mParentInputMethodManager.isActive() && !isFinished();
+    }
 
-    protected abstract InputMethodManager getIMM();
+    public View getServedView() {
+        return mServedView.get();
+    }
+
+    public void deactivate() {
+        if (isFinished()) {
+            // This is a small performance optimization.  Still only the 1st call of
+            // reportFinish() will take effect.
+            return;
+        }
+        closeConnection();
+
+        // Notify the app that the InputConnection was closed.
+        final View servedView = mServedView.get();
+        if (servedView != null) {
+            final Handler handler = servedView.getHandler();
+            // The handler is null if the view is already detached. When that's the case, for
+            // now, we simply don't dispatch this callback.
+            if (handler != null) {
+                if (DEBUG) {
+                    Log.v(TAG, "Calling View.onInputConnectionClosed: view=" + servedView);
+                }
+                if (handler.getLooper().isCurrentThread()) {
+                    servedView.onInputConnectionClosedInternal();
+                } else {
+                    handler.post(servedView::onInputConnectionClosedInternal);
+                }
+            }
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "IInputConnectionWrapper{"
+                + "connection=" + getInputConnection()
+                + " finished=" + isFinished()
+                + " mParentInputMethodManager.isActive()=" + mParentInputMethodManager.isActive()
+                + " mServedView=" + mServedView.get()
+                + "}";
+    }
+
+    public void dumpDebug(ProtoOutputStream proto, long fieldId) {
+        synchronized (mLock) {
+            // Check that the call is initiated in the main thread of the current InputConnection
+            // {@link InputConnection#getHandler} since the messages to IInputConnectionWrapper are
+            // executed on this thread. Otherwise the messages are dispatched to the correct thread
+            // in IInputConnectionWrapper, but this is not wanted while dumpng, for performance
+            // reasons.
+            if ((mInputConnection instanceof DumpableInputConnection)
+                    && Looper.myLooper() == mMainLooper) {
+                ((DumpableInputConnection) mInputConnection).dumpDebug(proto, fieldId);
+            }
+        }
+    }
 
     public void getTextAfterCursor(int length, int flags, ICharSequenceResultCallback callback) {
         dispatchMessage(mH.obtainMessage(DO_GET_TEXT_AFTER_CURSOR, length, flags, callback));
@@ -161,6 +221,10 @@
         dispatchMessage(mH.obtainMessage(DO_GET_SURROUNDING_TEXT, flags, 0 /* unused */, args));
     }
 
+    public void setImeTemporarilyConsumesInput(boolean imeTemporarilyConsumesInput) {
+         // no-op
+    }
+
     public void getCursorCapsMode(int reqModes, IIntResultCallback callback) {
         dispatchMessage(
                 mH.obtainMessage(DO_GET_CURSOR_CAPS_MODE, reqModes, 0 /* unused */, callback));
@@ -309,7 +373,7 @@
                         icProto = InputConnectionHelper.buildGetTextAfterCursorProto(msg.arg1,
                                 msg.arg2, result);
                         ImeTracing.getInstance().triggerClientDump(
-                                TAG + "#getTextAfterCursor", getIMM(), icProto);
+                                TAG + "#getTextAfterCursor", mParentInputMethodManager, icProto);
                     }
                     try {
                         callback.onResult(result);
@@ -339,7 +403,7 @@
                         icProto = InputConnectionHelper.buildGetTextBeforeCursorProto(msg.arg1,
                                 msg.arg2, result);
                         ImeTracing.getInstance().triggerClientDump(
-                                TAG + "#getTextBeforeCursor", getIMM(), icProto);
+                                TAG + "#getTextBeforeCursor", mParentInputMethodManager, icProto);
                     }
                     try {
                         callback.onResult(result);
@@ -368,7 +432,7 @@
                     if (ImeTracing.getInstance().isEnabled()) {
                         icProto = InputConnectionHelper.buildGetSelectedTextProto(msg.arg1, result);
                         ImeTracing.getInstance().triggerClientDump(
-                                TAG + "#getSelectedText", getIMM(), icProto);
+                                TAG + "#getSelectedText", mParentInputMethodManager, icProto);
                     }
                     try {
                         callback.onResult(result);
@@ -402,7 +466,7 @@
                         icProto = InputConnectionHelper.buildGetSurroundingTextProto(beforeLength,
                                 afterLength, flags, result);
                         ImeTracing.getInstance().triggerClientDump(
-                                TAG + "#getSurroundingText", getIMM(), icProto);
+                                TAG + "#getSurroundingText", mParentInputMethodManager, icProto);
                     }
                     try {
                         callback.onResult(result);
@@ -432,7 +496,7 @@
                         icProto = InputConnectionHelper.buildGetCursorCapsModeProto(msg.arg1,
                                 result);
                         ImeTracing.getInstance().triggerClientDump(
-                                TAG + "#getCursorCapsMode", getIMM(), icProto);
+                                TAG + "#getCursorCapsMode", mParentInputMethodManager, icProto);
                     }
                     try {
                         callback.onResult(result);
@@ -464,7 +528,7 @@
                         icProto = InputConnectionHelper.buildGetExtractedTextProto(request,
                                 msg.arg1, result);
                         ImeTracing.getInstance().triggerClientDump(
-                                TAG + "#getExtractedText", getIMM(), icProto);
+                                TAG + "#getExtractedText", mParentInputMethodManager, icProto);
                     }
                     try {
                         callback.onResult(result);
diff --git a/core/java/com/android/internal/view/IInputMethod.aidl b/core/java/com/android/internal/view/IInputMethod.aidl
index 8d82e33..c336373 100644
--- a/core/java/com/android/internal/view/IInputMethod.aidl
+++ b/core/java/com/android/internal/view/IInputMethod.aidl
@@ -35,8 +35,7 @@
  * {@hide}
  */
 oneway interface IInputMethod {
-    void initializeInternal(IBinder token, int displayId, IInputMethodPrivilegedOperations privOps,
-             int configChanges);
+    void initializeInternal(IBinder token, int displayId, IInputMethodPrivilegedOperations privOps);
 
     void onCreateInlineSuggestionsRequest(in InlineSuggestionsRequestInfo requestInfo,
             in IInlineSuggestionsRequestCallback cb);
diff --git a/core/java/com/android/internal/view/InputBindResult.java b/core/java/com/android/internal/view/InputBindResult.java
index f29e95c..c9755a3 100644
--- a/core/java/com/android/internal/view/InputBindResult.java
+++ b/core/java/com/android/internal/view/InputBindResult.java
@@ -204,6 +204,8 @@
     @Nullable
     private final float[] mActivityViewToScreenMatrixValues;
 
+    public final boolean isInputMethodSuppressingSpellChecker;
+
     /**
      * @return {@link Matrix} that corresponds to {@link #mActivityViewToScreenMatrixValues}.
      *         {@code null} if {@link #mActivityViewToScreenMatrixValues} is {@code null}.
@@ -220,7 +222,8 @@
 
     public InputBindResult(@ResultCode int _result,
             IInputMethodSession _method, InputChannel _channel, String _id, int _sequence,
-            @Nullable Matrix activityViewToScreenMatrix) {
+            @Nullable Matrix activityViewToScreenMatrix,
+            boolean isInputMethodSuppressingSpellChecker) {
         result = _result;
         method = _method;
         channel = _channel;
@@ -232,6 +235,7 @@
             mActivityViewToScreenMatrixValues = new float[9];
             activityViewToScreenMatrix.getValues(mActivityViewToScreenMatrixValues);
         }
+        this.isInputMethodSuppressingSpellChecker = isInputMethodSuppressingSpellChecker;
     }
 
     InputBindResult(Parcel source) {
@@ -245,6 +249,7 @@
         id = source.readString();
         sequence = source.readInt();
         mActivityViewToScreenMatrixValues = source.createFloatArray();
+        isInputMethodSuppressingSpellChecker = source.readBoolean();
     }
 
     @Override
@@ -252,6 +257,7 @@
         return "InputBindResult{result=" + getResultString() + " method="+ method + " id=" + id
                 + " sequence=" + sequence
                 + " activityViewToScreenMatrix=" + getActivityViewToScreenMatrix()
+                + " isInputMethodSuppressingSpellChecker=" + isInputMethodSuppressingSpellChecker
                 + "}";
     }
 
@@ -274,6 +280,7 @@
         dest.writeString(id);
         dest.writeInt(sequence);
         dest.writeFloatArray(mActivityViewToScreenMatrixValues);
+        dest.writeBoolean(isInputMethodSuppressingSpellChecker);
     }
 
     /**
@@ -340,7 +347,7 @@
     }
 
     private static InputBindResult error(@ResultCode int result) {
-        return new InputBindResult(result, null, null, null, -1, null);
+        return new InputBindResult(result, null, null, null, -1, null, false);
     }
 
     /**
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 3bc0ef4e..94ac183 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -637,6 +637,12 @@
     char saveResolvedClassesDelayMsOptsBuf[
             sizeof("-Xps-save-resolved-classes-delay-ms:")-1 + PROPERTY_VALUE_MAX];
     char madviseRandomOptsBuf[sizeof("-XX:MadviseRandomAccess:")-1 + PROPERTY_VALUE_MAX];
+    char madviseWillNeedFileSizeVdex[
+            sizeof("-XMadviseWillNeedVdexFileSize:")-1 + PROPERTY_VALUE_MAX];
+    char madviseWillNeedFileSizeOdex[
+            sizeof("-XMadviseWillNeedOdexFileSize:")-1 + PROPERTY_VALUE_MAX];
+    char madviseWillNeedFileSizeArt[
+            sizeof("-XMadviseWillNeedArtFileSize:")-1 + PROPERTY_VALUE_MAX];
     char gctypeOptsBuf[sizeof("-Xgc:")-1 + PROPERTY_VALUE_MAX];
     char backgroundgcOptsBuf[sizeof("-XX:BackgroundGC=")-1 + PROPERTY_VALUE_MAX];
     char heaptargetutilizationOptsBuf[sizeof("-XX:HeapTargetUtilization=")-1 + PROPERTY_VALUE_MAX];
@@ -845,6 +851,22 @@
     parseRuntimeOption("dalvik.vm.madvise-random", madviseRandomOptsBuf, "-XX:MadviseRandomAccess:");
 
     /*
+     * Use default platform configuration as limits for madvising,
+     * when no properties are specified.
+     */
+    parseRuntimeOption("dalvik.vm.madvise.vdexfile.size",
+                       madviseWillNeedFileSizeVdex,
+                       "-XMadviseWillNeedVdexFileSize:");
+
+    parseRuntimeOption("dalvik.vm.madvise.odexfile.size",
+                       madviseWillNeedFileSizeOdex,
+                       "-XMadviseWillNeedOdexFileSize:");
+
+    parseRuntimeOption("dalvik.vm.madvise.artfile.size",
+                       madviseWillNeedFileSizeArt,
+                       "-XMadviseWillNeedArtFileSize:");
+
+    /*
      * Profile related options.
      */
     parseRuntimeOption("dalvik.vm.hot-startup-method-samples", hotstartupsamplesOptsBuf,
diff --git a/core/jni/android_os_incremental_IncrementalManager.cpp b/core/jni/android_os_incremental_IncrementalManager.cpp
index 2384efa..413bcef 100644
--- a/core/jni/android_os_incremental_IncrementalManager.cpp
+++ b/core/jni/android_os_incremental_IncrementalManager.cpp
@@ -41,6 +41,10 @@
     return (jboolean)IncFs_IsIncFsPath(path.c_str());
 }
 
+static jboolean nativeIsIncrementalFd(JNIEnv* env, jobject clazz, jint fd) {
+    return (jboolean)IncFs_IsIncFsFd(fd);
+}
+
 static jbyteArray nativeUnsafeGetFileSignature(JNIEnv* env, jobject clazz, jstring javaPath) {
     ScopedUtfChars path(env, javaPath);
 
@@ -61,6 +65,7 @@
         {{"nativeIsEnabled", "()Z", (void*)nativeIsEnabled},
          {"nativeIsV2Available", "()Z", (void*)nativeIsV2Available},
          {"nativeIsIncrementalPath", "(Ljava/lang/String;)Z", (void*)nativeIsIncrementalPath},
+         {"nativeIsIncrementalFd", "(I)Z", (void*)nativeIsIncrementalFd},
          {"nativeUnsafeGetFileSignature", "(Ljava/lang/String;)[B",
           (void*)nativeUnsafeGetFileSignature}};
 
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index f7b3f30..2e4be14 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -1509,7 +1509,9 @@
             res = JNI_TRUE;
         } else {
             jniThrowException(env, "java/util/NoSuchElementException",
-                              "Death link does not exist");
+                              base::StringPrintf("Death link does not exist (%s)",
+                                                 statusToString(err).c_str())
+                                      .c_str());
         }
     }
 
diff --git a/core/jni/android_view_InputEventSender.cpp b/core/jni/android_view_InputEventSender.cpp
index 96326f5..97fdb43 100644
--- a/core/jni/android_view_InputEventSender.cpp
+++ b/core/jni/android_view_InputEventSender.cpp
@@ -237,8 +237,7 @@
 
             env->CallVoidMethod(senderObj.get(),
                                 gInputEventSenderClassInfo.dispatchInputEventFinished,
-                                static_cast<jint>(result->seq),
-                                static_cast<jboolean>(result->handled));
+                                static_cast<jint>(seq), static_cast<jboolean>(result->handled));
             if (env->ExceptionCheck()) {
                 ALOGE("Exception dispatching finished signal.");
                 skipCallbacks = true;
diff --git a/core/jni/android_view_KeyCharacterMap.cpp b/core/jni/android_view_KeyCharacterMap.cpp
index ebc507a..469e577 100644
--- a/core/jni/android_view_KeyCharacterMap.cpp
+++ b/core/jni/android_view_KeyCharacterMap.cpp
@@ -16,9 +16,10 @@
 
 #include <android_runtime/AndroidRuntime.h>
 
-#include <input/KeyCharacterMap.h>
-#include <input/Input.h>
 #include <binder/Parcel.h>
+#include <input/Input.h>
+#include <input/InputDevice.h>
+#include <input/KeyCharacterMap.h>
 
 #include <jni.h>
 #include <nativehelper/JNIHelp.h>
@@ -75,6 +76,10 @@
                           reinterpret_cast<jlong>(nativeMap));
 }
 
+static jobject nativeObtainEmptyKeyCharacterMap(JNIEnv* env, jobject /* clazz */, jint deviceId) {
+    return android_view_KeyCharacterMap_create(env, deviceId, nullptr);
+}
+
 static jlong nativeReadFromParcel(JNIEnv *env, jobject clazz, jobject parcelObj) {
     Parcel* parcel = parcelForJavaObject(env, parcelObj);
     if (!parcel) {
@@ -224,33 +229,37 @@
     return result;
 }
 
+static jboolean nativeEquals(JNIEnv* env, jobject clazz, jlong ptr1, jlong ptr2) {
+    const std::shared_ptr<KeyCharacterMap>& map1 =
+            (reinterpret_cast<NativeKeyCharacterMap*>(ptr1))->getMap();
+    const std::shared_ptr<KeyCharacterMap>& map2 =
+            (reinterpret_cast<NativeKeyCharacterMap*>(ptr2))->getMap();
+    if (map1 == nullptr || map2 == nullptr) {
+        return map1 == map2;
+    }
+    return static_cast<jboolean>(*map1 == *map2);
+}
 
 /*
  * JNI registration.
  */
 
 static const JNINativeMethod g_methods[] = {
-    /* name, signature, funcPtr */
-    { "nativeReadFromParcel", "(Landroid/os/Parcel;)J",
-            (void*)nativeReadFromParcel },
-    { "nativeWriteToParcel", "(JLandroid/os/Parcel;)V",
-            (void*)nativeWriteToParcel },
-    { "nativeDispose", "(J)V",
-            (void*)nativeDispose },
-    { "nativeGetCharacter", "(JII)C",
-            (void*)nativeGetCharacter },
-    { "nativeGetFallbackAction", "(JIILandroid/view/KeyCharacterMap$FallbackAction;)Z",
-            (void*)nativeGetFallbackAction },
-    { "nativeGetNumber", "(JI)C",
-            (void*)nativeGetNumber },
-    { "nativeGetMatch", "(JI[CI)C",
-            (void*)nativeGetMatch },
-    { "nativeGetDisplayLabel", "(JI)C",
-            (void*)nativeGetDisplayLabel },
-    { "nativeGetKeyboardType", "(J)I",
-            (void*)nativeGetKeyboardType },
-    { "nativeGetEvents", "(J[C)[Landroid/view/KeyEvent;",
-            (void*)nativeGetEvents },
+        /* name, signature, funcPtr */
+        {"nativeReadFromParcel", "(Landroid/os/Parcel;)J", (void*)nativeReadFromParcel},
+        {"nativeWriteToParcel", "(JLandroid/os/Parcel;)V", (void*)nativeWriteToParcel},
+        {"nativeDispose", "(J)V", (void*)nativeDispose},
+        {"nativeGetCharacter", "(JII)C", (void*)nativeGetCharacter},
+        {"nativeGetFallbackAction", "(JIILandroid/view/KeyCharacterMap$FallbackAction;)Z",
+         (void*)nativeGetFallbackAction},
+        {"nativeGetNumber", "(JI)C", (void*)nativeGetNumber},
+        {"nativeGetMatch", "(JI[CI)C", (void*)nativeGetMatch},
+        {"nativeGetDisplayLabel", "(JI)C", (void*)nativeGetDisplayLabel},
+        {"nativeGetKeyboardType", "(J)I", (void*)nativeGetKeyboardType},
+        {"nativeGetEvents", "(J[C)[Landroid/view/KeyEvent;", (void*)nativeGetEvents},
+        {"nativeObtainEmptyKeyCharacterMap", "(I)Landroid/view/KeyCharacterMap;",
+         (void*)nativeObtainEmptyKeyCharacterMap},
+        {"nativeEquals", "(JJ)Z", (void*)nativeEquals},
 };
 
 int register_android_view_KeyCharacterMap(JNIEnv* env)
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index cf96fe6..0bed29b 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -193,7 +193,7 @@
  * If it exceeds 2s, PROC_START_TIMEOUT_MSG will kill the starting app anyway,
  * so it's fine to assume max retries is 5 mins.
  */
-static constexpr int STORAGE_DIR_CHECK_TIMEOUT_US = 1000 * 60 * 5;
+static constexpr int STORAGE_DIR_CHECK_TIMEOUT_US = 1000 * 1000 * 60 * 5;
 
 /**
  * A helper class containing accounting information for USAPs.
diff --git a/core/proto/OWNERS b/core/proto/OWNERS
index e62b5c1..ea5e7f72 100644
--- a/core/proto/OWNERS
+++ b/core/proto/OWNERS
@@ -14,9 +14,10 @@
 # Frameworks
 ogunwale@google.com
 jjaggi@google.com
+kwekua@google.com
 roosa@google.com
 per-file package_item_info.proto = toddke@google.com
-per-file usagestatsservice.proto, usagestatsservice_v2.proto = mwachens@google.com
+per-file usagestatsservice.proto, usagestatsservice_v2.proto = file:/core/java/android/app/usage/OWNERS
 per-file apphibernationservice.proto = file:/core/java/android/apphibernation/OWNERS
 
 # Biometrics
diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto
index f26bf7c..a7127ad 100644
--- a/core/proto/android/server/windowmanagerservice.proto
+++ b/core/proto/android/server/windowmanagerservice.proto
@@ -346,6 +346,7 @@
     optional int32 proc_id = 29;
     optional bool translucent = 30;
     optional bool pip_auto_enter_enabled = 31;
+    optional bool in_size_compat_mode = 32;
 }
 
 /* represents WindowToken */
@@ -406,7 +407,7 @@
     optional int64 finished_seamless_rotation_frame = 40;
     optional WindowFramesProto window_frames = 41;
     optional bool force_seamless_rotation = 42;
-    optional bool in_size_compat_mode = 43;
+    optional bool has_compat_scale = 43;
     optional float global_scale = 44;
 }
 
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 99ad6d1..f9227617 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -5419,6 +5419,8 @@
          intents}.
          <p>Protection level: normal -->
     <permission android:name="android.permission.USE_FULL_SCREEN_INTENT"
+                android:label="@string/permlab_fullScreenIntent"
+                android:description="@string/permdesc_fullScreenIntent"
                 android:protectionLevel="normal" />
 
     <!-- @SystemApi Allows requesting the framework broadcast the
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 7c446a9..62278d5 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3564,16 +3564,7 @@
         <attr name="__removed2" format="boolean" />
         <!-- Specifies whether the IME supports showing inline suggestions. -->
         <attr name="supportsInlineSuggestions" format="boolean" />
-        <!-- Specify one or more configuration changes that the IME will handle itself. If not
-             specified, the IME will be restarted if any of these configuration changes happen in
-              the system.  Otherwise, the IME will remain running and its
-             {@link android.inputmethodservice.InputMethodService#onConfigurationChanged}
-             method is called with the new configuration.
-             <p>Note that all of these configuration changes can impact the
-             resource values seen by the application, so you will generally need
-             to re-retrieve all resources (including view layouts, drawables, etc)
-             to correctly handle any configuration change.-->
-        <attr name="configChanges" />
+        <attr name="suppressesSpellChecker" format="boolean" />
     </declare-styleable>
 
     <!-- This is the subtype of InputMethod. Subtype can describe locales (for example, en_US and
@@ -8173,7 +8164,7 @@
             <flag name="hide_from_picker" value="0x2" />
               <!-- The widget provides a default configuration. The host may decide not to launch
                    the provided configuration activity. -->
-           <flag name="configuration_optional" value="0x3" />
+           <flag name="configuration_optional" value="0x4" />
         </attr>
         <!-- A resource identifier for a string containing a short description of the widget. -->
         <attr name="description" />
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index cc52655ad7..601d66e 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -829,7 +829,6 @@
             {@code FLAG_ACTIVITY_MULTIPLE_TASK} is set.-->
         <enum name="singleInstancePerTask" value="4" />
     </attr>
-
     <!-- Specify the orientation an activity should be run in.  If not
          specified, it will run in the current preferred orientation
          of the screen.
@@ -1603,6 +1602,12 @@
        <enum name="sync" value="2" />
     </attr>
 
+    <!-- Attribution tag to be used for permission sub-attribution if a
+      permission is checked in  {@link android.content.Context#sendBroadcast(Intent, String)}.
+      Multiple tags can be specified separated by '|'.
+    -->
+    <attr name="attributionTags" format="string" />
+
     <!-- The <code>manifest</code> tag is the root of an
          <code>AndroidManifest.xml</code> file,
          describing the contents of an Android package (.apk) file.  One
@@ -2825,6 +2830,10 @@
 
              <p> See {@link android.content.pm.ActivityInfo#FLAG_PREFER_MINIMAL_POST_PROCESSING} -->
         <attr name="preferMinimalPostProcessing" format="boolean"/>
+        <!-- Specify the attributionTags to be used if a permission is required due to
+            {@link android.content.Context#sendBroadcast(Intent, String)} being used.
+            Multiple tags can be specified separated by '|'. -->
+        <attr name="attributionTags"/>
     </declare-styleable>
 
     <!-- The <code>activity-alias</code> tag declares a new
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index a3d0ab5..f6fee88 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -4722,4 +4722,97 @@
 
     <!-- Whether to allow the caching of the SIM PIN for verification after unattended reboot -->
     <bool name="config_allow_pin_storage_for_unattended_reboot">true</bool>
+
+    <!-- CEC Configuration -->
+    <bool name="config_cecHdmiCecEnabled_userConfigurable">true</bool>
+    <bool name="config_cecHdmiCecControlEnabled_allowed">true</bool>
+    <bool name="config_cecHdmiCecControlEnabled_default">true</bool>
+    <bool name="config_cecHdmiCecControlDisabled_allowed">true</bool>
+    <bool name="config_cecHdmiCecControlDisabled_default">false</bool>
+
+    <bool name="config_cecHdmiCecVersion_userConfigurable">true</bool>
+    <bool name="config_cecHdmiCecVersion14b_allowed">true</bool>
+    <bool name="config_cecHdmiCecVersion14b_default">true</bool>
+    <bool name="config_cecHdmiCecVersion20_allowed">true</bool>
+    <bool name="config_cecHdmiCecVersion20_default">false</bool>
+
+    <bool name="config_cecSendStandbyOnSleep_userConfigurable">true</bool>
+    <bool name="config_cecPowerControlModeTv_allowed">true</bool>
+    <bool name="config_cecPowerControlModeTv_default">true</bool>
+    <bool name="config_cecPowerControlModeBroadcast_allowed">true</bool>
+    <bool name="config_cecPowerControlModeBroadcast_default">false</bool>
+    <bool name="config_cecPowerControlModeNone_allowed">true</bool>
+    <bool name="config_cecPowerControlModeNone_default">false</bool>
+
+    <bool name="config_cecPowerStateChangeOnActiveSourceLost_userConfigurable">true</bool>
+    <bool name="config_cecPowerStateChangeOnActiveSourceLostNone_allowed">true</bool>
+    <bool name="config_cecPowerStateChangeOnActiveSourceLostNone_default">true</bool>
+    <bool name="config_cecPowerStateChangeOnActiveSourceLostStandbyNow_allowed">true</bool>
+    <bool name="config_cecPowerStateChangeOnActiveSourceLostStandbyNow_default">false</bool>
+
+    <bool name="config_cecSystemAudioModeMuting_userConfigurable">true</bool>
+    <bool name="config_cecSystemAudioModeMutingEnabled_allowed">true</bool>
+    <bool name="config_cecSystemAudioModeMutingEnabled_default">true</bool>
+    <bool name="config_cecSystemAudioModeMutingDisabled_allowed">true</bool>
+    <bool name="config_cecSystemAudioModeMutingDisabled_default">false</bool>
+
+    <bool name="config_cecVolumeControlMode_userConfigurable">true</bool>
+    <bool name="config_cecVolumeControlModeEnabled_allowed">true</bool>
+    <bool name="config_cecVolumeControlModeEnabled_default">true</bool>
+    <bool name="config_cecVolumeControlModeDisabled_allowed">true</bool>
+    <bool name="config_cecVolumeControlModeDisabled_default">false</bool>
+
+    <bool name="config_cecTvWakeOnOneTouchPlay_userConfigurable">true</bool>
+    <bool name="config_cecTvWakeOnOneTouchPlayEnabled_allowed">true</bool>
+    <bool name="config_cecTvWakeOnOneTouchPlayEnabled_default">true</bool>
+    <bool name="config_cecTvWakeOnOneTouchPlayDisabled_allowed">true</bool>
+    <bool name="config_cecTvWakeOnOneTouchPlayDisabled_default">false</bool>
+
+    <bool name="config_cecTvSendStandbyOnSleep_userConfigurable">true</bool>
+    <bool name="config_cecTvSendStandbyOnSleepEnabled_allowed">true</bool>
+    <bool name="config_cecTvSendStandbyOnSleepEnabled_default">true</bool>
+    <bool name="config_cecTvSendStandbyOnSleepDisabled_allowed">true</bool>
+    <bool name="config_cecTvSendStandbyOnSleepDisabled_default">false</bool>
+
+    <bool name="config_cecRcProfileTv_userConfigurable">true</bool>
+    <bool name="config_cecRcProfileTvNone_allowed">true</bool>
+    <bool name="config_cecRcProfileTvNone_default">true</bool>
+    <bool name="config_cecRcProfileTvOne_allowed">true</bool>
+    <bool name="config_cecRcProfileTvOne_default">false</bool>
+    <bool name="config_cecRcProfileTvTwo_allowed">true</bool>
+    <bool name="config_cecRcProfileTvTwo_default">false</bool>
+    <bool name="config_cecRcProfileTvThree_allowed">true</bool>
+    <bool name="config_cecRcProfileTvThree_default">false</bool>
+    <bool name="config_cecRcProfileTvFour_allowed">true</bool>
+    <bool name="config_cecRcProfileTvFour_default">false</bool>
+
+    <bool name="config_cecRcProfileSourceRootMenu_userConfigurable">true</bool>
+    <bool name="config_cecRcProfileSourceRootMenuHandled_allowed">true</bool>
+    <bool name="config_cecRcProfileSourceRootMenuHandled_default">true</bool>
+    <bool name="config_cecRcProfileSourceRootMenuNotHandled_allowed">true</bool>
+    <bool name="config_cecRcProfileSourceRootMenuNotHandled_default">false</bool>
+
+    <bool name="config_cecRcProfileSourceSetupMenu_userConfigurable">true</bool>
+    <bool name="config_cecRcProfileSourceSetupMenuHandled_allowed">true</bool>
+    <bool name="config_cecRcProfileSourceSetupMenuHandled_default">true</bool>
+    <bool name="config_cecRcProfileSourceSetupMenuNotHandled_allowed">true</bool>
+    <bool name="config_cecRcProfileSourceSetupMenuNotHandled_default">false</bool>
+
+    <bool name="config_cecRcProfileSourceContentsMenu_userConfigurable">true</bool>
+    <bool name="config_cecRcProfileSourceContentsMenuHandled_allowed">true</bool>
+    <bool name="config_cecRcProfileSourceContentsMenuHandled_default">false</bool>
+    <bool name="config_cecRcProfileSourceContentsMenuNotHandled_allowed">true</bool>
+    <bool name="config_cecRcProfileSourceContentsMenuNotHandled_default">true</bool>
+
+    <bool name="config_cecRcProfileSourceTopMenu_userConfigurable">true</bool>
+    <bool name="config_cecRcProfileSourceTopMenuHandled_allowed">true</bool>
+    <bool name="config_cecRcProfileSourceTopMenuHandled_default">false</bool>
+    <bool name="config_cecRcProfileSourceTopMenuNotHandled_allowed">true</bool>
+    <bool name="config_cecRcProfileSourceTopMenuNotHandled_default">true</bool>
+
+    <bool name="config_cecRcProfileSourceMediaContextSensitiveMenu_userConfigurable">true</bool>
+    <bool name="config_cecRcProfileSourceMediaContextSensitiveMenuHandled_allowed">true</bool>
+    <bool name="config_cecRcProfileSourceMediaContextSensitiveMenuHandled_default">false</bool>
+    <bool name="config_cecRcProfileSourceMediaContextSensitiveMenuNotHandled_allowed">true</bool>
+    <bool name="config_cecRcProfileSourceMediaContextSensitiveMenuNotHandled_default">true</bool>
 </resources>
diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml
index 3a41d5f..7bc4663 100644
--- a/core/res/res/values/ids.xml
+++ b/core/res/res/values/ids.xml
@@ -247,4 +247,10 @@
 
   <!-- Accessibility action identifier for {@link android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction#ACTION_IME_ENTER}. -->
   <item type="id" name="accessibilityActionImeEnter" />
+
+  <!-- View tag for remote views to store the index of the next child when adding nested remote views dynamically. -->
+  <item type="id" name="remote_views_next_child" />
+
+  <!-- View tag associating a view with its stable id for potential recycling. -->
+  <item type="id" name = "remote_views_stable_id" />
 </resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index e0a728c..0979ab55 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3087,6 +3087,8 @@
     <public name="passwordsActivity"/>
     <public name="selectableAsDefault"/>
     <public name="isAccessibilityTool"/>
+    <public name="attributionTags"/>
+    <public name="suppressesSpellChecker" />
   </public-group>
 
   <public-group type="drawable" first-id="0x010800b5">
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 4af561b..930bb87 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -889,6 +889,11 @@
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_expandStatusBar">Allows the app to expand or collapse the status bar.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permlab_fullScreenIntent">display notifications as full screen activities on a locked device</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_fullScreenIntent">Allows the app to display notifications as full screen activities on a locked device</string>
+
     <!-- Title of an application permission, listed so the user can install application shortcuts
     in their Launcher -->
     <string name="permlab_install_shortcut">install shortcuts</string>
@@ -3691,6 +3696,8 @@
     <string name="ext_media_checking_notification_title">Checking <xliff:g id="name" example="SD card">%s</xliff:g>\u2026</string>
     <!-- Notification body when external media is being checked [CHAR LIMIT=NONE] -->
     <string name="ext_media_checking_notification_message">Reviewing current content</string>
+    <!-- TV specific notification body when external media is being checked [CHAR LIMIT=75] -->
+    <string name="ext_media_checking_notification_message" product="tv">Analyzing media storage</string>
 
     <!-- Notification body when new external media is detected [CHAR LIMIT=30] -->
     <string name="ext_media_new_notification_title">New <xliff:g id="name" example="SD card">%s</xliff:g></string>
@@ -3698,11 +3705,15 @@
     <string name="ext_media_new_notification_title" product="automotive"><xliff:g id="name" example="SD card">%s</xliff:g> isn\u2019t working</string>
     <!-- Notification body when new external media is detected [CHAR LIMIT=NONE] -->
     <string name="ext_media_new_notification_message">Tap to set up</string>
+    <!-- TV specific notification body when new external media is detected [CHAR LIMIT=75] -->
+    <string name="ext_media_new_notification_message" product="tv">Select to set up</string>
     <!-- Automotive specific notification body when new external media is detected. [CHAR LIMIT=NONE] -->
     <string name="ext_media_new_notification_message" product="automotive">You may need to reformat the device. Tap to eject.</string>
 
     <!-- Notification body when external media is ready for use [CHAR LIMIT=NONE] -->
     <string name="ext_media_ready_notification_message">For transferring photos and media</string>
+    <!-- TV specific notification body when external media is ready for use [CHAR LIMIT=75] -->
+    <string name="ext_media_ready_notification_message" product="tv">Browse media files</string>
 
     <!-- Notification title when external media is unmountable (corrupt) [CHAR LIMIT=30] -->
     <string name="ext_media_unmountable_notification_title">Issue with <xliff:g id="name" example="SD card">%s</xliff:g></string>
@@ -3721,8 +3732,8 @@
     <string name="ext_media_unsupported_notification_title" product="automotive"><xliff:g id="name" example="SD card">%s</xliff:g> isn\u2019t working</string>
     <!-- Notification body when external media is unsupported [CHAR LIMIT=NONE] -->
     <string name="ext_media_unsupported_notification_message">This device doesn\u2019t support this <xliff:g id="name" example="SD card">%s</xliff:g>. Tap to set up in a supported format.</string>
-    <!-- TV-specific notification body when external media is unsupported [CHAR LIMIT=NONE] -->
-    <string name="ext_media_unsupported_notification_message" product="tv">This device doesn\u2019t support this <xliff:g id="name" example="SD card">%s</xliff:g>. Select to set up in a supported format.</string>
+    <!-- TV-specific notification body when external media is unsupported [CHAR LIMIT=75] -->
+    <string name="ext_media_unsupported_notification_message" product="tv">Select to set up <xliff:g id="name" example="SD card">%s</xliff:g> in a supported format.</string>
     <!-- Automotive specific notification body when external media is unsupported [CHAR LIMIT=NONE] -->
     <string name="ext_media_unsupported_notification_message" product="automotive">You may need to reformat the device</string>
 
@@ -5873,9 +5884,9 @@
     <!-- Window magnification prompt related string. -->
 
     <!-- Notification title to prompt the user that new magnification feature is available. [CHAR LIMIT=50] -->
-    <string name="window_magnification_prompt_title">New: Window Magnifier</string>
-    <!-- Notification content to prompt the user that new magnification feature is available. [CHAR LIMIT=50] -->
-    <string name="window_magnification_prompt_content">You can now magnify some or all of your screen</string>
+    <string name="window_magnification_prompt_title">Magnify part of your screen</string>
+    <!-- Notification content to prompt the user that new magnification feature is available. [CHAR LIMIT=NONE] -->
+    <string name="window_magnification_prompt_content">You can now magnify your full screen, a specific area, or switch between both options.</string>
     <!-- Notification action to bring the user to magnification settings page. [CHAR LIMIT=50] -->
     <string name="turn_on_magnification_settings_action">Turn on in Settings</string>
     <!-- Notification action to dismiss. [CHAR LIMIT=50] -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index f194052..5a7b1fa 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -4224,4 +4224,100 @@
   <java-symbol type="bool" name="config_voice_data_sms_auto_fallback" />
 
   <java-symbol type="bool" name="config_enableOneHandedKeyguard" />
+
+  <!-- CEC Configuration -->
+  <java-symbol type="bool" name="config_cecHdmiCecEnabled_userConfigurable" />
+  <java-symbol type="bool" name="config_cecHdmiCecControlEnabled_allowed" />
+  <java-symbol type="bool" name="config_cecHdmiCecControlEnabled_default" />
+  <java-symbol type="bool" name="config_cecHdmiCecControlDisabled_allowed" />
+  <java-symbol type="bool" name="config_cecHdmiCecControlDisabled_default" />
+
+  <java-symbol type="bool" name="config_cecHdmiCecVersion_userConfigurable" />
+  <java-symbol type="bool" name="config_cecHdmiCecVersion14b_allowed" />
+  <java-symbol type="bool" name="config_cecHdmiCecVersion14b_default" />
+  <java-symbol type="bool" name="config_cecHdmiCecVersion20_allowed" />
+  <java-symbol type="bool" name="config_cecHdmiCecVersion20_default" />
+
+  <java-symbol type="bool" name="config_cecSendStandbyOnSleep_userConfigurable" />
+  <java-symbol type="bool" name="config_cecPowerControlModeTv_allowed" />
+  <java-symbol type="bool" name="config_cecPowerControlModeTv_default" />
+  <java-symbol type="bool" name="config_cecPowerControlModeBroadcast_allowed" />
+  <java-symbol type="bool" name="config_cecPowerControlModeBroadcast_default" />
+  <java-symbol type="bool" name="config_cecPowerControlModeNone_allowed" />
+  <java-symbol type="bool" name="config_cecPowerControlModeNone_default" />
+
+  <java-symbol type="bool" name="config_cecPowerStateChangeOnActiveSourceLost_userConfigurable" />
+  <java-symbol type="bool" name="config_cecPowerStateChangeOnActiveSourceLostNone_allowed" />
+  <java-symbol type="bool" name="config_cecPowerStateChangeOnActiveSourceLostNone_default" />
+  <java-symbol type="bool" name="config_cecPowerStateChangeOnActiveSourceLostStandbyNow_allowed" />
+  <java-symbol type="bool" name="config_cecPowerStateChangeOnActiveSourceLostStandbyNow_default" />
+
+  <java-symbol type="bool" name="config_cecSystemAudioModeMuting_userConfigurable" />
+  <java-symbol type="bool" name="config_cecSystemAudioModeMutingEnabled_allowed" />
+  <java-symbol type="bool" name="config_cecSystemAudioModeMutingEnabled_default" />
+  <java-symbol type="bool" name="config_cecSystemAudioModeMutingDisabled_allowed" />
+  <java-symbol type="bool" name="config_cecSystemAudioModeMutingDisabled_default" />
+
+  <java-symbol type="bool" name="config_cecVolumeControlMode_userConfigurable" />
+  <java-symbol type="bool" name="config_cecVolumeControlModeEnabled_allowed" />
+  <java-symbol type="bool" name="config_cecVolumeControlModeEnabled_default" />
+  <java-symbol type="bool" name="config_cecVolumeControlModeDisabled_allowed" />
+  <java-symbol type="bool" name="config_cecVolumeControlModeDisabled_default" />
+
+  <java-symbol type="bool" name="config_cecTvWakeOnOneTouchPlay_userConfigurable" />
+  <java-symbol type="bool" name="config_cecTvWakeOnOneTouchPlayEnabled_allowed" />
+  <java-symbol type="bool" name="config_cecTvWakeOnOneTouchPlayEnabled_default" />
+  <java-symbol type="bool" name="config_cecTvWakeOnOneTouchPlayDisabled_allowed" />
+  <java-symbol type="bool" name="config_cecTvWakeOnOneTouchPlayDisabled_default" />
+
+  <java-symbol type="bool" name="config_cecTvSendStandbyOnSleep_userConfigurable" />
+  <java-symbol type="bool" name="config_cecTvSendStandbyOnSleepEnabled_allowed" />
+  <java-symbol type="bool" name="config_cecTvSendStandbyOnSleepEnabled_default" />
+  <java-symbol type="bool" name="config_cecTvSendStandbyOnSleepDisabled_allowed" />
+  <java-symbol type="bool" name="config_cecTvSendStandbyOnSleepDisabled_default" />
+
+  <java-symbol type="bool" name="config_cecRcProfileTv_userConfigurable" />
+  <java-symbol type="bool" name="config_cecRcProfileTvNone_allowed" />
+  <java-symbol type="bool" name="config_cecRcProfileTvNone_default" />
+  <java-symbol type="bool" name="config_cecRcProfileTvOne_allowed" />
+  <java-symbol type="bool" name="config_cecRcProfileTvOne_default" />
+  <java-symbol type="bool" name="config_cecRcProfileTvTwo_allowed" />
+  <java-symbol type="bool" name="config_cecRcProfileTvTwo_default" />
+  <java-symbol type="bool" name="config_cecRcProfileTvThree_allowed" />
+  <java-symbol type="bool" name="config_cecRcProfileTvThree_default" />
+  <java-symbol type="bool" name="config_cecRcProfileTvFour_allowed" />
+  <java-symbol type="bool" name="config_cecRcProfileTvFour_default" />
+
+  <java-symbol type="bool" name="config_cecRcProfileSourceRootMenu_userConfigurable" />
+  <java-symbol type="bool" name="config_cecRcProfileSourceRootMenuHandled_allowed" />
+  <java-symbol type="bool" name="config_cecRcProfileSourceRootMenuHandled_default" />
+  <java-symbol type="bool" name="config_cecRcProfileSourceRootMenuNotHandled_allowed" />
+  <java-symbol type="bool" name="config_cecRcProfileSourceRootMenuNotHandled_default" />
+
+  <java-symbol type="bool" name="config_cecRcProfileSourceSetupMenu_userConfigurable" />
+  <java-symbol type="bool" name="config_cecRcProfileSourceSetupMenuHandled_allowed" />
+  <java-symbol type="bool" name="config_cecRcProfileSourceSetupMenuHandled_default" />
+  <java-symbol type="bool" name="config_cecRcProfileSourceSetupMenuNotHandled_allowed" />
+  <java-symbol type="bool" name="config_cecRcProfileSourceSetupMenuNotHandled_default" />
+
+  <java-symbol type="bool" name="config_cecRcProfileSourceContentsMenu_userConfigurable" />
+  <java-symbol type="bool" name="config_cecRcProfileSourceContentsMenuHandled_allowed" />
+  <java-symbol type="bool" name="config_cecRcProfileSourceContentsMenuHandled_default" />
+  <java-symbol type="bool" name="config_cecRcProfileSourceContentsMenuNotHandled_allowed" />
+  <java-symbol type="bool" name="config_cecRcProfileSourceContentsMenuNotHandled_default" />
+
+  <java-symbol type="bool" name="config_cecRcProfileSourceTopMenu_userConfigurable" />
+  <java-symbol type="bool" name="config_cecRcProfileSourceTopMenuHandled_allowed" />
+  <java-symbol type="bool" name="config_cecRcProfileSourceTopMenuHandled_default" />
+  <java-symbol type="bool" name="config_cecRcProfileSourceTopMenuNotHandled_allowed" />
+  <java-symbol type="bool" name="config_cecRcProfileSourceTopMenuNotHandled_default" />
+
+  <java-symbol type="bool" name="config_cecRcProfileSourceMediaContextSensitiveMenu_userConfigurable" />
+  <java-symbol type="bool" name="config_cecRcProfileSourceMediaContextSensitiveMenuHandled_allowed" />
+  <java-symbol type="bool" name="config_cecRcProfileSourceMediaContextSensitiveMenuHandled_default" />
+  <java-symbol type="bool" name="config_cecRcProfileSourceMediaContextSensitiveMenuNotHandled_allowed" />
+  <java-symbol type="bool" name="config_cecRcProfileSourceMediaContextSensitiveMenuNotHandled_default" />
+
+  <java-symbol type="id" name="remote_views_next_child" />
+  <java-symbol type="id" name="remote_views_stable_id" />
 </resources>
diff --git a/core/tests/coretests/src/android/inputmethodservice/InputMethodServiceTest.java b/core/tests/coretests/src/android/inputmethodservice/InputMethodServiceTest.java
deleted file mode 100644
index 4863cfe..0000000
--- a/core/tests/coretests/src/android/inputmethodservice/InputMethodServiceTest.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.inputmethodservice;
-
-import static android.content.res.Configuration.KEYBOARD_12KEY;
-import static android.content.res.Configuration.NAVIGATION_NONAV;
-
-import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
-
-
-import static junit.framework.Assert.assertFalse;
-
-import static org.junit.Assert.assertTrue;
-
-import android.content.Context;
-import android.content.pm.ActivityInfo;
-import android.content.res.Configuration;
-import android.os.Build;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.rule.ServiceTestRule;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.concurrent.TimeoutException;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class InputMethodServiceTest {
-    private InputMethodService mService;
-    private Context mContext;
-    @Rule
-    public final ServiceTestRule serviceRule = new ServiceTestRule();
-
-    @Before
-    public void setUp() throws TimeoutException {
-        mContext = getInstrumentation().getContext();
-        mService = new InputMethodService();
-    }
-
-    @Test
-    public void testShouldImeRestartForConfig() throws Exception {
-        // Make sure we preserve Pre-S behavior i.e. Service restarts.
-        mContext.getApplicationInfo().targetSdkVersion = Build.VERSION_CODES.R;
-        Configuration config = mContext.getResources().getConfiguration();
-        mService.setLastKnownConfig(config);
-        assertTrue("IME should restart for Pre-S",
-                mService.shouldImeRestartForConfig(config));
-
-        // IME shouldn't restart on targetSdk S+ (with no config changes).
-        mContext.getApplicationInfo().targetSdkVersion = Build.VERSION_CODES.S;
-        assertFalse("IME shouldn't restart for S+",
-                mService.shouldImeRestartForConfig(config));
-
-        // Screen density changed but IME doesn't handle congfigChanges
-        config.densityDpi = 99;
-        assertTrue("IME should restart for unhandled configChanges",
-                mService.shouldImeRestartForConfig(config));
-
-        // opt-in IME to handle config changes.
-        mService.setHandledConfigChanges(ActivityInfo.CONFIG_DENSITY);
-        assertFalse("IME shouldn't restart for S+ since it handles configChanges",
-                mService.shouldImeRestartForConfig(config));
-    }
-}
diff --git a/core/tests/coretests/src/android/os/VibratorInfoTest.java b/core/tests/coretests/src/android/os/VibratorInfoTest.java
index c06405a..09c36dd 100644
--- a/core/tests/coretests/src/android/os/VibratorInfoTest.java
+++ b/core/tests/coretests/src/android/os/VibratorInfoTest.java
@@ -16,9 +16,10 @@
 
 package android.os;
 
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertTrue;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
 
 import android.hardware.vibrator.IVibrator;
 import android.platform.test.annotations.Presubmit;
@@ -33,72 +34,128 @@
 
     @Test
     public void testHasAmplitudeControl() {
-        assertFalse(createInfo(/* capabilities= */ 0).hasAmplitudeControl());
-        assertTrue(createInfo(IVibrator.CAP_COMPOSE_EFFECTS
-                | IVibrator.CAP_AMPLITUDE_CONTROL).hasAmplitudeControl());
+        VibratorInfo noCapabilities = new InfoBuilder().build();
+        assertFalse(noCapabilities.hasAmplitudeControl());
+        VibratorInfo composeAndAmplitudeControl = new InfoBuilder()
+                .setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS
+                        | IVibrator.CAP_AMPLITUDE_CONTROL)
+                .build();
+        assertTrue(composeAndAmplitudeControl.hasAmplitudeControl());
     }
 
     @Test
     public void testHasCapabilities() {
-        assertTrue(createInfo(IVibrator.CAP_COMPOSE_EFFECTS)
-                .hasCapability(IVibrator.CAP_COMPOSE_EFFECTS));
-        assertFalse(createInfo(IVibrator.CAP_COMPOSE_EFFECTS)
-                .hasCapability(IVibrator.CAP_AMPLITUDE_CONTROL));
+        VibratorInfo info = new InfoBuilder()
+                .setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS)
+                .build();
+        assertTrue(info.hasCapability(IVibrator.CAP_COMPOSE_EFFECTS));
+        assertFalse(info.hasCapability(IVibrator.CAP_AMPLITUDE_CONTROL));
     }
 
     @Test
     public void testIsEffectSupported() {
-        VibratorInfo info = new VibratorInfo(/* id= */ 0, /* capabilities= */0,
-                new int[]{VibrationEffect.EFFECT_CLICK}, null);
+        VibratorInfo noEffects = new InfoBuilder().build();
+        VibratorInfo canClick = new InfoBuilder()
+                .setSupportedEffects(VibrationEffect.EFFECT_CLICK)
+                .build();
         assertEquals(Vibrator.VIBRATION_EFFECT_SUPPORT_UNKNOWN,
-                createInfo(/* capabilities= */ 0).isEffectSupported(VibrationEffect.EFFECT_CLICK));
+                noEffects.isEffectSupported(VibrationEffect.EFFECT_CLICK));
         assertEquals(Vibrator.VIBRATION_EFFECT_SUPPORT_YES,
-                info.isEffectSupported(VibrationEffect.EFFECT_CLICK));
+                canClick.isEffectSupported(VibrationEffect.EFFECT_CLICK));
         assertEquals(Vibrator.VIBRATION_EFFECT_SUPPORT_NO,
-                info.isEffectSupported(VibrationEffect.EFFECT_TICK));
+                canClick.isEffectSupported(VibrationEffect.EFFECT_TICK));
     }
 
     @Test
     public void testIsPrimitiveSupported() {
-        VibratorInfo info = new VibratorInfo(/* id= */ 0, IVibrator.CAP_COMPOSE_EFFECTS,
-                null, new int[]{VibrationEffect.Composition.PRIMITIVE_CLICK});
+        VibratorInfo info = new InfoBuilder()
+                .setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS)
+                .setSupportedPrimitives(VibrationEffect.Composition.PRIMITIVE_CLICK)
+                .build();
         assertTrue(info.isPrimitiveSupported(VibrationEffect.Composition.PRIMITIVE_CLICK));
         assertFalse(info.isPrimitiveSupported(VibrationEffect.Composition.PRIMITIVE_TICK));
 
         // Returns false when there is no compose capability.
-        info = new VibratorInfo(/* id= */ 0, /* capabilities= */ 0,
-                null, new int[]{VibrationEffect.Composition.PRIMITIVE_CLICK});
+        info = new InfoBuilder()
+                .setSupportedPrimitives(VibrationEffect.Composition.PRIMITIVE_CLICK)
+                .build();
         assertFalse(info.isPrimitiveSupported(VibrationEffect.Composition.PRIMITIVE_CLICK));
     }
 
     @Test
     public void testEquals() {
-        VibratorInfo empty = new VibratorInfo(1, 0, null, null);
-        VibratorInfo complete = new VibratorInfo(1, IVibrator.CAP_AMPLITUDE_CONTROL,
-                new int[]{VibrationEffect.EFFECT_CLICK},
-                new int[]{VibrationEffect.Composition.PRIMITIVE_CLICK});
+        InfoBuilder completeBuilder = new InfoBuilder()
+                .setId(1)
+                .setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL)
+                .setSupportedEffects(VibrationEffect.EFFECT_CLICK)
+                .setSupportedPrimitives(VibrationEffect.Composition.PRIMITIVE_CLICK)
+                .setQFactor(2f)
+                .setResonantFrequency(150f);
+        VibratorInfo complete = completeBuilder.build();
 
         assertEquals(complete, complete);
-        assertEquals(complete, new VibratorInfo(1, IVibrator.CAP_AMPLITUDE_CONTROL,
-                new int[]{VibrationEffect.EFFECT_CLICK},
-                new int[]{VibrationEffect.Composition.PRIMITIVE_CLICK}));
+        assertEquals(complete, completeBuilder.build());
 
-        assertFalse(empty.equals(new VibratorInfo(1, 0, new int[]{}, new int[]{})));
-        assertFalse(complete.equals(new VibratorInfo(1, IVibrator.CAP_COMPOSE_EFFECTS,
-                new int[]{VibrationEffect.EFFECT_CLICK},
-                new int[]{VibrationEffect.Composition.PRIMITIVE_CLICK})));
-        assertFalse(complete.equals(new VibratorInfo(1, IVibrator.CAP_AMPLITUDE_CONTROL,
-                new int[]{}, new int[]{})));
-        assertFalse(complete.equals(new VibratorInfo(1, IVibrator.CAP_AMPLITUDE_CONTROL,
-                null, new int[]{VibrationEffect.Composition.PRIMITIVE_CLICK})));
-        assertFalse(complete.equals(new VibratorInfo(1, IVibrator.CAP_AMPLITUDE_CONTROL,
-                new int[]{VibrationEffect.EFFECT_CLICK}, null)));
+        VibratorInfo completeWithComposeControl = completeBuilder
+                .setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS)
+                .build();
+        assertNotEquals(complete, completeWithComposeControl);
+
+        VibratorInfo completeWithNoEffects = completeBuilder
+                .setSupportedEffects()
+                .setSupportedPrimitives()
+                .build();
+        assertNotEquals(complete, completeWithNoEffects);
+
+        VibratorInfo completeWithUnknownEffects = completeBuilder
+                .setSupportedEffects(null)
+                .build();
+        assertNotEquals(complete, completeWithNoEffects);
+
+        VibratorInfo completeWithUnknownPrimitives = completeBuilder
+                .setSupportedPrimitives(null)
+                .build();
+        assertNotEquals(complete, completeWithUnknownPrimitives);
+
+        VibratorInfo completeWithDifferentF0 = completeBuilder
+                .setResonantFrequency(complete.getResonantFrequency() + 3f)
+                .build();
+        assertNotEquals(complete, completeWithDifferentF0);
+
+        VibratorInfo completeWithUnknownF0 = completeBuilder
+                .setResonantFrequency(Float.NaN)
+                .build();
+        assertNotEquals(complete, completeWithUnknownF0);
+
+        VibratorInfo completeWithUnknownQFactor = completeBuilder
+                .setQFactor(Float.NaN)
+                .build();
+        assertNotEquals(complete, completeWithUnknownQFactor);
+
+        VibratorInfo completeWithDifferentQFactor = completeBuilder
+                .setQFactor(complete.getQFactor() + 3f)
+                .build();
+        assertNotEquals(complete, completeWithDifferentQFactor);
+
+        VibratorInfo empty = new InfoBuilder().setId(1).build();
+        VibratorInfo emptyWithKnownSupport = new InfoBuilder()
+                .setId(1)
+                .setSupportedEffects()
+                .setSupportedPrimitives()
+                .build();
+        assertNotEquals(empty, emptyWithKnownSupport);
     }
 
     @Test
-    public void testSerialization() {
-        VibratorInfo original = new VibratorInfo(1, IVibrator.CAP_COMPOSE_EFFECTS,
-                new int[]{VibrationEffect.EFFECT_CLICK}, null);
+    public void testParceling() {
+        VibratorInfo original = new InfoBuilder()
+                .setId(1)
+                .setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS)
+                .setSupportedEffects(VibrationEffect.EFFECT_CLICK)
+                .setSupportedPrimitives(null)
+                .setResonantFrequency(1.3f)
+                .setQFactor(Float.NaN)
+                .build();
 
         Parcel parcel = Parcel.obtain();
         original.writeToParcel(parcel, 0);
@@ -107,7 +164,47 @@
         assertEquals(original, restored);
     }
 
-    private static VibratorInfo createInfo(long capabilities) {
-        return new VibratorInfo(/* id= */ 0, capabilities, null, null);
+    private static class InfoBuilder {
+        private int mId = 0;
+        private int mCapabilities = 0;
+        private int[] mSupportedEffects = null;
+        private int[] mSupportedPrimitives = null;
+        private float mResonantFrequency = Float.NaN;
+        private float mQFactor = Float.NaN;
+
+        public InfoBuilder setId(int id) {
+            mId = id;
+            return this;
+        }
+
+        public InfoBuilder setCapabilities(int capabilities) {
+            mCapabilities = capabilities;
+            return this;
+        }
+
+        public InfoBuilder setSupportedEffects(int... supportedEffects) {
+            mSupportedEffects = supportedEffects;
+            return this;
+        }
+
+        public InfoBuilder setSupportedPrimitives(int... supportedPrimitives) {
+            mSupportedPrimitives = supportedPrimitives;
+            return this;
+        }
+
+        public InfoBuilder setResonantFrequency(float resonantFrequency) {
+            mResonantFrequency = resonantFrequency;
+            return this;
+        }
+
+        public InfoBuilder setQFactor(float qFactor) {
+            mQFactor = qFactor;
+            return this;
+        }
+
+        public VibratorInfo build() {
+            return new VibratorInfo(mId, mCapabilities, mSupportedEffects, mSupportedPrimitives,
+                    mResonantFrequency, mQFactor);
+        }
     }
 }
diff --git a/core/tests/coretests/src/android/widget/SuggestionsPopupWindowTest.java b/core/tests/coretests/src/android/widget/SuggestionsPopupWindowTest.java
index f6e02bc..28f9ccc 100644
--- a/core/tests/coretests/src/android/widget/SuggestionsPopupWindowTest.java
+++ b/core/tests/coretests/src/android/widget/SuggestionsPopupWindowTest.java
@@ -41,7 +41,9 @@
 
 import static org.hamcrest.Matchers.is;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
 
 import android.content.res.TypedArray;
 import android.text.Selection;
@@ -356,4 +358,71 @@
                     .perform(clearText());
         }
     }
+
+    @Test
+    public void testCursorVisibility() {
+        final TextView textView = getActivity().findViewById(R.id.textview);
+        final String text = "abc";
+
+        assertTrue(textView.isCursorVisible());
+
+        onView(withId(R.id.textview)).perform(click());
+        onView(withId(R.id.textview)).perform(replaceText(text));
+        final SuggestionSpan suggestionSpan = new SuggestionSpan(getActivity(),
+                new String[]{"ABC"}, SuggestionSpan.FLAG_AUTO_CORRECTION);
+        setSuggestionSpan(suggestionSpan, text.indexOf('a'), text.indexOf('c') + 1);
+        showSuggestionsPopup();
+
+        assertSuggestionsPopupIsDisplayed();
+        assertSuggestionsPopupContainsItem("ABC");
+        assertFalse(textView.isCursorVisible());
+
+        // Delete an item.
+        clickSuggestionsPopupItem(
+                getActivity().getString(com.android.internal.R.string.delete));
+        assertSuggestionsPopupIsNotDisplayed();
+        assertTrue(textView.isCursorVisible());
+    }
+
+    @Test
+    public void testCursorVisibilityWhenImeConsumesInput() {
+        final TextView textView = getActivity().findViewById(R.id.textview);
+        final String text = "abc";
+
+        assertTrue(textView.isCursorVisible());
+
+        onView(withId(R.id.textview)).perform(click());
+        onView(withId(R.id.textview)).perform(replaceText(text));
+        setImeConsumesInputWithExpect(textView, true /* imeConsumesInput */,
+                false /* expectedCursorVisibility */);
+        final SuggestionSpan suggestionSpan = new SuggestionSpan(getActivity(),
+                new String[]{"ABC"}, SuggestionSpan.FLAG_AUTO_CORRECTION);
+        setSuggestionSpan(suggestionSpan, text.indexOf('a'), text.indexOf('c') + 1);
+        showSuggestionsPopup();
+
+        assertSuggestionsPopupIsDisplayed();
+        assertSuggestionsPopupContainsItem("ABC");
+        assertFalse(textView.isCursorVisible());
+
+        // Delete an item.
+        clickSuggestionsPopupItem(
+                getActivity().getString(com.android.internal.R.string.delete));
+        assertSuggestionsPopupIsNotDisplayed();
+        assertFalse(textView.isCursorVisible());
+
+        // Set IME not consumes input, cursor should be back to visible.
+        setImeConsumesInputWithExpect(textView, false /* imeConsumesInput */,
+                true /* expectedCursorVisibility */);
+    }
+
+    private void setImeConsumesInputWithExpect(
+            final TextView textView, boolean imeConsumesInput, boolean expectedCursorVisibility) {
+        textView.post(() -> textView.setImeConsumesInput(imeConsumesInput));
+        getInstrumentation().waitForIdleSync();
+        if (expectedCursorVisibility) {
+            assertTrue(textView.isCursorVisible());
+        } else {
+            assertFalse(textView.isCursorVisible());
+        }
+    }
 }
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 7088890..10ff3a4 100644
--- a/core/tests/coretests/src/com/android/internal/os/CpuPowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/CpuPowerCalculatorTest.java
@@ -19,18 +19,22 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
 import android.os.BatteryConsumer;
+import android.os.BatteryUsageStatsQuery;
 import android.os.Process;
 import android.os.UidBatteryConsumer;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.internal.power.MeasuredEnergyStats;
+
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -81,6 +85,10 @@
     public void setUp() {
         MockitoAnnotations.initMocks(this);
 
+        final boolean[] supportedPowerBuckets =
+                new boolean[MeasuredEnergyStats.NUMBER_STANDARD_POWER_BUCKETS];
+        supportedPowerBuckets[MeasuredEnergyStats.POWER_BUCKET_CPU] = true;
+
         mStatsRule.getBatteryStats()
                 .setUserInfoProvider(mMockUserInfoProvider)
                 .setKernelCpuSpeedReaders(mMockKernelCpuSpeedReaders)
@@ -88,7 +96,8 @@
                 .setKernelCpuUidClusterTimeReader(mMockKernelCpuUidClusterTimeReader)
                 .setKernelCpuUidUserSysTimeReader(mMockKernelCpuUidUserSysTimeReader)
                 .setKernelCpuUidActiveTimeReader(mMockKerneCpuUidActiveTimeReader)
-                .setSystemServerCpuThreadReader(mMockSystemServerCpuThreadReader);
+                .setSystemServerCpuThreadReader(mMockSystemServerCpuThreadReader)
+                .initMeasuredEnergyStatsLocked(supportedPowerBuckets, 0);
     }
 
     @Test
@@ -103,28 +112,28 @@
 
         // User/System CPU time
         doAnswer(invocation -> {
-            final KernelCpuUidTimeReader.Callback<long[]> callback = invocation.getArgument(0);
+            final KernelCpuUidTimeReader.Callback<long[]> callback = invocation.getArgument(1);
             // User/system time in microseconds
             callback.onUidCpuTime(APP_UID1, new long[]{1111000, 2222000});
             callback.onUidCpuTime(APP_UID2, new long[]{3333000, 4444000});
             return null;
-        }).when(mMockKernelCpuUidUserSysTimeReader).readDelta(any());
+        }).when(mMockKernelCpuUidUserSysTimeReader).readDelta(anyBoolean(), any());
 
         // Active CPU time
         doAnswer(invocation -> {
-            final KernelCpuUidTimeReader.Callback<Long> callback = invocation.getArgument(0);
+            final KernelCpuUidTimeReader.Callback<Long> callback = invocation.getArgument(1);
             callback.onUidCpuTime(APP_UID1, 1111L);
             callback.onUidCpuTime(APP_UID2, 3333L);
             return null;
-        }).when(mMockKerneCpuUidActiveTimeReader).readDelta(any());
+        }).when(mMockKerneCpuUidActiveTimeReader).readDelta(anyBoolean(), any());
 
         // Per-cluster CPU time
         doAnswer(invocation -> {
-            final KernelCpuUidTimeReader.Callback<long[]> callback = invocation.getArgument(0);
+            final KernelCpuUidTimeReader.Callback<long[]> callback = invocation.getArgument(1);
             callback.onUidCpuTime(APP_UID1, new long[]{1111, 2222});
             callback.onUidCpuTime(APP_UID2, new long[]{3333, 4444});
             return null;
-        }).when(mMockKernelCpuUidClusterTimeReader).readDelta(any());
+        }).when(mMockKernelCpuUidClusterTimeReader).readDelta(anyBoolean(), any());
 
         mStatsRule.getBatteryStats().updateCpuTimeLocked(true, true, null);
 
@@ -134,7 +143,8 @@
         CpuPowerCalculator calculator =
                 new CpuPowerCalculator(mStatsRule.getPowerProfile());
 
-        mStatsRule.apply(calculator);
+        mStatsRule.apply(new BatteryUsageStatsQuery.Builder().powerProfileModeledOnly().build(),
+                calculator);
 
         UidBatteryConsumer uidConsumer1 = mStatsRule.getUidBatteryConsumer(APP_UID1);
         assertThat(uidConsumer1.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_CPU))
@@ -150,4 +160,64 @@
                 .isWithin(PRECISION).of(2.672322);
         assertThat(uidConsumer2.getPackageWithHighestDrain()).isNull();
     }
+
+    @Test
+    public void testMeasuredEnergyBasedModel() {
+        when(mMockUserInfoProvider.exists(anyInt())).thenReturn(true);
+
+        when(mMockKernelCpuSpeedReaders[0].readDelta()).thenReturn(new long[]{1000, 2000});
+        when(mMockKernelCpuSpeedReaders[1].readDelta()).thenReturn(new long[]{3000, 4000});
+
+        when(mMockCpuUidFreqTimeReader.perClusterTimesAvailable()).thenReturn(false);
+
+        // User/System CPU time
+        doAnswer(invocation -> {
+            final KernelCpuUidTimeReader.Callback<long[]> callback = invocation.getArgument(1);
+            // User/system time in microseconds
+            callback.onUidCpuTime(APP_UID1, new long[]{1111000, 2222000});
+            callback.onUidCpuTime(APP_UID2, new long[]{3333000, 4444000});
+            return null;
+        }).when(mMockKernelCpuUidUserSysTimeReader).readDelta(anyBoolean(), any());
+
+        // Active CPU time
+        doAnswer(invocation -> {
+            final KernelCpuUidTimeReader.Callback<Long> callback = invocation.getArgument(1);
+            callback.onUidCpuTime(APP_UID1, 1111L);
+            callback.onUidCpuTime(APP_UID2, 3333L);
+            return null;
+        }).when(mMockKerneCpuUidActiveTimeReader).readDelta(anyBoolean(), any());
+
+        // Per-cluster CPU time
+        doAnswer(invocation -> {
+            final KernelCpuUidTimeReader.Callback<long[]> callback = invocation.getArgument(1);
+            callback.onUidCpuTime(APP_UID1, new long[]{1111, 2222});
+            callback.onUidCpuTime(APP_UID2, new long[]{3333, 4444});
+            return null;
+        }).when(mMockKernelCpuUidClusterTimeReader).readDelta(anyBoolean(), any());
+
+        final long[] clusterChargesUC = new long[]{13577531, 24688642};
+        mStatsRule.getBatteryStats().updateCpuTimeLocked(true, true, clusterChargesUC);
+
+        mStatsRule.getUidStats(APP_UID1).getProcessStatsLocked("foo").addCpuTimeLocked(4321, 1234);
+        mStatsRule.getUidStats(APP_UID1).getProcessStatsLocked("bar").addCpuTimeLocked(5432, 2345);
+
+        CpuPowerCalculator calculator =
+                new CpuPowerCalculator(mStatsRule.getPowerProfile());
+
+        mStatsRule.apply(calculator);
+
+        UidBatteryConsumer uidConsumer1 = mStatsRule.getUidBatteryConsumer(APP_UID1);
+        assertThat(uidConsumer1.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_CPU))
+                .isEqualTo(3333);
+        assertThat(uidConsumer1.getConsumedPower(BatteryConsumer.POWER_COMPONENT_CPU))
+                .isWithin(PRECISION).of(3.18877);
+        assertThat(uidConsumer1.getPackageWithHighestDrain()).isEqualTo("bar");
+
+        UidBatteryConsumer uidConsumer2 = mStatsRule.getUidBatteryConsumer(APP_UID2);
+        assertThat(uidConsumer2.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_CPU))
+                .isEqualTo(7777);
+        assertThat(uidConsumer2.getConsumedPower(BatteryConsumer.POWER_COMPONENT_CPU))
+                .isWithin(PRECISION).of(7.44072);
+        assertThat(uidConsumer2.getPackageWithHighestDrain()).isNull();
+    }
 }
diff --git a/core/tests/mockingcoretests/src/android/view/DisplayTests.java b/core/tests/mockingcoretests/src/android/view/DisplayTests.java
index 678f21f..a036db2 100644
--- a/core/tests/mockingcoretests/src/android/view/DisplayTests.java
+++ b/core/tests/mockingcoretests/src/android/view/DisplayTests.java
@@ -73,6 +73,11 @@
     private static Rect sAppBoundsPortrait = buildAppBounds(LOGICAL_WIDTH, LOGICAL_HEIGHT);
     private static Rect sAppBoundsLandscape = buildAppBounds(LOGICAL_HEIGHT, LOGICAL_WIDTH);
 
+    // Bounds of the device.
+    private static Rect sDeviceBoundsPortrait = new Rect(0, 0, LOGICAL_WIDTH, LOGICAL_HEIGHT);
+    private static Rect sDeviceBoundsLandscape = new Rect(0, 0, LOGICAL_HEIGHT, LOGICAL_WIDTH);
+
+
     private StaticMockitoSession mMockitoSession;
 
     private DisplayManagerGlobal mDisplayManagerGlobal;
@@ -278,29 +283,57 @@
     }
 
     @Test
-    public void testGetRealSize_resourcesPortraitSandboxed_matchesSandboxBounds() {
+    public void testGetRealSize_resourcesPortraitSandboxed_matchesAppSandboxBounds() {
         // GIVEN display is not rotated.
         setDisplayInfoPortrait(mDisplayInfo);
         // GIVEN app is letterboxed.
-        setMaxBoundsSandboxedToMatchAppBounds(mApplicationContext.getResources(),
-                sAppBoundsPortrait);
+        setMaxBoundsSandboxed(mApplicationContext.getResources(), sAppBoundsPortrait);
         final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
                 mApplicationContext.getResources());
         // THEN real size matches app bounds.
-        verifyRealSizeMatchesApp(display, sAppBoundsPortrait);
+        verifyRealSizeMatchesBounds(display, sAppBoundsPortrait);
     }
 
     @Test
-    public void testGetRealSize_resourcesLandscapeSandboxed_matchesSandboxBounds() {
+    public void testGetRealSize_resourcesPortraitSandboxed_matchesDisplayAreaSandboxBounds() {
+        // GIVEN display is not rotated.
+        setDisplayInfoPortrait(mDisplayInfo);
+        // GIVEN max bounds reflect DisplayArea size, which is the same size as the display.
+        setMaxBoundsSandboxed(mApplicationContext.getResources(), sDeviceBoundsPortrait);
+        // GIVEN app bounds do not stretch to include the full DisplayArea.
+        mApplicationContext.getResources().getConfiguration().windowConfiguration
+                .setAppBounds(buildAppBounds(LOGICAL_WIDTH, LOGICAL_HEIGHT - 10));
+        final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
+                mApplicationContext.getResources());
+        // THEN real metrics matches max bounds for the DisplayArea.
+        verifyRealSizeMatchesBounds(display, sDeviceBoundsPortrait);
+    }
+
+    @Test
+    public void testGetRealSize_resourcesLandscapeSandboxed_matchesAppSandboxBounds() {
         // GIVEN display is rotated.
         setDisplayInfoLandscape(mDisplayInfo);
         // GIVEN app is letterboxed.
-        setMaxBoundsSandboxedToMatchAppBounds(mApplicationContext.getResources(),
-                sAppBoundsLandscape);
+        setMaxBoundsSandboxed(mApplicationContext.getResources(), sAppBoundsLandscape);
         final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
                 mApplicationContext.getResources());
         // THEN real size matches app bounds.
-        verifyRealSizeMatchesApp(display, sAppBoundsLandscape);
+        verifyRealSizeMatchesBounds(display, sAppBoundsLandscape);
+    }
+
+    @Test
+    public void testGetRealSize_resourcesLandscapeSandboxed_matchesDisplayAreaSandboxBounds() {
+        // GIVEN display is rotated.
+        setDisplayInfoLandscape(mDisplayInfo);
+        // GIVEN max bounds reflect DisplayArea size, which is the same size as the display.
+        setMaxBoundsSandboxed(mApplicationContext.getResources(), sDeviceBoundsLandscape);
+        // GIVEN app bounds do not stretch to include the full DisplayArea.
+        mApplicationContext.getResources().getConfiguration().windowConfiguration
+                .setAppBounds(buildAppBounds(LOGICAL_HEIGHT, LOGICAL_WIDTH - 10));
+        final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
+                mApplicationContext.getResources());
+        // THEN real metrics matches max bounds for the DisplayArea.
+        verifyRealSizeMatchesBounds(display, sDeviceBoundsLandscape);
     }
 
     @Test
@@ -396,29 +429,57 @@
     }
 
     @Test
-    public void testGetRealMetrics_resourcesPortraitSandboxed_matchesSandboxBounds() {
+    public void testGetRealMetrics_resourcesPortraitSandboxed_matchesAppSandboxBounds() {
         // GIVEN display is not rotated.
         setDisplayInfoPortrait(mDisplayInfo);
         // GIVEN app is letterboxed.
-        setMaxBoundsSandboxedToMatchAppBounds(mApplicationContext.getResources(),
-                sAppBoundsPortrait);
+        setMaxBoundsSandboxed(mApplicationContext.getResources(), sAppBoundsPortrait);
         final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
                 mApplicationContext.getResources());
         // THEN real metrics matches app bounds.
-        verifyRealMetricsMatchesApp(display, sAppBoundsPortrait);
+        verifyRealMetricsMatchesBounds(display, sAppBoundsPortrait);
     }
 
     @Test
-    public void testGetRealMetrics_resourcesLandscapeSandboxed_matchesSandboxBounds() {
+    public void testGetRealMetrics_resourcesPortraitSandboxed_matchesDisplayAreaSandboxBounds() {
+        // GIVEN display is not rotated.
+        setDisplayInfoPortrait(mDisplayInfo);
+        // GIVEN max bounds reflect DisplayArea size, which is the same size as the display.
+        setMaxBoundsSandboxed(mApplicationContext.getResources(), sDeviceBoundsPortrait);
+        // GIVEN app bounds do not stretch to include the full DisplayArea.
+        mApplicationContext.getResources().getConfiguration().windowConfiguration
+                .setAppBounds(buildAppBounds(LOGICAL_WIDTH, LOGICAL_HEIGHT - 10));
+        final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
+                mApplicationContext.getResources());
+        // THEN real metrics matches max bounds for the DisplayArea.
+        verifyRealMetricsMatchesBounds(display, sDeviceBoundsPortrait);
+    }
+
+    @Test
+    public void testGetRealMetrics_resourcesLandscapeSandboxed_matchesAppSandboxBounds() {
         // GIVEN display is rotated.
         setDisplayInfoLandscape(mDisplayInfo);
         // GIVEN app is letterboxed.
-        setMaxBoundsSandboxedToMatchAppBounds(mApplicationContext.getResources(),
-                sAppBoundsLandscape);
+        setMaxBoundsSandboxed(mApplicationContext.getResources(), sAppBoundsLandscape);
         final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
                 mApplicationContext.getResources());
         // THEN real metrics matches app bounds.
-        verifyRealMetricsMatchesApp(display, sAppBoundsLandscape);
+        verifyRealMetricsMatchesBounds(display, sAppBoundsLandscape);
+    }
+
+    @Test
+    public void testGetRealMetrics_resourcesLandscapeSandboxed_matchesDisplayAreaSandboxBounds() {
+        // GIVEN display is rotated.
+        setDisplayInfoLandscape(mDisplayInfo);
+        // GIVEN max bounds reflect DisplayArea size, which is the same size as the display.
+        setMaxBoundsSandboxed(mApplicationContext.getResources(), sDeviceBoundsLandscape);
+        // GIVEN app bounds do not stretch to include the full DisplayArea.
+        mApplicationContext.getResources().getConfiguration().windowConfiguration
+                .setAppBounds(buildAppBounds(LOGICAL_HEIGHT, LOGICAL_WIDTH - 10));
+        final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
+                mApplicationContext.getResources());
+        // THEN real metrics matches max bounds for the DisplayArea.
+        verifyRealMetricsMatchesBounds(display, sDeviceBoundsLandscape);
     }
 
     // Given rotated display dimensions, calculate the letterboxed app bounds.
@@ -450,8 +511,8 @@
      * Set max bounds to be sandboxed to the app bounds, indicating the app is in
      * size compat mode or letterbox.
      */
-    private static void setMaxBoundsSandboxedToMatchAppBounds(Resources resources, Rect appBounds) {
-        resources.getConfiguration().windowConfiguration.setMaxBounds(appBounds);
+    private static void setMaxBoundsSandboxed(Resources resources, Rect bounds) {
+        resources.getConfiguration().windowConfiguration.setMaxBounds(bounds);
     }
 
     /**
@@ -492,17 +553,17 @@
         assertThat(metrics.heightPixels).isEqualTo(LOGICAL_HEIGHT);
     }
 
-    private static void verifyRealSizeMatchesApp(Display display, Rect appBounds) {
+    private static void verifyRealSizeMatchesBounds(Display display, Rect bounds) {
         Point size = new Point();
         display.getRealSize(size);
-        assertThat(size).isEqualTo(new Point(appBounds.width(), appBounds.height()));
+        assertThat(size).isEqualTo(new Point(bounds.width(), bounds.height()));
     }
 
-    private static void verifyRealMetricsMatchesApp(Display display, Rect appBounds) {
+    private static void verifyRealMetricsMatchesBounds(Display display, Rect bounds) {
         DisplayMetrics metrics = new DisplayMetrics();
         display.getRealMetrics(metrics);
-        assertThat(metrics.widthPixels).isEqualTo(appBounds.width());
-        assertThat(metrics.heightPixels).isEqualTo(appBounds.height());
+        assertThat(metrics.widthPixels).isEqualTo(bounds.width());
+        assertThat(metrics.heightPixels).isEqualTo(bounds.height());
     }
 
     private static FixedRotationAdjustments setOverrideFixedRotationAdjustments(
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 77a38a9..b3a180d 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -154,6 +154,7 @@
     <assign-permission name="android.permission.GET_PROCESS_STATE_AND_OOM_SCORE" uid="media" />
     <assign-permission name="android.permission.PACKAGE_USAGE_STATS" uid="media" />
     <assign-permission name="android.permission.REGISTER_MEDIA_RESOURCE_OBSERVER" uid="media" />
+    <assign-permission name="android.permission.REGISTER_STATS_PULL_ATOM" uid="media" />
 
     <assign-permission name="android.permission.INTERNET" uid="media" />
 
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index c49fe85..a7b6636 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -488,6 +488,8 @@
         <permission name="android.permission.MANAGE_UI_TRANSLATION" />
         <!-- Permission required for CTS test - ClipboardManagerTest -->
         <permission name="android.permission.SET_CLIP_SOURCE" />
+        <!-- Permission required for CTS test - FontManagerTest -->
+        <permission name="android.permission.UPDATE_FONTS" />
     </privapp-permissions>
 
     <privapp-permissions package="com.android.statementservice">
diff --git a/graphics/java/android/graphics/drawable/RippleShader.java b/graphics/java/android/graphics/drawable/RippleShader.java
index 2549277..657a32c 100644
--- a/graphics/java/android/graphics/drawable/RippleShader.java
+++ b/graphics/java/android/graphics/drawable/RippleShader.java
@@ -61,53 +61,6 @@
             + "  return 1. - smoothstep(1. - blurHalf, 1. + blurHalf, d / radius);\n"
             + "}\n"
             + "\n"
-            + "float softRing(vec2 uv, vec2 xy, float radius, float blur) {\n"
-            + "  float thickness = 0.4;\n"
-            + "  float circle_outer = softCircle(uv, xy, radius + thickness * 0.5, blur);\n"
-            + "  float circle_inner = softCircle(uv, xy, radius - thickness * 0.5, blur);\n"
-            + "  return circle_outer - circle_inner;\n"
-            + "}\n"
-            + "\n"
-            + "struct Viewport {\n"
-            + "  float aspect;\n"
-            + "  vec2 uv;\n"
-            + "  vec2 resolution_pixels;\n"
-            + "};\n"
-            + "\n"
-            + "Viewport getViewport(vec2 frag_coord, vec2 resolution_pixels) {\n"
-            + "  Viewport v;\n"
-            + "  v.aspect = resolution_pixels.y / resolution_pixels.x;\n"
-            + "  v.uv = frag_coord / resolution_pixels;\n"
-            + "  v.uv.y = (1.0 - v.uv.y) * v.aspect;\n"
-            + "  v.resolution_pixels = resolution_pixels;\n"
-            + "  return v;\n"
-            + "}\n"
-            + "\n"
-            + "vec2 getTouch(vec2 touch_position_pixels, Viewport viewport) {\n"
-            + "  vec2 touch = touch_position_pixels / viewport.resolution_pixels;\n"
-            + "  touch.y *= viewport.aspect;\n"
-            + "  return touch;\n"
-            + "}\n"
-            + "\n"
-            + "struct Wave {\n"
-            + "  float ring;\n"
-            + "  float circle;\n"
-            + "};\n"
-            + "\n"
-            + "Wave getWave(Viewport viewport, vec2 touch, float progress) {\n"
-            + "  float fade = pow((clamp(progress, 0.8, 1.0)), 8.);\n"
-            + "  Wave w;\n"
-            + "  w.ring = max(softRing(viewport.uv, touch, progress, 0.45) - fade, 0.);\n"
-            + "  w.circle = softCircle(viewport.uv, touch, 2.0 * progress, 0.2) - progress;\n"
-            + "  return w;\n"
-            + "}\n"
-            + "\n"
-            + "vec4 getRipple(vec4 color, float loudness, float sparkle, Wave wave) {\n"
-            + "  float alpha = wave.ring * sparkle * loudness\n"
-            + "        + wave.circle * color.a;\n"
-            + "  return vec4(color.rgb, saturate(alpha));\n"
-            + "}\n"
-            + "\n"
             + "float getRingMask(vec2 frag, vec2 center, float r, float progress) {\n"
             + "      float dist = distance(frag, center);\n"
             + "      float expansion = r * .6;\n"
@@ -126,19 +79,15 @@
             + "    float fadeIn = subProgress(0., 0.175, in_progress);\n"
             + "    float fadeOutNoise = subProgress(0.375, 1., in_progress);\n"
             + "    float fadeOutRipple = subProgress(0.375, 0.75, in_progress);\n"
-            + "    Viewport vp = getViewport(p, in_resolution);\n"
-            + "    vec2 touch = getTouch(in_origin, vp);\n"
-            + "    Wave w = getWave(vp, touch, in_progress * 0.25);\n"
             + "    float ring = getRingMask(p, in_origin, in_maxRadius, fadeIn);\n"
             + "    float alpha = min(fadeIn, 1. - fadeOutNoise);\n"
             + "    float sparkle = sparkles(p, in_progress * 0.25 + in_secondsOffset)\n"
             + "        * ring * alpha;\n"
-            + "    vec4 r = getRipple(in_color, 1., sparkle, w);\n"
             + "    float fade = min(fadeIn, 1.-fadeOutRipple);\n"
-            + "    vec4 circle = vec4(in_color.rgb, softCircle(p, in_origin, in_maxRadius "
-            + "      * fadeIn, 0.2) * fade * in_color.a);\n"
+            + "    vec4 circle = in_color * (softCircle(p, in_origin, in_maxRadius "
+            + "      * fadeIn, 0.2) * fade);\n"
             + "    float mask = in_hasMask == 1. ? sample(in_shader).a > 0. ? 1. : 0. : 1.;\n"
-            + "    return mix(circle, vec4(1.), sparkle * mask);\n"
+            + "    return mix(circle, vec4(sparkle), sparkle) * mask;\n"
             + "}";
     private static final String SHADER = SHADER_UNIFORMS + SHADER_LIB + SHADER_MAIN;
 
diff --git a/graphics/java/android/graphics/fonts/FontFileUtil.java b/graphics/java/android/graphics/fonts/FontFileUtil.java
index af49619..917eef2 100644
--- a/graphics/java/android/graphics/fonts/FontFileUtil.java
+++ b/graphics/java/android/graphics/fonts/FontFileUtil.java
@@ -183,6 +183,23 @@
         return nIsPostScriptType1Font(buffer, index);
     }
 
+    /**
+     * Analyze the file content and returns 1 if the font file is an OpenType collection file, 0 if
+     * the font file is a OpenType font file, -1 otherwise.
+     */
+    public static int isCollectionFont(@NonNull ByteBuffer buffer) {
+        ByteBuffer copied = buffer.slice();
+        copied.order(ByteOrder.BIG_ENDIAN);
+        int magicNumber = copied.getInt(0);
+        if (magicNumber == TTC_TAG) {
+            return 1;
+        } else if (magicNumber == SFNT_VERSION_1 || magicNumber == SFNT_VERSION_OTTO) {
+            return 0;
+        } else {
+            return -1;
+        }
+    }
+
     @FastNative
     private static native long nGetFontRevision(@NonNull ByteBuffer buffer,
             @IntRange(from = 0) int index);
diff --git a/keystore/java/android/security/AndroidKeyStoreMaintenance.java b/keystore/java/android/security/AndroidKeyStoreMaintenance.java
index 5501569..35b1c16 100644
--- a/keystore/java/android/security/AndroidKeyStoreMaintenance.java
+++ b/keystore/java/android/security/AndroidKeyStoreMaintenance.java
@@ -121,4 +121,22 @@
             return SYSTEM_ERROR;
         }
     }
+
+    /**
+     * Queries user state from Keystore 2.0.
+     *
+     * @param userId - Android user id of the user.
+     * @return UserState enum variant as integer if successful or an error
+     */
+    public static int getState(int userId) {
+        try {
+            return getService().getState(userId);
+        } catch (ServiceSpecificException e) {
+            Log.e(TAG, "getState failed", e);
+            return e.errorCode;
+        } catch (Exception e) {
+            Log.e(TAG, "Can not connect to keystore", e);
+            return SYSTEM_ERROR;
+        }
+    }
 }
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index 93658e6..937f01c 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -43,6 +43,7 @@
 import android.security.keystore.KeyProperties;
 import android.security.keystore.KeystoreResponse;
 import android.security.keystore.UserNotAuthenticatedException;
+import android.security.maintenance.UserState;
 import android.system.keystore2.Domain;
 import android.util.Log;
 
@@ -196,6 +197,19 @@
     public State state(int userId) {
         final int ret;
         try {
+            if (android.security.keystore2.AndroidKeyStoreProvider.isInstalled()) {
+                int userState = AndroidKeyStoreMaintenance.getState(userId);
+                switch (userState) {
+                    case UserState.UNINITIALIZED:
+                        return KeyStore.State.UNINITIALIZED;
+                    case UserState.LSKF_UNLOCKED:
+                        return KeyStore.State.UNLOCKED;
+                    case UserState.LSKF_LOCKED:
+                        return KeyStore.State.LOCKED;
+                    default:
+                        throw new AssertionError(KeyStore.VALUE_CORRUPTED);
+                }
+            }
             ret = mBinder.getState(userId);
         } catch (RemoteException e) {
             Log.w(TAG, "Cannot connect to keystore", e);
diff --git a/libs/WindowManager/Shell/Android.bp b/libs/WindowManager/Shell/Android.bp
index 1b5dc8b..3f03302 100644
--- a/libs/WindowManager/Shell/Android.bp
+++ b/libs/WindowManager/Shell/Android.bp
@@ -38,6 +38,14 @@
     path: "src",
 }
 
+filegroup {
+    name: "wm_shell-aidls",
+    srcs: [
+        "src/**/*.aidl",
+    ],
+    path: "src",
+}
+
 // TODO(b/168581922) protologtool do not support kotlin(*.kt)
 filegroup {
     name: "wm_shell-sources-kt",
@@ -98,7 +106,7 @@
         ":wm_shell_protolog_src",
         // TODO(b/168581922) protologtool do not support kotlin(*.kt)
         ":wm_shell-sources-kt",
-        "src/**/I*.aidl",
+        ":wm_shell-aidls",
     ],
     resource_dirs: [
         "res",
diff --git a/libs/WindowManager/Shell/AndroidManifest.xml b/libs/WindowManager/Shell/AndroidManifest.xml
index c0bc73d..d2b3cf6 100644
--- a/libs/WindowManager/Shell/AndroidManifest.xml
+++ b/libs/WindowManager/Shell/AndroidManifest.xml
@@ -18,4 +18,5 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.android.wm.shell">
     <uses-permission android:name="android.permission.ROTATE_SURFACE_FLINGER" />
+    <uses-permission android:name="android.permission.READ_FRAME_BUFFER" />
 </manifest>
diff --git a/libs/WindowManager/Shell/res/values/config.xml b/libs/WindowManager/Shell/res/values/config.xml
index 2419865..c2f591b 100644
--- a/libs/WindowManager/Shell/res/values/config.xml
+++ b/libs/WindowManager/Shell/res/values/config.xml
@@ -51,4 +51,10 @@
 
     <!-- maximum animation duration for the icon when entering the starting window -->
     <integer name="max_starting_window_intro_icon_anim_duration">1000</integer>
+
+    <!-- Animation duration when exit starting window: icon going away -->
+    <integer name="starting_window_icon_exit_anim_duration">166</integer>
+
+    <!-- Animation duration when exit starting window: reveal app -->
+    <integer name="starting_window_app_reveal_anim_duration">333</integer>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml
index 75bed37..3ced8d3 100644
--- a/libs/WindowManager/Shell/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -188,4 +188,13 @@
 
     <!-- The height of the brand image on staring surface. -->
     <dimen name="starting_surface_brand_image_height">80dp</dimen>
+
+    <!-- The length of the shift of main window when exit starting window. -->
+    <dimen name="starting_surface_exit_animation_window_shift_length">20dp</dimen>
+
+    <!-- The distance of the shift icon when normal exit starting window. -->
+    <dimen name="starting_surface_normal_exit_icon_distance">120dp</dimen>
+
+    <!-- The distance of the shift icon when early exit starting window. -->
+    <dimen name="starting_surface_early_exit_icon_distance">32dp</dimen>
 </resources>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandlerImpl.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandlerImpl.java
index eaed24d..d451f4a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandlerImpl.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandlerImpl.java
@@ -47,21 +47,7 @@
     private final ShellExecutor mMainExecutor;
     private final HandlerImpl mImpl = new HandlerImpl();
 
-    public static ShellCommandHandler create(
-            ShellTaskOrganizer shellTaskOrganizer,
-            Optional<LegacySplitScreenController> legacySplitScreenOptional,
-            Optional<SplitScreenController> splitScreenOptional,
-            Optional<Pip> pipOptional,
-            Optional<OneHandedController> oneHandedOptional,
-            Optional<HideDisplayCutoutController> hideDisplayCutout,
-            Optional<AppPairsController> appPairsOptional,
-            ShellExecutor mainExecutor) {
-        return new ShellCommandHandlerImpl(shellTaskOrganizer, legacySplitScreenOptional,
-                splitScreenOptional, pipOptional, oneHandedOptional, hideDisplayCutout,
-                appPairsOptional, mainExecutor).mImpl;
-    }
-
-    private ShellCommandHandlerImpl(
+    public ShellCommandHandlerImpl(
             ShellTaskOrganizer shellTaskOrganizer,
             Optional<LegacySplitScreenController> legacySplitScreenOptional,
             Optional<SplitScreenController> splitScreenOptional,
@@ -80,6 +66,10 @@
         mMainExecutor = mainExecutor;
     }
 
+    public ShellCommandHandler asShellCommandHandler() {
+        return mImpl;
+    }
+
     /** Dumps WM Shell internal state. */
     private void dump(PrintWriter pw) {
         mShellTaskOrganizer.dump(pw, "");
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java
index 85bd24c..6f4550c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java
@@ -26,7 +26,7 @@
 import com.android.wm.shell.legacysplitscreen.LegacySplitScreenController;
 import com.android.wm.shell.pip.phone.PipTouchHandler;
 import com.android.wm.shell.splitscreen.SplitScreenController;
-import com.android.wm.shell.startingsurface.StartingSurface;
+import com.android.wm.shell.startingsurface.StartingWindowController;
 import com.android.wm.shell.transition.Transitions;
 
 import java.util.Optional;
@@ -47,44 +47,20 @@
     private final FullscreenTaskListener mFullscreenTaskListener;
     private final ShellExecutor mMainExecutor;
     private final Transitions mTransitions;
-    private final Optional<StartingSurface> mStartingSurfaceOptional;
+    private final StartingWindowController mStartingWindow;
 
     private final InitImpl mImpl = new InitImpl();
 
-    public static ShellInit create(DisplayImeController displayImeController,
+    public ShellInitImpl(DisplayImeController displayImeController,
             DragAndDropController dragAndDropController,
             ShellTaskOrganizer shellTaskOrganizer,
             Optional<LegacySplitScreenController> legacySplitScreenOptional,
             Optional<SplitScreenController> splitScreenOptional,
             Optional<AppPairsController> appPairsOptional,
-            Optional<StartingSurface> startingSurfaceOptional,
             Optional<PipTouchHandler> pipTouchHandlerOptional,
             FullscreenTaskListener fullscreenTaskListener,
             Transitions transitions,
-            ShellExecutor mainExecutor) {
-        return new ShellInitImpl(displayImeController,
-                dragAndDropController,
-                shellTaskOrganizer,
-                legacySplitScreenOptional,
-                splitScreenOptional,
-                appPairsOptional,
-                startingSurfaceOptional,
-                pipTouchHandlerOptional,
-                fullscreenTaskListener,
-                transitions,
-                mainExecutor).mImpl;
-    }
-
-    private ShellInitImpl(DisplayImeController displayImeController,
-            DragAndDropController dragAndDropController,
-            ShellTaskOrganizer shellTaskOrganizer,
-            Optional<LegacySplitScreenController> legacySplitScreenOptional,
-            Optional<SplitScreenController> splitScreenOptional,
-            Optional<AppPairsController> appPairsOptional,
-            Optional<StartingSurface> startingSurfaceOptional,
-            Optional<PipTouchHandler> pipTouchHandlerOptional,
-            FullscreenTaskListener fullscreenTaskListener,
-            Transitions transitions,
+            StartingWindowController startingWindow,
             ShellExecutor mainExecutor) {
         mDisplayImeController = displayImeController;
         mDragAndDropController = dragAndDropController;
@@ -96,17 +72,21 @@
         mPipTouchHandlerOptional = pipTouchHandlerOptional;
         mTransitions = transitions;
         mMainExecutor = mainExecutor;
-        mStartingSurfaceOptional = startingSurfaceOptional;
+        mStartingWindow = startingWindow;
+    }
+
+    public ShellInit asShellInit() {
+        return mImpl;
     }
 
     private void init() {
         // Start listening for display changes
         mDisplayImeController.startMonitorDisplays();
 
+        // Setup the shell organizer
         mShellTaskOrganizer.addListenerForType(
                 mFullscreenTaskListener, TASK_LISTENER_TYPE_FULLSCREEN);
-        mStartingSurfaceOptional.ifPresent(mShellTaskOrganizer::initStartingSurface);
-        // Register the shell organizer
+        mShellTaskOrganizer.initStartingWindow(mStartingWindow);
         mShellTaskOrganizer.registerOrganizer();
 
         mAppPairsOptional.ifPresent(AppPairsController::onOrganizerRegistered);
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 cb04bd7..94d13ea 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
@@ -31,6 +31,7 @@
 import android.app.TaskInfo;
 import android.content.Context;
 import android.content.LocusId;
+import android.graphics.Rect;
 import android.os.Binder;
 import android.os.IBinder;
 import android.util.ArrayMap;
@@ -47,7 +48,7 @@
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.sizecompatui.SizeCompatUIController;
-import com.android.wm.shell.startingsurface.StartingSurface;
+import com.android.wm.shell.startingsurface.StartingWindowController;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -132,7 +133,7 @@
     private final ArraySet<LocusIdListener> mLocusIdListeners = new ArraySet<>();
 
     private final Object mLock = new Object();
-    private StartingSurface mStartingSurface;
+    private StartingWindowController mStartingWindow;
 
     /**
      * In charge of showing size compat UI. Can be {@code null} if device doesn't support size
@@ -183,8 +184,8 @@
     /**
      * @hide
      */
-    public void initStartingSurface(StartingSurface startingSurface) {
-        mStartingSurface = startingSurface;
+    public void initStartingWindow(StartingWindowController startingWindow) {
+        mStartingWindow = startingWindow;
     }
 
     /**
@@ -301,22 +302,23 @@
 
     @Override
     public void addStartingWindow(StartingWindowInfo info, IBinder appToken) {
-        if (mStartingSurface != null) {
-            mStartingSurface.addStartingWindow(info, appToken);
+        if (mStartingWindow != null) {
+            mStartingWindow.addStartingWindow(info, appToken);
         }
     }
 
     @Override
-    public void removeStartingWindow(int taskId) {
-        if (mStartingSurface != null) {
-            mStartingSurface.removeStartingWindow(taskId);
+    public void removeStartingWindow(int taskId, SurfaceControl leash, Rect frame,
+            boolean playRevealAnimation) {
+        if (mStartingWindow != null) {
+            mStartingWindow.removeStartingWindow(taskId, leash, frame, playRevealAnimation);
         }
     }
 
     @Override
     public void copySplashScreenView(int taskId) {
-        if (mStartingSurface != null) {
-            mStartingSurface.copySplashScreenView(taskId);
+        if (mStartingWindow != null) {
+            mStartingWindow.copySplashScreenView(taskId);
         }
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java
index 46884fe..7d65a08 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java
@@ -83,6 +83,7 @@
     private boolean mIsInitialized;
     private Listener mListener;
     private Executor mListenerExecutor;
+    private Rect mObscuredTouchRect;
 
     private final Rect mTmpRect = new Rect();
     private final Rect mTmpRootRect = new Rect();
@@ -161,6 +162,15 @@
     }
 
     /**
+     * Indicates a region of the view that is not touchable.
+     *
+     * @param obscuredRect the obscured region of the view.
+     */
+    public void setObscuredTouchRect(Rect obscuredRect) {
+        mObscuredTouchRect = obscuredRect;
+    }
+
+    /**
      * Call when view position or size has changed. Do not call when animating.
      */
     public void onLocationChanged() {
@@ -384,6 +394,10 @@
         mTmpRect.set(mTmpLocation[0], mTmpLocation[1],
                 mTmpLocation[0] + getWidth(), mTmpLocation[1] + getHeight());
         inoutInfo.touchableRegion.op(mTmpRect, Region.Op.DIFFERENCE);
+
+        if (mObscuredTouchRect != null) {
+            inoutInfo.touchableRegion.union(mObscuredTouchRect);
+        }
     }
 
     @Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java
index 562b32b..b6d408a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java
@@ -23,6 +23,7 @@
 import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_TASK_ORG;
 
 import android.app.ActivityManager;
+import android.app.ActivityTaskManager;
 import android.graphics.Rect;
 import android.view.SurfaceControl;
 import android.window.WindowContainerToken;
@@ -88,7 +89,8 @@
         ProtoLog.v(WM_SHELL_TASK_ORG, "pair task1=%d task2=%d in AppPair=%s",
                 task1.taskId, task2.taskId, this);
 
-        if (!task1.isResizeable || !task2.isResizeable) {
+        if ((!task1.isResizeable || !task2.isResizeable)
+                && !ActivityTaskManager.supportsNonResizableMultiWindow()) {
             ProtoLog.e(WM_SHELL_TASK_ORG,
                     "Can't pair unresizeable tasks task1.isResizeable=%b task1.isResizeable=%b",
                     task1.isResizeable, task2.isResizeable);
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 64a44ca..16ede73 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
@@ -41,7 +41,6 @@
 import android.graphics.PointF;
 import android.graphics.Rect;
 import android.graphics.RectF;
-import android.graphics.Region;
 import android.os.Bundle;
 import android.provider.Settings;
 import android.util.Log;
@@ -1046,6 +1045,7 @@
         }
     };
 
+    // TODO: Create ManageMenuView and move setup / animations there
     private void setUpManageMenu() {
         if (mManageMenu != null) {
             removeView(mManageMenu);
@@ -2146,50 +2146,6 @@
     }
 
     /**
-     * This method is called by {@link android.app.ActivityView} because the BubbleStackView has a
-     * higher Z-index than the ActivityView (so that dragged-out bubbles are visible over the AV).
-     * ActivityView is asking BubbleStackView to subtract the stack's bounds from the provided
-     * touchable region, so that the ActivityView doesn't consume events meant for the stack. Due to
-     * the special nature of ActivityView, it does not respect the standard
-     * {@link #dispatchTouchEvent} and {@link #onInterceptTouchEvent} methods typically used for
-     * this purpose.
-     *
-     * BubbleStackView is MATCH_PARENT, so that bubbles can be positioned via their translation
-     * properties for performance reasons. This means that the default implementation of this method
-     * subtracts the entirety of the screen from the ActivityView's touchable region, resulting in
-     * it not receiving any touch events. This was previously addressed by returning false in the
-     * stack's {@link View#canReceivePointerEvents()} method, but this precluded the use of any
-     * touch handlers in the stack or its child views.
-     *
-     * To support touch handlers, we're overriding this method to leave the ActivityView's touchable
-     * region alone. The only touchable part of the stack that can ever overlap the AV is a
-     * dragged-out bubble that is animating back into the row of bubbles. It's not worth continually
-     * updating the touchable region to allow users to grab a bubble while it completes its ~50ms
-     * animation back to the bubble row.
-     *
-     * NOTE: Any future additions to the stack that obscure the ActivityView region will need their
-     * bounds subtracted here in order to receive touch events.
-     */
-    @Override
-    public void subtractObscuredTouchableRegion(Region touchableRegion, View view) {
-        // If the notification shade is expanded, or the manage menu is open, or we are showing
-        // manage bubbles user education, we shouldn't let the ActivityView steal any touch events
-        // from any location.
-        if (!mIsExpanded
-                || mShowingManage
-                || (mManageEduView != null
-                    && mManageEduView.getVisibility() == VISIBLE)) {
-            touchableRegion.setEmpty();
-        }
-    }
-
-    /**
-     * If you're here because you're not receiving touch events on a view that is a descendant of
-     * BubbleStackView, and you think BSV is intercepting them - it's not! You need to subtract the
-     * bounds of the view in question in {@link #subtractObscuredTouchableRegion}. The ActivityView
-     * consumes all touch events within its bounds, even for views like the BubbleStackView that are
-     * above it. It ignores typical view touch handling methods like this one and
-     * dispatchTouchEvent.
      */
     @Override
     public boolean onInterceptTouchEvent(MotionEvent ev) {
@@ -2539,6 +2495,11 @@
         }
 
         mExpandedBubble.getExpandedView().getManageButtonBoundsOnScreen(mTempRect);
+        if (mExpandedBubble.getExpandedView().getTaskView() != null) {
+            mExpandedBubble.getExpandedView().getTaskView().setObscuredTouchRect(mShowingManage
+                    ? new Rect(0, 0, getWidth(), getHeight())
+                    : null);
+        }
 
         final boolean isLtr =
                 getResources().getConfiguration().getLayoutDirection() == LAYOUT_DIRECTION_LTR;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/ExecutorUtils.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/ExecutorUtils.java
new file mode 100644
index 0000000..b29058b
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/ExecutorUtils.java
@@ -0,0 +1,64 @@
+/*
+ * 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;
+
+import android.Manifest;
+import android.util.Slog;
+
+import java.util.function.Consumer;
+
+/**
+ * Helpers for working with executors
+ */
+public class ExecutorUtils {
+
+    /**
+     * Checks that the caller has the MANAGE_ACTIVITY_TASKS permission and executes the given
+     * callback.
+     */
+    public static <T> void executeRemoteCallWithTaskPermission(RemoteCallable<T> controllerInstance,
+            String log, Consumer<T> callback) {
+        executeRemoteCallWithTaskPermission(controllerInstance, log, callback,
+                false /* blocking */);
+    }
+
+    /**
+     * Checks that the caller has the MANAGE_ACTIVITY_TASKS permission and executes the given
+     * callback.
+     */
+    public static <T> void executeRemoteCallWithTaskPermission(RemoteCallable<T> controllerInstance,
+            String log, Consumer<T> callback, boolean blocking) {
+        if (controllerInstance == null) return;
+
+        final RemoteCallable<T> controller = controllerInstance;
+        controllerInstance.getContext().enforceCallingPermission(
+                Manifest.permission.MANAGE_ACTIVITY_TASKS, log);
+        if (blocking) {
+            try {
+                controllerInstance.getRemoteCallExecutor().executeBlocking(() -> {
+                    callback.accept((T) controller);
+                });
+            } catch (InterruptedException e) {
+                Slog.e("ExecutorUtils", "Remote call failed", e);
+            }
+        } else {
+            controllerInstance.getRemoteCallExecutor().execute(() -> {
+                callback.accept((T) controller);
+            });
+        }
+    }
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISplitScreenListener.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/common/RemoteCallable.java
similarity index 61%
copy from packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISplitScreenListener.aidl
copy to libs/WindowManager/Shell/src/com/android/wm/shell/common/RemoteCallable.java
index 54242be..30f535b 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISplitScreenListener.aidl
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/RemoteCallable.java
@@ -14,12 +14,21 @@
  * limitations under the License.
  */
 
-package com.android.systemui.shared.recents;
+package com.android.wm.shell.common;
+
+import android.content.Context;
 
 /**
- * Listener interface that Launcher attaches to SystemUI to get split-screen callbacks.
+ * An interface for controllers that can receive remote calls.
  */
-oneway interface ISplitScreenListener {
-    void onStagePositionChanged(int stage, int position);
-    void onTaskStageChanged(int taskId, int stage, boolean visible);
-}
+public interface RemoteCallable<T> {
+    /**
+     * Returns a context used for permission checking.
+     */
+    Context getContext();
+
+    /**
+     * Returns the executor to post the handler callback to.
+     */
+    ShellExecutor getRemoteCallExecutor();
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
index aab2334..9a09ca4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
@@ -235,7 +235,7 @@
             mStarter.startShortcut(packageName, id, stage, position, opts, user);
         } else {
             mStarter.startIntent(intent.getParcelableExtra(EXTRA_PENDING_INTENT),
-                    mContext, null, stage, position, opts);
+                    null, stage, position, opts);
         }
     }
 
@@ -295,7 +295,7 @@
                 @Nullable Bundle options);
         void startShortcut(String packageName, String shortcutId, @StageType int stage,
                 @StagePosition int position, @Nullable Bundle options, UserHandle user);
-        void startIntent(PendingIntent intent, Context context, Intent fillInIntent,
+        void startIntent(PendingIntent intent, Intent fillInIntent,
                 @StageType int stage, @StagePosition int position,
                 @Nullable Bundle options);
         void enterSplitScreen(int taskId, boolean leftOrTop);
@@ -337,9 +337,8 @@
         }
 
         @Override
-        public void startIntent(PendingIntent intent, Context context,
-                @Nullable Intent fillInIntent, int stage, int position,
-                @Nullable Bundle options) {
+        public void startIntent(PendingIntent intent, @Nullable Intent fillInIntent, int stage,
+                int position, @Nullable Bundle options) {
             try {
                 intent.send(mContext, 0, fillInIntent, null, null, null, options);
             } catch (PendingIntent.CanceledException e) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/SplitScreenTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/SplitScreenTransitions.java
index eea5c08..d06064a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/SplitScreenTransitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/SplitScreenTransitions.java
@@ -30,6 +30,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.ActivityManager;
+import android.app.ActivityTaskManager;
 import android.app.WindowConfiguration;
 import android.graphics.Rect;
 import android.os.IBinder;
@@ -91,9 +92,11 @@
                         // is nothing behind it.
                         ((type == TRANSIT_CLOSE || type == TRANSIT_TO_BACK)
                                 && triggerTask.parentTaskId == mListener.mPrimary.taskId)
-                        // if a non-resizable is launched, we also need to leave split-screen.
+                        // if a non-resizable is launched when it is not supported in multi window,
+                        // we also need to leave split-screen.
                         || ((type == TRANSIT_OPEN || type == TRANSIT_TO_FRONT)
-                                && !triggerTask.isResizeable);
+                                && !triggerTask.isResizeable
+                                && !ActivityTaskManager.supportsNonResizableMultiWindow());
                 // In both cases, dismiss the primary
                 if (shouldDismiss) {
                     WindowManagerProxy.buildDismissSplit(out, mListener,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/WindowManagerProxy.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/WindowManagerProxy.java
index 82468ad..5a2ef56 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/WindowManagerProxy.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/WindowManagerProxy.java
@@ -46,6 +46,7 @@
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.function.BooleanSupplier;
 
 /**
  * Proxy to simplify calls into window manager/activity manager
@@ -208,11 +209,17 @@
             return false;
         }
         ActivityManager.RunningTaskInfo topHomeTask = null;
+        // One-time lazy wrapper to avoid duplicated IPC in loop. Not store as class variable
+        // because the value can be changed at runtime.
+        final BooleanSupplier supportsNonResizableMultiWindow =
+                createSupportsNonResizableMultiWindowSupplier();
         for (int i = rootTasks.size() - 1; i >= 0; --i) {
             final ActivityManager.RunningTaskInfo rootTask = rootTasks.get(i);
-            // Only move resizeable task to split secondary. However, we have an exception
-            // for non-resizable home because we will minimize to show it.
-            if (!rootTask.isResizeable && rootTask.topActivityType != ACTIVITY_TYPE_HOME) {
+            // Check whether to move resizeable task to split secondary.
+            // Also, we have an exception for non-resizable home because we will minimize to show
+            // it.
+            if (!rootTask.isResizeable && rootTask.topActivityType != ACTIVITY_TYPE_HOME
+                    && !supportsNonResizableMultiWindow.getAsBoolean()) {
                 continue;
             }
             // Only move fullscreen tasks to split secondary.
@@ -357,6 +364,21 @@
         outWct.setFocusable(tiles.mPrimary.token, true /* focusable */);
     }
 
+    /** Creates a lazy wrapper to get whether it supports non-resizable in multi window. */
+    private static BooleanSupplier createSupportsNonResizableMultiWindowSupplier() {
+        return new BooleanSupplier() {
+            private Boolean mSupportsNonResizableMultiWindow;
+            @Override
+            public boolean getAsBoolean() {
+                if (mSupportsNonResizableMultiWindow == null) {
+                    mSupportsNonResizableMultiWindow =
+                            ActivityTaskManager.supportsNonResizableMultiWindow();
+                }
+                return mSupportsNonResizableMultiWindow;
+            }
+        };
+    }
+
     /**
      * Utility to apply a sync transaction serially with other sync transactions.
      *
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISplitScreenListener.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/IOneHanded.aidl
similarity index 66%
copy from packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISplitScreenListener.aidl
copy to libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/IOneHanded.aidl
index 54242be..008b508 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISplitScreenListener.aidl
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/IOneHanded.aidl
@@ -14,12 +14,20 @@
  * limitations under the License.
  */
 
-package com.android.systemui.shared.recents;
+package com.android.wm.shell.onehanded;
 
 /**
- * Listener interface that Launcher attaches to SystemUI to get split-screen callbacks.
+ * Interface that is exposed to remote callers to manipulate the OneHanded feature.
  */
-oneway interface ISplitScreenListener {
-    void onStagePositionChanged(int stage, int position);
-    void onTaskStageChanged(int taskId, int stage, boolean visible);
+interface IOneHanded {
+
+    /**
+     * Enters one handed mode.
+     */
+    oneway void startOneHanded() = 1;
+
+    /**
+     * Exits one handed mode.
+     */
+    oneway void stopOneHanded() = 2;
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHanded.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHanded.java
index 4f31c37..a7e9a01 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHanded.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHanded.java
@@ -26,6 +26,14 @@
  */
 @ExternalThread
 public interface OneHanded {
+
+    /**
+     * Returns a binder that can be passed to an external process to manipulate OneHanded.
+     */
+    default IOneHanded createExternalInterface() {
+        return null;
+    }
+
     /**
      * Return one handed settings enabled or not.
      */
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 5fc7c98..8022c1b 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
@@ -18,6 +18,10 @@
 
 import static android.os.UserHandle.USER_CURRENT;
 
+import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
+
+import android.Manifest;
+import android.annotation.BinderThread;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.om.IOverlayManager;
@@ -43,6 +47,8 @@
 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.ExecutorUtils;
+import com.android.wm.shell.common.RemoteCallable;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.TaskStackListenerCallback;
 import com.android.wm.shell.common.TaskStackListenerImpl;
@@ -54,7 +60,7 @@
 /**
  * Manages and manipulates the one handed states, transitions, and gesture for phones.
  */
-public class OneHandedController {
+public class OneHandedController implements RemoteCallable<OneHandedController> {
     private static final String TAG = "OneHandedController";
 
     private static final String ONE_HANDED_MODE_OFFSET_PERCENTAGE =
@@ -239,6 +245,16 @@
         return mImpl;
     }
 
+    @Override
+    public Context getContext() {
+        return mContext;
+    }
+
+    @Override
+    public ShellExecutor getRemoteCallExecutor() {
+        return mMainExecutor;
+    }
+
     /**
      * Set one handed enabled or disabled when user update settings
      */
@@ -567,8 +583,22 @@
         }
     }
 
+    /**
+     * The interface for calls from outside the Shell, within the host process.
+     */
     @ExternalThread
     private class OneHandedImpl implements OneHanded {
+        private IOneHandedImpl mIOneHanded;
+
+        @Override
+        public IOneHanded createExternalInterface() {
+            if (mIOneHanded != null) {
+                mIOneHanded.invalidate();
+            }
+            mIOneHanded = new IOneHandedImpl(OneHandedController.this);
+            return mIOneHanded;
+        }
+
         @Override
         public boolean isOneHandedEnabled() {
             // This is volatile so return directly
@@ -637,4 +667,39 @@
             });
         }
     }
+
+    /**
+     * The interface for calls from outside the host process.
+     */
+    @BinderThread
+    private static class IOneHandedImpl extends IOneHanded.Stub {
+        private OneHandedController mController;
+
+        IOneHandedImpl(OneHandedController controller) {
+            mController = controller;
+        }
+
+        /**
+         * Invalidates this instance, preventing future calls from updating the controller.
+         */
+        void invalidate() {
+            mController = null;
+        }
+
+        @Override
+        public void startOneHanded() {
+            executeRemoteCallWithTaskPermission(mController, "startOneHanded",
+                    (controller) -> {
+                        controller.startOneHanded();
+                    });
+        }
+
+        @Override
+        public void stopOneHanded() {
+            executeRemoteCallWithTaskPermission(mController, "stopOneHanded",
+                    (controller) -> {
+                        controller.stopOneHanded();
+                    });
+        }
+    }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPip.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPip.aidl
new file mode 100644
index 0000000..a6ffa6e
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPip.aidl
@@ -0,0 +1,63 @@
+/*
+ * 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.pip;
+
+import android.app.PictureInPictureParams;
+import android.content.ComponentName;
+import android.content.pm.ActivityInfo;
+import android.graphics.Rect;
+
+import com.android.wm.shell.pip.IPipAnimationListener;
+
+/**
+ * Interface that is exposed to remote callers to manipulate the Pip feature.
+ */
+interface IPip {
+
+    /**
+     * Notifies that Activity is about to be swiped to home with entering PiP transition and
+     * queries the destination bounds for PiP depends on Launcher's rotation and shelf height.
+     *
+     * @param componentName ComponentName represents the Activity
+     * @param activityInfo ActivityInfo tied to the Activity
+     * @param pictureInPictureParams PictureInPictureParams tied to the Activity
+     * @param launcherRotation Launcher rotation to calculate the PiP destination bounds
+     * @param shelfHeight Shelf height of launcher to calculate the PiP destination bounds
+     * @return destination bounds the PiP window should land into
+     */
+    Rect startSwipePipToHome(in ComponentName componentName, in ActivityInfo activityInfo,
+                in PictureInPictureParams pictureInPictureParams,
+                int launcherRotation, int shelfHeight) = 1;
+
+    /**
+     * Notifies the swiping Activity to PiP onto home transition is finished
+     *
+     * @param componentName ComponentName represents the Activity
+     * @param destinationBounds the destination bounds the PiP window lands into
+     */
+    oneway void stopSwipePipToHome(in ComponentName componentName, in Rect destinationBounds) = 2;
+
+    /**
+     * Sets listener to get pinned stack animation callbacks.
+     */
+    oneway void setPinnedStackAnimationListener(IPipAnimationListener listener) = 3;
+
+    /**
+     * Sets the shelf height and visibility.
+     */
+    oneway void setShelfHeight(boolean visible, int shelfHeight) = 4;
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IPinnedStackAnimationListener.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPipAnimationListener.aidl
similarity index 68%
rename from packages/SystemUI/shared/src/com/android/systemui/shared/recents/IPinnedStackAnimationListener.aidl
rename to libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPipAnimationListener.aidl
index 97aa512..2569b78 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IPinnedStackAnimationListener.aidl
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPipAnimationListener.aidl
@@ -14,15 +14,14 @@
  * limitations under the License.
  */
 
-package com.android.systemui.shared.recents;
+package com.android.wm.shell.pip;
 
 /**
- * Listener interface that Launcher attaches to SystemUI to get
- * pinned stack animation callbacks.
+ * Listener interface that Launcher attaches to SystemUI to get Pip animation callbacks.
  */
-oneway interface IPinnedStackAnimationListener {
+oneway interface IPipAnimationListener {
     /**
-     * Notifies the pinned stack animation is started.
+     * Notifies the listener that the Pip animation is started.
      */
-    void onPinnedStackAnimationStarted();
+    void onPipAnimationStarted();
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java
index d14c3e3c..6d4773b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java
@@ -16,15 +16,10 @@
 
 package com.android.wm.shell.pip;
 
-import android.annotation.Nullable;
-import android.app.PictureInPictureParams;
-import android.content.ComponentName;
-import android.content.pm.ActivityInfo;
 import android.content.res.Configuration;
 import android.graphics.Rect;
 
 import com.android.wm.shell.common.annotations.ExternalThread;
-import com.android.wm.shell.pip.phone.PipTouchHandler;
 
 import java.io.PrintWriter;
 import java.util.function.Consumer;
@@ -34,6 +29,14 @@
  */
 @ExternalThread
 public interface Pip {
+
+    /**
+     * Returns a binder that can be passed to an external process to manipulate PIP.
+     */
+    default IPip createExternalInterface() {
+        return null;
+    }
+
     /**
      * Expand PIP, it's possible that specific request to activate the window via Alt-tab.
      */
@@ -109,30 +112,6 @@
     default void showPictureInPictureMenu() {}
 
     /**
-     * Called by Launcher when swiping an auto-pip enabled Activity to home starts
-     * @param componentName {@link ComponentName} represents the Activity entering PiP
-     * @param activityInfo {@link ActivityInfo} tied to the Activity
-     * @param pictureInPictureParams {@link PictureInPictureParams} tied to the Activity
-     * @param launcherRotation Rotation Launcher is in
-     * @param shelfHeight Shelf height when landing PiP window onto Launcher
-     * @return Destination bounds of PiP window based on the parameters passed in
-     */
-    default Rect startSwipePipToHome(ComponentName componentName, ActivityInfo activityInfo,
-            PictureInPictureParams pictureInPictureParams,
-            int launcherRotation, int shelfHeight) {
-        return null;
-    }
-
-    /**
-     * Called by Launcher when swiping an auto-pip enable Activity to home finishes
-     * @param componentName {@link ComponentName} represents the Activity entering PiP
-     * @param destinationBounds Destination bounds of PiP window
-     */
-    default void stopSwipePipToHome(ComponentName componentName, Rect destinationBounds) {
-        return;
-    }
-
-    /**
      * Called by NavigationBar in order to listen in for PiP bounds change. This is mostly used
      * for times where the PiP bounds could conflict with SystemUI elements, such as a stashed
      * PiP and the Back-from-Edge gesture.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
index 9a584c6..501b90e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
@@ -21,8 +21,10 @@
 import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
 import static android.view.WindowManager.INPUT_CONSUMER_PIP;
 
+import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
 import static com.android.wm.shell.pip.PipAnimationController.isOutPipDirection;
 
+import android.Manifest;
 import android.app.ActivityManager;
 import android.app.ActivityTaskManager;
 import android.app.PictureInPictureParams;
@@ -33,6 +35,7 @@
 import android.content.pm.ParceledListSlice;
 import android.content.res.Configuration;
 import android.graphics.Rect;
+import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -44,6 +47,7 @@
 import android.view.WindowManagerGlobal;
 import android.window.WindowContainerTransaction;
 
+import androidx.annotation.BinderThread;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
@@ -51,9 +55,13 @@
 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.ExecutorUtils;
+import com.android.wm.shell.common.RemoteCallable;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.TaskStackListenerCallback;
 import com.android.wm.shell.common.TaskStackListenerImpl;
+import com.android.wm.shell.pip.IPip;
+import com.android.wm.shell.pip.IPipAnimationListener;
 import com.android.wm.shell.pip.PinnedStackListenerForwarder;
 import com.android.wm.shell.pip.Pip;
 import com.android.wm.shell.pip.PipBoundsAlgorithm;
@@ -71,7 +79,8 @@
 /**
  * Manages the picture-in-picture (PIP) UI and states for Phones.
  */
-public class PipController implements PipTransitionController.PipTransitionCallback {
+public class PipController implements PipTransitionController.PipTransitionCallback,
+        RemoteCallable<PipController> {
     private static final String TAG = "PipController";
 
     private Context mContext;
@@ -85,12 +94,12 @@
     private PipBoundsState mPipBoundsState;
     private PipTouchHandler mTouchHandler;
     private PipTransitionController mPipTransitionController;
-    protected final PipImpl mImpl = new PipImpl();
+    protected final PipImpl mImpl;
 
     private final Rect mTmpInsetBounds = new Rect();
 
     private boolean mIsInFixedRotation;
-    private Consumer<Boolean> mPinnedStackAnimationRecentsCallback;
+    private IPipAnimationListener mPinnedStackAnimationRecentsCallback;
 
     protected PhonePipMenuController mMenuController;
     protected PipTaskOrganizer mPipTaskOrganizer;
@@ -264,6 +273,7 @@
         }
 
         mContext = context;
+        mImpl = new PipImpl();
         mWindowManagerShellWrapper = windowManagerShellWrapper;
         mDisplayController = displayController;
         mPipBoundsAlgorithm = pipBoundsAlgorithm;
@@ -366,6 +376,16 @@
                 });
     }
 
+    @Override
+    public Context getContext() {
+        return mContext;
+    }
+
+    @Override
+    public ShellExecutor getRemoteCallExecutor() {
+        return mMainExecutor;
+    }
+
     private void onConfigurationChanged(Configuration newConfig) {
         mPipBoundsAlgorithm.onConfigurationChanged(mContext);
         mTouchHandler.onConfigurationChanged();
@@ -474,7 +494,7 @@
         mPipTaskOrganizer.setOneShotAnimationType(animationType);
     }
 
-    private void setPinnedStackAnimationListener(Consumer<Boolean> callback) {
+    private void setPinnedStackAnimationListener(IPipAnimationListener callback) {
         mPinnedStackAnimationRecentsCallback = callback;
     }
 
@@ -512,7 +532,11 @@
         // Disable touches while the animation is running
         mTouchHandler.setTouchEnabled(false);
         if (mPinnedStackAnimationRecentsCallback != null) {
-            mPinnedStackAnimationRecentsCallback.accept(true);
+            try {
+                mPinnedStackAnimationRecentsCallback.onPipAnimationStarted();
+            } catch (RemoteException e) {
+                Log.e(TAG, "Failed to call onPinnedStackAnimationStarted()", e);
+            }
         }
     }
 
@@ -638,7 +662,21 @@
         mPipInputConsumer.dump(pw, innerPrefix);
     }
 
+    /**
+     * The interface for calls from outside the Shell, within the host process.
+     */
     private class PipImpl implements Pip {
+        private IPipImpl mIPip;
+
+        @Override
+        public IPip createExternalInterface() {
+            if (mIPip != null) {
+                mIPip.invalidate();
+            }
+            mIPip = new IPipImpl(PipController.this);
+            return mIPip;
+        }
+
         @Override
         public void hidePipMenu(Runnable onStartCallback, Runnable onEndCallback) {
             mMainExecutor.execute(() -> {
@@ -696,13 +734,6 @@
         }
 
         @Override
-        public void setPinnedStackAnimationListener(Consumer<Boolean> callback) {
-            mMainExecutor.execute(() -> {
-                PipController.this.setPinnedStackAnimationListener(callback);
-            });
-        }
-
-        @Override
         public void setPinnedStackAnimationType(int animationType) {
             mMainExecutor.execute(() -> {
                 PipController.this.setPinnedStackAnimationType(animationType);
@@ -724,29 +755,6 @@
         }
 
         @Override
-        public Rect startSwipePipToHome(ComponentName componentName, ActivityInfo activityInfo,
-                PictureInPictureParams pictureInPictureParams, int launcherRotation,
-                int shelfHeight) {
-            Rect[] result = new Rect[1];
-            try {
-                mMainExecutor.executeBlocking(() -> {
-                    result[0] = PipController.this.startSwipePipToHome(componentName, activityInfo,
-                            pictureInPictureParams, launcherRotation, shelfHeight);
-                });
-            } catch (InterruptedException e) {
-                Slog.e(TAG, "Failed to start swipe pip to home");
-            }
-            return result[0];
-        }
-
-        @Override
-        public void stopSwipePipToHome(ComponentName componentName, Rect destinationBounds) {
-            mMainExecutor.execute(() -> {
-                PipController.this.stopSwipePipToHome(componentName, destinationBounds);
-            });
-        }
-
-        @Override
         public void dump(PrintWriter pw) {
             try {
                 mMainExecutor.executeBlocking(() -> {
@@ -757,4 +765,89 @@
             }
         }
     }
+
+    /**
+     * The interface for calls from outside the host process.
+     */
+    @BinderThread
+    private static class IPipImpl extends IPip.Stub {
+        private PipController mController;
+        private IPipAnimationListener mListener;
+        private final IBinder.DeathRecipient mListenerDeathRecipient =
+                new IBinder.DeathRecipient() {
+                    @Override
+                    @BinderThread
+                    public void binderDied() {
+                        final PipController controller = mController;
+                        controller.getRemoteCallExecutor().execute(() -> {
+                            mListener = null;
+                            controller.setPinnedStackAnimationListener(null);
+                        });
+                    }
+                };
+
+        IPipImpl(PipController controller) {
+            mController = controller;
+        }
+
+        /**
+         * Invalidates this instance, preventing future calls from updating the controller.
+         */
+        void invalidate() {
+            mController = null;
+        }
+
+        @Override
+        public Rect startSwipePipToHome(ComponentName componentName, ActivityInfo activityInfo,
+                PictureInPictureParams pictureInPictureParams, int launcherRotation,
+                int shelfHeight) {
+            Rect[] result = new Rect[1];
+            executeRemoteCallWithTaskPermission(mController, "startSwipePipToHome",
+                    (controller) -> {
+                        result[0] = controller.startSwipePipToHome(componentName, activityInfo,
+                                pictureInPictureParams, launcherRotation, shelfHeight);
+                    }, true /* blocking */);
+            return result[0];
+        }
+
+        @Override
+        public void stopSwipePipToHome(ComponentName componentName, Rect destinationBounds) {
+            executeRemoteCallWithTaskPermission(mController, "stopSwipePipToHome",
+                    (controller) -> {
+                        controller.stopSwipePipToHome(componentName, destinationBounds);
+                    });
+        }
+
+        @Override
+        public void setShelfHeight(boolean visible, int height) {
+            executeRemoteCallWithTaskPermission(mController, "setShelfHeight",
+                    (controller) -> {
+                        controller.setShelfHeight(visible, height);
+                    });
+        }
+
+        @Override
+        public void setPinnedStackAnimationListener(IPipAnimationListener listener) {
+            executeRemoteCallWithTaskPermission(mController, "setPinnedStackAnimationListener",
+                    (controller) -> {
+                        if (mListener != null) {
+                            // Reset the old death recipient
+                            mListener.asBinder().unlinkToDeath(mListenerDeathRecipient,
+                                    0 /* flags */);
+                        }
+                        if (listener != null) {
+                            // Register the death recipient for the new listener to clear the listener
+                            try {
+                                listener.asBinder().linkToDeath(mListenerDeathRecipient,
+                                        0 /* flags */);
+                            } catch (RemoteException e) {
+                                Slog.e(TAG, "Failed to link to death");
+                                return;
+                            }
+                        }
+                        mListener = listener;
+                        controller.setPinnedStackAnimationListener(listener);
+                    });
+        }
+    }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl
new file mode 100644
index 0000000..0c46eab
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl
@@ -0,0 +1,77 @@
+/*
+ * 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.splitscreen;
+
+import android.app.PendingIntent;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.UserHandle;
+
+import com.android.wm.shell.splitscreen.ISplitScreenListener;
+
+/**
+ * Interface that is exposed to remote callers to manipulate the splitscreen feature.
+ */
+interface ISplitScreen {
+
+    /**
+     * Registers a split screen listener.
+     */
+    oneway void registerSplitScreenListener(in ISplitScreenListener listener) = 1;
+
+    /**
+     * Unregisters a split screen listener.
+     */
+    oneway void unregisterSplitScreenListener(in ISplitScreenListener listener) = 2;
+
+    /**
+     * Hides the side-stage if it is currently visible.
+     */
+    oneway void setSideStageVisibility(boolean visible) = 3;
+
+    /**
+     * Removes a task from the side stage.
+     */
+    oneway void removeFromSideStage(int taskId) = 4;
+
+    /**
+     * Removes the split-screen stages.
+     */
+    oneway void exitSplitScreen() = 5;
+
+    /**
+     * @param exitSplitScreenOnHide if to exit split-screen if both stages are not visible.
+     */
+    oneway void exitSplitScreenOnHide(boolean exitSplitScreenOnHide) = 6;
+
+    /**
+     * Starts a task in a stage.
+     */
+    oneway void startTask(int taskId, int stage, int position, in Bundle options) = 7;
+
+    /**
+     * Starts a shortcut in a stage.
+     */
+    oneway void startShortcut(String packageName, String shortcutId, int stage, int position,
+            in Bundle options, in UserHandle user) = 8;
+
+    /**
+     * Starts an activity in a stage.
+     */
+    oneway void startIntent(in PendingIntent intent, in Intent fillInIntent, int stage,
+            int position, in Bundle options) = 9;
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISplitScreenListener.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreenListener.aidl
similarity index 83%
rename from packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISplitScreenListener.aidl
rename to libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreenListener.aidl
index 54242be..faab4c2 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISplitScreenListener.aidl
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreenListener.aidl
@@ -14,12 +14,20 @@
  * limitations under the License.
  */
 
-package com.android.systemui.shared.recents;
+package com.android.wm.shell.splitscreen;
 
 /**
  * Listener interface that Launcher attaches to SystemUI to get split-screen callbacks.
  */
 oneway interface ISplitScreenListener {
+
+    /**
+     * Called when the stage position changes.
+     */
     void onStagePositionChanged(int stage, int position);
+
+    /**
+     * Called when a task changes stages.
+     */
     void onTaskStageChanged(int taskId, int stage, boolean visible);
-}
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
index 25a84bd..340b55d7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
@@ -35,7 +35,7 @@
  * TODO: Figure out which of these are actually needed outside of the Shell
  */
 @ExternalThread
-public interface SplitScreen extends DragAndDropPolicy.Starter {
+public interface SplitScreen {
     /**
      * Stage position isn't specified normally meaning to use what ever it is currently set to.
      */
@@ -89,35 +89,10 @@
         void onTaskStageChanged(int taskId, @StageType int stage, boolean visible);
     }
 
-    /** @return {@code true} if split-screen is currently visible. */
-    boolean isSplitScreenVisible();
-    /** Moves a task in the side-stage of split-screen. */
-    boolean moveToSideStage(int taskId, @StagePosition int sideStagePosition);
-    /** Moves a task in the side-stage of split-screen. */
-    boolean moveToSideStage(ActivityManager.RunningTaskInfo task,
-            @StagePosition int sideStagePosition);
-    /** Removes a task from the side-stage of split-screen. */
-    boolean removeFromSideStage(int taskId);
-    /** Sets the position of the side-stage. */
-    void setSideStagePosition(@StagePosition int sideStagePosition);
-    /** Hides the side-stage if it is currently visible. */
-    void setSideStageVisibility(boolean visible);
-
-    /** Removes the split-screen stages. */
-    void exitSplitScreen();
-    /** @param exitSplitScreenOnHide if to exit split-screen if both stages are not visible. */
-    void exitSplitScreenOnHide(boolean exitSplitScreenOnHide);
-    /** Gets the stage bounds. */
-    void getStageBounds(Rect outTopOrLeftBounds, Rect outBottomOrRightBounds);
-
-    void registerSplitScreenListener(SplitScreenListener listener);
-    void unregisterSplitScreenListener(SplitScreenListener listener);
-
-    void startTask(int taskId,
-            @StageType int stage, @StagePosition int position, @Nullable Bundle options);
-    void startShortcut(String packageName, String shortcutId, @StageType int stage,
-            @StagePosition int position, @Nullable Bundle options, UserHandle user);
-    void startIntent(PendingIntent intent, Context context,
-            @Nullable Intent fillInIntent, @StageType int stage,
-            @StagePosition int position, @Nullable Bundle options);
+    /**
+     * Returns a binder that can be passed to an external process to manipulate SplitScreen.
+     */
+    default ISplitScreen createExternalInterface() {
+        return null;
+    }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index bb6f6f2..d4362ef 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -18,6 +18,7 @@
 
 import static android.view.Display.DEFAULT_DISPLAY;
 
+import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
 import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_POSITION_BOTTOM_OR_RIGHT;
 import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_POSITION_TOP_OR_LEFT;
 import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_POSITION_UNDEFINED;
@@ -34,19 +35,24 @@
 import android.content.pm.LauncherApps;
 import android.graphics.Rect;
 import android.os.Bundle;
+import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.util.Slog;
 
+import androidx.annotation.BinderThread;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
 import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
 import com.android.wm.shell.ShellTaskOrganizer;
 import com.android.wm.shell.common.DisplayImeController;
+import com.android.wm.shell.common.RemoteCallable;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.SyncTransactionQueue;
+import com.android.wm.shell.common.annotations.ExternalThread;
 import com.android.wm.shell.draganddrop.DragAndDropPolicy;
+import com.android.wm.shell.splitscreen.ISplitScreenListener;
 
 import java.io.PrintWriter;
 
@@ -55,7 +61,8 @@
  * {@link SplitScreen}.
  * @see StageCoordinator
  */
-public class SplitScreenController implements DragAndDropPolicy.Starter {
+public class SplitScreenController implements DragAndDropPolicy.Starter,
+        RemoteCallable<SplitScreenController> {
     private static final String TAG = SplitScreenController.class.getSimpleName();
 
     private final ShellTaskOrganizer mTaskOrganizer;
@@ -84,6 +91,16 @@
         return mImpl;
     }
 
+    @Override
+    public Context getContext() {
+        return mContext;
+    }
+
+    @Override
+    public ShellExecutor getRemoteCallExecutor() {
+        return mMainExecutor;
+    }
+
     public void onOrganizerRegistered() {
         if (mStageCoordinator == null) {
             // TODO: Multi-display
@@ -172,13 +189,13 @@
         }
     }
 
-    public void startIntent(PendingIntent intent, Context context,
-            Intent fillInIntent, @SplitScreen.StageType int stage,
-            @SplitScreen.StagePosition int position, @Nullable Bundle options) {
+    public void startIntent(PendingIntent intent, Intent fillInIntent,
+            @SplitScreen.StageType int stage, @SplitScreen.StagePosition int position,
+            @Nullable Bundle options) {
         options = resolveStartStage(stage, position, options);
 
         try {
-            intent.send(context, 0, fillInIntent, null, null, null, options);
+            intent.send(mContext, 0, fillInIntent, null, null, null, options);
         } catch (PendingIntent.CanceledException e) {
             Slog.e(TAG, "Failed to launch activity", e);
         }
@@ -242,121 +259,170 @@
         }
     }
 
+    /**
+     * The interface for calls from outside the Shell, within the host process.
+     */
+    @ExternalThread
     private class SplitScreenImpl implements SplitScreen {
+        private ISplitScreenImpl mISplitScreen;
+
         @Override
-        public boolean isSplitScreenVisible() {
-            return mMainExecutor.executeBlockingForResult(() -> {
-                return SplitScreenController.this.isSplitScreenVisible();
-            }, Boolean.class);
+        public ISplitScreen createExternalInterface() {
+            if (mISplitScreen != null) {
+                mISplitScreen.invalidate();
+            }
+            mISplitScreen = new ISplitScreenImpl(SplitScreenController.this);
+            return mISplitScreen;
+        }
+    }
+
+    /**
+     * The interface for calls from outside the host process.
+     */
+    @BinderThread
+    private static class ISplitScreenImpl extends ISplitScreen.Stub {
+        private SplitScreenController mController;
+        private ISplitScreenListener mListener;
+        private final SplitScreen.SplitScreenListener mSplitScreenListener =
+                new SplitScreen.SplitScreenListener() {
+                    @Override
+                    public void onStagePositionChanged(int stage, int position) {
+                        try {
+                            if (mListener != null) {
+                                mListener.onStagePositionChanged(stage, position);
+                            }
+                        } catch (RemoteException e) {
+                            Slog.e(TAG, "onStagePositionChanged", e);
+                        }
+                    }
+
+                    @Override
+                    public void onTaskStageChanged(int taskId, int stage, boolean visible) {
+                        try {
+                            if (mListener != null) {
+                                mListener.onTaskStageChanged(taskId, stage, visible);
+                            }
+                        } catch (RemoteException e) {
+                            Slog.e(TAG, "onTaskStageChanged", e);
+                        }
+                    }
+                };
+        private final IBinder.DeathRecipient mListenerDeathRecipient =
+                new IBinder.DeathRecipient() {
+                    @Override
+                    @BinderThread
+                    public void binderDied() {
+                        final SplitScreenController controller = mController;
+                        controller.getRemoteCallExecutor().execute(() -> {
+                            mListener = null;
+                            controller.unregisterSplitScreenListener(mSplitScreenListener);
+                        });
+                    }
+                };
+
+        public ISplitScreenImpl(SplitScreenController controller) {
+            mController = controller;
+        }
+
+        /**
+         * Invalidates this instance, preventing future calls from updating the controller.
+         */
+        void invalidate() {
+            mController = null;
         }
 
         @Override
-        public boolean moveToSideStage(int taskId, int sideStagePosition) {
-            return mMainExecutor.executeBlockingForResult(() -> {
-                return SplitScreenController.this.moveToSideStage(taskId, sideStagePosition);
-            }, Boolean.class);
+        public void registerSplitScreenListener(ISplitScreenListener listener) {
+            executeRemoteCallWithTaskPermission(mController, "registerSplitScreenListener",
+                    (controller) -> {
+                        if (mListener != null) {
+                            mListener.asBinder().unlinkToDeath(mListenerDeathRecipient,
+                                    0 /* flags */);
+                        }
+                        if (listener != null) {
+                            try {
+                                listener.asBinder().linkToDeath(mListenerDeathRecipient,
+                                        0 /* flags */);
+                            } catch (RemoteException e) {
+                                Slog.e(TAG, "Failed to link to death");
+                                return;
+                            }
+                        }
+                        mListener = listener;
+                        controller.registerSplitScreenListener(mSplitScreenListener);
+                    });
         }
 
         @Override
-        public boolean moveToSideStage(ActivityManager.RunningTaskInfo task,
-                int sideStagePosition) {
-            return mMainExecutor.executeBlockingForResult(() -> {
-                return SplitScreenController.this.moveToSideStage(task, sideStagePosition);
-            }, Boolean.class);
-        }
-
-        @Override
-        public boolean removeFromSideStage(int taskId) {
-            return mMainExecutor.executeBlockingForResult(() -> {
-                return SplitScreenController.this.removeFromSideStage(taskId);
-            }, Boolean.class);
-        }
-
-        @Override
-        public void setSideStagePosition(int sideStagePosition) {
-            mMainExecutor.execute(() -> {
-                SplitScreenController.this.setSideStagePosition(sideStagePosition);
-            });
-        }
-
-        @Override
-        public void setSideStageVisibility(boolean visible) {
-            mMainExecutor.execute(() -> {
-                SplitScreenController.this.setSideStageVisibility(visible);
-            });
-        }
-
-        @Override
-        public void enterSplitScreen(int taskId, boolean leftOrTop) {
-            mMainExecutor.execute(() -> {
-                SplitScreenController.this.enterSplitScreen(taskId, leftOrTop);
-            });
+        public void unregisterSplitScreenListener(ISplitScreenListener listener) {
+            executeRemoteCallWithTaskPermission(mController, "unregisterSplitScreenListener",
+                    (controller) -> {
+                        if (mListener != null) {
+                            mListener.asBinder().unlinkToDeath(mListenerDeathRecipient,
+                                    0 /* flags */);
+                        }
+                        mListener = null;
+                        controller.unregisterSplitScreenListener(mSplitScreenListener);
+                    });
         }
 
         @Override
         public void exitSplitScreen() {
-            mMainExecutor.execute(() -> {
-                SplitScreenController.this.exitSplitScreen();
-            });
+            executeRemoteCallWithTaskPermission(mController, "exitSplitScreen",
+                    (controller) -> {
+                        controller.exitSplitScreen();
+                    });
         }
 
         @Override
         public void exitSplitScreenOnHide(boolean exitSplitScreenOnHide) {
-            mMainExecutor.execute(() -> {
-                SplitScreenController.this.exitSplitScreenOnHide(exitSplitScreenOnHide);
-            });
+            executeRemoteCallWithTaskPermission(mController, "exitSplitScreenOnHide",
+                    (controller) -> {
+                        controller.exitSplitScreenOnHide(exitSplitScreenOnHide);
+                    });
         }
 
         @Override
-        public void getStageBounds(Rect outTopOrLeftBounds, Rect outBottomOrRightBounds) {
-            try {
-                mMainExecutor.executeBlocking(() -> {
-                    SplitScreenController.this.getStageBounds(outTopOrLeftBounds,
-                            outBottomOrRightBounds);
-                });
-            } catch (InterruptedException e) {
-                Slog.e(TAG, "Failed to get stage bounds in 2s");
-            }
+        public void setSideStageVisibility(boolean visible) {
+            executeRemoteCallWithTaskPermission(mController, "setSideStageVisibility",
+                    (controller) -> {
+                        controller.setSideStageVisibility(visible);
+                    });
         }
 
         @Override
-        public void registerSplitScreenListener(SplitScreenListener listener) {
-            mMainExecutor.execute(() -> {
-                SplitScreenController.this.registerSplitScreenListener(listener);
-            });
-        }
-
-        @Override
-        public void unregisterSplitScreenListener(SplitScreenListener listener) {
-            mMainExecutor.execute(() -> {
-                SplitScreenController.this.unregisterSplitScreenListener(listener);
-            });
+        public void removeFromSideStage(int taskId) {
+            executeRemoteCallWithTaskPermission(mController, "removeFromSideStage",
+                    (controller) -> {
+                        controller.removeFromSideStage(taskId);
+                    });
         }
 
         @Override
         public void startTask(int taskId, int stage, int position, @Nullable Bundle options) {
-            mMainExecutor.execute(() -> {
-                SplitScreenController.this.startTask(taskId, stage, position, options);
-            });
+            executeRemoteCallWithTaskPermission(mController, "startTask",
+                    (controller) -> {
+                        controller.startTask(taskId, stage, position, options);
+                    });
         }
 
         @Override
         public void startShortcut(String packageName, String shortcutId, int stage, int position,
                 @Nullable Bundle options, UserHandle user) {
-            mMainExecutor.execute(() -> {
-                SplitScreenController.this.startShortcut(packageName, shortcutId, stage, position,
-                        options, user);
-            });
+            executeRemoteCallWithTaskPermission(mController, "startShortcut",
+                    (controller) -> {
+                        controller.startShortcut(packageName, shortcutId, stage, position,
+                                options, user);
+                    });
         }
 
         @Override
-        public void startIntent(PendingIntent intent, Context context, Intent fillInIntent,
-                int stage, int position, @Nullable Bundle options) {
-            mMainExecutor.execute(() -> {
-                SplitScreenController.this.startIntent(intent, context, fillInIntent, stage,
-                        position, options);
-            });
+        public void startIntent(PendingIntent intent, Intent fillInIntent, int stage, int position,
+                @Nullable Bundle options) {
+            executeRemoteCallWithTaskPermission(mController, "startIntent",
+                    (controller) -> {
+                        controller.startIntent(intent, fillInIntent, stage, position, options);
+                    });
         }
     }
-
 }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISplitScreenListener.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/IStartingWindow.aidl
similarity index 62%
copy from packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISplitScreenListener.aidl
copy to libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/IStartingWindow.aidl
index 54242be..546c406 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISplitScreenListener.aidl
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/IStartingWindow.aidl
@@ -14,12 +14,16 @@
  * limitations under the License.
  */
 
-package com.android.systemui.shared.recents;
+package com.android.wm.shell.startingsurface;
+
+import com.android.wm.shell.startingsurface.IStartingWindowListener;
 
 /**
- * Listener interface that Launcher attaches to SystemUI to get split-screen callbacks.
+ * Interface that is exposed to remote callers to manipulate starting windows.
  */
-oneway interface ISplitScreenListener {
-    void onStagePositionChanged(int stage, int position);
-    void onTaskStageChanged(int taskId, int stage, boolean visible);
+interface IStartingWindow {
+    /**
+     * Sets listener to get task launching callbacks.
+     */
+    oneway void setStartingWindowListener(IStartingWindowListener listener) = 43;
 }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IStartingWindowListener.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/IStartingWindowListener.aidl
similarity index 90%
rename from packages/SystemUI/shared/src/com/android/systemui/shared/recents/IStartingWindowListener.aidl
rename to libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/IStartingWindowListener.aidl
index eb3e60c..f562c8f 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IStartingWindowListener.aidl
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/IStartingWindowListener.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.
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.shared.recents;
+package com.android.wm.shell.startingsurface;
 
 /**
  * Listener interface that Launcher attaches to SystemUI to get
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimation.java
new file mode 100644
index 0000000..5bc2afd
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimation.java
@@ -0,0 +1,328 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.wm.shell.startingsurface;
+
+import static android.view.View.GONE;
+
+import android.animation.Animator;
+import android.animation.ValueAnimator;
+import android.graphics.BlendMode;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.Point;
+import android.graphics.RadialGradient;
+import android.graphics.Rect;
+import android.graphics.Shader;
+import android.util.Slog;
+import android.view.SurfaceControl;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.view.animation.AlphaAnimation;
+import android.view.animation.Animation;
+import android.view.animation.AnimationSet;
+import android.view.animation.Interpolator;
+import android.view.animation.PathInterpolator;
+import android.view.animation.Transformation;
+import android.view.animation.TranslateYAnimation;
+import android.window.SplashScreenView;
+
+import com.android.wm.shell.common.TransactionPool;
+
+/**
+ * Default animation for exiting the splash screen window.
+ * @hide
+ */
+public class SplashScreenExitAnimation implements Animator.AnimatorListener {
+    private static final boolean DEBUG_EXIT_ANIMATION = false;
+    private static final boolean DEBUG_EXIT_ANIMATION_BLEND = false;
+    private static final String TAG = StartingSurfaceDrawer.TAG;
+
+    private static final Interpolator ICON_EXIT_INTERPOLATOR = new PathInterpolator(1f, 0f, 1f, 1f);
+    private static final Interpolator APP_EXIT_INTERPOLATOR = new PathInterpolator(0f, 0f, 0f, 1f);
+
+    private static final int EXTRA_REVEAL_DELAY = 133;
+    private final Matrix mTmpTransform = new Matrix();
+    private final float[] mTmpFloat9 = new float[9];
+    private SurfaceControl mFirstWindowSurface;
+    private final Rect mFirstWindowFrame = new Rect();
+    private final SplashScreenView mSplashScreenView;
+    private final int mMainWindowShiftLength;
+    private final int mIconShiftLength;
+    private final int mAppDuration;
+    private final int mIconDuration;
+    private final TransactionPool mTransactionPool;
+
+    private ValueAnimator mMainAnimator;
+    private Animation mShiftUpAnimation;
+    private AnimationSet mIconAnimationSet;
+    private Runnable mFinishCallback;
+
+    SplashScreenExitAnimation(SplashScreenView view, SurfaceControl leash, Rect frame,
+            int appDuration, int iconDuration, int mainWindowShiftLength, int iconShiftLength,
+            TransactionPool pool, Runnable handleFinish) {
+        mSplashScreenView = view;
+        mFirstWindowSurface = leash;
+        if (frame != null) {
+            mFirstWindowFrame.set(frame);
+        }
+        mAppDuration = appDuration;
+        mIconDuration = iconDuration;
+        mMainWindowShiftLength = mainWindowShiftLength;
+        mIconShiftLength = iconShiftLength;
+        mFinishCallback = handleFinish;
+        mTransactionPool = pool;
+    }
+
+    void prepareAnimations() {
+        prepareRevealAnimation();
+        prepareShiftAnimation();
+    }
+
+    void startAnimations() {
+        if (mIconAnimationSet != null) {
+            mIconAnimationSet.start();
+        }
+        if (mMainAnimator != null) {
+            mMainAnimator.start();
+        }
+        if (mShiftUpAnimation != null) {
+            mShiftUpAnimation.start();
+        }
+    }
+
+    // reveal splash screen, shift up main window
+    private void prepareRevealAnimation() {
+        // splash screen
+        mMainAnimator = ValueAnimator.ofFloat(0f, 1f);
+        mMainAnimator.setDuration(mAppDuration);
+        mMainAnimator.setInterpolator(APP_EXIT_INTERPOLATOR);
+        mMainAnimator.addListener(this);
+
+        final int startDelay = mIconDuration + EXTRA_REVEAL_DELAY;
+        final float transparentRatio = 0.95f;
+        final int globalHeight = mSplashScreenView.getHeight();
+        final int verticalCircleCenter = 0;
+        final int finalVerticalLength = globalHeight - verticalCircleCenter;
+        final int halfWidth = mSplashScreenView.getWidth() / 2;
+        final int endRadius = (int) (0.5 + (1f / transparentRatio * (int)
+                Math.sqrt(finalVerticalLength * finalVerticalLength + halfWidth * halfWidth)));
+        final RadialVanishAnimation radialVanishAnimation = new RadialVanishAnimation(
+                mSplashScreenView, mMainAnimator);
+        radialVanishAnimation.setCircleCenter(halfWidth, verticalCircleCenter);
+        radialVanishAnimation.setRadius(0/* initRadius */, endRadius);
+        final int[] colors = {Color.TRANSPARENT, Color.TRANSPARENT, Color.WHITE};
+        final float[] stops = {0f, transparentRatio, 1f};
+        radialVanishAnimation.setRadialPaintParam(colors, stops);
+        radialVanishAnimation.setReady();
+        mMainAnimator.setStartDelay(startDelay);
+
+        if (mFirstWindowSurface != null) {
+            // shift up main window
+            View occludeHoleView = new View(mSplashScreenView.getContext());
+            if (DEBUG_EXIT_ANIMATION_BLEND) {
+                occludeHoleView.setBackgroundColor(Color.BLUE);
+            } else {
+                occludeHoleView.setBackgroundColor(mSplashScreenView.getInitBackgroundColor());
+            }
+            final ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(
+                    WindowManager.LayoutParams.MATCH_PARENT, mMainWindowShiftLength);
+            mSplashScreenView.addView(occludeHoleView, params);
+
+            mShiftUpAnimation = new ShiftUpAnimation(0, -mMainWindowShiftLength);
+            mShiftUpAnimation.setDuration(mAppDuration);
+            mShiftUpAnimation.setInterpolator(APP_EXIT_INTERPOLATOR);
+            mShiftUpAnimation.setStartOffset(startDelay);
+
+            occludeHoleView.setAnimation(mShiftUpAnimation);
+        }
+    }
+
+    // shift down icon and branding view
+    private void prepareShiftAnimation() {
+        final View iconView = mSplashScreenView.getIconView();
+        if (iconView == null) {
+            return;
+        }
+        if (mIconShiftLength > 0) {
+            mIconAnimationSet = new AnimationSet(true /* shareInterpolator */);
+            if (DEBUG_EXIT_ANIMATION) {
+                Slog.v(TAG, "first exit animation, shift length: " + mIconShiftLength);
+            }
+            mIconAnimationSet.addAnimation(new TranslateYAnimation(0, mIconShiftLength));
+            mIconAnimationSet.addAnimation(new AlphaAnimation(1, 0));
+            mIconAnimationSet.setAnimationListener(new Animation.AnimationListener() {
+                @Override
+                public void onAnimationStart(Animation animation) {
+
+                }
+
+                @Override
+                public void onAnimationEnd(Animation animation) {
+                    if (DEBUG_EXIT_ANIMATION) {
+                        Slog.v(TAG, "first exit animation finished");
+                    }
+                    iconView.post(() -> iconView.setVisibility(GONE));
+                }
+
+                @Override
+                public void onAnimationRepeat(Animation animation) {
+                    // ignore
+                }
+            });
+            mIconAnimationSet.setDuration(mIconDuration);
+            mIconAnimationSet.setInterpolator(ICON_EXIT_INTERPOLATOR);
+            iconView.setAnimation(mIconAnimationSet);
+            final View brandingView = mSplashScreenView.getBrandingView();
+            if (brandingView != null) {
+                brandingView.setAnimation(mIconAnimationSet);
+            }
+        }
+    }
+
+    private static class RadialVanishAnimation extends View {
+        private SplashScreenView mView;
+        private int mInitRadius;
+        private int mFinishRadius;
+        private boolean mReady;
+
+        private final Point mCircleCenter = new Point();
+        private final Matrix mVanishMatrix = new Matrix();
+        private final Paint mVanishPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+
+        RadialVanishAnimation(SplashScreenView target, ValueAnimator animator) {
+            super(target.getContext());
+            mView = target;
+            animator.addUpdateListener((animation) -> {
+                if (mVanishPaint.getShader() == null) {
+                    return;
+                }
+                final float value = (float) animation.getAnimatedValue();
+                final float scale = (mFinishRadius - mInitRadius) * value + mInitRadius;
+                mVanishMatrix.setScale(scale, scale);
+                mVanishMatrix.postTranslate(mCircleCenter.x, mCircleCenter.y);
+                mVanishPaint.getShader().setLocalMatrix(mVanishMatrix);
+                mView.postInvalidate();
+            });
+            mView.addView(this);
+        }
+
+        void setRadius(int initRadius, int finishRadius) {
+            if (DEBUG_EXIT_ANIMATION) {
+                Slog.v(TAG, "RadialVanishAnimation setRadius init: " + initRadius
+                        + " final " + finishRadius);
+            }
+            mInitRadius = initRadius;
+            mFinishRadius = finishRadius;
+        }
+
+        void setCircleCenter(int x, int y) {
+            if (DEBUG_EXIT_ANIMATION) {
+                Slog.v(TAG, "RadialVanishAnimation setCircleCenter x: " + x + " y " + y);
+            }
+            mCircleCenter.set(x, y);
+        }
+
+        void setRadialPaintParam(int[] colors, float[] stops) {
+            // setup gradient shader
+            final RadialGradient rShader =
+                    new RadialGradient(0, 0, 1, colors, stops, Shader.TileMode.CLAMP);
+            mVanishPaint.setShader(rShader);
+            if (!DEBUG_EXIT_ANIMATION_BLEND) {
+                mVanishPaint.setBlendMode(BlendMode.MODULATE);
+            }
+        }
+
+        void setReady() {
+            mReady = true;
+        }
+
+        @Override
+        protected void onDraw(Canvas canvas) {
+            super.onDraw(canvas);
+            if (mReady) {
+                canvas.drawRect(0, 0, mView.getWidth(), mView.getHeight(), mVanishPaint);
+            }
+        }
+    }
+
+    private final class ShiftUpAnimation extends TranslateYAnimation {
+        ShiftUpAnimation(float fromYDelta, float toYDelta) {
+            super(fromYDelta, toYDelta);
+        }
+
+        @Override
+        protected void applyTransformation(float interpolatedTime, Transformation t) {
+            super.applyTransformation(interpolatedTime, t);
+
+            if (mFirstWindowSurface == null) {
+                return;
+            }
+            mTmpTransform.set(t.getMatrix());
+            final SurfaceControl.Transaction tx = mTransactionPool.acquire();
+            mTmpTransform.postTranslate(mFirstWindowFrame.left,
+                    mFirstWindowFrame.top + mMainWindowShiftLength);
+            tx.setMatrix(mFirstWindowSurface, mTmpTransform, mTmpFloat9);
+            // TODO set the vsyncId to ensure the transaction doesn't get applied too early.
+            //  Additionally, do you want to have this synchronized with your view animations?
+            //  If so, you'll need to use SyncRtSurfaceTransactionApplier
+            tx.apply();
+            mTransactionPool.release(tx);
+        }
+    }
+
+    private void reset() {
+        if (DEBUG_EXIT_ANIMATION) {
+            Slog.v(TAG, "vanish animation finished");
+        }
+        mSplashScreenView.post(() -> {
+            mSplashScreenView.setVisibility(GONE);
+            if (mFinishCallback != null) {
+                mFinishCallback.run();
+                mFinishCallback = null;
+            }
+        });
+        if (mFirstWindowSurface != null) {
+            final SurfaceControl.Transaction tx = mTransactionPool.acquire();
+            tx.setWindowCrop(mFirstWindowSurface, null);
+            tx.apply();
+            mFirstWindowSurface.release();
+            mFirstWindowSurface = null;
+        }
+    }
+
+    @Override
+    public void onAnimationStart(Animator animation) {
+        // ignore
+    }
+
+    @Override
+    public void onAnimationEnd(Animator animation) {
+        reset();
+    }
+
+    @Override
+    public void onAnimationCancel(Animator animation) {
+        reset();
+    }
+
+    @Override
+    public void onAnimationRepeat(Animator animation) {
+        // ignore
+    }
+}
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 2973b50..3f9c271 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,12 +31,14 @@
 import android.graphics.drawable.LayerDrawable;
 import android.os.Build;
 import android.util.Slog;
+import android.view.SurfaceControl;
 import android.window.SplashScreenView;
 
 import com.android.internal.R;
 import com.android.internal.graphics.palette.Palette;
 import com.android.internal.graphics.palette.Quantizer;
 import com.android.internal.graphics.palette.VariationalKMeansQuantizer;
+import com.android.wm.shell.common.TransactionPool;
 
 import java.util.List;
 
@@ -56,15 +58,25 @@
     // also 108*108 pixels, then do not enlarge this icon if only need to show foreground icon.
     private static final float ENLARGE_FOREGROUND_ICON_THRESHOLD = (72f * 72f) / (108f * 108f);
     private final Context mContext;
-    private final int mMaxIconAnimationDuration;
+    private final int mMaxAnimatableIconDuration;
 
     private int mIconSize;
     private int mBrandingImageWidth;
     private int mBrandingImageHeight;
+    private final int mAppRevealDuration;
+    private final int mIconExitDuration;
+    private int mMainWindowShiftLength;
+    private int mIconNormalExitDistance;
+    private int mIconEarlyExitDistance;
+    private final TransactionPool mTransactionPool;
 
-    SplashscreenContentDrawer(Context context, int maxIconAnimationDuration) {
+    SplashscreenContentDrawer(Context context, int maxAnimatableIconDuration,
+            int iconExitAnimDuration, int appRevealAnimDuration, TransactionPool pool) {
         mContext = context;
-        mMaxIconAnimationDuration = maxIconAnimationDuration;
+        mMaxAnimatableIconDuration = maxAnimatableIconDuration;
+        mAppRevealDuration = appRevealAnimDuration;
+        mIconExitDuration = iconExitAnimDuration;
+        mTransactionPool = pool;
     }
 
     private void updateDensity() {
@@ -74,6 +86,12 @@
                 com.android.wm.shell.R.dimen.starting_surface_brand_image_width);
         mBrandingImageHeight = mContext.getResources().getDimensionPixelSize(
                 com.android.wm.shell.R.dimen.starting_surface_brand_image_height);
+        mMainWindowShiftLength = mContext.getResources().getDimensionPixelSize(
+                com.android.wm.shell.R.dimen.starting_surface_exit_animation_window_shift_length);
+        mIconNormalExitDistance = mContext.getResources().getDimensionPixelSize(
+                com.android.wm.shell.R.dimen.starting_surface_normal_exit_icon_distance);
+        mIconEarlyExitDistance = mContext.getResources().getDimensionPixelSize(
+                com.android.wm.shell.R.dimen.starting_surface_early_exit_icon_distance);
     }
 
     private int getSystemBGColor() {
@@ -119,7 +137,7 @@
         if (attrs.mReplaceIcon != null) {
             iconDrawable = attrs.mReplaceIcon;
             animationDuration = Math.max(0,
-                    Math.min(attrs.mAnimationDuration, mMaxIconAnimationDuration));
+                    Math.min(attrs.mAnimationDuration, mMaxAnimatableIconDuration));
         } else {
             iconDrawable = iconRes != 0 ? context.getDrawable(iconRes)
                     : context.getPackageManager().getDefaultActivityIcon();
@@ -439,8 +457,8 @@
         }
 
         /**
-         * For ColorDrawable only.
-         * There will be only one color so don't spend too much resource for it.
+         * For ColorDrawable only. There will be only one color so don't spend too much resource for
+         * it.
          */
         private static class SingleColorTester implements ColorTester {
             private final ColorDrawable mColorDrawable;
@@ -472,9 +490,8 @@
         }
 
         /**
-         * For any other Drawable except ColorDrawable.
-         * This will use the Palette API to check the color information and use a quantizer to
-         * filter out transparent colors when needed.
+         * For any other Drawable except ColorDrawable. This will use the Palette API to check the
+         * color information and use a quantizer to filter out transparent colors when needed.
          */
         private static class ComplexDrawableTester implements ColorTester {
             private static final int MAX_BITMAP_SIZE = 40;
@@ -593,4 +610,17 @@
             }
         }
     }
+
+    /**
+     * Create and play the default exit animation for splash screen view.
+     */
+    void applyExitAnimation(SplashScreenView view, SurfaceControl leash,
+            Rect frame, boolean isEarlyExit, Runnable finishCallback) {
+        final SplashScreenExitAnimation animation = new SplashScreenExitAnimation(view, leash,
+                frame, mAppRevealDuration, mIconExitDuration, mMainWindowShiftLength,
+                isEarlyExit ? mIconEarlyExitDistance : mIconNormalExitDistance, mTransactionPool,
+                finishCallback);
+        animation.prepareAnimations();
+        animation.startAnimations();
+    }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurface.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurface.java
index a594a9f..079d689 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurface.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurface.java
@@ -16,32 +16,15 @@
 
 package com.android.wm.shell.startingsurface;
 
-import android.os.IBinder;
-import android.window.StartingWindowInfo;
-
-import java.util.function.BiConsumer;
 /**
  * Interface to engage starting window feature.
  */
 public interface StartingSurface {
-    /**
-     * Called when a task need a starting window.
-     */
-    void addStartingWindow(StartingWindowInfo windowInfo, IBinder appToken);
-    /**
-     * Called when the content of a task is ready to show, starting window can be removed.
-     */
-    void removeStartingWindow(int taskId);
-    /**
-     * Called when the Task wants to copy the splash screen.
-     * @param taskId
-     */
-    void copySplashScreenView(int taskId);
 
     /**
-     * Registers the starting window listener.
-     *
-     * @param listener The callback when need a starting window.
+     * Returns a binder that can be passed to an external process to manipulate starting windows.
      */
-    void setStartingWindowListener(BiConsumer<Integer, Integer> listener);
+    default IStartingWindow createExternalInterface() {
+        return null;
+    }
 }
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 2d1d65b..14fbaac 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
@@ -29,14 +29,18 @@
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
+import android.graphics.Color;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.drawable.ColorDrawable;
 import android.hardware.display.DisplayManager;
 import android.os.IBinder;
+import android.os.SystemClock;
 import android.util.Slog;
 import android.util.SparseArray;
-import android.view.Choreographer;
 import android.view.Display;
+import android.view.SurfaceControl;
 import android.view.View;
-import android.view.Window;
 import android.view.WindowManager;
 import android.window.SplashScreenView;
 import android.window.SplashScreenView.SplashScreenViewParcelable;
@@ -46,6 +50,7 @@
 import com.android.internal.R;
 import com.android.internal.policy.PhoneWindow;
 import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.common.TransactionPool;
 
 import java.util.function.Consumer;
 
@@ -62,23 +67,23 @@
     private final DisplayManager mDisplayManager;
     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 splashScreenExecutor) {
+    public StartingSurfaceDrawer(Context context, ShellExecutor splashScreenExecutor,
+            TransactionPool pool) {
         mContext = context;
         mDisplayManager = mContext.getSystemService(DisplayManager.class);
         mSplashScreenExecutor = splashScreenExecutor;
-        final int maxIconAnimDuration = context.getResources().getInteger(
+        final int maxAnimatableIconDuration = 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();
+        final int iconExitAnimDuration = context.getResources().getInteger(
+                com.android.wm.shell.R.integer.starting_window_icon_exit_anim_duration);
+        final int appRevealAnimDuration = context.getResources().getInteger(
+                com.android.wm.shell.R.integer.starting_window_app_reveal_anim_duration);
+        mSplashscreenContentDrawer = new SplashscreenContentDrawer(mContext,
+                maxAnimatableIconDuration, iconExitAnimDuration, appRevealAnimDuration, pool);
     }
 
     private final SparseArray<StartingWindowRecord> mStartingWindowRecords = new SparseArray<>();
@@ -195,6 +200,7 @@
         }
 
         final PhoneWindow win = new PhoneWindow(context);
+        win.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
         win.setIsStartingWindow(true);
 
         CharSequence label = context.getResources().getText(labelRes, null);
@@ -211,7 +217,7 @@
         // the keyguard is being hidden. This is okay because starting windows never show
         // secret information.
         // TODO(b/113840485): Occluded may not only happen on default display
-        if (displayId == DEFAULT_DISPLAY) {
+        if (displayId == DEFAULT_DISPLAY && windowInfo.isKeyguardOccluded) {
             windowFlags |= WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
         }
 
@@ -247,6 +253,7 @@
         // Setting as trusted overlay to let touches pass through. This is safe because this
         // window is controlled by the system.
         params.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
+        params.format = PixelFormat.RGBA_8888;
 
         final Resources res = context.getResources();
         final boolean supportsScreen = res != null && (res.getCompatibilityInfo() != null
@@ -257,98 +264,25 @@
 
         params.setTitle("Splash Screen " + activityInfo.packageName);
 
-        // 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;
-        }
-
-        private void createInitialView() {
-            View tempView = new View(mContext);
-            mWin.setContentView(tempView);
-            mSequence++;
-            final View view = mWin.getDecorView();
+        // TODO(b/173975965) tracking performance
+        final int taskId = taskInfo.taskId;
+        SplashScreenView sView = null;
+        try {
+            sView = mSplashscreenContentDrawer.makeSplashScreenContentView(context, iconRes,
+                            splashscreenContentResId[0]);
+            final View view = win.getDecorView();
             final WindowManager wm = mContext.getSystemService(WindowManager.class);
-            if (postAddWindow(mTaskId, mAppToken, view, wm, mLayoutParams)) {
-                mChoreographer.postCallback(Choreographer.CALLBACK_COMMIT, this, null);
+            if (postAddWindow(taskId, appToken, view, wm, params)) {
+                win.setContentView(sView);
+                sView.cacheRootWindow(win);
             }
-        }
-
-        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);
-                }
-            }
+        } 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 {
+            setSplashScreenRecord(taskId, sView);
         }
     }
 
@@ -359,8 +293,10 @@
             TaskSnapshot snapshot) {
         final int taskId = startingWindowInfo.taskInfo.taskId;
         final TaskSnapshotWindow surface = TaskSnapshotWindow.create(startingWindowInfo, appToken,
-                snapshot, mSplashScreenExecutor, () -> removeWindowSynced(taskId));
-        mSplashScreenExecutor.executeDelayed(() -> removeWindowSynced(taskId), REMOVE_WHEN_TIMEOUT);
+                snapshot, mSplashScreenExecutor,
+                () -> removeWindowNoAnimate(taskId));
+        mSplashScreenExecutor.executeDelayed(() -> removeWindowNoAnimate(taskId),
+                REMOVE_WHEN_TIMEOUT);
         final StartingWindowRecord tView =
                 new StartingWindowRecord(null/* decorView */, surface);
         mStartingWindowRecords.put(taskId, tView);
@@ -369,11 +305,12 @@
     /**
      * Called when the content of a task is ready to show, starting window can be removed.
      */
-    public void removeStartingWindow(int taskId) {
+    public void removeStartingWindow(int taskId, SurfaceControl leash, Rect frame,
+            boolean playRevealAnimation) {
         if (DEBUG_SPLASH_SCREEN || DEBUG_TASK_SNAPSHOT) {
             Slog.d(TAG, "Task start finish, remove starting surface for task " + taskId);
         }
-        removeWindowSynced(taskId);
+        removeWindowSynced(taskId, leash, frame, playRevealAnimation);
     }
 
     /**
@@ -383,13 +320,6 @@
     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);
@@ -413,12 +343,6 @@
             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");
@@ -427,9 +351,9 @@
             }
         }
         if (shouldSaveView) {
-            removeWindowSynced(taskId);
-            mSplashScreenExecutor.executeDelayed(() -> removeWindowSynced(taskId),
-                    REMOVE_WHEN_TIMEOUT);
+            removeWindowNoAnimate(taskId);
+            mSplashScreenExecutor.executeDelayed(
+                    () -> removeWindowNoAnimate(taskId), REMOVE_WHEN_TIMEOUT);
             saveSplashScreenRecord(taskId, view);
         }
         return shouldSaveView;
@@ -449,24 +373,30 @@
         }
     }
 
-    protected void removeWindowSynced(int taskId) {
+    private void removeWindowNoAnimate(int taskId) {
+        removeWindowSynced(taskId, null, null, false);
+    }
+
+    protected void removeWindowSynced(int taskId, SurfaceControl leash, Rect frame,
+            boolean playRevealAnimation) {
         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);
                 }
-                final WindowManager wm = record.mDecorView.getContext()
-                        .getSystemService(WindowManager.class);
-                wm.removeView(record.mDecorView);
+                if (record.mContentView != null) {
+                    final HandleExitFinish exitFinish = new HandleExitFinish(record.mDecorView);
+                    if (leash != null || playRevealAnimation) {
+                        mSplashscreenContentDrawer.applyExitAnimation(record.mContentView,
+                                leash, frame, record.isEarlyExit(), exitFinish);
+                        mSplashScreenExecutor.executeDelayed(exitFinish, REMOVE_WHEN_TIMEOUT);
+                    } else {
+                        // the SplashScreenView has been copied to client, skip default exit
+                        // animation
+                        exitFinish.run();
+                    }
+                }
             }
             if (record.mTaskSnapshotWindow != null) {
                 if (DEBUG_TASK_SNAPSHOT) {
@@ -478,6 +408,26 @@
         }
     }
 
+    private static class HandleExitFinish implements Runnable {
+        private View mDecorView;
+
+        HandleExitFinish(View decorView) {
+            mDecorView = decorView;
+        }
+
+        @Override
+        public void run() {
+            if (mDecorView == null) {
+                return;
+            }
+            final WindowManager wm = mDecorView.getContext().getSystemService(WindowManager.class);
+            if (wm != null) {
+                wm.removeView(mDecorView);
+            }
+            mDecorView = null;
+        }
+    }
+
     private void getWindowResFromContext(Context ctx, Consumer<TypedArray> consumer) {
         final TypedArray a = ctx.obtainStyledAttributes(R.styleable.Window);
         consumer.accept(a);
@@ -488,10 +438,12 @@
      * Record the view or surface for a starting window.
      */
     private static class StartingWindowRecord {
+        private static final long EARLY_START_MINIMUM_TIME_MS = 250;
         private final View mDecorView;
         private final TaskSnapshotWindow mTaskSnapshotWindow;
         private SplashScreenView mContentView;
         private boolean mSetSplashScreen;
+        private long mContentCreateTime;
 
         StartingWindowRecord(View decorView, TaskSnapshotWindow taskSnapshotWindow) {
             mDecorView = decorView;
@@ -503,11 +455,12 @@
                 return;
             }
             mContentView = splashScreenView;
+            mContentCreateTime = SystemClock.uptimeMillis();
             mSetSplashScreen = true;
         }
 
-        private boolean isWaitForContent() {
-            return mDecorView != null && !mSetSplashScreen;
+        boolean isEarlyExit() {
+            return SystemClock.uptimeMillis() - mContentCreateTime < EARLY_START_MINIMUM_TIME_MS;
         }
     }
 }
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 5eb7071..b6ca869 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
@@ -25,17 +25,25 @@
 import static android.window.StartingWindowInfo.TYPE_PARAMETER_PROCESS_RUNNING;
 import static android.window.StartingWindowInfo.TYPE_PARAMETER_TASK_SWITCH;
 
+import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
+
 import android.app.ActivityManager.RunningTaskInfo;
 import android.app.ActivityTaskManager;
 import android.content.Context;
+import android.graphics.Rect;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.util.Slog;
+import android.view.SurfaceControl;
 import android.window.StartingWindowInfo;
 import android.window.TaskOrganizer;
 import android.window.TaskSnapshot;
 
+import androidx.annotation.BinderThread;
+
+import com.android.wm.shell.common.RemoteCallable;
 import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.common.TransactionPool;
 
 import java.util.function.BiConsumer;
 
@@ -55,7 +63,7 @@
  * constructor to keep everything synchronized.
  * @hide
  */
-public class StartingWindowController {
+public class StartingWindowController implements RemoteCallable<StartingWindowController> {
     private static final String TAG = StartingWindowController.class.getSimpleName();
     static final boolean DEBUG_SPLASH_SCREEN = false;
     static final boolean DEBUG_TASK_SNAPSHOT = false;
@@ -65,10 +73,18 @@
 
     private BiConsumer<Integer, Integer> mTaskLaunchingCallback;
     private final StartingSurfaceImpl mImpl = new StartingSurfaceImpl();
+    private final Context mContext;
     private final ShellExecutor mSplashScreenExecutor;
 
+    // For Car Launcher
     public StartingWindowController(Context context, ShellExecutor splashScreenExecutor) {
-        mStartingSurfaceDrawer = new StartingSurfaceDrawer(context, splashScreenExecutor);
+        this(context, splashScreenExecutor, new TransactionPool());
+    }
+
+    public StartingWindowController(Context context, ShellExecutor splashScreenExecutor,
+            TransactionPool pool) {
+        mContext = context;
+        mStartingSurfaceDrawer = new StartingSurfaceDrawer(context, splashScreenExecutor, pool);
         mSplashScreenExecutor = splashScreenExecutor;
     }
 
@@ -79,6 +95,16 @@
         return mImpl;
     }
 
+    @Override
+    public Context getContext() {
+        return mContext;
+    }
+
+    @Override
+    public ShellExecutor getRemoteCallExecutor() {
+        return mSplashScreenExecutor;
+    }
+
     private static class StartingTypeChecker {
         TaskSnapshot mSnapshot;
 
@@ -112,7 +138,8 @@
                         + " allowTaskSnapshot " + allowTaskSnapshot
                         + " activityCreated " + activityCreated);
             }
-            if (newTask || !processRunning || (taskSwitch && !activityCreated)) {
+            if ((newTask || !processRunning || (taskSwitch && !activityCreated))
+                    && windowInfo.taskInfo.topActivityType != ACTIVITY_TYPE_HOME) {
                 return STARTING_WINDOW_TYPE_SPLASH_SCREEN;
             }
             if (taskSwitch && allowTaskSnapshot) {
@@ -176,56 +203,121 @@
     /**
      * Called when a task need a starting window.
      */
-    void addStartingWindow(StartingWindowInfo windowInfo, IBinder appToken) {
-        final int suggestionType = mStartingTypeChecker.estimateStartingWindowType(windowInfo);
-        final RunningTaskInfo runningTaskInfo = windowInfo.taskInfo;
-        if (mTaskLaunchingCallback != null) {
-            mTaskLaunchingCallback.accept(runningTaskInfo.taskId, suggestionType);
-        }
-        if (suggestionType == STARTING_WINDOW_TYPE_SPLASH_SCREEN) {
-            mStartingSurfaceDrawer.addSplashScreenStartingWindow(windowInfo, appToken);
-        } else if (suggestionType == STARTING_WINDOW_TYPE_SNAPSHOT) {
-            final TaskSnapshot snapshot = mStartingTypeChecker.mSnapshot;
-            mStartingSurfaceDrawer.makeTaskSnapshotWindow(windowInfo, appToken, snapshot);
-        }
-        // If prefer don't show, then don't show!
+    public void addStartingWindow(StartingWindowInfo windowInfo, IBinder appToken) {
+        mSplashScreenExecutor.execute(() -> {
+            final int suggestionType = mStartingTypeChecker.estimateStartingWindowType(windowInfo);
+            final RunningTaskInfo runningTaskInfo = windowInfo.taskInfo;
+            if (mTaskLaunchingCallback != null) {
+                mTaskLaunchingCallback.accept(runningTaskInfo.taskId, suggestionType);
+            }
+            if (suggestionType == STARTING_WINDOW_TYPE_SPLASH_SCREEN) {
+                mStartingSurfaceDrawer.addSplashScreenStartingWindow(windowInfo, appToken);
+            } else if (suggestionType == STARTING_WINDOW_TYPE_SNAPSHOT) {
+                final TaskSnapshot snapshot = mStartingTypeChecker.mSnapshot;
+                mStartingSurfaceDrawer.makeTaskSnapshotWindow(windowInfo, appToken, snapshot);
+            }
+            // If prefer don't show, then don't show!
+        });
     }
 
-    void copySplashScreenView(int taskId) {
-        mStartingSurfaceDrawer.copySplashScreenView(taskId);
+    public void copySplashScreenView(int taskId) {
+        mSplashScreenExecutor.execute(() -> {
+            mStartingSurfaceDrawer.copySplashScreenView(taskId);
+        });
     }
 
     /**
      * Called when the content of a task is ready to show, starting window can be removed.
      */
-    void removeStartingWindow(int taskId) {
-        mStartingSurfaceDrawer.removeStartingWindow(taskId);
+    public void removeStartingWindow(int taskId, SurfaceControl leash, Rect frame,
+            boolean playRevealAnimation) {
+        mSplashScreenExecutor.execute(() -> {
+            mStartingSurfaceDrawer.removeStartingWindow(taskId, leash, frame, playRevealAnimation);
+        });
     }
 
+    /**
+     * The interface for calls from outside the Shell, within the host process.
+     */
     private class StartingSurfaceImpl implements StartingSurface {
+        private IStartingWindowImpl mIStartingWindow;
 
         @Override
-        public void addStartingWindow(StartingWindowInfo windowInfo, IBinder appToken) {
-            mSplashScreenExecutor.execute(() ->
-                    StartingWindowController.this.addStartingWindow(windowInfo, appToken));
+        public IStartingWindowImpl createExternalInterface() {
+            if (mIStartingWindow != null) {
+                mIStartingWindow.invalidate();
+            }
+            mIStartingWindow = new IStartingWindowImpl(StartingWindowController.this);
+            return mIStartingWindow;
+        }
+    }
+
+    /**
+     * The interface for calls from outside the host process.
+     */
+    @BinderThread
+    private static class IStartingWindowImpl extends IStartingWindow.Stub {
+        private StartingWindowController mController;
+        private IStartingWindowListener mListener;
+        private final BiConsumer<Integer, Integer> mStartingWindowListener =
+                this::notifyIStartingWindowListener;
+        private final IBinder.DeathRecipient mListenerDeathRecipient =
+                new IBinder.DeathRecipient() {
+                    @Override
+                    @BinderThread
+                    public void binderDied() {
+                        final StartingWindowController controller = mController;
+                        controller.getRemoteCallExecutor().execute(() -> {
+                            mListener = null;
+                            controller.setStartingWindowListener(null);
+                        });
+                    }
+                };
+
+        public IStartingWindowImpl(StartingWindowController controller) {
+            mController = controller;
+        }
+
+        /**
+         * Invalidates this instance, preventing future calls from updating the controller.
+         */
+        void invalidate() {
+            mController = null;
         }
 
         @Override
-        public void removeStartingWindow(int taskId) {
-            mSplashScreenExecutor.execute(() ->
-                    StartingWindowController.this.removeStartingWindow(taskId));
+        public void setStartingWindowListener(IStartingWindowListener listener) {
+            executeRemoteCallWithTaskPermission(mController, "setStartingWindowListener",
+                    (controller) -> {
+                        if (mListener != null) {
+                            // Reset the old death recipient
+                            mListener.asBinder().unlinkToDeath(mListenerDeathRecipient,
+                                    0 /* flags */);
+                        }
+                        if (listener != null) {
+                            try {
+                                listener.asBinder().linkToDeath(mListenerDeathRecipient,
+                                        0 /* flags */);
+                            } catch (RemoteException e) {
+                                Slog.e(TAG, "Failed to link to death");
+                                return;
+                            }
+                        }
+                        mListener = listener;
+                        controller.setStartingWindowListener(mStartingWindowListener);
+                    });
         }
 
-        @Override
-        public void copySplashScreenView(int taskId) {
-            mSplashScreenExecutor.execute(() ->
-                    StartingWindowController.this.copySplashScreenView(taskId));
-        }
+        private void notifyIStartingWindowListener(int taskId, int supportedType) {
+            if (mListener == null) {
+                return;
+            }
 
-        @Override
-        public void setStartingWindowListener(BiConsumer<Integer, Integer> listener) {
-            mSplashScreenExecutor.execute(() ->
-                    StartingWindowController.this.setStartingWindowListener(listener));
+            try {
+                mListener.onTaskLaunching(taskId, supportedType);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Failed to notify task launching", e);
+            }
         }
     }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/IShellTransitions.aidl
similarity index 63%
copy from libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitions.java
copy to libs/WindowManager/Shell/src/com/android/wm/shell/transition/IShellTransitions.aidl
index 85bbf74..dffc700 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/IShellTransitions.aidl
@@ -16,25 +16,22 @@
 
 package com.android.wm.shell.transition;
 
-import android.annotation.NonNull;
 import android.window.IRemoteTransition;
 import android.window.TransitionFilter;
 
-import com.android.wm.shell.common.annotations.ExternalThread;
-
 /**
- * Interface to manage remote transitions.
+ * Interface that is exposed to remote callers to manipulate the transitions feature.
  */
-@ExternalThread
-public interface RemoteTransitions {
-    /**
-     * Registers a remote transition.
-     */
-    void registerRemote(@NonNull TransitionFilter filter,
-            @NonNull IRemoteTransition remoteTransition);
+interface IShellTransitions {
 
     /**
-     * Unregisters a remote transition.
+     * Registers a remote transition handler.
      */
-    void unregisterRemote(@NonNull IRemoteTransition remoteTransition);
+    oneway void registerRemote(in TransitionFilter filter,
+            in IRemoteTransition remoteTransition) = 1;
+
+    /**
+     * Unregisters a remote transition handler.
+     */
+    oneway void unregisterRemote(in IRemoteTransition remoteTransition) = 2;
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java
index ac93a17..9667f4b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java
@@ -16,6 +16,8 @@
 
 package com.android.wm.shell.transition;
 
+import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.os.IBinder;
@@ -23,6 +25,7 @@
 import android.util.ArrayMap;
 import android.util.Log;
 import android.util.Pair;
+import android.util.Slog;
 import android.view.SurfaceControl;
 import android.window.IRemoteTransition;
 import android.window.IRemoteTransitionFinishedCallback;
@@ -31,6 +34,8 @@
 import android.window.TransitionRequestInfo;
 import android.window.WindowContainerTransaction;
 
+import androidx.annotation.BinderThread;
+
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.protolog.ShellProtoLogGroup;
@@ -42,6 +47,8 @@
  * if the request includes a specific remote.
  */
 public class RemoteTransitionHandler implements Transitions.TransitionHandler {
+    private static final String TAG = "RemoteTransitionHandler";
+
     private final ShellExecutor mMainExecutor;
 
     /** Includes remotes explicitly requested by, eg, ActivityOptions */
@@ -51,15 +58,33 @@
     private final ArrayList<Pair<TransitionFilter, IRemoteTransition>> mFilters =
             new ArrayList<>();
 
+    private final IBinder.DeathRecipient mTransitionDeathRecipient =
+            new IBinder.DeathRecipient() {
+                @Override
+                @BinderThread
+                public void binderDied() {
+                    mMainExecutor.execute(() -> {
+                        mFilters.clear();
+                    });
+                }
+            };
+
     RemoteTransitionHandler(@NonNull ShellExecutor mainExecutor) {
         mMainExecutor = mainExecutor;
     }
 
     void addFiltered(TransitionFilter filter, IRemoteTransition remote) {
+        try {
+            remote.asBinder().linkToDeath(mTransitionDeathRecipient, 0 /* flags */);
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Failed to link to death");
+            return;
+        }
         mFilters.add(new Pair<>(filter, remote));
     }
 
     void removeFiltered(IRemoteTransition remote) {
+        remote.asBinder().unlinkToDeath(mTransitionDeathRecipient, 0 /* flags */);
         for (int i = mFilters.size() - 1; i >= 0; --i) {
             if (mFilters.get(i).second == remote) {
                 mFilters.remove(i);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ShellTransitions.java
similarity index 83%
rename from libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitions.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/transition/ShellTransitions.java
index 85bbf74..bc42c6e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ShellTransitions.java
@@ -26,7 +26,15 @@
  * Interface to manage remote transitions.
  */
 @ExternalThread
-public interface RemoteTransitions {
+public interface ShellTransitions {
+
+    /**
+     * Returns a binder that can be passed to an external process to manipulate remote transitions.
+     */
+    default IShellTransitions createExternalInterface() {
+        return null;
+    }
+
     /**
      * Registers a remote transition.
      */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
index 677db10..ca1b53d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
@@ -23,6 +23,8 @@
 import static android.view.WindowManager.TRANSIT_TO_FRONT;
 import static android.window.TransitionInfo.FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT;
 
+import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.ContentResolver;
@@ -51,6 +53,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.common.RemoteCallable;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.TransactionPool;
 import com.android.wm.shell.common.annotations.ExternalThread;
@@ -60,7 +63,7 @@
 import java.util.Arrays;
 
 /** Plays transition animations */
-public class Transitions {
+public class Transitions implements RemoteCallable<Transitions> {
     static final String TAG = "ShellTransitions";
 
     /** Set to {@code true} to enable shell transitions. */
@@ -73,7 +76,7 @@
     private final ShellExecutor mAnimExecutor;
     private final TransitionPlayerImpl mPlayerImpl;
     private final RemoteTransitionHandler mRemoteTransitionHandler;
-    private final RemoteTransitionImpl mImpl = new RemoteTransitionImpl();
+    private final ShellTransitionImpl mImpl = new ShellTransitionImpl();
 
     /** List of possible handlers. Ordered by specificity (eg. tapped back to front). */
     private final ArrayList<TransitionHandler> mHandlers = new ArrayList<>();
@@ -87,10 +90,6 @@
     /** Keeps track of currently tracked transitions and all the animations associated with each */
     private final ArrayMap<IBinder, ActiveTransition> mActiveTransitions = new ArrayMap<>();
 
-    public static RemoteTransitions asRemoteTransitions(Transitions transitions) {
-        return transitions.mImpl;
-    }
-
     public Transitions(@NonNull WindowOrganizer organizer, @NonNull TransactionPool pool,
             @NonNull Context context, @NonNull ShellExecutor mainExecutor,
             @NonNull ShellExecutor animExecutor) {
@@ -126,6 +125,20 @@
         mRemoteTransitionHandler = null;
     }
 
+    public ShellTransitions asRemoteTransitions() {
+        return mImpl;
+    }
+
+    @Override
+    public Context getContext() {
+        return mContext;
+    }
+
+    @Override
+    public ShellExecutor getRemoteCallExecutor() {
+        return mMainExecutor;
+    }
+
     private void dispatchAnimScaleSetting(float scale) {
         for (int i = mHandlers.size() - 1; i >= 0; --i) {
             mHandlers.get(i).setAnimScaleSetting(scale);
@@ -134,8 +147,8 @@
 
     /** Create an empty/non-registering transitions object for system-ui tests. */
     @VisibleForTesting
-    public static RemoteTransitions createEmptyForTesting() {
-        return new RemoteTransitions() {
+    public static ShellTransitions createEmptyForTesting() {
+        return new ShellTransitions() {
             @Override
             public void registerRemote(@androidx.annotation.NonNull TransitionFilter filter,
                     @androidx.annotation.NonNull IRemoteTransition remoteTransition) {
@@ -426,24 +439,74 @@
         }
     }
 
+    /**
+     * The interface for calls from outside the Shell, within the host process.
+     */
     @ExternalThread
-    private class RemoteTransitionImpl implements RemoteTransitions {
+    private class ShellTransitionImpl implements ShellTransitions {
+        private IShellTransitionsImpl mIShellTransitions;
+
+        @Override
+        public IShellTransitions createExternalInterface() {
+            if (mIShellTransitions != null) {
+                mIShellTransitions.invalidate();
+            }
+            mIShellTransitions = new IShellTransitionsImpl(Transitions.this);
+            return mIShellTransitions;
+        }
+
         @Override
         public void registerRemote(@NonNull TransitionFilter filter,
                 @NonNull IRemoteTransition remoteTransition) {
             mMainExecutor.execute(() -> {
-                Transitions.this.registerRemote(filter, remoteTransition);
+                mRemoteTransitionHandler.addFiltered(filter, remoteTransition);
             });
         }
 
         @Override
         public void unregisterRemote(@NonNull IRemoteTransition remoteTransition) {
             mMainExecutor.execute(() -> {
-                Transitions.this.unregisterRemote(remoteTransition);
+                mRemoteTransitionHandler.removeFiltered(remoteTransition);
             });
         }
     }
 
+    /**
+     * The interface for calls from outside the host process.
+     */
+    @BinderThread
+    private static class IShellTransitionsImpl extends IShellTransitions.Stub {
+        private Transitions mTransitions;
+
+        IShellTransitionsImpl(Transitions transitions) {
+            mTransitions = transitions;
+        }
+
+        /**
+         * Invalidates this instance, preventing future calls from updating the controller.
+         */
+        void invalidate() {
+            mTransitions = null;
+        }
+
+        @Override
+        public void registerRemote(@NonNull TransitionFilter filter,
+                @NonNull IRemoteTransition remoteTransition) {
+            executeRemoteCallWithTaskPermission(mTransitions, "registerRemote",
+                    (transitions) -> {
+                        transitions.mRemoteTransitionHandler.addFiltered(filter, remoteTransition);
+                    });
+        }
+
+        @Override
+        public void unregisterRemote(@NonNull IRemoteTransition remoteTransition) {
+            executeRemoteCallWithTaskPermission(mTransitions, "unregisterRemote",
+                    (transitions) -> {
+                        transitions.mRemoteTransitionHandler.removeFiltered(remoteTransition);
+                    });
+        }
+    }
+
     private class SettingsObserver extends ContentObserver {
 
         SettingsObserver() {
diff --git a/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml b/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml
index f06d57c..ad4ccc0 100644
--- a/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml
+++ b/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml
@@ -11,6 +11,8 @@
         <option name="force-skip-system-props" value="true" />
         <!-- set WM tracing verbose level to all -->
         <option name="run-command" value="cmd window tracing level all" />
+        <!-- set WM tracing to frame (avoid incomplete states) -->
+        <option name="run-command" value="cmd window tracing frame" />
         <!-- restart launcher to activate TAPL -->
         <option name="run-command" value="setprop ro.test_harness 1 ; am force-stop com.google.android.apps.nexuslauncher" />
     </target_preparer>
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt
index 90e7137..98ce274 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt
@@ -18,6 +18,8 @@
 
 import android.os.SystemClock
 import android.platform.test.annotations.Presubmit
+import android.provider.Settings
+import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.FlickerParametersRunnerFactory
 import com.android.server.wm.flicker.FlickerTestParameter
@@ -25,6 +27,8 @@
 import com.android.server.wm.flicker.dsl.FlickerBuilder
 import com.android.wm.shell.flicker.appPairsDividerIsInvisible
 import com.android.wm.shell.flicker.helpers.AppPairsHelper
+import org.junit.After
+import org.junit.Before
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -32,11 +36,10 @@
 import org.junit.runners.Parameterized
 
 /**
- * Test AppPairs launch.
- * To run this test: `atest WMShellFlickerTests:AppPairsTest`
- */
-/**
- * Test cold launch app from launcher.
+ * Test cold launch app from launcher. When the device doesn't support non-resizable in multi window
+ * {@link Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW}, app pairs should not pair
+ * non-resizable apps.
+ *
  * To run this test: `atest WMShellFlickerTests:AppPairsTestCannotPairNonResizeableApps`
  */
 @RequiresDevice
@@ -46,6 +49,7 @@
 class AppPairsTestCannotPairNonResizeableApps(
     testSpec: FlickerTestParameter
 ) : AppPairsTransition(testSpec) {
+    var prevSupportNonResizableInMultiWindow = 0
 
     override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
         get() = {
@@ -59,6 +63,32 @@
             }
         }
 
+    @Before
+    fun setup() {
+        prevSupportNonResizableInMultiWindow = Settings.Global.getInt(context.contentResolver,
+            Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW)
+        if (prevSupportNonResizableInMultiWindow == 1) {
+            // Not support non-resizable in multi window
+            Settings.Global.putInt(context.contentResolver,
+                    Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW, 0)
+        }
+    }
+
+    @After
+    fun teardown() {
+        Settings.Global.putInt(context.contentResolver,
+                Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW,
+                prevSupportNonResizableInMultiWindow)
+    }
+
+    @FlakyTest
+    @Test
+    override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
+
+    @FlakyTest
+    @Test
+    override fun statusBarLayerRotatesScales() = super.statusBarLayerRotatesScales()
+
     @Presubmit
     @Test
     fun appPairsDividerIsInvisible() = testSpec.appPairsDividerIsInvisible()
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestPairPrimaryAndSecondaryApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestPairPrimaryAndSecondaryApps.kt
index dc51b4f..63e9a78 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestPairPrimaryAndSecondaryApps.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestPairPrimaryAndSecondaryApps.kt
@@ -56,6 +56,14 @@
             }
         }
 
+    @FlakyTest
+    @Test
+    override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
+
+    @FlakyTest
+    @Test
+    override fun statusBarLayerRotatesScales() = super.statusBarLayerRotatesScales()
+
     @Presubmit
     @Test
     fun appPairsDividerIsVisible() = testSpec.appPairsDividerIsVisible()
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestSupportPairNonResizeableApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestSupportPairNonResizeableApps.kt
new file mode 100644
index 0000000..1e3595c
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestSupportPairNonResizeableApps.kt
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.apppairs
+
+import android.os.SystemClock
+import android.platform.test.annotations.Presubmit
+import android.provider.Settings
+import androidx.test.filters.FlakyTest
+import androidx.test.filters.RequiresDevice
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.wm.shell.flicker.appPairsDividerIsVisible
+import com.android.wm.shell.flicker.helpers.AppPairsHelper
+import org.junit.After
+import org.junit.Before
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test cold launch app from launcher. When the device supports non-resizable in multi window
+ * {@link Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW}, app pairs can pair
+ * non-resizable apps.
+ *
+ * To run this test: `atest WMShellFlickerTests:AppPairsTestSupportPairNonResizeableApps`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+class AppPairsTestSupportPairNonResizeableApps(
+    testSpec: FlickerTestParameter
+) : AppPairsTransition(testSpec) {
+    var prevSupportNonResizableInMultiWindow = 0
+
+    override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
+        get() = {
+            super.transition(this, it)
+            transitions {
+                nonResizeableApp?.launchViaIntent(wmHelper)
+                // TODO pair apps through normal UX flow
+                executeShellCommand(
+                        composePairsCommand(primaryTaskId, nonResizeableTaskId, pair = true))
+                SystemClock.sleep(AppPairsHelper.TIMEOUT_MS)
+            }
+        }
+
+    @Before
+    fun setup() {
+        prevSupportNonResizableInMultiWindow = Settings.Global.getInt(context.contentResolver,
+                Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW)
+        if (prevSupportNonResizableInMultiWindow == 0) {
+            // Support non-resizable in multi window
+            Settings.Global.putInt(context.contentResolver,
+                    Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW, 1)
+        }
+    }
+
+    @After
+    fun teardown() {
+        Settings.Global.putInt(context.contentResolver,
+                Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW,
+                prevSupportNonResizableInMultiWindow)
+    }
+
+    @FlakyTest
+    @Test
+    override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
+
+    @FlakyTest
+    @Test
+    override fun statusBarLayerRotatesScales() = super.statusBarLayerRotatesScales()
+
+    @Presubmit
+    @Test
+    fun appPairsDividerIsVisible() = testSpec.appPairsDividerIsVisible()
+
+    @Presubmit
+    @Test
+    fun bothAppWindowVisible() {
+        val nonResizeableApp = nonResizeableApp
+        require(nonResizeableApp != null) {
+            "Non resizeable app not initialized"
+        }
+        testSpec.assertWmEnd {
+            isVisible(nonResizeableApp.defaultWindowName)
+            isVisible(primaryApp.defaultWindowName)
+        }
+    }
+
+    companion object {
+        @Parameterized.Parameters(name = "{0}")
+        @JvmStatic
+        fun getParams(): List<FlickerTestParameter> {
+            return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
+                    repetitions = AppPairsHelper.TEST_REPETITIONS)
+        }
+    }
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt
index 5bb9b2f..234dda4 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt
@@ -61,6 +61,14 @@
             }
         }
 
+    @FlakyTest
+    @Test
+    override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
+
+    @FlakyTest
+    @Test
+    override fun statusBarLayerRotatesScales() = super.statusBarLayerRotatesScales()
+
     @Presubmit
     @Test
     fun appPairsDividerIsInvisible() = testSpec.appPairsDividerIsInvisible()
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTransition.kt
index 91e080f..134d00b 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTransition.kt
@@ -17,22 +17,27 @@
 package com.android.wm.shell.flicker.apppairs
 
 import android.app.Instrumentation
+import android.content.Context
 import android.platform.test.annotations.Presubmit
 import android.system.helpers.ActivityHelper
 import android.util.Log
+import android.view.Surface
 import androidx.test.platform.app.InstrumentationRegistry
 import com.android.compatibility.common.util.SystemUtil
 import com.android.server.wm.flicker.FlickerBuilderProvider
 import com.android.server.wm.flicker.FlickerTestParameter
 import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.endRotation
 import com.android.server.wm.flicker.helpers.isRotated
 import com.android.server.wm.flicker.helpers.setRotation
 import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
 import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerRotatesAndScales
 import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
 import com.android.server.wm.flicker.repetitions
 import com.android.server.wm.flicker.startRotation
 import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerRotatesScales
 import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
 import com.android.wm.shell.flicker.helpers.AppPairsHelper
 import com.android.wm.shell.flicker.helpers.SplitScreenHelper
@@ -42,6 +47,7 @@
 
 abstract class AppPairsTransition(protected val testSpec: FlickerTestParameter) {
     protected val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+    protected val context: Context = instrumentation.context
     protected val isRotated = testSpec.config.startRotation.isRotated()
     protected val activityHelper = ActivityHelper.getInstance()
     protected val appPairsHelper = AppPairsHelper(instrumentation,
@@ -134,17 +140,39 @@
 
     @Presubmit
     @Test
-    open fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+    open fun navBarLayerIsAlwaysVisible() {
+        testSpec.navBarLayerIsAlwaysVisible()
+    }
 
     @Presubmit
     @Test
-    open fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
+    open fun statusBarLayerIsAlwaysVisible() {
+        testSpec.statusBarLayerIsAlwaysVisible()
+    }
 
     @Presubmit
     @Test
-    open fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+    open fun navBarWindowIsAlwaysVisible() {
+        testSpec.navBarWindowIsAlwaysVisible()
+    }
 
     @Presubmit
     @Test
-    open fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+    open fun statusBarWindowIsAlwaysVisible() {
+        testSpec.statusBarWindowIsAlwaysVisible()
+    }
+
+    @Presubmit
+    @Test
+    open fun navBarLayerRotatesAndScales() {
+        testSpec.navBarLayerRotatesAndScales(Surface.ROTATION_0,
+            testSpec.config.endRotation)
+    }
+
+    @Presubmit
+    @Test
+    open fun statusBarLayerRotatesScales() {
+        testSpec.statusBarLayerRotatesScales(Surface.ROTATION_0,
+            testSpec.config.endRotation)
+    }
 }
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt
index 5f003ba..d341bb1 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt
@@ -27,8 +27,6 @@
 import com.android.server.wm.flicker.dsl.FlickerBuilder
 import com.android.server.wm.flicker.endRotation
 import com.android.server.wm.flicker.helpers.setRotation
-import com.android.server.wm.flicker.navBarLayerRotatesAndScales
-import com.android.server.wm.flicker.statusBarLayerRotatesScales
 import com.android.wm.shell.flicker.appPairsDividerIsVisible
 import com.android.wm.shell.flicker.appPairsPrimaryBoundsIsVisible
 import com.android.wm.shell.flicker.appPairsSecondaryBoundsIsVisible
@@ -75,16 +73,6 @@
     @Test
     fun appPairsDividerIsVisible() = testSpec.appPairsDividerIsVisible()
 
-    @Presubmit
-    @Test
-    fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales(Surface.ROTATION_0,
-        testSpec.config.endRotation)
-
-    @Presubmit
-    @Test
-    fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales(Surface.ROTATION_0,
-        testSpec.config.endRotation)
-
     @FlakyTest(bugId = 172776659)
     @Test
     fun appPairsPrimaryBoundsIsVisible() =
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt
index d479208..3bf0296 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt
@@ -27,16 +27,13 @@
 import com.android.server.wm.flicker.dsl.FlickerBuilder
 import com.android.server.wm.flicker.endRotation
 import com.android.server.wm.flicker.helpers.setRotation
-import com.android.server.wm.flicker.navBarLayerRotatesAndScales
 import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.statusBarLayerRotatesScales
 import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
 import com.android.wm.shell.flicker.appPairsDividerIsVisible
 import com.android.wm.shell.flicker.appPairsPrimaryBoundsIsVisible
 import com.android.wm.shell.flicker.appPairsSecondaryBoundsIsVisible
 import com.android.wm.shell.flicker.helpers.AppPairsHelper
 import com.android.wm.shell.flicker.helpers.SplitScreenHelper
-import org.junit.Assume
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -67,20 +64,10 @@
 
     @Presubmit
     @Test
-    fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales(Surface.ROTATION_0,
-        testSpec.config.endRotation)
-
-    @Presubmit
-    @Test
     fun appPairsDividerIsVisible() = testSpec.appPairsDividerIsVisible()
 
     @Presubmit
     @Test
-    fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales(
-        Surface.ROTATION_0, testSpec.config.endRotation)
-
-    @Presubmit
-    @Test
     override fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
 
     @Presubmit
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterExitPipTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterExitPipTest.kt
index 75c33c6..0333227 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterExitPipTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterExitPipTest.kt
@@ -23,13 +23,7 @@
 import com.android.server.wm.flicker.FlickerTestParameter
 import com.android.server.wm.flicker.FlickerTestParameterFactory
 import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.WindowUtils
 import com.android.wm.shell.flicker.helpers.FixedAppHelper
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
-import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
-import com.android.server.wm.flicker.startRotation
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -48,7 +42,6 @@
     testSpec: FlickerTestParameter
 ) : PipTransition(testSpec) {
     private val testApp = FixedAppHelper(instrumentation)
-    private val displayBounds = WindowUtils.getDisplayBounds(testSpec.config.startRotation)
 
     override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
         get() = buildTransition(eachRun = true) {
@@ -84,14 +77,6 @@
 
     @Presubmit
     @Test
-    fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
-
-    @Presubmit
-    @Test
-    fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
-
-    @Presubmit
-    @Test
     fun showBothAppLayersThenHidePip() {
         testSpec.assertLayers {
             isVisible(testApp.defaultWindowName)
@@ -118,14 +103,6 @@
         }
     }
 
-    @Presubmit
-    @Test
-    fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
-
-    @Presubmit
-    @Test
-    fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
-
     companion object {
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
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 2f08db1..4847c98 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
@@ -16,6 +16,7 @@
 
 package com.android.wm.shell.flicker.pip
 
+import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
 import android.view.Surface
 import androidx.test.filters.FlakyTest
@@ -24,14 +25,6 @@
 import com.android.server.wm.flicker.FlickerTestParameter
 import com.android.server.wm.flicker.FlickerTestParameterFactory
 import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
-import com.android.server.wm.flicker.navBarLayerRotatesAndScales
-import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
-import com.android.server.wm.flicker.statusBarLayerRotatesScales
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.noUncoveredRegions
-import com.android.server.wm.flicker.startRotation
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -57,15 +50,7 @@
 
     @Presubmit
     @Test
-    fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
-
-    @Presubmit
-    @Test
-    fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
-
-    @Presubmit
-    @Test
-    fun pipWindowBecomesVisible() {
+    fun pipAppWindowAlwaysVisible() {
         testSpec.assertWm {
             this.showsAppWindow(pipApp.defaultWindowName)
         }
@@ -73,34 +58,37 @@
 
     @Presubmit
     @Test
-    fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
-
-    @Presubmit
-    @Test
-    fun statusBarLayerRotatesScales() =
-        testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0)
-
-    @Presubmit
-    @Test
     fun pipLayerBecomesVisible() {
         testSpec.assertLayers {
             this.isVisible(pipApp.launcherName)
         }
     }
 
-    @FlakyTest(bugId = 140855415)
+    @Postsubmit
     @Test
-    fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+    fun pipWindowBecomesVisible() {
+        testSpec.assertWm {
+            invoke("pipWindowIsNotVisible") { !it.wmState.hasPipWindow() }
+                .then()
+                .invoke("pipWindowIsVisible") { it.wmState.hasPipWindow() }
+        }
+    }
 
     @FlakyTest(bugId = 140855415)
     @Test
-    fun navBarLayerRotatesAndScales() =
-        testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0)
+    override fun navBarLayerIsAlwaysVisible() = super.navBarLayerIsAlwaysVisible()
 
     @FlakyTest(bugId = 140855415)
     @Test
-    fun noUncoveredRegions() =
-        testSpec.noUncoveredRegions(testSpec.config.startRotation, Surface.ROTATION_0)
+    override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
+
+    @FlakyTest(bugId = 140855415)
+    @Test
+    override fun statusBarLayerRotatesScales() = super.statusBarLayerRotatesScales()
+
+    @FlakyTest(bugId = 140855415)
+    @Test
+    override fun noUncoveredRegions() = super.noUncoveredRegions()
 
     companion object {
         @Parameterized.Parameters(name = "{0}")
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt
index 9011f1a..ba88ee5 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt
@@ -18,16 +18,13 @@
 
 import android.platform.test.annotations.Presubmit
 import android.view.Surface
+import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.FlickerParametersRunnerFactory
 import com.android.server.wm.flicker.FlickerTestParameter
 import com.android.server.wm.flicker.FlickerTestParameterFactory
 import com.android.server.wm.flicker.dsl.FlickerBuilder
 import com.android.server.wm.flicker.helpers.WindowUtils
-import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
 import com.android.wm.shell.flicker.helpers.FixedAppHelper
 import com.android.wm.shell.flicker.pip.PipTransition.BroadcastActionTrigger.Companion.ORIENTATION_LANDSCAPE
 import com.android.wm.shell.flicker.pip.PipTransition.BroadcastActionTrigger.Companion.ORIENTATION_PORTRAIT
@@ -83,6 +80,14 @@
             }
         }
 
+    @FlakyTest
+    @Test
+    override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
+
+    @FlakyTest
+    @Test
+    override fun statusBarLayerRotatesScales() = super.statusBarLayerRotatesScales()
+
     @Presubmit
     @Test
     fun pipAppWindowIsAlwaysOnTop() {
@@ -109,14 +114,6 @@
 
     @Presubmit
     @Test
-    fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
-
-    @Presubmit
-    @Test
-    fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
-
-    @Presubmit
-    @Test
     fun pipAppLayerHidesTestApp() {
         testSpec.assertLayersStart {
             coversExactly(startingBounds, pipApp.defaultWindowName)
@@ -132,14 +129,6 @@
         }
     }
 
-    @Presubmit
-    @Test
-    fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
-
-    @Presubmit
-    @Test
-    fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
-
     companion object {
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseTransition.kt
index 3e33176..eae7e97 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseTransition.kt
@@ -24,14 +24,7 @@
 import com.android.server.wm.flicker.dsl.FlickerBuilder
 import com.android.server.wm.flicker.focusChanges
 import com.android.server.wm.flicker.helpers.setRotation
-import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
-import com.android.server.wm.flicker.navBarLayerRotatesAndScales
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.noUncoveredRegions
 import com.android.server.wm.flicker.startRotation
-import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
-import com.android.server.wm.flicker.statusBarLayerRotatesScales
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
 import org.junit.Test
 import org.junit.runners.Parameterized
 
@@ -52,22 +45,6 @@
 
     @Presubmit
     @Test
-    open fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
-
-    @Presubmit
-    @Test
-    open fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
-
-    @Presubmit
-    @Test
-    open fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
-
-    @Presubmit
-    @Test
-    open fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
-
-    @Presubmit
-    @Test
     open fun pipWindowBecomesInvisible() {
         testSpec.assertWm {
             this.showsAppWindow(PIP_WINDOW_TITLE)
@@ -86,21 +63,6 @@
         }
     }
 
-    @Presubmit
-    @Test
-    open fun statusBarLayerRotatesScales() =
-        testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0)
-
-    @Presubmit
-    @Test
-    open fun noUncoveredRegions() =
-        testSpec.noUncoveredRegions(testSpec.config.startRotation, Surface.ROTATION_0)
-
-    @Presubmit
-    @Test
-    open fun navBarLayerRotatesAndScales() =
-        testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0)
-
     @FlakyTest(bugId = 151179149)
     @Test
     open fun focusChanges() = testSpec.focusChanges(pipApp.launcherName, "NexusLauncherActivity")
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt
index 97afc65..3309e10 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt
@@ -24,17 +24,11 @@
 import com.android.server.wm.flicker.FlickerTestParameter
 import com.android.server.wm.flicker.FlickerTestParameterFactory
 import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.WindowUtils
 import com.android.server.wm.flicker.helpers.launchSplitScreen
 import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
-import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
 import com.android.wm.shell.flicker.helpers.ImeAppHelper
 import com.android.wm.shell.flicker.helpers.FixedAppHelper
 import com.android.server.wm.flicker.repetitions
-import com.android.server.wm.flicker.startRotation
-import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
 import com.android.wm.shell.flicker.removeAllTasksButHome
 import com.android.wm.shell.flicker.testapp.Components.PipActivity.EXTRA_ENTER_PIP
 import org.junit.FixMethodOrder
@@ -55,7 +49,6 @@
 class PipLegacySplitScreenTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
     private val imeApp = ImeAppHelper(instrumentation)
     private val testApp = FixedAppHelper(instrumentation)
-    private val displayBounds = WindowUtils.getDisplayBounds(testSpec.config.startRotation)
 
     override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
         get() = {
@@ -105,11 +98,11 @@
 
     @Postsubmit
     @Test
-    fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+    override fun navBarWindowIsAlwaysVisible() = super.navBarWindowIsAlwaysVisible()
 
     @Postsubmit
     @Test
-    fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+    override fun statusBarWindowIsAlwaysVisible() = super.statusBarWindowIsAlwaysVisible()
 
     @Postsubmit
     @Test
@@ -130,11 +123,11 @@
 
     @Postsubmit
     @Test
-    fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+    override fun navBarLayerIsAlwaysVisible() = super.navBarLayerIsAlwaysVisible()
 
     @Postsubmit
     @Test
-    fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
+    override fun statusBarLayerIsAlwaysVisible() = super.statusBarLayerIsAlwaysVisible()
 
     companion object {
         const val TEST_REPETITIONS = 2
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipMovesInAllApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipMovesInAllApps.kt
index 4c95da2..d011419 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipMovesInAllApps.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipMovesInAllApps.kt
@@ -24,8 +24,6 @@
 import com.android.server.wm.flicker.FlickerTestParameter
 import com.android.server.wm.flicker.FlickerTestParameterFactory
 import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
 import com.google.common.truth.Truth
 import org.junit.FixMethodOrder
 import org.junit.Test
@@ -59,11 +57,11 @@
 
     @Postsubmit
     @Test
-    fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+    override fun statusBarWindowIsAlwaysVisible() = super.statusBarWindowIsAlwaysVisible()
 
     @Postsubmit
     @Test
-    fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+    override fun navBarWindowIsAlwaysVisible() = super.navBarWindowIsAlwaysVisible()
 
     @Postsubmit
     @Test
@@ -71,6 +69,14 @@
 
     @Postsubmit
     @Test
+    fun pipLayerInsideDisplay() {
+        testSpec.assertLayersStart {
+            coversAtMost(displayBounds, pipApp.defaultWindowName)
+        }
+    }
+
+    @Postsubmit
+    @Test
     fun pipWindowMovesUp() = testSpec.assertWmEnd {
         val initialState = this.trace?.first()?.wmState
             ?: error("Trace should not be empty")
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt
index df835d2..49a1055 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt
@@ -29,10 +29,6 @@
 import com.android.server.wm.flicker.helpers.setRotation
 import com.android.server.wm.flicker.startRotation
 import com.android.wm.shell.flicker.helpers.FixedAppHelper
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
-import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
 import com.android.server.wm.flicker.noUncoveredRegions
 import com.android.server.wm.flicker.navBarLayerRotatesAndScales
 import com.android.server.wm.flicker.statusBarLayerRotatesScales
@@ -77,34 +73,18 @@
 
     @Presubmit
     @Test
-    fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
-
-    @Presubmit
-    @Test
-    fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
-
-    @Presubmit
-    @Test
-    fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation,
+    override fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation,
         testSpec.config.endRotation, allStates = false)
 
-    @Presubmit
-    @Test
-    fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
-
-    @Presubmit
-    @Test
-    fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
-
     @FlakyTest(bugId = 140855415)
     @Test
-    fun navBarLayerRotatesAndScales() =
+    override fun navBarLayerRotatesAndScales() =
         testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation,
             testSpec.config.endRotation)
 
     @FlakyTest(bugId = 140855415)
     @Test
-    fun statusBarLayerRotatesScales() =
+    override fun statusBarLayerRotatesScales() =
         testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation,
             testSpec.config.endRotation)
 
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToAppTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToAppTest.kt
index 1bb1d28..945a20b 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToAppTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToAppTest.kt
@@ -26,14 +26,7 @@
 import com.android.server.wm.flicker.dsl.FlickerBuilder
 import com.android.server.wm.flicker.focusChanges
 import com.android.server.wm.flicker.helpers.setRotation
-import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
-import com.android.server.wm.flicker.navBarLayerRotatesAndScales
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.noUncoveredRegions
 import com.android.server.wm.flicker.startRotation
-import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
-import com.android.server.wm.flicker.statusBarLayerRotatesScales
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -68,22 +61,6 @@
 
     @Presubmit
     @Test
-    fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
-
-    @Presubmit
-    @Test
-    fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
-
-    @Presubmit
-    @Test
-    fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
-
-    @Presubmit
-    @Test
-    fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
-
-    @Presubmit
-    @Test
     fun appReplacesPipWindow() {
         testSpec.assertWm {
             this.showsAppWindow(PIP_WINDOW_TITLE)
@@ -94,11 +71,6 @@
 
     @Presubmit
     @Test
-    fun statusBarLayerRotatesScales() =
-        testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0)
-
-    @Presubmit
-    @Test
     fun appReplacesPipLayer() {
         testSpec.assertLayers {
             this.isVisible(PIP_WINDOW_TITLE)
@@ -107,15 +79,13 @@
         }
     }
 
-    @Presubmit
+    @FlakyTest
     @Test
-    fun noUncoveredRegions() =
-        testSpec.noUncoveredRegions(testSpec.config.startRotation, Surface.ROTATION_0)
-
-    @Presubmit
-    @Test
-    fun navBarLayerRotatesAndScales() =
-        testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0)
+    fun testAppCoversFullScreen() {
+        testSpec.assertLayersStart {
+            coversExactly(displayBounds, pipApp.defaultWindowName)
+        }
+    }
 
     @FlakyTest(bugId = 151179149)
     @Test
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt
index b0a9afe..7dc7e7d 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt
@@ -18,27 +18,37 @@
 
 import android.app.Instrumentation
 import android.content.Intent
+import android.platform.test.annotations.Presubmit
 import android.view.Surface
 import androidx.test.platform.app.InstrumentationRegistry
 import com.android.server.wm.flicker.FlickerBuilderProvider
 import com.android.server.wm.flicker.FlickerTestParameter
 import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.helpers.WindowUtils
 import com.android.server.wm.flicker.helpers.isRotated
 import com.android.server.wm.flicker.helpers.setRotation
 import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
+import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerRotatesAndScales
+import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.noUncoveredRegions
 import com.android.server.wm.flicker.repetitions
 import com.android.server.wm.flicker.startRotation
+import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerRotatesScales
+import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
 import com.android.wm.shell.flicker.helpers.PipAppHelper
 import com.android.wm.shell.flicker.removeAllTasksButHome
 import com.android.wm.shell.flicker.testapp.Components
+import org.junit.Test
 
 abstract class PipTransition(protected val testSpec: FlickerTestParameter) {
     protected val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
     protected val isRotated = testSpec.config.startRotation.isRotated()
     protected val pipApp = PipAppHelper(instrumentation)
+    protected val displayBounds = WindowUtils.getDisplayBounds(testSpec.config.startRotation)
     protected val broadcastActionTrigger = BroadcastActionTrigger(instrumentation)
     protected abstract val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
-
     // Helper class to process test actions by broadcast.
     protected class BroadcastActionTrigger(private val instrumentation: Instrumentation) {
         private fun createIntentWithAction(broadcastAction: String): Intent {
@@ -148,4 +158,35 @@
             extraSpec(this, configuration)
         }
     }
+
+    @Presubmit
+    @Test
+    open fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+
+    @Presubmit
+    @Test
+    open fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+
+    @Presubmit
+    @Test
+    open fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+
+    @Presubmit
+    @Test
+    open fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
+
+    @Presubmit
+    @Test
+    open fun navBarLayerRotatesAndScales() =
+        testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0)
+
+    @Presubmit
+    @Test
+    open fun statusBarLayerRotatesScales() =
+        testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0)
+
+    @Presubmit
+    @Test
+    open fun noUncoveredRegions() =
+        testSpec.noUncoveredRegions(testSpec.config.startRotation, Surface.ROTATION_0)
 }
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt
index 7916ce5..67e1768 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.wm.shell.flicker.pip
 
+import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
 import android.view.Surface
 import androidx.test.filters.FlakyTest
@@ -25,10 +26,6 @@
 import com.android.server.wm.flicker.FlickerTestParameterFactory
 import com.android.server.wm.flicker.dsl.FlickerBuilder
 import com.android.server.wm.flicker.helpers.WindowUtils
-import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
 import com.android.wm.shell.flicker.pip.PipTransition.BroadcastActionTrigger.Companion.ORIENTATION_LANDSCAPE
 import com.android.wm.shell.flicker.testapp.Components.FixedActivity.EXTRA_FIXED_ORIENTATION
 import com.android.wm.shell.flicker.testapp.Components.PipActivity.EXTRA_ENTER_PIP
@@ -83,6 +80,14 @@
             }
         }
 
+    @FlakyTest
+    @Test
+    override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
+
+    @FlakyTest
+    @Test
+    override fun statusBarLayerRotatesScales() = super.statusBarLayerRotatesScales()
+
     @Presubmit
     @Test
     fun pipWindowInsideDisplay() {
@@ -101,20 +106,18 @@
 
     @Presubmit
     @Test
-    fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
-
-    @Presubmit
-    @Test
-    fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
-
-    @Presubmit
-    @Test
     fun pipLayerInsideDisplay() {
         testSpec.assertLayersStart {
             coversAtMost(startingBounds, pipApp.defaultWindowName)
         }
     }
 
+    @Postsubmit
+    @Test
+    fun pipAlwaysVisible() = testSpec.assertWm {
+        this.showsAppWindow(pipApp.windowName)
+    }
+
     @Presubmit
     @Test
     fun pipAppLayerCoversFullScreen() {
@@ -123,14 +126,6 @@
         }
     }
 
-    @Presubmit
-    @Test
-    fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
-
-    @Presubmit
-    @Test
-    fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
-
     companion object {
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
index c1c4c6d..2f2bbba 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
@@ -205,7 +205,7 @@
                 mPolicy.getTargets(mInsets), TYPE_FULLSCREEN);
 
         mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
-        verify(mSplitScreenStarter).startIntent(any(), any(), any(),
+        verify(mSplitScreenStarter).startIntent(any(), any(),
                 eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any());
     }
 
@@ -217,12 +217,12 @@
                 mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT);
 
         mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
-        verify(mSplitScreenStarter).startIntent(any(), any(), any(),
+        verify(mSplitScreenStarter).startIntent(any(), any(),
                 eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any());
         reset(mSplitScreenStarter);
 
         mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_RIGHT), mActivityClipData);
-        verify(mSplitScreenStarter).startIntent(any(), any(), any(),
+        verify(mSplitScreenStarter).startIntent(any(), any(),
                 eq(STAGE_TYPE_SIDE), eq(STAGE_POSITION_BOTTOM_OR_RIGHT), any());
     }
 
@@ -234,12 +234,12 @@
                 mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_TOP, TYPE_SPLIT_BOTTOM);
 
         mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
-        verify(mSplitScreenStarter).startIntent(any(), any(), any(),
+        verify(mSplitScreenStarter).startIntent(any(), any(),
                 eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any());
         reset(mSplitScreenStarter);
 
         mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_BOTTOM), mActivityClipData);
-        verify(mSplitScreenStarter).startIntent(any(), any(), any(),
+        verify(mSplitScreenStarter).startIntent(any(), any(),
                 eq(STAGE_TYPE_SIDE), eq(STAGE_POSITION_BOTTOM_OR_RIGHT), any());
     }
 
@@ -251,7 +251,7 @@
                 mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT);
 
         mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
-        verify(mSplitScreenStarter).startIntent(any(), any(), any(),
+        verify(mSplitScreenStarter).startIntent(any(), any(),
                 eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any());
     }
 
@@ -263,7 +263,7 @@
                 mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT);
 
         mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
-        verify(mSplitScreenStarter).startIntent(any(), any(), any(),
+        verify(mSplitScreenStarter).startIntent(any(), any(),
                 eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any());
     }
 
@@ -276,13 +276,13 @@
                 mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT);
 
         mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
-        verify(mSplitScreenStarter).startIntent(any(), any(), any(),
+        verify(mSplitScreenStarter).startIntent(any(), any(),
                 eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any());
         reset(mSplitScreenStarter);
 
         // TODO(b/169894807): Just verify starting for the non-docked task until we have app pairs
         mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_RIGHT), mActivityClipData);
-        verify(mSplitScreenStarter).startIntent(any(), any(), any(),
+        verify(mSplitScreenStarter).startIntent(any(), any(),
                 eq(STAGE_TYPE_SIDE), eq(STAGE_POSITION_BOTTOM_OR_RIGHT), any());
     }
 
@@ -295,13 +295,13 @@
                 mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_TOP, TYPE_SPLIT_BOTTOM);
 
         mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
-        verify(mSplitScreenStarter).startIntent(any(), any(), any(),
+        verify(mSplitScreenStarter).startIntent(any(), any(),
                 eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any());
         reset(mSplitScreenStarter);
 
         // TODO(b/169894807): Just verify starting for the non-docked task until we have app pairs
         mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_BOTTOM), mActivityClipData);
-        verify(mSplitScreenStarter).startIntent(any(), any(), any(),
+        verify(mSplitScreenStarter).startIntent(any(), any(),
                 eq(STAGE_TYPE_SIDE), eq(STAGE_POSITION_BOTTOM_OR_RIGHT), any());
     }
 
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 a531ef5..207db9e 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
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package unittest.src.com.android.wm.shell.startingsurface;
+package com.android.wm.shell.startingsurface;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
@@ -33,11 +33,12 @@
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
+import android.graphics.Rect;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
 import android.testing.TestableContext;
-import android.view.Choreographer;
+import android.view.SurfaceControl;
 import android.view.View;
 import android.view.WindowManager;
 import android.view.WindowMetrics;
@@ -49,7 +50,7 @@
 
 import com.android.wm.shell.common.HandlerExecutor;
 import com.android.wm.shell.common.ShellExecutor;
-import com.android.wm.shell.startingsurface.StartingSurfaceDrawer;
+import com.android.wm.shell.common.TransactionPool;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -68,7 +69,7 @@
     @Mock
     private WindowManager mMockWindowManager;
     @Mock
-    private static Choreographer sFakeChoreographer;
+    private TransactionPool mTransactionPool;
 
     TestStartingSurfaceDrawer mStartingSurfaceDrawer;
 
@@ -76,13 +77,9 @@
         int mAddWindowForTask = 0;
         int mViewThemeResId;
 
-        TestStartingSurfaceDrawer(Context context, ShellExecutor executor) {
-            super(context, executor);
-        }
-
-        @Override
-        protected void initChoreographer() {
-            mChoreographer = sFakeChoreographer;
+        TestStartingSurfaceDrawer(Context context, ShellExecutor animExecutor,
+                TransactionPool pool) {
+            super(context, animExecutor, pool);
         }
 
         @Override
@@ -95,7 +92,8 @@
         }
 
         @Override
-        protected void removeWindowSynced(int taskId) {
+        protected void removeWindowSynced(int taskId, SurfaceControl leash, Rect frame,
+                boolean playRevealAnimation) {
             // listen for removeView
             if (mAddWindowForTask == taskId) {
                 mAddWindowForTask = 0;
@@ -123,7 +121,8 @@
         doNothing().when(mMockWindowManager).addView(any(), any());
 
         mStartingSurfaceDrawer = spy(new TestStartingSurfaceDrawer(context,
-                new HandlerExecutor(new Handler(Looper.getMainLooper()))));
+                new HandlerExecutor(new Handler(Looper.getMainLooper())),
+                mTransactionPool));
     }
 
     @Test
@@ -137,9 +136,9 @@
         verify(mStartingSurfaceDrawer).postAddWindow(eq(taskId), eq(mBinder), any(), any(), any());
         assertEquals(mStartingSurfaceDrawer.mAddWindowForTask, taskId);
 
-        mStartingSurfaceDrawer.removeStartingWindow(windowInfo.taskInfo.taskId);
+        mStartingSurfaceDrawer.removeStartingWindow(windowInfo.taskInfo.taskId, null, null, false);
         waitHandlerIdle(mainLoop);
-        verify(mStartingSurfaceDrawer).removeWindowSynced(eq(taskId));
+        verify(mStartingSurfaceDrawer).removeWindowSynced(eq(taskId), any(), any(), eq(false));
         assertEquals(mStartingSurfaceDrawer.mAddWindowForTask, 0);
     }
 
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/TaskSnapshotWindowTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/TaskSnapshotWindowTest.java
index 27e5f51..b908df2 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/TaskSnapshotWindowTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/TaskSnapshotWindowTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package unittest.src.com.android.wm.shell.startingsurface;
+package com.android.wm.shell.startingsurface;
 
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
@@ -48,7 +48,6 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.wm.shell.TestShellExecutor;
-import com.android.wm.shell.startingsurface.TaskSnapshotWindow;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index c0ef7be..7e45f95 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -226,8 +226,6 @@
 }
 
 void AssetManager2::DumpToLog() const {
-  base::ScopedLogSeverity _log(base::INFO);
-
   LOG(INFO) << base::StringPrintf("AssetManager2(this=%p)", this);
 
   std::string list;
@@ -1721,7 +1719,6 @@
 }
 
 void Theme::Dump() const {
-  base::ScopedLogSeverity _log(base::INFO);
   LOG(INFO) << base::StringPrintf("Theme(this=%p, AssetManager2=%p)", this, asset_manager_);
 
   for (int p = 0; p < packages_.size(); p++) {
diff --git a/media/jni/soundpool/Sound.cpp b/media/jni/soundpool/Sound.cpp
index f8b4bdb..50e0d33 100644
--- a/media/jni/soundpool/Sound.cpp
+++ b/media/jni/soundpool/Sound.cpp
@@ -99,8 +99,8 @@
                                     __func__);
                             break;
                         }
-                        int sampleSize = AMediaExtractor_readSampleData(ex.get(), buf, bufsize);
-                        ALOGV("%s: read %d", __func__, sampleSize);
+                        ssize_t sampleSize = AMediaExtractor_readSampleData(ex.get(), buf, bufsize);
+                        ALOGV("%s: read %zd", __func__, sampleSize);
                         if (sampleSize < 0) {
                             sampleSize = 0;
                             sawInputEOS = true;
@@ -124,8 +124,8 @@
                 }
 
                 AMediaCodecBufferInfo info;
-                const int status = AMediaCodec_dequeueOutputBuffer(codec.get(), &info, 1);
-                ALOGV("%s: dequeueoutput returned: %d", __func__, status);
+                const ssize_t status = AMediaCodec_dequeueOutputBuffer(codec.get(), &info, 1);
+                ALOGV("%s: dequeueoutput returned: %zd", __func__, status);
                 if (status >= 0) {
                     if (info.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) {
                         ALOGV("%s: output EOS", __func__);
@@ -167,10 +167,10 @@
                 } else if (status == AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
                     ALOGV("%s: no output buffer right now", __func__);
                 } else if (status <= AMEDIA_ERROR_BASE) {
-                    ALOGE("%s: decode error: %d", __func__, status);
+                    ALOGE("%s: decode error: %zd", __func__, status);
                     break;
                 } else {
-                    ALOGV("%s: unexpected info code: %d", __func__, status);
+                    ALOGV("%s: unexpected info code: %zd", __func__, status);
                 }
             }
 
diff --git a/media/jni/soundpool/Stream.cpp b/media/jni/soundpool/Stream.cpp
index abb0f12..95fe000 100644
--- a/media/jni/soundpool/Stream.cpp
+++ b/media/jni/soundpool/Stream.cpp
@@ -320,7 +320,8 @@
             // audio track while the new one is being started and avoids processing them with
             // wrong audio audio buffer size  (mAudioBufferSize)
             auto toggle = mToggle ^ 1;
-            void* userData = (void*)((uintptr_t)this | toggle);
+            // NOLINTNEXTLINE(performance-no-int-to-ptr)
+            void* userData = reinterpret_cast<void*>((uintptr_t)this | toggle);
             audio_channel_mask_t soundChannelMask = sound->getChannelMask();
             // When sound contains a valid channel mask, use it as is.
             // Otherwise, use stream count to calculate channel mask.
@@ -391,6 +392,7 @@
 void Stream::staticCallback(int event, void* user, void* info)
 {
     const auto userAsInt = (uintptr_t)user;
+    // NOLINTNEXTLINE(performance-no-int-to-ptr)
     auto stream = reinterpret_cast<Stream*>(userAsInt & ~1);
     stream->callback(event, info, int(userAsInt & 1), 0 /* tries */);
 }
diff --git a/media/jni/soundpool/StreamManager.cpp b/media/jni/soundpool/StreamManager.cpp
index 502ee00..8b84bf3 100644
--- a/media/jni/soundpool/StreamManager.cpp
+++ b/media/jni/soundpool/StreamManager.cpp
@@ -330,7 +330,7 @@
 
     // streams on mProcessingStreams are undergoing processing by the StreamManager thread
     // and do not participate in normal stream migration.
-    return found;
+    return (ssize_t)found;
 }
 
 void StreamManager::addToRestartQueue_l(Stream *stream) {
diff --git a/media/jni/soundpool/android_media_SoundPool.cpp b/media/jni/soundpool/android_media_SoundPool.cpp
index 357cc63..a66d99f 100644
--- a/media/jni/soundpool/android_media_SoundPool.cpp
+++ b/media/jni/soundpool/android_media_SoundPool.cpp
@@ -34,7 +34,8 @@
     jclass      mSoundPoolClass;
 } fields;
 static inline SoundPool* MusterSoundPool(JNIEnv *env, jobject thiz) {
-    return (SoundPool*)env->GetLongField(thiz, fields.mNativeContext);
+    // NOLINTNEXTLINE(performance-no-int-to-ptr)
+    return reinterpret_cast<SoundPool*>(env->GetLongField(thiz, fields.mNativeContext));
 }
 static const char* const kAudioAttributesClassPathName = "android/media/AudioAttributes";
 struct audio_attributes_fields_t {
diff --git a/packages/Connectivity/framework/api/current.txt b/packages/Connectivity/framework/api/current.txt
index a8f1a4d..243e4ca 100644
--- a/packages/Connectivity/framework/api/current.txt
+++ b/packages/Connectivity/framework/api/current.txt
@@ -143,6 +143,7 @@
 
   public static class ConnectivityManager.NetworkCallback {
     ctor public ConnectivityManager.NetworkCallback();
+    ctor public ConnectivityManager.NetworkCallback(int);
     method public void onAvailable(@NonNull android.net.Network);
     method public void onBlockedStatusChanged(@NonNull android.net.Network, boolean);
     method public void onCapabilitiesChanged(@NonNull android.net.Network, @NonNull android.net.NetworkCapabilities);
@@ -150,6 +151,7 @@
     method public void onLosing(@NonNull android.net.Network, int);
     method public void onLost(@NonNull android.net.Network);
     method public void onUnavailable();
+    field public static final int FLAG_INCLUDE_LOCATION_INFO = 1; // 0x1
   }
 
   public static interface ConnectivityManager.OnNetworkActiveListener {
@@ -293,6 +295,7 @@
     method @Nullable public android.net.NetworkSpecifier getNetworkSpecifier();
     method public int getOwnerUid();
     method public int getSignalStrength();
+    method @NonNull public java.util.Set<java.lang.Integer> getSubIds();
     method @Nullable public android.net.TransportInfo getTransportInfo();
     method public boolean hasCapability(int);
     method public boolean hasTransport(int);
@@ -399,6 +402,11 @@
     method public android.net.NetworkRequest.Builder removeTransportType(int);
     method @Deprecated public android.net.NetworkRequest.Builder setNetworkSpecifier(String);
     method public android.net.NetworkRequest.Builder setNetworkSpecifier(android.net.NetworkSpecifier);
+    method @NonNull public android.net.NetworkRequest.Builder setSubIds(@NonNull java.util.Set<java.lang.Integer>);
+  }
+
+  public class ParseException extends java.lang.RuntimeException {
+    field public String response;
   }
 
   public class ProxyInfo implements android.os.Parcelable {
diff --git a/packages/Connectivity/framework/api/module-lib-current.txt b/packages/Connectivity/framework/api/module-lib-current.txt
index 5b64d52..4b33366 100644
--- a/packages/Connectivity/framework/api/module-lib-current.txt
+++ b/packages/Connectivity/framework/api/module-lib-current.txt
@@ -7,6 +7,7 @@
 
   public class ConnectivityManager {
     method @NonNull @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public java.util.List<android.net.NetworkStateSnapshot> getAllNetworkStateSnapshot();
+    method @NonNull public static android.util.Range<java.lang.Integer> getIpSecNetIdRange();
     method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void registerSystemDefaultNetworkCallback(@NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler);
     method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void requestBackgroundNetwork(@NonNull android.net.NetworkRequest, @NonNull android.os.Handler, @NonNull android.net.ConnectivityManager.NetworkCallback);
     method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_TEST_NETWORKS, android.Manifest.permission.NETWORK_STACK}) public void simulateDataStall(int, long, @NonNull android.net.Network, @NonNull android.os.PersistableBundle);
diff --git a/packages/Connectivity/framework/api/system-current.txt b/packages/Connectivity/framework/api/system-current.txt
index a732430..a98f14e 100644
--- a/packages/Connectivity/framework/api/system-current.txt
+++ b/packages/Connectivity/framework/api/system-current.txt
@@ -296,6 +296,7 @@
     method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setRequestorUid(int);
     method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP) public android.net.NetworkCapabilities.Builder setSignalStrength(int);
     method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setSsid(@Nullable String);
+    method @NonNull public android.net.NetworkCapabilities.Builder setSubIds(@NonNull java.util.Set<java.lang.Integer>);
     method @NonNull public android.net.NetworkCapabilities.Builder setTransportInfo(@Nullable android.net.TransportInfo);
   }
 
diff --git a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
index 3314af5..7189be1 100644
--- a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
+++ b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
@@ -16,7 +16,6 @@
 package android.net;
 
 import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
-import static android.net.IpSecManager.INVALID_RESOURCE_ID;
 import static android.net.NetworkRequest.Type.BACKGROUND_REQUEST;
 import static android.net.NetworkRequest.Type.LISTEN;
 import static android.net.NetworkRequest.Type.REQUEST;
@@ -44,6 +43,7 @@
 import android.net.TetheringManager.StartTetheringCallback;
 import android.net.TetheringManager.TetheringEventCallback;
 import android.net.TetheringManager.TetheringRequest;
+import android.net.wifi.WifiNetworkSuggestion;
 import android.os.Binder;
 import android.os.Build;
 import android.os.Build.VERSION_CODES;
@@ -1315,7 +1315,7 @@
     }
 
     /**
-     * Returns an array of {@link android.net.NetworkCapabilities} objects, representing
+     * Returns an array of {@link NetworkCapabilities} objects, representing
      * the Networks that applications run by the given user will use by default.
      * @hide
      */
@@ -1395,11 +1395,19 @@
     }
 
     /**
-     * Get the {@link android.net.NetworkCapabilities} for the given {@link Network}.  This
+     * Get the {@link NetworkCapabilities} for the given {@link Network}.  This
      * will return {@code null} if the network is unknown.
      *
+     * This will remove any location sensitive data in {@link TransportInfo} embedded in
+     * {@link NetworkCapabilities#getTransportInfo()}. Some transport info instances like
+     * {@link android.net.wifi.WifiInfo} contain location sensitive information. Retrieving
+     * this location sensitive information (subject to app's location permissions) will be
+     * noted by system. To include any location sensitive data in {@link TransportInfo},
+     * use a {@link NetworkCallback} with
+     * {@link NetworkCallback#FLAG_INCLUDE_LOCATION_INFO} flag.
+     *
      * @param network The {@link Network} object identifying the network in question.
-     * @return The {@link android.net.NetworkCapabilities} for the network, or {@code null}.
+     * @return The {@link NetworkCapabilities} for the network, or {@code null}.
      */
     @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
     @Nullable
@@ -1997,7 +2005,7 @@
             dup = createInvalidFd();
         }
         return new NattSocketKeepalive(mService, network, dup,
-                INVALID_RESOURCE_ID /* Unused */, source, destination, executor, callback);
+                -1 /* Unused */, source, destination, executor, callback);
     }
 
     /**
@@ -3245,6 +3253,54 @@
      */
     public static class NetworkCallback {
         /**
+         * No flags associated with this callback.
+         * @hide
+         */
+        public static final int FLAG_NONE = 0;
+        /**
+         * Use this flag to include any location sensitive data in {@link NetworkCapabilities} sent
+         * via {@link #onCapabilitiesChanged(Network, NetworkCapabilities)}.
+         * <p>
+         * These include:
+         * <li> Some transport info instances (retrieved via
+         * {@link NetworkCapabilities#getTransportInfo()}) like {@link android.net.wifi.WifiInfo}
+         * contain location sensitive information.
+         * <li> OwnerUid (retrieved via {@link NetworkCapabilities#getOwnerUid()} is location
+         * sensitive for wifi suggestor apps (i.e using {@link WifiNetworkSuggestion}).</li>
+         * </p>
+         * <p>
+         * Note:
+         * <li> Retrieving this location sensitive information (subject to app's location
+         * permissions) will be noted by system. </li>
+         * <li> Without this flag any {@link NetworkCapabilities} provided via the callback does
+         * not include location sensitive info.
+         * </p>
+         */
+        public static final int FLAG_INCLUDE_LOCATION_INFO = 1 << 0;
+
+        /** @hide */
+        @Retention(RetentionPolicy.SOURCE)
+        @IntDef(flag = true, prefix = "FLAG_", value = {
+                FLAG_NONE,
+                FLAG_INCLUDE_LOCATION_INFO
+        })
+        public @interface Flag { }
+
+        /**
+         * All the valid flags for error checking.
+         */
+        private static final int VALID_FLAGS = FLAG_INCLUDE_LOCATION_INFO;
+
+        public NetworkCallback() {
+            this(FLAG_NONE);
+        }
+
+        public NetworkCallback(@Flag int flags) {
+            Preconditions.checkArgument((flags & VALID_FLAGS) == flags);
+            mFlags = flags;
+        }
+
+        /**
          * Called when the framework connects to a new network to evaluate whether it satisfies this
          * request. If evaluation succeeds, this callback may be followed by an {@link #onAvailable}
          * callback. There is no guarantee that this new network will satisfy any requests, or that
@@ -3381,7 +3437,7 @@
          * calling these methods while in a callback may return an outdated or even a null object.
          *
          * @param network The {@link Network} whose capabilities have changed.
-         * @param networkCapabilities The new {@link android.net.NetworkCapabilities} for this
+         * @param networkCapabilities The new {@link NetworkCapabilities} for this
          *                            network.
          */
         public void onCapabilitiesChanged(@NonNull Network network,
@@ -3450,6 +3506,7 @@
         public void onBlockedStatusChanged(@NonNull Network network, boolean blocked) {}
 
         private NetworkRequest networkRequest;
+        private final int mFlags;
     }
 
     /**
@@ -3639,14 +3696,15 @@
                 }
                 Messenger messenger = new Messenger(handler);
                 Binder binder = new Binder();
+                final int callbackFlags = callback.mFlags;
                 if (reqType == LISTEN) {
                     request = mService.listenForNetwork(
-                            need, messenger, binder, callingPackageName,
+                            need, messenger, binder, callbackFlags, callingPackageName,
                             getAttributionTag());
                 } else {
                     request = mService.requestNetwork(
                             need, reqType.ordinal(), messenger, timeoutMs, binder, legacyType,
-                            callingPackageName, getAttributionTag());
+                            callbackFlags, callingPackageName, getAttributionTag());
                 }
                 if (request != null) {
                     sCallbacks.put(request, callback);
@@ -3693,7 +3751,7 @@
     }
 
     /**
-     * Request a network to satisfy a set of {@link android.net.NetworkCapabilities}.
+     * Request a network to satisfy a set of {@link NetworkCapabilities}.
      *
      * <p>This method will attempt to find the best network that matches the passed
      * {@link NetworkRequest}, and to bring up one that does if none currently satisfies the
@@ -3777,7 +3835,7 @@
     }
 
     /**
-     * Request a network to satisfy a set of {@link android.net.NetworkCapabilities}.
+     * Request a network to satisfy a set of {@link NetworkCapabilities}.
      *
      * This method behaves identically to {@link #requestNetwork(NetworkRequest, NetworkCallback)}
      * but runs all the callbacks on the passed Handler.
@@ -3799,7 +3857,7 @@
     }
 
     /**
-     * Request a network to satisfy a set of {@link android.net.NetworkCapabilities}, limited
+     * Request a network to satisfy a set of {@link NetworkCapabilities}, limited
      * by a timeout.
      *
      * This function behaves identically to the non-timed-out version
@@ -3834,7 +3892,7 @@
     }
 
     /**
-     * Request a network to satisfy a set of {@link android.net.NetworkCapabilities}, limited
+     * Request a network to satisfy a set of {@link NetworkCapabilities}, limited
      * by a timeout.
      *
      * This method behaves identically to
@@ -3879,7 +3937,7 @@
 
 
     /**
-     * Request a network to satisfy a set of {@link android.net.NetworkCapabilities}.
+     * Request a network to satisfy a set of {@link NetworkCapabilities}.
      *
      * This function behaves identically to the version that takes a NetworkCallback, but instead
      * of {@link NetworkCallback} a {@link PendingIntent} is used.  This means
@@ -4911,7 +4969,7 @@
     }
 
     /**
-     * Request a network to satisfy a set of {@link android.net.NetworkCapabilities}, but
+     * Request a network to satisfy a set of {@link NetworkCapabilities}, but
      * does not cause any networks to retain the NET_CAPABILITY_FOREGROUND capability. This can
      * be used to request that the system provide a network without causing the network to be
      * in the foreground.
@@ -5053,4 +5111,21 @@
             throw e.rethrowFromSystemServer();
         }
     }
+
+    // The first network ID of IPSec tunnel interface.
+    private static final int TUN_INTF_NETID_START = 0xFC00;
+    // The network ID range of IPSec tunnel interface.
+    private static final int TUN_INTF_NETID_RANGE = 0x0400;
+
+    /**
+     * Get the network ID range reserved for IPSec tunnel interfaces.
+     *
+     * @return A Range which indicates the network ID range of IPSec tunnel interface.
+     * @hide
+     */
+    @SystemApi(client = MODULE_LIBRARIES)
+    @NonNull
+    public static Range<Integer> getIpSecNetIdRange() {
+        return new Range(TUN_INTF_NETID_START, TUN_INTF_NETID_START + TUN_INTF_NETID_RANGE - 1);
+    }
 }
diff --git a/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl b/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl
index cd49258..f9393e3 100644
--- a/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl
+++ b/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl
@@ -143,7 +143,7 @@
 
     NetworkRequest requestNetwork(in NetworkCapabilities networkCapabilities, int reqType,
             in Messenger messenger, int timeoutSec, in IBinder binder, int legacy,
-            String callingPackageName, String callingAttributionTag);
+            int callbackFlags, String callingPackageName, String callingAttributionTag);
 
     NetworkRequest pendingRequestForNetwork(in NetworkCapabilities networkCapabilities,
             in PendingIntent operation, String callingPackageName, String callingAttributionTag);
@@ -151,7 +151,7 @@
     void releasePendingNetworkRequest(in PendingIntent operation);
 
     NetworkRequest listenForNetwork(in NetworkCapabilities networkCapabilities,
-            in Messenger messenger, in IBinder binder, String callingPackageName,
+            in Messenger messenger, in IBinder binder, int callbackFlags, String callingPackageName,
             String callingAttributionTag);
 
     void pendingListenForNetwork(in NetworkCapabilities networkCapabilities,
diff --git a/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java b/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
index c82cd3b..058f3c9 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
@@ -25,6 +25,7 @@
 import android.annotation.SystemApi;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.net.ConnectivityManager.NetworkCallback;
+import android.net.wifi.WifiNetworkSuggestion;
 import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -131,6 +132,7 @@
         mPrivateDnsBroken = false;
         mRequestorUid = Process.INVALID_UID;
         mRequestorPackageName = null;
+        mSubIds = new ArraySet<>();
     }
 
     /**
@@ -159,6 +161,7 @@
         mPrivateDnsBroken = nc.mPrivateDnsBroken;
         mRequestorUid = nc.mRequestorUid;
         mRequestorPackageName = nc.mRequestorPackageName;
+        mSubIds = new ArraySet<>(nc.mSubIds);
     }
 
     /**
@@ -1048,6 +1051,16 @@
      *
      * Instances of NetworkCapabilities sent to apps without the appropriate permissions will have
      * this field cleared out.
+     *
+     * <p>
+     * This field will only be populated for VPN and wifi network suggestor apps (i.e using
+     * {@link WifiNetworkSuggestion}), and only for the network they own.
+     * In the case of wifi network suggestors apps, this field is also location sensitive, so the
+     * app needs to hold {@link android.Manifest.permission#ACCESS_FINE_LOCATION} permission. If the
+     * app targets SDK version greater than or equal to {@link Build.VERSION_CODES#S}, then they
+     * also need to use {@link NetworkCallback#FLAG_INCLUDE_LOCATION_INFO} to get the info in their
+     * callback. The app will be blamed for location access if this field is included.
+     * </p>
      */
     public int getOwnerUid() {
         return mOwnerUid;
@@ -1655,6 +1668,7 @@
         combineSSIDs(nc);
         combineRequestor(nc);
         combineAdministratorUids(nc);
+        combineSubIds(nc);
     }
 
     /**
@@ -1674,8 +1688,9 @@
                 && satisfiedBySpecifier(nc)
                 && (onlyImmutable || satisfiedBySignalStrength(nc))
                 && (onlyImmutable || satisfiedByUids(nc))
-                && (onlyImmutable || satisfiedBySSID(nc)))
-                && (onlyImmutable || satisfiedByRequestor(nc));
+                && (onlyImmutable || satisfiedBySSID(nc))
+                && (onlyImmutable || satisfiedByRequestor(nc))
+                && (onlyImmutable || satisfiedBySubIds(nc)));
     }
 
     /**
@@ -1771,7 +1786,8 @@
                 && equalsOwnerUid(that)
                 && equalsPrivateDnsBroken(that)
                 && equalsRequestor(that)
-                && equalsAdministratorUids(that);
+                && equalsAdministratorUids(that)
+                && equalsSubIds(that);
     }
 
     @Override
@@ -1793,7 +1809,8 @@
                 + Objects.hashCode(mPrivateDnsBroken) * 47
                 + Objects.hashCode(mRequestorUid) * 53
                 + Objects.hashCode(mRequestorPackageName) * 59
-                + Arrays.hashCode(mAdministratorUids) * 61;
+                + Arrays.hashCode(mAdministratorUids) * 61
+                + Objects.hashCode(mSubIds) * 67;
     }
 
     @Override
@@ -1827,6 +1844,7 @@
         dest.writeInt(mOwnerUid);
         dest.writeInt(mRequestorUid);
         dest.writeString(mRequestorPackageName);
+        dest.writeIntArray(CollectionUtils.toIntArray(mSubIds));
     }
 
     public static final @android.annotation.NonNull Creator<NetworkCapabilities> CREATOR =
@@ -1850,6 +1868,11 @@
                 netCap.mOwnerUid = in.readInt();
                 netCap.mRequestorUid = in.readInt();
                 netCap.mRequestorPackageName = in.readString();
+                netCap.mSubIds = new ArraySet<>();
+                final int[] subIdInts = Objects.requireNonNull(in.createIntArray());
+                for (int i = 0; i < subIdInts.length; i++) {
+                    netCap.mSubIds.add(subIdInts[i]);
+                }
                 return netCap;
             }
             @Override
@@ -1933,11 +1956,14 @@
             sb.append(" SSID: ").append(mSSID);
         }
 
-
         if (mPrivateDnsBroken) {
             sb.append(" PrivateDnsBroken");
         }
 
+        if (!mSubIds.isEmpty()) {
+            sb.append(" SubscriptionIds: ").append(mSubIds);
+        }
+
         sb.append("]");
         return sb.toString();
     }
@@ -2251,6 +2277,67 @@
     }
 
     /**
+     * Set of the subscription IDs that identifies the network or request, empty if none.
+     */
+    @NonNull
+    private ArraySet<Integer> mSubIds = new ArraySet<>();
+
+    /**
+     * Sets the subscription ID set that associated to this network or request.
+     *
+     * @hide
+     */
+    @NonNull
+    public NetworkCapabilities setSubIds(@NonNull Set<Integer> subIds) {
+        mSubIds = new ArraySet(Objects.requireNonNull(subIds));
+        return this;
+    }
+
+    /**
+     * Gets the subscription ID set that associated to this network or request.
+     * @return
+     */
+    @NonNull
+    public Set<Integer> getSubIds() {
+        return new ArraySet<>(mSubIds);
+    }
+
+    /**
+     * Tests if the subscription ID set of this network is the same as that of the passed one.
+     */
+    private boolean equalsSubIds(@NonNull NetworkCapabilities nc) {
+        return Objects.equals(mSubIds, nc.mSubIds);
+    }
+
+    /**
+     * Check if the subscription ID set requirements of this object are matched by the passed one.
+     * If specified in the request, the passed one need to have at least one subId and at least
+     * one of them needs to be in the request set.
+     */
+    private boolean satisfiedBySubIds(@NonNull NetworkCapabilities nc) {
+        if (mSubIds.isEmpty()) return true;
+        if (nc.mSubIds.isEmpty()) return false;
+        for (final Integer subId : nc.mSubIds) {
+            if (mSubIds.contains(subId)) return true;
+        }
+        return false;
+    }
+
+    /**
+     * Combine subscription ID set of the capabilities.
+     *
+     * <p>This is only legal if the subscription Ids are equal.
+     *
+     * <p>If both subscription IDs are not equal, they belong to different subscription
+     * (or no subscription). In this case, it would not make sense to add them together.
+     */
+    private void combineSubIds(@NonNull NetworkCapabilities nc) {
+        if (!Objects.equals(mSubIds, nc.mSubIds)) {
+            throw new IllegalStateException("Can't combine two subscription ID sets");
+        }
+    }
+
+    /**
      * Builder class for NetworkCapabilities.
      *
      * This class is mainly for for {@link NetworkAgent} instances to use. Many fields in
@@ -2556,6 +2643,18 @@
         }
 
         /**
+         * Set the subscription ID set.
+         *
+         * @param subIds a set that represent the subscription IDs. Empty if clean up.
+         * @return this builder.
+         */
+        @NonNull
+        public Builder setSubIds(@NonNull final Set<Integer> subIds) {
+            mCaps.setSubIds(subIds);
+            return this;
+        }
+
+        /**
          * Builds the instance of the capabilities.
          *
          * @return the built instance of NetworkCapabilities.
diff --git a/packages/Connectivity/framework/src/android/net/NetworkInfo.java b/packages/Connectivity/framework/src/android/net/NetworkInfo.java
index d752901..bb23494 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkInfo.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkInfo.java
@@ -21,7 +21,6 @@
 import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.telephony.Annotation.NetworkType;
 import android.text.TextUtils;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -164,7 +163,7 @@
      * @param typeName a human-readable string for the network type, or an empty string or null.
      * @param subtypeName a human-readable string for the subtype, or an empty string or null.
      */
-    public NetworkInfo(int type, @NetworkType int subtype,
+    public NetworkInfo(int type, int subtype,
             @Nullable String typeName, @Nullable String subtypeName) {
         if (!ConnectivityManager.isNetworkTypeValid(type)
                 && type != ConnectivityManager.TYPE_NONE) {
diff --git a/packages/Connectivity/framework/src/android/net/NetworkRequest.java b/packages/Connectivity/framework/src/android/net/NetworkRequest.java
index aa69756..3fd95ee 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkRequest.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkRequest.java
@@ -461,6 +461,21 @@
             }
             nc.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
         }
+
+        /**
+         * Sets the optional subscription ID set.
+         * <p>
+         * This specify the subscription IDs requirement.
+         * A network will satisfy this request only if it matches one of the subIds in this set.
+         * An empty set matches all networks, including those without a subId.
+         *
+         * @param subIds A {@code Set} that represents subscription IDs.
+         */
+        @NonNull
+        public Builder setSubIds(@NonNull Set<Integer> subIds) {
+            mNetworkCapabilities.setSubIds(subIds);
+            return this;
+        }
     }
 
     // implement the Parcelable interface
diff --git a/packages/Connectivity/framework/src/android/net/NetworkState.java b/packages/Connectivity/framework/src/android/net/NetworkState.java
index d010265..9b69674 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkState.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkState.java
@@ -22,7 +22,7 @@
 import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.util.Slog;
+import android.util.Log;
 
 /**
  * Snapshot of network state.
@@ -83,7 +83,7 @@
         if (VALIDATE_ROAMING_STATE && networkInfo != null && networkCapabilities != null) {
             if (networkInfo.isRoaming() == networkCapabilities
                     .hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING)) {
-                Slog.wtf("NetworkState", "Roaming state disagreement between " + networkInfo
+                Log.wtf("NetworkState", "Roaming state disagreement between " + networkInfo
                         + " and " + networkCapabilities);
             }
         }
diff --git a/core/java/android/net/ParseException.java b/packages/Connectivity/framework/src/android/net/ParseException.java
similarity index 100%
rename from core/java/android/net/ParseException.java
rename to packages/Connectivity/framework/src/android/net/ParseException.java
diff --git a/packages/Connectivity/framework/src/android/net/QosSocketInfo.java b/packages/Connectivity/framework/src/android/net/QosSocketInfo.java
index d37c469..53d9669 100644
--- a/packages/Connectivity/framework/src/android/net/QosSocketInfo.java
+++ b/packages/Connectivity/framework/src/android/net/QosSocketInfo.java
@@ -92,7 +92,7 @@
         Objects.requireNonNull(socket, "socket cannot be null");
 
         mNetwork = Objects.requireNonNull(network, "network cannot be null");
-        mParcelFileDescriptor = ParcelFileDescriptor.dup(socket.getFileDescriptor$());
+        mParcelFileDescriptor = ParcelFileDescriptor.fromSocket(socket);
         mLocalSocketAddress =
                 new InetSocketAddress(socket.getLocalAddress(), socket.getLocalPort());
     }
@@ -114,10 +114,10 @@
         try {
             return new InetSocketAddress(InetAddress.getByAddress(address), port);
         } catch (final UnknownHostException e) {
-            /* The catch block was purposely left empty.  UnknownHostException will never be thrown
+            /* This can never happen. UnknownHostException will never be thrown
                since the address provided is numeric and non-null. */
+            throw new RuntimeException("UnknownHostException on numeric address", e);
         }
-        return new InetSocketAddress();
     }
 
     @Override
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
index c1dca5d..16a946d 100644
--- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
@@ -138,9 +138,6 @@
     private long mCurrentPartitionSize;
     private long mCurrentPartitionInstalledSize;
 
-    private boolean mJustCancelledByUser;
-    private boolean mKeepNotification;
-
     // This is for testing only now
     private boolean mEnableWhenCompleted;
 
@@ -174,11 +171,6 @@
         if (cache != null) {
             cache.flush();
         }
-
-        if (!mKeepNotification) {
-            // Cancel the persistent notification.
-            mNM.cancel(NOTIFICATION_ID);
-        }
     }
 
     @Override
@@ -231,9 +223,11 @@
             return;
         }
 
+        boolean removeNotification = false;
         switch (result) {
             case RESULT_CANCELLED:
                 postStatus(STATUS_NOT_STARTED, CAUSE_INSTALL_CANCELLED, null);
+                removeNotification = true;
                 break;
 
             case RESULT_ERROR_IO:
@@ -251,7 +245,7 @@
         }
 
         // if it's not successful, reset the task and stop self.
-        resetTaskAndStop();
+        resetTaskAndStop(removeNotification);
     }
 
     private void executeInstallCommand(Intent intent) {
@@ -302,12 +296,12 @@
             return;
         }
 
-        stopForeground(true);
-        mJustCancelledByUser = true;
-
         if (mInstallTask.cancel(false)) {
-            // Will stopSelf() in onResult()
+            // onResult() would call resetTaskAndStop() upon task completion.
             Log.d(TAG, "Cancel request filed successfully");
+            // Dismiss the notification as soon as possible as DynamicSystemManager.remove() may
+            // block.
+            stopForeground(STOP_FOREGROUND_REMOVE);
         } else {
             Log.e(TAG, "Trying to cancel installation while it's already completed.");
         }
@@ -322,8 +316,7 @@
         if (!isDynamicSystemInstalled() && (getStatus() != STATUS_READY)) {
             Log.e(TAG, "Trying to discard AOT while there is no complete installation");
             // Stop foreground state and dismiss stale notification.
-            stopForeground(STOP_FOREGROUND_REMOVE);
-            resetTaskAndStop();
+            resetTaskAndStop(true);
             return;
         }
 
@@ -331,8 +324,8 @@
                 getString(R.string.toast_dynsystem_discarded),
                 Toast.LENGTH_LONG).show();
 
-        resetTaskAndStop();
         postStatus(STATUS_NOT_STARTED, CAUSE_INSTALL_CANCELLED, null);
+        resetTaskAndStop(true);
 
         mDynSystem.remove();
     }
@@ -412,12 +405,13 @@
     }
 
     private void resetTaskAndStop() {
-        mInstallTask = null;
+        resetTaskAndStop(/* removeNotification= */ false);
+    }
 
-        new Handler().postDelayed(() -> {
-            stopForeground(STOP_FOREGROUND_DETACH);
-            stopSelf();
-        }, 50);
+    private void resetTaskAndStop(boolean removeNotification) {
+        mInstallTask = null;
+        stopForeground(removeNotification ? STOP_FOREGROUND_REMOVE : STOP_FOREGROUND_DETACH);
+        stopSelf();
     }
 
     private void prepareNotification() {
@@ -525,7 +519,7 @@
     private void postStatus(int status, int cause, Throwable detail) {
         String statusString;
         String causeString;
-        mKeepNotification = false;
+        boolean notifyOnNotificationBar = true;
 
         switch (status) {
             case STATUS_NOT_STARTED:
@@ -551,18 +545,16 @@
                 break;
             case CAUSE_INSTALL_CANCELLED:
                 causeString = "INSTALL_CANCELLED";
+                notifyOnNotificationBar = false;
                 break;
             case CAUSE_ERROR_IO:
                 causeString = "ERROR_IO";
-                mKeepNotification = true;
                 break;
             case CAUSE_ERROR_INVALID_URL:
                 causeString = "ERROR_INVALID_URL";
-                mKeepNotification = true;
                 break;
             case CAUSE_ERROR_EXCEPTION:
                 causeString = "ERROR_EXCEPTION";
-                mKeepNotification = true;
                 break;
             default:
                 causeString = "CAUSE_NOT_SPECIFIED";
@@ -571,16 +563,6 @@
 
         Log.d(TAG, "status=" + statusString + ", cause=" + causeString + ", detail=" + detail);
 
-        boolean notifyOnNotificationBar = true;
-
-        if (status == STATUS_NOT_STARTED
-                && cause == CAUSE_INSTALL_CANCELLED
-                && mJustCancelledByUser) {
-            // if task is cancelled by user, do not notify them
-            notifyOnNotificationBar = false;
-            mJustCancelledByUser = false;
-        }
-
         if (notifyOnNotificationBar) {
             mNM.notify(NOTIFICATION_ID, buildNotification(status, cause, detail));
         }
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 1a67b5e..0ee44f8 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -424,8 +424,7 @@
     <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>
-    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
-    <skip />
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Verstel hoe kleure op jou toestel vertoon. Dit kan nuttig wees wanneer jy:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; Kleure meer akkuraat wil sien&lt;/li&gt; &lt;li&gt; Kleure wil verwyder om jou te help fokus&lt;/li&gt; &lt;/ol&gt;"</string>
     <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>
@@ -516,8 +515,7 @@
     <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="media_transfer_this_phone" msgid="7194341457812151531">"Hierdie foon"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Kan nie koppel nie. Skakel toestel af en weer aan"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Bedrade oudiotoestel"</string>
     <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 97abce1..9fb676f 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -424,8 +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>
-    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
-    <skip />
+    <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,8 +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>
-    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
-    <skip />
+    <string name="media_transfer_this_phone" msgid="7194341457812151531">"ይህ ስልክ"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"መገናኘት ላይ ችግር። መሳሪያውን ያጥፉት እና እንደገና ያብሩት"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ባለገመድ የኦዲዮ መሣሪያ"</string>
     <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 f9e12c7..cdb418a 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -424,8 +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>
-    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
-    <skip />
+    <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>
@@ -520,8 +519,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>
-    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
-    <skip />
+    <string name="media_transfer_this_phone" msgid="7194341457812151531">"هذا الهاتف"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"حدثت مشكلة أثناء الاتصال. يُرجى إيقاف الجهاز ثم إعادة تشغيله."</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"جهاز سماعي سلكي"</string>
     <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 efd813a..442a19d 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -424,8 +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>
-    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
-    <skip />
+    <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,8 +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>
-    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
-    <skip />
+    <string name="media_transfer_this_phone" msgid="7194341457812151531">"এই ফ’নটো"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"সংযোগ হোৱাত সমস্যা হৈছে। ডিভাইচটো অফ কৰি পুনৰ অন কৰক"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"তাঁৰযুক্ত অডিঅ’ ডিভাইচ"</string>
     <string name="help_label" msgid="3528360748637781274">"সহায় আৰু মতামত"</string>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index 7a5aec4..950a5ae 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -424,8 +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>
-    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
-    <skip />
+    <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>
@@ -518,8 +517,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>
-    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
-    <skip />
+    <string name="media_transfer_this_phone" msgid="7194341457812151531">"Гэты тэлефон"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Праблема з падключэннем. Выключыце і зноў уключыце прыладу"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Правадная аўдыяпрылада"</string>
     <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 675d179..4cc9abf 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -424,8 +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>
-    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
-    <skip />
+    <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,8 +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>
-    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
-    <skip />
+    <string name="media_transfer_this_phone" msgid="7194341457812151531">"এই ফোনটি"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"কানেক্ট করতে সমস্যা হচ্ছে। ডিভাইস বন্ধ করে আবার চালু করুন"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ওয়্যার অডিও ডিভাইস"</string>
     <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 97083ad..e4bc5a1 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -424,8 +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">"Ispravka boje"</string>
-    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
-    <skip />
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Podešavanje načina na koji se boje prikazuju na uređaju. To može biti korisno kada želite:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; tačnije prikazati boje&lt;/li&gt; &lt;li&gt; ukloniti boje da se lakše fokusirate&lt;/li&gt; &lt;/ol&gt;"</string>
     <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>
@@ -517,8 +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>
-    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
-    <skip />
+    <string name="media_transfer_this_phone" msgid="7194341457812151531">"Ovaj telefon"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Došlo je do problema prilikom povezivanja. Isključite, pa ponovo uključite uređaj"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Žičani audio uređaj"</string>
     <string name="help_label" msgid="3528360748637781274">"Pomoć i povratne informacije"</string>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index 4889220..fa441a2 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -424,8 +424,7 @@
     <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>
-    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
-    <skip />
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Ajusta com es mostren els colors al teu dispositiu. Això pot ser útil quan vulguis:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; Veure els colors amb més claredat.&lt;/li&gt; &lt;li&gt; Suprimir colors per poder enfocar més fàcilment.&lt;/li&gt; &lt;/ol&gt;"</string>
     <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>
@@ -516,8 +515,7 @@
     <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="media_transfer_this_phone" msgid="7194341457812151531">"Aquest telèfon"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Hi ha hagut un problema amb la connexió. 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 e857e60..717b681 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -424,8 +424,7 @@
     <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>
-    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
-    <skip />
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Upravte zobrazování barev na svém zařízení. To se může hodit, když chcete:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; Aby se barvy zobrazovaly přesněji&lt;/li&gt; &lt;li&gt; Odstranit barvy, abyste se mohli lépe soustředit&lt;/li&gt; &lt;/ol&gt;"</string>
     <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>
@@ -518,8 +517,7 @@
     <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="media_transfer_this_phone" msgid="7194341457812151531">"Tento telefon"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problém s připojením. Vypněte zařízení a znovu jej zapněte"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Kabelové audiozařízení"</string>
     <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 53e21ba..6b17db1 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -424,8 +424,7 @@
     <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>
-    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
-    <skip />
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Juster, hvordan farverne vises på skærmen. Dette kan være nyttigt, når du vil:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; Se farver mere nøjagtigt&lt;/li&gt; &lt;li&gt; Fjerne farver, så du bedre kan fokusere&lt;/li&gt; &lt;/ol&gt;"</string>
     <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>
@@ -516,8 +515,7 @@
     <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="media_transfer_this_phone" msgid="7194341457812151531">"Denne telefon"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Der kunne ikke oprettes forbindelse. Sluk og tænd enheden"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Lydenhed med ledning"</string>
     <string name="help_label" msgid="3528360748637781274">"Hjælp og feedback"</string>
@@ -541,7 +539,7 @@
     <string name="user_add_profile_item_title" msgid="3111051717414643029">"Begrænset profil"</string>
     <string name="user_add_user_title" msgid="5457079143694924885">"Vil du tilføje en ny bruger?"</string>
     <string name="user_add_user_message_long" msgid="1527434966294733380">"Du kan dele denne enhed med andre ved at oprette ekstra brugere. Hver bruger har sit personlige område, som kan tilpasses med apps, baggrund osv. Brugerne kan også justere enhedsindstillinger, som for eksempel Wi-Fi, som påvirker alle.\n\nNår du tilføjer en ny bruger, skal vedkommende konfigurere sit område.\n\nAlle brugere kan opdatere apps for alle andre brugere. Indstillinger og tjenester for hjælpefunktioner overføres muligvis ikke til den nye bruger."</string>
-    <string name="user_add_user_message_short" msgid="3295959985795716166">"Når du tilføjer en ny bruger, skal personen konfigurere sit rum.\n\nEnhver bruger kan opdatere apps for alle andre brugere."</string>
+    <string name="user_add_user_message_short" msgid="3295959985795716166">"Når du tilføjer en ny bruger, skal personen konfigurere sit rum.\n\nAlle brugere kan opdatere apps for alle de andre brugere."</string>
     <string name="user_setup_dialog_title" msgid="8037342066381939995">"Vil du konfigurere brugeren nu?"</string>
     <string name="user_setup_dialog_message" msgid="269931619868102841">"Sørg for, at brugeren har mulighed for at tage enheden og konfigurere sit eget rum"</string>
     <string name="user_setup_profile_dialog_message" msgid="4788197052296962620">"Vil du oprette en profil nu?"</string>
@@ -557,7 +555,7 @@
     <string name="user_switch_to_user" msgid="6975428297154968543">"Skift til <xliff:g id="USER_NAME">%s</xliff:g>"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Opretter ny bruger…"</string>
     <string name="user_nickname" msgid="262624187455825083">"Kaldenavn"</string>
-    <string name="guest_new_guest" msgid="3482026122932643557">"Tilføj gæsten"</string>
+    <string name="guest_new_guest" msgid="3482026122932643557">"Tilføj gæst"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"Fjern gæsten"</string>
     <string name="guest_nickname" msgid="6332276931583337261">"Gæst"</string>
     <string name="user_image_take_photo" msgid="467512954561638530">"Tag et billede"</string>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index a4a976f..bb11ed1 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -424,8 +424,7 @@
     <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>
-    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
-    <skip />
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Hier kannst du anpassen, wie Farben auf deinem Gerät dargestellt werden sollen. Das kann in folgenden Fällen hilfreich sein:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; Wenn Farben genauer dargestellt werden sollen&lt;/li&gt; &lt;li&gt; Wenn du Farben entfernen möchtest, um dich besser konzentrieren zu können&lt;/li&gt; &lt;/ol&gt;"</string>
     <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>
@@ -516,8 +515,7 @@
     <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="media_transfer_this_phone" msgid="7194341457812151531">"Dieses Smartphone"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Verbindung kann nicht hergestellt werden. Schalte das Gerät aus &amp; und wieder ein."</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Netzbetriebenes Audiogerät"</string>
     <string name="help_label" msgid="3528360748637781274">"Hilfe und Feedback"</string>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index 71cf5cb..fb294c8 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -424,8 +424,7 @@
     <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>
-    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
-    <skip />
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Ajusta cómo se muestran los colores en tu dispositivo. Esto puede ser útil cuando quieres:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; Ver colores con más exactitud&lt;/li&gt; &lt;li&gt; Quitar colores para mejorar tu concentración&lt;/li&gt; &lt;/ol&gt;"</string>
     <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>
@@ -516,8 +515,7 @@
     <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="media_transfer_this_phone" msgid="7194341457812151531">"Este teléfono"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Error al establecer la conexión. Apaga el dispositivo y vuelve a encenderlo."</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositivo de audio con cable"</string>
     <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 a7d7b21..2c5eff2 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -424,8 +424,7 @@
     <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>
-    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
-    <skip />
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Ajusta el modo en que se muestran los colores en tu dispositivo. Esto puede ser útil cuando quieras hacer lo siguiente:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; Ver los colores con más precisión&lt;/li&gt; &lt;li&gt; Eliminar colores para ayudarte a mantener la concentración&lt;/li&gt; &lt;/ol&gt;"</string>
     <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>
@@ -516,8 +515,7 @@
     <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="media_transfer_this_phone" msgid="7194341457812151531">"Este teléfono"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"No se ha podido conectar; reinicia el dispositivo"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositivo de audio con cable"</string>
     <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 add25f8..116faad 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -424,8 +424,7 @@
     <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>
-    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
-    <skip />
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Kohandage seadmes värvide kuvamist. Sellest võib olla kasu, kui soovite:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; värve täpsemalt näha;&lt;/li&gt; &lt;li&gt; värve eemaldada, et paremini keskenduda.&lt;/li&gt; &lt;/ol&gt;"</string>
     <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>
@@ -516,8 +515,7 @@
     <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="media_transfer_this_phone" msgid="7194341457812151531">"See telefon"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Probleem ühendamisel. Lülitage seade välja ja uuesti sisse"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Juhtmega heliseade"</string>
     <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 c95d157..bfb4efc 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -424,8 +424,7 @@
     <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>
-    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
-    <skip />
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Doitu nola bistaratzen diren koloreak gailuan. Kasu hauetan izan daiteke lagungarria:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; Koloreak zehatzago ikusi nahi dituzunean.&lt;/li&gt; &lt;li&gt; Hobeto fokuratzeko, koloreak kendu nahi dituzunean.&lt;/li&gt; &lt;/ol&gt;"</string>
     <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>
@@ -516,8 +515,7 @@
     <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="media_transfer_this_phone" msgid="7194341457812151531">"Telefono hau"</string>
     <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 631ff5e..f3018ba 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -424,8 +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>
-    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
-    <skip />
+    <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; وقتی می‌خواهید رنگ‌ها را حذف کنید تا تمرکز بیشتری داشته باشید"</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,8 +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>
-    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
-    <skip />
+    <string name="media_transfer_this_phone" msgid="7194341457812151531">"این تلفن"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"مشکل در اتصال. دستگاه را خاموش و دوباره روشن کنید"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"دستگاه صوتی سیمی"</string>
     <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 7591c91..7089937 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -424,8 +424,7 @@
     <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>
-    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
-    <skip />
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Muuta värien näkymistä laitteellasi. Tästä voi olla hyötyä, kun haluat&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; nähdä värit tarkemmin&lt;/li&gt; &lt;li&gt; poistaa värejä voidaksesi keskittyä paremmin&lt;/li&gt; &lt;/ol&gt;"</string>
     <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>
@@ -516,8 +515,7 @@
     <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="media_transfer_this_phone" msgid="7194341457812151531">"Tämä puhelin"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Yhteysvirhe. Sammuta laite ja käynnistä se uudelleen."</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Langallinen äänilaite"</string>
     <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 a390257..ac8adde 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -424,8 +424,7 @@
     <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>
-    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
-    <skip />
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Ajustez l\'affichage des couleurs sur votre appareil. Ce paramètre peut être utile si vous voulez :&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; Mieux distinguer les couleurs&lt;/li&gt; &lt;li&gt; Enlever les couleurs pour vous aider à vous concentrer&lt;/li&gt; &lt;/ol&gt;"</string>
     <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>
@@ -516,8 +515,7 @@
     <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="media_transfer_this_phone" msgid="7194341457812151531">"Ce téléphone"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problème de connexion. Éteingez et rallumez l\'appareil"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Appareil audio à câble"</string>
     <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 8cf8c6e..e4e4293 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -424,8 +424,7 @@
     <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>
-    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
-    <skip />
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Ajustez l\'affichage des couleurs sur votre appareil. Cette option peut vous être utile pour :&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; accentuer la précision des couleurs ;&lt;/li&gt; &lt;li&gt; supprimer les couleurs pour mieux vous concentrer.&lt;/li&gt; &lt;/ol&gt;"</string>
     <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>
@@ -516,8 +515,7 @@
     <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="media_transfer_this_phone" msgid="7194341457812151531">"Ce téléphone"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problème de connexion. Éteignez l\'appareil, puis rallumez-le"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Appareil audio filaire"</string>
     <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 c1ba51d..062b7b3 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -424,8 +424,7 @@
     <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>
-    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
-    <skip />
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Axusta a maneira en que se mostran as cores no teu dispositivo. Esta opción pode resultarche útil se queres:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; Ver mellor as cores&lt;/li&gt; &lt;li&gt; Quitar as cores para concentrarte mellor&lt;/li&gt; &lt;/ol&gt;"</string>
     <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>
@@ -516,8 +515,7 @@
     <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="media_transfer_this_phone" msgid="7194341457812151531">"Este teléfono"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Produciuse un problema coa conexión. Apaga e acende o dispositivo."</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositivo de audio con cable"</string>
     <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 94d83e0..174d0a1 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -424,8 +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>
-    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
-    <skip />
+    <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,8 +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>
-    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
-    <skip />
+    <string name="media_transfer_this_phone" msgid="7194341457812151531">"આ ફોન"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"કનેક્ટ કરવામાં સમસ્યા આવી રહી છે. ડિવાઇસને બંધ કરીને ફરી ચાલુ કરો"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"વાયરવાળો ઑડિયો ડિવાઇસ"</string>
     <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 e99d4cb..3d06baa 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -424,8 +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 boje"</string>
-    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
-    <skip />
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Prilagodite način prikazivanja boja na svojem uređaju. To može biti korisno kad želite:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; vidjeti boje točnije&lt;/li&gt; &lt;li&gt; ukloniti boje kako biste se lakše usredotočili&lt;/li&gt; &lt;/ol&gt;"</string>
     <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>
@@ -517,8 +516,7 @@
     <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="media_transfer_this_phone" msgid="7194341457812151531">"Ovaj telefon"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem s povezivanjem. Isključite i ponovo uključite uređaj"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Žičani audiouređaj"</string>
     <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 503ee60..546a038 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -424,8 +424,7 @@
     <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>
-    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
-    <skip />
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Korrigálhatja a színek megjelenítését az eszközén. Ez a következő esetekben lehet hasznos:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; ha pontosabb színeket szeretne látni;&lt;/li&gt; &lt;li&gt; ha szeretné eltávolítani a színeket, hogy jobban tudjon koncentrálni.&lt;/li&gt; &lt;/ol&gt;"</string>
     <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>
@@ -516,8 +515,7 @@
     <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="media_transfer_this_phone" msgid="7194341457812151531">"Ez a telefon"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Sikertelen csatlakozás. Kapcsolja ki az eszközt, majd kapcsolja be újra."</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Vezetékes audioeszköz"</string>
     <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 3686dd1..7c0963d 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -424,8 +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>
-    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
-    <skip />
+    <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,8 +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>
-    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
-    <skip />
+    <string name="media_transfer_this_phone" msgid="7194341457812151531">"Այս հեռախոսը"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Կապի խնդիր կա: Սարքն անջատեք և նորից միացրեք:"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Լարով աուդիո սարք"</string>
     <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 035be7d..2f8bb46 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -424,8 +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">"Koreksi warna"</string>
-    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
-    <skip />
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Sesuaikan cara warna ditampilkan di perangkat Anda. Ini dapat bermanfaat saat Anda ingin:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; Melihat warna dengan lebih akurat&lt;/li&gt; &lt;li&gt; Menghapus warna untuk membantu Anda fokus&lt;/li&gt; &lt;/ol&gt;"</string>
     <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>
@@ -516,8 +515,7 @@
     <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="media_transfer_this_phone" msgid="7194341457812151531">"Ponsel ini"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Ada masalah saat menghubungkan. Nonaktifkan perangkat &amp; aktifkan kembali"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Perangkat audio berkabel"</string>
     <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 718b5be..ea29258 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -424,8 +424,7 @@
     <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>
-    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
-    <skip />
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Stilltu litabirtingu í tækinu þínu. Þetta getur gagnast þegar þú vilt:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; Sjá liti skýrar&lt;/li&gt; &lt;li&gt; Fjarlægja liti til að fókusa betur&lt;/li&gt; &lt;/ol&gt;"</string>
     <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>
@@ -516,8 +515,7 @@
     <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="media_transfer_this_phone" msgid="7194341457812151531">"Þessi sími"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Vandamál í tengingu. Slökktu og kveiktu á tækinu"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Snúrutengt hljómtæki"</string>
     <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 d2176d9..5dd7a52 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -424,8 +424,7 @@
     <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>
-    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
-    <skip />
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Regola la modalità di visualizzazione dei colori sul tuo dispositivo. Può essere utile se vuoi:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; Vedere i colori con più precisione&lt;/li&gt; &lt;li&gt; Rimuovere colori per mettere a fuoco più facilmente&lt;/li&gt; &lt;/ol&gt;"</string>
     <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>
@@ -516,8 +515,7 @@
     <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="media_transfer_this_phone" msgid="7194341457812151531">"Questo telefono"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problema di connessione. Spegni e riaccendi il dispositivo"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositivo audio cablato"</string>
     <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 1357cae..20d1e1b 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -424,8 +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>
-    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
-    <skip />
+    <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>
@@ -518,8 +517,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>
-    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
-    <skip />
+    <string name="media_transfer_this_phone" msgid="7194341457812151531">"הטלפון הזה"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"יש בעיה בחיבור. עליך לכבות את המכשיר ולהפעיל אותו מחדש"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"התקן אודיו חוטי"</string>
     <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 8bb6ba8..37db15c 100644
--- a/packages/SettingsLib/res/values-ka/strings.xml
+++ b/packages/SettingsLib/res/values-ka/strings.xml
@@ -424,8 +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>
-    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
-    <skip />
+    <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,8 +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>
-    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
-    <skip />
+    <string name="media_transfer_this_phone" msgid="7194341457812151531">"ეს ტელეფონი"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"დაკავშირებისას წარმოიქმნა პრობლემა. გამორთეთ და კვლავ ჩართეთ მოწყობილობა"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"სადენიანი აუდიო მოწყობილობა"</string>
     <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 6a2c21e..878966d 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -424,8 +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>
-    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
-    <skip />
+    <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>
@@ -503,7 +502,7 @@
     <string name="cancel" msgid="5665114069455378395">"Бас тарту"</string>
     <string name="okay" msgid="949938843324579502">"Жарайды"</string>
     <string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Қосу"</string>
-    <string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"\"Мазаламау\" режимін қосу"</string>
+    <string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Мазаламау режимін қосу"</string>
     <string name="zen_mode_settings_summary_off" msgid="3832876036123504076">"Ешқашан"</string>
     <string name="zen_interruption_level_priority" msgid="5392140786447823299">"Маңыздылары ғана"</string>
     <string name="zen_mode_and_condition" msgid="8877086090066332516">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
@@ -516,8 +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>
-    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
-    <skip />
+    <string name="media_transfer_this_phone" msgid="7194341457812151531">"Осы телефон"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Байланыс орнату қатесі шығуып жатыр. Құрылғыны өшіріп, қайта қосыңыз."</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Сымды аудио құрылғысы"</string>
     <string name="help_label" msgid="3528360748637781274">"Анықтама және пікір"</string>
@@ -557,8 +555,8 @@
     <string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g> пайдаланушысына ауысу"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Жаңа пайдаланушы профилі жасалуда…"</string>
     <string name="user_nickname" msgid="262624187455825083">"Лақап ат"</string>
-    <string name="guest_new_guest" msgid="3482026122932643557">"Қонақты енгізу"</string>
-    <string name="guest_exit_guest" msgid="5908239569510734136">"Қонақты өшіру"</string>
+    <string name="guest_new_guest" msgid="3482026122932643557">"Қонақ қосу"</string>
+    <string name="guest_exit_guest" msgid="5908239569510734136">"Қонақты жою"</string>
     <string name="guest_nickname" msgid="6332276931583337261">"Қонақ"</string>
     <string name="user_image_take_photo" msgid="467512954561638530">"Фотосуретке түсіру"</string>
     <string name="user_image_choose_photo" msgid="1363820919146782908">"Сурет таңдау"</string>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index f4cece4..708879a 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -556,7 +556,7 @@
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"កំពុងបង្កើត​អ្នកប្រើប្រាស់ថ្មី…"</string>
     <string name="user_nickname" msgid="262624187455825083">"ឈ្មោះ​ហៅក្រៅ"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"បញ្ចូល​ភ្ញៀវ"</string>
-    <string name="guest_exit_guest" msgid="5908239569510734136">"លុប​​​ភ្ញៀវ"</string>
+    <string name="guest_exit_guest" msgid="5908239569510734136">"ដកភ្ញៀវចេញ"</string>
     <string name="guest_nickname" msgid="6332276931583337261">"ភ្ញៀវ"</string>
     <string name="user_image_take_photo" msgid="467512954561638530">"ថតរូប"</string>
     <string name="user_image_choose_photo" msgid="1363820919146782908">"ជ្រើសរើស​រូបភាព"</string>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index a844ee6..daf7b6f 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -424,8 +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>
-    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
-    <skip />
+    <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,8 +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>
-    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
-    <skip />
+    <string name="media_transfer_this_phone" msgid="7194341457812151531">"ಈ ಫೋನ್"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"ಕನೆಕ್ಟ್ ಮಾಡುವಾಗ ಸಮಸ್ಯೆ ಎದುರಾಗಿದೆ ಸಾಧನವನ್ನು ಆಫ್ ಮಾಡಿ ಹಾಗೂ ನಂತರ ಪುನಃ ಆನ್ ಮಾಡಿ"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ವೈರ್ ಹೊಂದಿರುವ ಆಡಿಯೋ ಸಾಧನ"</string>
     <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 4ca6567..834200d 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -424,8 +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>
-    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
-    <skip />
+    <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,8 +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>
-    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
-    <skip />
+    <string name="media_transfer_this_phone" msgid="7194341457812151531">"Ушул телефон"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Туташууда маселе келип чыкты. Түзмөктү өчүрүп, кайра күйгүзүп көрүңүз"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Зымдуу аудио түзмөк"</string>
     <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 176c80f..0dcf1627 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -424,8 +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>
-    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
-    <skip />
+    <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,8 +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>
-    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
-    <skip />
+    <string name="media_transfer_this_phone" msgid="7194341457812151531">"ໂທລະສັບນີ້"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"ເກີດບັນຫາໃນການເຊື່ອມຕໍ່. ປິດອຸປະກອນແລ້ວເປີດກັບຄືນມາໃໝ່"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ອຸປະກອນສຽງແບບມີສາຍ"</string>
     <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 b0ab8f4..c3f9202 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -424,8 +424,7 @@
     <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>
-    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
-    <skip />
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Koreguokite, kaip spalvos rodomos jūsų įrenginyje. Tai gali būti naudinga, kai norite:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; matyti tikslesnes spalvas;&lt;/li&gt; &lt;li&gt; pašalinti spalvas, kad būtų lengviau susitelkti.&lt;/li&gt; &lt;/ol&gt;"</string>
     <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>
@@ -518,8 +517,7 @@
     <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="media_transfer_this_phone" msgid="7194341457812151531">"Šis telefonas"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Prisijungiant kilo problema. Išjunkite įrenginį ir vėl jį įjunkite"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Laidinis garso įrenginys"</string>
     <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 2633f13..5090df0 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -424,8 +424,7 @@
     <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>
-    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
-    <skip />
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Pielāgojiet krāsu attēlojumu jūsu ierīcē. Izmantojiet šo funkciju, lai:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; skatītu precīzāku krāsu attēlojumu;&lt;/li&gt; &lt;li&gt; noņemtu krāsas, kad jāpievēršas kādam uzdevumam.&lt;/li&gt; &lt;/ol&gt;"</string>
     <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>
@@ -517,8 +516,7 @@
     <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="media_transfer_this_phone" msgid="7194341457812151531">"Šis tālrunis"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Radās problēma ar savienojuma izveidi. Izslēdziet un atkal ieslēdziet ierīci."</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Vadu audioierīce"</string>
     <string name="help_label" msgid="3528360748637781274">"Palīdzība un atsauksmes"</string>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index e4173d0..c4890d4 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -424,8 +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>
-    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
-    <skip />
+    <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,8 +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>
-    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
-    <skip />
+    <string name="media_transfer_this_phone" msgid="7194341457812151531">"Овој телефон"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Проблем со поврзување. Исклучете го уредот и повторно вклучете го"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Жичен аудиоуред"</string>
     <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 3cfe479..829d474 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -424,8 +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>
-    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
-    <skip />
+    <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,8 +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>
-    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
-    <skip />
+    <string name="media_transfer_this_phone" msgid="7194341457812151531">"ഈ ഫോൺ"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"കണക്‌റ്റ് ചെയ്യുന്നതിൽ പ്രശ്‌നമുണ്ടായി. ഉപകരണം ഓഫാക്കി വീണ്ടും ഓണാക്കുക"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"വയർ മുഖേന ബന്ധിപ്പിച്ച ഓഡിയോ ഉപകരണം"</string>
     <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 f8d9089..e9fe1dd 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -424,8 +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>
-    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
-    <skip />
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"तुमच्या डिव्हाइसवर रंग कसे प्रदर्शित केले जातात ते अ‍ॅडजस्ट करा. तुम्हाला &lt;/br&gt;&lt;br&gt; &lt;/br&gt;&lt;br&gt; &lt;/br&gt;&lt;br&gt;अधिक स्पष्टपणे रंग पाहणे &lt;/br&gt;&lt;br&gt; &lt;/br&gt;&lt;br&gt; तुम्हाला फोकस करण्यात मदत करण्यासाठी रंग काढून टाकणे&lt;/br&gt;&lt;br&gt; &lt;/br&gt;&lt;br&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,8 +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>
-    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
-    <skip />
+    <string name="media_transfer_this_phone" msgid="7194341457812151531">"हा फोन"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"कनेक्‍ट करण्‍यात समस्‍या आली. डिव्हाइस बंद करा आणि नंतर सुरू करा"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"वायर असलेले ऑडिओ डिव्हाइस"</string>
     <string name="help_label" msgid="3528360748637781274">"मदत आणि फीडबॅक"</string>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index f10e539..d80242ef 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -424,8 +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>
-    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
-    <skip />
+    <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,8 +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>
-    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
-    <skip />
+    <string name="media_transfer_this_phone" msgid="7194341457812151531">"ဤဖုန်း"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"ချိတ်ဆက်ရာတွင် ပြဿနာရှိပါသည်။ စက်ကိုပိတ်ပြီး ပြန်ဖွင့်ပါ"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ကြိုးတပ် အသံစက်ပစ္စည်း"</string>
     <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 9fb68d0..7b49b40 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -424,8 +424,7 @@
     <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>
-    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
-    <skip />
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Juster hvordan farger vises på enheten. Dette kan være nyttig når du vil&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; se farger mer nøyaktig&lt;/li&gt; &lt;li&gt; fjerne farger for å gjøre det enklere å fokusere&lt;/li&gt; &lt;/ol&gt;"</string>
     <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>
@@ -516,8 +515,7 @@
     <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="media_transfer_this_phone" msgid="7194341457812151531">"Denne telefonen"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Tilkoblingsproblemer. Slå enheten av og på igjen"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Lydenhet med kabel"</string>
     <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 4c847cf..4d380a5 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -424,8 +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>
-    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
-    <skip />
+    <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,8 +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>
-    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
-    <skip />
+    <string name="media_transfer_this_phone" msgid="7194341457812151531">"यो फोन"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"जोड्ने क्रममा समस्या भयो। यन्त्रलाई निष्क्रिय पारेर फेरि सक्रिय गर्नुहोस्"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"तारयुक्त अडियो यन्त्र"</string>
     <string name="help_label" msgid="3528360748637781274">"मद्दत र प्रतिक्रिया"</string>
@@ -541,7 +539,7 @@
     <string name="user_add_profile_item_title" msgid="3111051717414643029">"प्रतिबन्धित प्रोफाइल"</string>
     <string name="user_add_user_title" msgid="5457079143694924885">"नयाँ प्रयोगकर्ता थप्ने हो?"</string>
     <string name="user_add_user_message_long" msgid="1527434966294733380">"तपाईं थप प्रयोगकर्ताहरू सिर्जना गरेर ती प्रयोगकर्तालाई यो यन्त्र प्रयोग गर्न दिन सक्नुहुन्छ। हरेक प्रयोगकर्ताको आफ्नै ठाउँ हुन्छ। उनीहरू यो ठाउँमा आफ्नै एप, वालपेपर आदिका लागि प्रयोग गर्न सक्छन्। उनीहरू सबैजनालाई असर पार्ने Wi-Fi जस्ता यन्त्रका सेटिङहरू पनि परिवर्तन गर्न सक्छन्।\n\nतपाईंले नयाँ प्रयोगकर्ता थप्दा उक्त व्यक्तिले आफ्नो ठाउँ सेटअप गर्नु पर्ने हुन्छ।\n\nसबै प्रयोगकर्ता अन्य सबै प्रयोगकर्ताले प्रयोग गर्ने एपहरू अद्यावधिक गर्न सक्छन्। तर पहुँचसम्बन्धी सेटिङ तथा सेवाहरू नयाँ प्रयोगकर्तामा नसर्न सक्छ।"</string>
-    <string name="user_add_user_message_short" msgid="3295959985795716166">"जब तपाईंले नयाँ प्रयोगकर्ता थप्नुहुन्छ, त्यो व्यक्तिले आफ्नो ठाउँ सेट गर्न आवश्यक छ।\n\nकुनै पनि प्रयोगकर्ताले सबै अन्य प्रयोगकर्ताहरूका लागि एपहरू अद्यावधिक गर्न सक्छन्।"</string>
+    <string name="user_add_user_message_short" msgid="3295959985795716166">"तपाईंले नयाँ प्रयोगकर्ता थप्नुभयो भने ती प्रयोगकर्ताले आफ्नो स्पेस सेट गर्नु पर्ने हुन्छ।\n\nसबै प्रयोगकर्ताले अरू प्रयोगकर्ताका एपहरू अपडेट गर्न सक्छन्।"</string>
     <string name="user_setup_dialog_title" msgid="8037342066381939995">"अहिले प्रयोगकर्ता सेटअप गर्ने हो?"</string>
     <string name="user_setup_dialog_message" msgid="269931619868102841">"यी व्यक्ति यन्त्र यो यन्त्र चलाउन र आफ्नो ठाउँ सेट गर्न उपलब्ध छन् भन्ने कुरा सुनिश्चित गर्नुहोस्"</string>
     <string name="user_setup_profile_dialog_message" msgid="4788197052296962620">"अहिले प्रोफाइल सेटअप गर्ने हो?"</string>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index 4cb755b..518aaa9 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -371,7 +371,7 @@
     <string name="app_process_limit_title" msgid="8361367869453043007">"Achtergrondproceslimiet"</string>
     <string name="show_all_anrs" msgid="9160563836616468726">"ANR\'s op de achtergrond"</string>
     <string name="show_all_anrs_summary" msgid="8562788834431971392">"Dialoogvenster \'App reageert niet\' weergeven voor achtergrond-apps"</string>
-    <string name="show_notification_channel_warnings" msgid="3448282400127597331">"Kanaalwaarschuwingen voor meldingen weergeven"</string>
+    <string name="show_notification_channel_warnings" msgid="3448282400127597331">"Kanaalwaarschuwingen voor meldingen tonen"</string>
     <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Geeft een waarschuwing op het scherm weer wanneer een app een melding post zonder geldig kanaal"</string>
     <string name="force_allow_on_external" msgid="9187902444231637880">"Toestaan van apps op externe opslag afdwingen"</string>
     <string name="force_allow_on_external_summary" msgid="8525425782530728238">"Hiermee komt elke app in aanmerking voor schrijven naar externe opslag, ongeacht de manifestwaarden"</string>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index b7c93e5..b0fff21 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -424,8 +424,7 @@
     <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>
-    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
-    <skip />
+    <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,8 +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>
-    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
-    <skip />
+    <string name="media_transfer_this_phone" msgid="7194341457812151531">"ଏହି ଫୋନ୍"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"ସଂଯୋଗ କରିବାରେ ସମସ୍ୟା ହେଉଛି। ଡିଭାଇସ୍ ବନ୍ଦ କରି ପୁଣି ଚାଲୁ କରନ୍ତୁ"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ତାରଯୁକ୍ତ ଅଡିଓ ଡିଭାଇସ୍"</string>
     <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 896a100..71e2dba 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -424,8 +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>
-    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
-    <skip />
+    <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,8 +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>
-    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
-    <skip />
+    <string name="media_transfer_this_phone" msgid="7194341457812151531">"ਇਹ ਫ਼ੋਨ"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"ਕਨੈਕਟ ਕਰਨ ਵਿੱਚ ਸਮੱਸਿਆ ਆਈ। ਡੀਵਾਈਸ ਨੂੰ ਬੰਦ ਕਰਕੇ ਵਾਪਸ ਚਾਲੂ ਕਰੋ"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ਤਾਰ ਵਾਲਾ ਆਡੀਓ ਡੀਵਾਈਸ"</string>
     <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 663f3fc..c8d7287 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -424,8 +424,7 @@
     <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>
-    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
-    <skip />
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Dostosuj sposób wyświetlania kolorów na ekranie urządzenia. Może to być pomocne, gdy chcesz:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; dokładniej widzieć kolory;,&lt;/li&gt; &lt;li&gt; usunąć wybrane kolory, aby móc skuteczniej się skupić.&lt;/li&gt; &lt;/ol&gt;"</string>
     <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>
@@ -518,8 +517,7 @@
     <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="media_transfer_this_phone" msgid="7194341457812151531">"Ten telefon"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem z połączeniem. Wyłącz i ponownie włącz urządzenie"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Przewodowe urządzenie audio"</string>
     <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 8eab928..1d6624d 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -424,8 +424,7 @@
     <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>
-    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
-    <skip />
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Ajuste as cores exibidas no seu dispositivo. Esta opção pode ser útil quando você quer:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; ver cores com mais precisão;&lt;/li&gt; &lt;li&gt; remover cores para se concentrar melhor.&lt;/li&gt; &lt;/ol&gt;"</string>
     <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>
@@ -516,8 +515,7 @@
     <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="media_transfer_this_phone" msgid="7194341457812151531">"Este smartphone"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Ocorreu um problema na conexão. Desligue o dispositivo e ligue-o novamente"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositivo de áudio com fio"</string>
     <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 f28d70a..66d4b23 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -424,8 +424,7 @@
     <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>
-    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
-    <skip />
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Ajuste a visualização das cores no dispositivo. Isto pode ser útil quando pretender:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; Ver cores com maior precisão&lt;/li&gt; &lt;li&gt; Remover cores para melhorar a sua concentração&lt;/li&gt; &lt;/ol&gt;"</string>
     <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>
@@ -516,8 +515,7 @@
     <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="media_transfer_this_phone" msgid="7194341457812151531">"Este telemóvel"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problema ao ligar. Desligue e volte a ligar o dispositivo."</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositivo de áudio com fios"</string>
     <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 8eab928..1d6624d 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -424,8 +424,7 @@
     <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>
-    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
-    <skip />
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Ajuste as cores exibidas no seu dispositivo. Esta opção pode ser útil quando você quer:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; ver cores com mais precisão;&lt;/li&gt; &lt;li&gt; remover cores para se concentrar melhor.&lt;/li&gt; &lt;/ol&gt;"</string>
     <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>
@@ -516,8 +515,7 @@
     <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="media_transfer_this_phone" msgid="7194341457812151531">"Este smartphone"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Ocorreu um problema na conexão. Desligue o dispositivo e ligue-o novamente"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositivo de áudio com fio"</string>
     <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 0a4e462..3e77ab6 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -424,8 +424,7 @@
     <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>
-    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
-    <skip />
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Ajustați modul în care se afișează culorile pe dispozitiv. Acest lucru poate fi util când doriți să:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; vedeți culorile mai bine&lt;/li&gt; &lt;li&gt; eliminați culorile pentru a vă ajuta să vă concentrați&lt;/li&gt; &lt;/ol&gt;"</string>
     <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>
@@ -517,8 +516,7 @@
     <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="media_transfer_this_phone" msgid="7194341457812151531">"Acest telefon"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problemă la conectare. Opriți și reporniți dispozitivul."</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispozitiv audio cu fir"</string>
     <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 b030715..b342287 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -424,8 +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>
-    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
-    <skip />
+    <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>
@@ -518,8 +517,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>
-    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
-    <skip />
+    <string name="media_transfer_this_phone" msgid="7194341457812151531">"Этот смартфон"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Ошибка подключения. Выключите и снова включите устройство."</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Проводное аудиоустройство"</string>
     <string name="help_label" msgid="3528360748637781274">"Справка/отзыв"</string>
@@ -559,7 +557,7 @@
     <string name="user_switch_to_user" msgid="6975428297154968543">"Переключиться на этот аккаунт: <xliff:g id="USER_NAME">%s</xliff:g>"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Создаем нового пользователя…"</string>
     <string name="user_nickname" msgid="262624187455825083">"Псевдоним"</string>
-    <string name="guest_new_guest" msgid="3482026122932643557">"Добавить аккаунт гостя"</string>
+    <string name="guest_new_guest" msgid="3482026122932643557">"Добавить гостя"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"Удалить аккаунт гостя"</string>
     <string name="guest_nickname" msgid="6332276931583337261">"Гость"</string>
     <string name="user_image_take_photo" msgid="467512954561638530">"Сделать снимок"</string>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index d9d5351..b24ac8e 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -424,8 +424,7 @@
     <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>
-    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
-    <skip />
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Upravte si zobrazovanie farieb v zariadení. Môže to byť užitočné, ak chcete:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; zobraziť presnejšie viac farieb;y&lt;/li&gt; &lt;li&gt; odstrániť farby, aby ste sa mohli lepšie sústrediť.&lt;/li&gt; &lt;/ol&gt;"</string>
     <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>
@@ -518,8 +517,7 @@
     <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="media_transfer_this_phone" msgid="7194341457812151531">"Tento telefón"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Pri pripájaní sa vyskytol problém. Zariadenie vypnite a znova zapnite."</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Audio zariadenie s káblom"</string>
     <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 81b1b60..626402a 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -424,8 +424,7 @@
     <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>
-    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
-    <skip />
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Prilagodite prikaz barv v napravi. To je uporabno, ko želite:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; videti bolj prave barve;&lt;/li&gt; &lt;li&gt; odstraniti barve, da se lažje osredotočite.&lt;/li&gt; &lt;/ol&gt;"</string>
     <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>
@@ -518,8 +517,7 @@
     <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="media_transfer_this_phone" msgid="7194341457812151531">"Ta telefon"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Težava pri povezovanju. Napravo izklopite in znova vklopite."</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Žična zvočna naprava"</string>
     <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 b71e51f..4f22348 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -424,8 +424,7 @@
     <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>
-    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
-    <skip />
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Rregullo mënyrën se si ngjyrat afishohen në pajisjen tënde. Kjo mund të jetë e dobishme kur dëshiron që:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; T\'i shikosh ngjyrat me më shumë saktësi&lt;/li&gt; &lt;li&gt; T\'i heqësh ngjyrat për të të ndihmuar të fokusohesh&lt;/li&gt; &lt;/ol&gt;"</string>
     <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>
@@ -516,8 +515,7 @@
     <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="media_transfer_this_phone" msgid="7194341457812151531">"Ky telefon"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem me lidhjen. Fike dhe ndize përsëri pajisjen"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Pajisja audio me tel"</string>
     <string name="help_label" msgid="3528360748637781274">"Ndihma dhe komentet"</string>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index 2ec2ded..069b6a5 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -424,8 +424,7 @@
     <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>
-    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
-    <skip />
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Ändra hur färger visas på enheten. Det kan vara ett bra hjälpmedel när du vill&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; att färger ska visas mer exakt&lt;/li&gt; &lt;li&gt; ta bort färger för att fokusera bättre&lt;/li&gt; &lt;/ol&gt;"</string>
     <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>
@@ -516,8 +515,7 @@
     <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="media_transfer_this_phone" msgid="7194341457812151531">"Den här telefonen"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Det gick inte att ansluta. Stäng av enheten och slå på den igen"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Ljudenhet med kabelanslutning"</string>
     <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 410a4aa..0fb620c 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -555,7 +555,7 @@
     <string name="user_switch_to_user" msgid="6975428297154968543">"Badili utumie <xliff:g id="USER_NAME">%s</xliff:g>"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Inaweka mtumiaji mpya…"</string>
     <string name="user_nickname" msgid="262624187455825083">"Jina wakilishi"</string>
-    <string name="guest_new_guest" msgid="3482026122932643557">"Weka mgeni"</string>
+    <string name="guest_new_guest" msgid="3482026122932643557">"Ongeza mgeni"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"Ondoa mgeni"</string>
     <string name="guest_nickname" msgid="6332276931583337261">"Mgeni"</string>
     <string name="user_image_take_photo" msgid="467512954561638530">"Piga picha"</string>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index 14eb25d..3106a69 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -424,8 +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>
-    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
-    <skip />
+    <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,8 +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>
-    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
-    <skip />
+    <string name="media_transfer_this_phone" msgid="7194341457812151531">"இந்த மொபைல்"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"இணைப்பதில் சிக்கல். சாதனத்தை ஆஃப் செய்து மீண்டும் ஆன் செய்யவும்"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"வயருடன்கூடிய ஆடியோ சாதனம்"</string>
     <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 e652ab7..1f78c0c 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -424,8 +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>
-    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
-    <skip />
+    <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,8 +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>
-    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
-    <skip />
+    <string name="media_transfer_this_phone" msgid="7194341457812151531">"ఈ ఫోన్"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"కనెక్ట్ చేయడంలో సమస్య ఉంది. పరికరాన్ని ఆఫ్ చేసి, ఆపై తిరిగి ఆన్ చేయండి"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"వైర్ గల ఆడియో పరికరం"</string>
     <string name="help_label" msgid="3528360748637781274">"సహాయం &amp; ఫీడ్‌బ్యాక్"</string>
@@ -557,7 +555,7 @@
     <string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g>కు మార్చు"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"కొత్త యూజర్‌ను క్రియేట్ చేస్తోంది…"</string>
     <string name="user_nickname" msgid="262624187455825083">"మారుపేరు"</string>
-    <string name="guest_new_guest" msgid="3482026122932643557">"అతిథిని జోడించండి"</string>
+    <string name="guest_new_guest" msgid="3482026122932643557">"గెస్ట్‌ను జోడించండి"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"అతిథిని తీసివేయండి"</string>
     <string name="guest_nickname" msgid="6332276931583337261">"అతిథి"</string>
     <string name="user_image_take_photo" msgid="467512954561638530">"ఒక ఫోటో తీయండి"</string>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index 5fbf5d4..ef516c4 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -424,8 +424,7 @@
     <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>
-    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
-    <skip />
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Renklerin cihazınızda nasıl görüntüleneceğini düzenleyin Bu, şunları yapmak istediğinizde kullanışlı olur:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; Renkleri daha doğru görmek&lt;/li&gt; &lt;li&gt; Odaklanmanıza yardımcı olması için renkleri kaldırmak&lt;/li&gt; &lt;/ol&gt;"</string>
     <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>
@@ -516,8 +515,7 @@
     <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="media_transfer_this_phone" msgid="7194341457812151531">"Bu telefon"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Bağlanırken sorun oluştu. Cihazı kapatıp tekrar açın"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Kablolu ses cihazı"</string>
     <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 4511a4b..81528ad 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -424,8 +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>
-    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
-    <skip />
+    <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>
@@ -518,8 +517,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>
-    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
-    <skip />
+    <string name="media_transfer_this_phone" msgid="7194341457812151531">"Цей телефон"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Не вдається підключитися. Перезавантажте пристрій."</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Дротовий аудіопристрій"</string>
     <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 e61d281..798c885 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -424,8 +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>
-    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
-    <skip />
+    <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,8 +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>
-    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
-    <skip />
+    <string name="media_transfer_this_phone" msgid="7194341457812151531">"یہ فون"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"منسلک کرنے میں مسئلہ پیش آ گیا۔ آلہ کو آف اور بیک آن کریں"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"وائرڈ آڈیو آلہ"</string>
     <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 0730c6c..6efc0be 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -556,7 +556,7 @@
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Yangi foydalanuvchi yaratilmoqda…"</string>
     <string name="user_nickname" msgid="262624187455825083">"Nik"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"Mehmon kiritish"</string>
-    <string name="guest_exit_guest" msgid="5908239569510734136">"Mehmon rejimini olib tashlash"</string>
+    <string name="guest_exit_guest" msgid="5908239569510734136">"Mehmonni olib tashlash"</string>
     <string name="guest_nickname" msgid="6332276931583337261">"Mehmon"</string>
     <string name="user_image_take_photo" msgid="467512954561638530">"Suratga olish"</string>
     <string name="user_image_choose_photo" msgid="1363820919146782908">"Rasm tanlash"</string>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index 7d1bde3..67923c5 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -424,8 +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>
-    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
-    <skip />
+    <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,8 +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>
-    <!-- no translation found for media_transfer_this_phone (7194341457812151531) -->
-    <skip />
+    <string name="media_transfer_this_phone" msgid="7194341457812151531">"这部手机"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"连接时遇到问题。请关闭并重新开启设备"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"有线音频设备"</string>
     <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 06b5cd0..bf69b31 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="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="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,7 +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="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 2297cbe..7b0274a 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -424,8 +424,7 @@
     <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>
-    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) -->
-    <skip />
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Lungisa indlela imibala eboniswa ngayo kudivayisi yakkho. Lokhu kungaba usizo lapho ufuna:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; Ukubona imibala ngokunembilie&lt;/li&gt; &lt;li&gt; Ukususa imibala ukuze ugxile&lt;/li&gt; &lt;/ol&gt;"</string>
     <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>
@@ -516,8 +515,7 @@
     <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="media_transfer_this_phone" msgid="7194341457812151531">"Le foni"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Inkinga yokuxhumeka. Vala idivayisi futhi uphinde uyivule"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Idivayisi yomsindo enentambo"</string>
     <string name="help_label" msgid="3528360748637781274">"Usizo nempendulo"</string>
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index a28a1e3..b4194fd 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -426,6 +426,9 @@
     <!-- Permission required for CTS test - ClipboardManagerTest -->
     <uses-permission android:name="android.permission.SET_CLIP_SOURCE" />
 
+    <!-- Permission required for CTS test - FontManagerTest -->
+    <uses-permission android:name="android.permission.UPDATE_FONTS" />
+
     <application android:label="@string/app_label"
                 android:theme="@android:style/Theme.DeviceDefault.DayNight"
                 android:defaultToDeviceProtectedStorage="true"
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java
index 4fc1973..0d348e2 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java
@@ -44,7 +44,7 @@
     /**
      * Returns true if the FalsingManager thinks the last gesure was not a valid tap.
      *
-     * Accepts one parameter, robustCheck, that distinctly changes behavior. When set to false,
+     * The first parameter, robustCheck, distinctly changes behavior. When set to false,
      * this method simply looks at the last gesture and returns whether it is a tap or not, (as
      * opposed to a swipe or other non-tap gesture). When set to true, a more thorough analysis
      * is performed that can include historical interactions and other contextual cues to see
@@ -53,8 +53,11 @@
      * Set robustCheck to true if you want to validate a tap for launching an action, like opening
      * a notification. Set to false if you simply want to know if the last gesture looked like a
      * tap.
+     *
+     * The second parameter, falsePenalty, indicates how much this should affect future gesture
+     * classifications if this tap looks like a false.
      */
-    boolean isFalseTap(boolean robustCheck);
+    boolean isFalseTap(boolean robustCheck, double falsePenalty);
 
     /**
      * Returns true if the last two gestures do not look like a double tap.
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTileView.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTileView.java
index 53f7e44..ca13204 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTileView.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTileView.java
@@ -50,4 +50,8 @@
     public abstract void onStateChanged(State state);
 
     public abstract int getDetailY();
+
+    public View getLabelContainer() {
+        return null;
+    }
 }
diff --git a/packages/SystemUI/res/layout/udfps_animation_view_keyguard.xml b/packages/SystemUI/res/drawable/qs_tile_background.xml
similarity index 66%
copy from packages/SystemUI/res/layout/udfps_animation_view_keyguard.xml
copy to packages/SystemUI/res/drawable/qs_tile_background.xml
index 644d1ada..265f575 100644
--- a/packages/SystemUI/res/layout/udfps_animation_view_keyguard.xml
+++ b/packages/SystemUI/res/drawable/qs_tile_background.xml
@@ -14,9 +14,10 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-<com.android.systemui.biometrics.UdfpsAnimationViewKeyguard
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/udfps_animation_view"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent">
-</com.android.systemui.biometrics.UdfpsAnimationViewKeyguard>
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+    android:color="?android:attr/colorControlHighlight">
+    <item android:id="@android:id/mask"
+        android:drawable="@drawable/qs_tile_background_shape" />
+    <item android:id="@id/background"
+        android:drawable="@drawable/qs_tile_background_shape"/>
+</ripple>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/udfps_animation_view_keyguard.xml b/packages/SystemUI/res/drawable/qs_tile_background_shape.xml
similarity index 68%
copy from packages/SystemUI/res/layout/udfps_animation_view_keyguard.xml
copy to packages/SystemUI/res/drawable/qs_tile_background_shape.xml
index 644d1ada..f6b6834 100644
--- a/packages/SystemUI/res/layout/udfps_animation_view_keyguard.xml
+++ b/packages/SystemUI/res/drawable/qs_tile_background_shape.xml
@@ -14,9 +14,8 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-<com.android.systemui.biometrics.UdfpsAnimationViewKeyguard
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/udfps_animation_view"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent">
-</com.android.systemui.biometrics.UdfpsAnimationViewKeyguard>
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <corners android:radius="@dimen/qs_corner_radius" />
+    <solid android:color="#FFFFFF" />
+</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/udfps_animation_view_fpm_other.xml b/packages/SystemUI/res/layout/udfps_animation_view_fpm_other.xml
deleted file mode 100644
index f32faa0..0000000
--- a/packages/SystemUI/res/layout/udfps_animation_view_fpm_other.xml
+++ /dev/null
@@ -1,22 +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.
-  -->
-<com.android.systemui.biometrics.UdfpsAnimationViewFpmOther
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/udfps_animation_view"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent">
-</com.android.systemui.biometrics.UdfpsAnimationViewFpmOther>
diff --git a/packages/SystemUI/res/layout/udfps_animation_view_bp.xml b/packages/SystemUI/res/layout/udfps_bp_view.xml
similarity index 88%
rename from packages/SystemUI/res/layout/udfps_animation_view_bp.xml
rename to packages/SystemUI/res/layout/udfps_bp_view.xml
index 0cfbf2e..f1c55ef 100644
--- a/packages/SystemUI/res/layout/udfps_animation_view_bp.xml
+++ b/packages/SystemUI/res/layout/udfps_bp_view.xml
@@ -14,9 +14,9 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-<com.android.systemui.biometrics.UdfpsAnimationViewBp
+<com.android.systemui.biometrics.UdfpsBpView
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/udfps_animation_view"
     android:layout_width="match_parent"
     android:layout_height="match_parent">
-</com.android.systemui.biometrics.UdfpsAnimationViewBp>
+</com.android.systemui.biometrics.UdfpsBpView>
diff --git a/packages/SystemUI/res/layout/udfps_animation_view_enroll.xml b/packages/SystemUI/res/layout/udfps_enroll_view.xml
similarity index 79%
rename from packages/SystemUI/res/layout/udfps_animation_view_enroll.xml
rename to packages/SystemUI/res/layout/udfps_enroll_view.xml
index 9b5752d..4035305 100644
--- a/packages/SystemUI/res/layout/udfps_animation_view_enroll.xml
+++ b/packages/SystemUI/res/layout/udfps_enroll_view.xml
@@ -14,13 +14,13 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-<com.android.systemui.biometrics.UdfpsAnimationViewEnroll
+<com.android.systemui.biometrics.UdfpsEnrollView
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/udfps_animation_view"
     android:layout_width="match_parent"
     android:layout_height="match_parent">
 
-    <!-- Enrollment progress bar-->
+    <!-- Enrollment progress bar -->
     <com.android.systemui.biometrics.UdfpsProgressBar
         android:id="@+id/progress_bar"
         android:layout_width="match_parent"
@@ -31,4 +31,9 @@
         android:layout_gravity="center"
         android:visibility="gone"/>
 
-</com.android.systemui.biometrics.UdfpsAnimationViewEnroll>
+    <!-- Fingerprint -->
+    <ImageView
+        android:id="@+id/udfps_enroll_animation_fp_view"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"/>
+</com.android.systemui.biometrics.UdfpsEnrollView>
diff --git a/packages/SystemUI/res/layout/udfps_animation_view_keyguard.xml b/packages/SystemUI/res/layout/udfps_fpm_other_view.xml
similarity index 74%
rename from packages/SystemUI/res/layout/udfps_animation_view_keyguard.xml
rename to packages/SystemUI/res/layout/udfps_fpm_other_view.xml
index 644d1ada..6ecbb47 100644
--- a/packages/SystemUI/res/layout/udfps_animation_view_keyguard.xml
+++ b/packages/SystemUI/res/layout/udfps_fpm_other_view.xml
@@ -14,9 +14,15 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-<com.android.systemui.biometrics.UdfpsAnimationViewKeyguard
+<com.android.systemui.biometrics.UdfpsFpmOtherView
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/udfps_animation_view"
     android:layout_width="match_parent"
     android:layout_height="match_parent">
-</com.android.systemui.biometrics.UdfpsAnimationViewKeyguard>
+
+    <!-- Fingerprint -->
+    <ImageView
+        android:id="@+id/udfps_fpm_other_fp_view"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"/>
+</com.android.systemui.biometrics.UdfpsFpmOtherView>
diff --git a/packages/SystemUI/res/layout/udfps_animation_view_keyguard.xml b/packages/SystemUI/res/layout/udfps_keyguard_view.xml
similarity index 71%
copy from packages/SystemUI/res/layout/udfps_animation_view_keyguard.xml
copy to packages/SystemUI/res/layout/udfps_keyguard_view.xml
index 644d1ada..0199ccb 100644
--- a/packages/SystemUI/res/layout/udfps_animation_view_keyguard.xml
+++ b/packages/SystemUI/res/layout/udfps_keyguard_view.xml
@@ -14,9 +14,17 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-<com.android.systemui.biometrics.UdfpsAnimationViewKeyguard
+<com.android.systemui.biometrics.UdfpsKeyguardView
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/udfps_animation_view"
     android:layout_width="match_parent"
     android:layout_height="match_parent">
-</com.android.systemui.biometrics.UdfpsAnimationViewKeyguard>
+
+    <!-- TODO: add background protection -->
+
+    <!-- Fingerprint -->
+    <ImageView
+        android:id="@+id/udfps_keyguard_animation_fp_view"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"/>
+</com.android.systemui.biometrics.UdfpsKeyguardView>
diff --git a/packages/SystemUI/res/layout/udfps_view.xml b/packages/SystemUI/res/layout/udfps_view.xml
index e24c9e9..50b2f20 100644
--- a/packages/SystemUI/res/layout/udfps_view.xml
+++ b/packages/SystemUI/res/layout/udfps_view.xml
@@ -22,6 +22,11 @@
     android:layout_height="match_parent"
     systemui:sensorTouchAreaCoefficient="0.5">
 
+    <ViewStub
+        android:id="@+id/animation_view"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"/>
+
     <com.android.systemui.biometrics.UdfpsSurfaceView
         android:id="@+id/hbm_view"
         android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 92d9ca9..b0c5239 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -588,4 +588,7 @@
 
     <!-- Determines whether the shell features all run on another thread. -->
     <bool name="config_enableShellMainThread">false</bool>
+
+    <!-- Determines whether to allow the nav bar handle to be forced to be opaque. -->
+    <bool name="allow_force_nav_bar_handle_opaque">true</bool>
 </resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 885cd25..2062104 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -512,6 +512,7 @@
     <!-- The size of the gesture span needed to activate the "pull" notification expansion -->
     <dimen name="pull_span_min">25dp</dimen>
 
+    <dimen name="qs_corner_radius">14dp</dimen>
     <dimen name="qs_tile_height">96dp</dimen>
     <!--notification_side_paddings + notification_content_margin_start - (qs_quick_tile_size - qs_tile_background_size) / 2 -->
     <dimen name="qs_tile_layout_margin_side">18dp</dimen>
@@ -528,6 +529,8 @@
     <dimen name="qs_tile_margin_top">0dp</dimen>
     <dimen name="qs_tile_icon_background_stroke_width">-1dp</dimen>
     <dimen name="qs_tile_background_size">44dp</dimen>
+    <dimen name="qs_icon_size">20dp</dimen>
+    <dimen name="qs_label_container_margin">10dp</dimen>
     <dimen name="qs_quick_tile_size">48dp</dimen>
     <dimen name="qs_quick_tile_padding">12dp</dimen>
     <dimen name="qs_header_gear_translation">16dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 6207449..70be7c6 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2651,7 +2651,7 @@
     <!-- Content description for magnification mode switch. [CHAR LIMIT=NONE] -->
     <string name="magnification_mode_switch_description">Magnification switch</string>
     <!-- A11y state description for magnification mode switch that device is in full-screen mode. [CHAR LIMIT=NONE] -->
-    <string name="magnification_mode_switch_state_full_screen">Magnify entire screen</string>
+    <string name="magnification_mode_switch_state_full_screen">Magnify full screen</string>
     <!-- A11y state description for magnification mode switch that device is in window mode. [CHAR LIMIT=NONE] -->
     <string name="magnification_mode_switch_state_window">Magnify part of screen</string>
     <!-- Click action label for magnification switch. [CHAR LIMIT=NONE] -->
diff --git a/packages/SystemUI/shared/Android.bp b/packages/SystemUI/shared/Android.bp
index 09e9675a..f98a959 100644
--- a/packages/SystemUI/shared/Android.bp
+++ b/packages/SystemUI/shared/Android.bp
@@ -41,6 +41,7 @@
     srcs: [
         "src/**/*.java",
         "src/**/I*.aidl",
+        ":wm_shell-aidls",
     ],
 
     static_libs: [
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
index 49e86f5..3da3085 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
@@ -16,11 +16,6 @@
 
 package com.android.systemui.shared.recents;
 
-import android.app.PendingIntent;
-import android.app.PictureInPictureParams;
-import android.content.ComponentName;
-import android.content.Intent;
-import android.content.pm.ActivityInfo;
 import android.graphics.Bitmap;
 import android.graphics.Insets;
 import android.graphics.Rect;
@@ -28,26 +23,15 @@
 import android.os.UserHandle;
 import android.view.MotionEvent;
 
-import com.android.systemui.shared.recents.IPinnedStackAnimationListener;
-import com.android.systemui.shared.recents.ISplitScreenListener;
-import com.android.systemui.shared.recents.IStartingWindowListener;
 import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.system.RemoteTransitionCompat;
 
 /**
  * Temporary callbacks into SystemUI.
- * Next id = 44
  */
 interface ISystemUiProxy {
 
     /**
-     * Proxies SurfaceControl.screenshotToBuffer().
-     * @Removed
-     * GraphicBufferCompat screenshot(in Rect sourceCrop, int width, int height, int minLayer,
-     *             int maxLayer, boolean useIdentityTransform, int rotation) = 0;
-     */
-
-    /**
      * Begins screen pinning on the provided {@param taskId}.
      */
     void startScreenPinning(int taskId) = 1;
@@ -63,15 +47,9 @@
     Rect getNonMinimizedSplitScreenSecondaryBounds() = 7;
 
     /**
-     * Control the {@param alpha} of the back button in the navigation bar and {@param animate} if
-     * needed from current value
-     * @deprecated
-     */
-    void setBackButtonAlpha(float alpha, boolean animate) = 8;
-
-    /**
      * Control the {@param alpha} of the option nav bar button (back-button in 2 button mode
-     * and home bar in no-button mode) and {@param animate} if needed from current value
+     * and home handle & background in gestural mode).  The {@param animate} is currently only
+     * supported for 2 button mode.
      */
     void setNavBarButtonAlpha(float alpha, boolean animate) = 19;
 
@@ -121,11 +99,6 @@
     void stopScreenPinning() = 17;
 
     /**
-     * Sets the shelf height and visibility.
-     */
-    void setShelfHeight(boolean visible, int shelfHeight) = 20;
-
-    /**
      * Handle the provided image as if it was a screenshot.
      *
      * Deprecated, use handleImageBundleAsScreenshot with image bundle and UserTask
@@ -145,27 +118,12 @@
     void notifySwipeToHomeFinished() = 23;
 
     /**
-     * Sets listener to get pinned stack animation callbacks.
-     */
-    void setPinnedStackAnimationListener(IPinnedStackAnimationListener listener) = 24;
-
-    /**
      * Notifies that quickstep will switch to a new task
      * @param rotation indicates which Surface.Rotation the gesture was started in
      */
     void onQuickSwitchToNewTask(int rotation) = 25;
 
     /**
-     * Start the one-handed mode.
-     */
-    void startOneHandedMode() = 26;
-
-    /**
-     * Stop the one-handed mode.
-     */
-    void stopOneHandedMode() = 27;
-
-    /**
      * Handle the provided image as if it was a screenshot.
      */
     void handleImageBundleAsScreenshot(in Bundle screenImageBundle, in Rect locationInScreen,
@@ -176,88 +134,5 @@
      */
     void expandNotificationPanel() = 29;
 
-    /**
-     * Notifies that Activity is about to be swiped to home with entering PiP transition and
-     * queries the destination bounds for PiP depends on Launcher's rotation and shelf height.
-     *
-     * @param componentName ComponentName represents the Activity
-     * @param activityInfo ActivityInfo tied to the Activity
-     * @param pictureInPictureParams PictureInPictureParams tied to the Activity
-     * @param launcherRotation Launcher rotation to calculate the PiP destination bounds
-     * @param shelfHeight Shelf height of launcher to calculate the PiP destination bounds
-     * @return destination bounds the PiP window should land into
-     */
-    Rect startSwipePipToHome(in ComponentName componentName, in ActivityInfo activityInfo,
-                in PictureInPictureParams pictureInPictureParams,
-                int launcherRotation, int shelfHeight) = 30;
-
-    /**
-     * Notifies the swiping Activity to PiP onto home transition is finished
-     *
-     * @param componentName ComponentName represents the Activity
-     * @param destinationBounds the destination bounds the PiP window lands into
-     */
-    void stopSwipePipToHome(in ComponentName componentName, in Rect destinationBounds) = 31;
-
-    /**
-     * Registers a RemoteTransitionCompat that will handle transitions. This parameter bundles an
-     * IRemoteTransition and a filter that must pass for it.
-     */
-    void registerRemoteTransition(in RemoteTransitionCompat remoteTransition) = 32;
-
-    /** Unegisters a RemoteTransitionCompat that will handle transitions. */
-    void unregisterRemoteTransition(in RemoteTransitionCompat remoteTransition) = 33;
-
-// SplitScreen APIs...copied from SplitScreen.java
-    /**
-     * Stage position isn't specified normally meaning to use what ever it is currently set to.
-     */
-    //int STAGE_POSITION_UNDEFINED = -1;
-    /**
-     * Specifies that a stage is positioned at the top half of the screen if
-     * in portrait mode or at the left half of the screen if in landscape mode.
-     */
-    //int STAGE_POSITION_TOP_OR_LEFT = 0;
-    /**
-     * Specifies that a stage is positioned at the bottom half of the screen if
-     * in portrait mode or at the right half of the screen if in landscape mode.
-     */
-    //int STAGE_POSITION_BOTTOM_OR_RIGHT = 1;
-
-    /**
-     * Stage type isn't specified normally meaning to use what ever the default is.
-     * E.g. exit split-screen and launch the app in fullscreen.
-     */
-    //int STAGE_TYPE_UNDEFINED = -1;
-    /**
-     * The main stage type.
-     * @see MainStage
-     */
-    //int STAGE_TYPE_MAIN = 0;
-    /**
-     * The side stage type.
-     * @see SideStage
-     */
-    //int STAGE_TYPE_SIDE = 1;
-
-    void registerSplitScreenListener(in ISplitScreenListener listener) = 34;
-    void unregisterSplitScreenListener(in ISplitScreenListener listener) = 35;
-
-    /** Hides the side-stage if it is currently visible. */
-    void setSideStageVisibility(in boolean visible) = 36;
-    /** Removes the split-screen stages. */
-    void exitSplitScreen() = 37;
-    /** @param exitSplitScreenOnHide if to exit split-screen if both stages are not visible. */
-    void exitSplitScreenOnHide(boolean exitSplitScreenOnHide) = 38;
-    void startTask(in int taskId, in int stage, in int position, in Bundle options) = 39;
-    void startShortcut(in String packageName, in String shortcutId, in int stage, in int position,
-            in Bundle options, in UserHandle user) = 40;
-    void startIntent(
-            in PendingIntent intent, in Intent fillInIntent, in int stage, in int position,
-            in Bundle options) = 41;
-    void removeFromSideStage(in int taskId) = 42;
-    /**
-     * Sets listener to get task launching callbacks.
-     */
-    void setStartingWindowListener(IStartingWindowListener listener) = 43;
+    // Next id = 44
 }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java
index ebb6e30..e9e9b24 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java
@@ -289,15 +289,19 @@
     /**
      * Returns the visible width to height ratio. Returns 0f if snapshot data is not available.
      */
-    public float getVisibleThumbnailRatio() {
+    public float getVisibleThumbnailRatio(boolean clipInsets) {
         if (lastSnapshotData.taskSize == null || lastSnapshotData.contentInsets == null) {
             return 0f;
         }
 
-        float availableWidth = lastSnapshotData.taskSize.x - (lastSnapshotData.contentInsets.left
-                + lastSnapshotData.contentInsets.right);
-        float availableHeight = lastSnapshotData.taskSize.y - (lastSnapshotData.contentInsets.top
-                + lastSnapshotData.contentInsets.bottom);
+        float availableWidth = lastSnapshotData.taskSize.x;
+        float availableHeight = lastSnapshotData.taskSize.y;
+        if (clipInsets) {
+            availableWidth -=
+                    (lastSnapshotData.contentInsets.left + lastSnapshotData.contentInsets.right);
+            availableHeight -=
+                    (lastSnapshotData.contentInsets.top + lastSnapshotData.contentInsets.bottom);
+        }
         return availableWidth / availableHeight;
     }
 
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
index 937c1df..41840af 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
@@ -41,6 +41,18 @@
     public static final String KEY_EXTRA_INPUT_MONITOR = "extra_input_monitor";
     public static final String KEY_EXTRA_WINDOW_CORNER_RADIUS = "extra_window_corner_radius";
     public static final String KEY_EXTRA_SUPPORTS_WINDOW_CORNERS = "extra_supports_window_corners";
+    // See IPip.aidl
+    public static final String KEY_EXTRA_SHELL_PIP = "extra_shell_pip";
+    // See ISplitScreen.aidl
+    public static final String KEY_EXTRA_SHELL_SPLIT_SCREEN = "extra_shell_split_screen";
+    // See IOneHanded.aidl
+    public static final String KEY_EXTRA_SHELL_ONE_HANDED = "extra_shell_one_handed";
+    // See IShellTransitions.aidl
+    public static final String KEY_EXTRA_SHELL_SHELL_TRANSITIONS =
+            "extra_shell_shell_transitions";
+    // See IStartingWindow.aidl
+    public static final String KEY_EXTRA_SHELL_STARTING_WINDOW =
+            "extra_shell_starting_window";
 
     public static final String NAV_BAR_MODE_2BUTTON_OVERLAY =
             WindowManagerPolicyConstants.NAV_BAR_MODE_2BUTTON_OVERLAY;
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java
index af7c5da..c2d52a7 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java
@@ -16,11 +16,11 @@
 
 package com.android.systemui.shared.system;
 
-import android.window.TaskSnapshot;
 import android.graphics.Rect;
 import android.os.RemoteException;
 import android.util.Log;
 import android.view.IRecentsAnimationController;
+import android.window.TaskSnapshot;
 
 import com.android.systemui.shared.recents.model.ThumbnailData;
 
@@ -141,9 +141,9 @@
     /**
      * @see IRecentsAnimationController#detachNavigationBarFromApp
      */
-    public void detachNavigationBarFromApp() {
+    public void detachNavigationBarFromApp(boolean moveHomeToTop) {
         try {
-            mAnimationController.detachNavigationBarFromApp();
+            mAnimationController.detachNavigationBarFromApp(moveHomeToTop);
         } catch (RemoteException e) {
             Log.e(TAG, "Failed to detach the navigation bar from app", e);
         }
diff --git a/packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java b/packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java
index 1569fff..3f0e3eb 100644
--- a/packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java
+++ b/packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java
@@ -45,6 +45,7 @@
     private int mLockScreenColor;
 
     private boolean mIsDozing;
+    private float mDozeAmount;
     private Locale mLocale;
 
     private final NumberFormat mBurmeseNf = NumberFormat.getInstance(Locale.forLanguageTag("my"));
@@ -59,6 +60,7 @@
         super(view);
         mStatusBarStateController = statusBarStateController;
         mIsDozing = mStatusBarStateController.isDozing();
+        mDozeAmount = mStatusBarStateController.getDozeAmount();
         mBroadcastDispatcher = broadcastDispatcher;
 
         mBurmeseNumerals = mBurmeseNf.format(FORMAT_NUMBER);
@@ -82,6 +84,7 @@
                 new IntentFilter(Intent.ACTION_LOCALE_CHANGED));
         mStatusBarStateController.addCallback(mStatusBarStateListener);
         mIsDozing = mStatusBarStateController.isDozing();
+        mDozeAmount = mStatusBarStateController.getDozeAmount();
         refreshTime();
         initColors();
     }
@@ -136,9 +139,15 @@
     private final StatusBarStateController.StateListener mStatusBarStateListener =
             new StatusBarStateController.StateListener() {
                 @Override
-                public void onDozingChanged(boolean isDozing) {
-                    mIsDozing = isDozing;
-                    mView.animateDoze(mIsDozing, true);
+                public void onDozeAmountChanged(float linear, float eased) {
+                    boolean noAnimation = (mDozeAmount == 0f && linear == 1f)
+                            || (mDozeAmount == 1f && linear == 0f);
+                    boolean isDozing = linear > mDozeAmount;
+                    mDozeAmount = linear;
+                    if (mIsDozing != isDozing) {
+                        mIsDozing = isDozing;
+                        mView.animateDoze(mIsDozing, !noAnimation);
+                    }
                 }
             };
 }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java
index 5760565..a580663 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java
@@ -35,12 +35,15 @@
 import com.android.keyguard.KeyguardAbsKeyInputView.KeyDownListener;
 import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
 import com.android.systemui.R;
+import com.android.systemui.classifier.FalsingClassifier;
+import com.android.systemui.classifier.FalsingCollector;
 
 public abstract class KeyguardAbsKeyInputViewController<T extends KeyguardAbsKeyInputView>
         extends KeyguardInputViewController<T> {
     private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
     private final LockPatternUtils mLockPatternUtils;
     private final LatencyTracker mLatencyTracker;
+    private final FalsingCollector mFalsingCollector;
     private CountDownTimer mCountdownTimer;
     protected KeyguardMessageAreaController mMessageAreaController;
     private boolean mDismissing;
@@ -70,11 +73,12 @@
             LockPatternUtils lockPatternUtils,
             KeyguardSecurityCallback keyguardSecurityCallback,
             KeyguardMessageAreaController.Factory messageAreaControllerFactory,
-            LatencyTracker latencyTracker) {
+            LatencyTracker latencyTracker, FalsingCollector falsingCollector) {
         super(view, securityMode, keyguardSecurityCallback);
         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
         mLockPatternUtils = lockPatternUtils;
         mLatencyTracker = latencyTracker;
+        mFalsingCollector = falsingCollector;
         KeyguardMessageArea kma = KeyguardMessageArea.findSecurityMessageDisplay(mView);
         mMessageAreaController = messageAreaControllerFactory.create(kma);
     }
@@ -256,6 +260,7 @@
     }
 
     protected void onUserInput() {
+        mFalsingCollector.updateFalseConfidence(FalsingClassifier.Result.passed(0.6));
         getKeyguardSecurityCallback().userActivity();
         getKeyguardSecurityCallback().onUserInput();
         mMessageAreaController.setMessage("");
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardInputView.java
index 5e02e04..de64f07 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardInputView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardInputView.java
@@ -26,16 +26,11 @@
 import androidx.annotation.Nullable;
 
 import com.android.internal.jank.InteractionJankMonitor;
-import com.android.systemui.Gefingerpoken;
-
-import java.util.ArrayList;
-import java.util.List;
 
 /**
  * A Base class for all Keyguard password/pattern/pin related inputs.
  */
 public abstract class KeyguardInputView extends LinearLayout {
-    private final List<Gefingerpoken> mMotionEventListener = new ArrayList<>();
 
     public KeyguardInputView(Context context) {
         super(context);
@@ -53,7 +48,6 @@
     abstract CharSequence getTitle();
 
     void animateForIme(float interpolatedFraction) {
-        return;
     }
 
     boolean disallowInterceptTouch(MotionEvent event) {
@@ -66,27 +60,6 @@
         return false;
     }
 
-    void addMotionEventListener(Gefingerpoken listener) {
-        mMotionEventListener.add(listener);
-    }
-
-    void removeMotionEventListener(Gefingerpoken listener) {
-        mMotionEventListener.remove(listener);
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent event) {
-        return mMotionEventListener.stream().anyMatch(listener -> listener.onTouchEvent(event))
-                || super.onTouchEvent(event);
-    }
-
-    @Override
-    public boolean onInterceptTouchEvent(MotionEvent event) {
-        return mMotionEventListener.stream().anyMatch(
-                listener -> listener.onInterceptTouchEvent(event))
-                || super.onInterceptTouchEvent(event);
-    }
-
     protected AnimatorListenerAdapter getAnimationListener(int cuj) {
         return new AnimatorListenerAdapter() {
             private boolean mIsCancel;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java
index 957882d..05f33a9 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java
@@ -155,8 +155,8 @@
         private final InputMethodManager mInputMethodManager;
         private final DelayableExecutor mMainExecutor;
         private final Resources mResources;
-        private LiftToActivateListener mLiftToActivateListener;
-        private TelephonyManager mTelephonyManager;
+        private final LiftToActivateListener mLiftToActivateListener;
+        private final TelephonyManager mTelephonyManager;
         private final FalsingCollector mFalsingCollector;
         private final boolean mIsNewLayoutEnabled;
 
@@ -167,8 +167,7 @@
                 KeyguardMessageAreaController.Factory messageAreaControllerFactory,
                 InputMethodManager inputMethodManager, @Main DelayableExecutor mainExecutor,
                 @Main Resources resources, LiftToActivateListener liftToActivateListener,
-                TelephonyManager telephonyManager,
-                FalsingCollector falsingCollector,
+                TelephonyManager telephonyManager, FalsingCollector falsingCollector,
                 FeatureFlags featureFlags) {
             mKeyguardUpdateMonitor = keyguardUpdateMonitor;
             mLockPatternUtils = lockPatternUtils;
@@ -189,12 +188,13 @@
             if (keyguardInputView instanceof KeyguardPatternView) {
                 return new KeyguardPatternViewController((KeyguardPatternView) keyguardInputView,
                         mKeyguardUpdateMonitor, securityMode, mLockPatternUtils,
-                        keyguardSecurityCallback, mLatencyTracker, mMessageAreaControllerFactory);
+                        keyguardSecurityCallback, mLatencyTracker, mFalsingCollector,
+                        mMessageAreaControllerFactory);
             } else if (keyguardInputView instanceof KeyguardPasswordView) {
                 return new KeyguardPasswordViewController((KeyguardPasswordView) keyguardInputView,
                         mKeyguardUpdateMonitor, securityMode, mLockPatternUtils,
                         keyguardSecurityCallback, mMessageAreaControllerFactory, mLatencyTracker,
-                        mInputMethodManager, mMainExecutor, mResources);
+                        mInputMethodManager, mMainExecutor, mResources, mFalsingCollector);
             } else if (keyguardInputView instanceof KeyguardPINView) {
                 return new KeyguardPinViewController((KeyguardPINView) keyguardInputView,
                         mKeyguardUpdateMonitor, securityMode, mLockPatternUtils,
@@ -204,14 +204,14 @@
                 return new KeyguardSimPinViewController((KeyguardSimPinView) keyguardInputView,
                         mKeyguardUpdateMonitor, securityMode, mLockPatternUtils,
                         keyguardSecurityCallback, mMessageAreaControllerFactory, mLatencyTracker,
-                        mLiftToActivateListener, mTelephonyManager,
-                        mFalsingCollector, mIsNewLayoutEnabled);
+                        mLiftToActivateListener, mTelephonyManager, mFalsingCollector,
+                        mIsNewLayoutEnabled);
             } else if (keyguardInputView instanceof KeyguardSimPukView) {
                 return new KeyguardSimPukViewController((KeyguardSimPukView) keyguardInputView,
                         mKeyguardUpdateMonitor, securityMode, mLockPatternUtils,
                         keyguardSecurityCallback, mMessageAreaControllerFactory, mLatencyTracker,
-                        mLiftToActivateListener, mTelephonyManager,
-                        mFalsingCollector, mIsNewLayoutEnabled);
+                        mLiftToActivateListener, mTelephonyManager, mFalsingCollector,
+                        mIsNewLayoutEnabled);
             }
 
             throw new RuntimeException("Unable to find controller for " + keyguardInputView);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java
index 0f1c3c8..57b8cf0 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java
@@ -40,6 +40,7 @@
 import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
 import com.android.settingslib.Utils;
 import com.android.systemui.R;
+import com.android.systemui.classifier.FalsingCollector;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.util.concurrency.DelayableExecutor;
 
@@ -112,9 +113,10 @@
             LatencyTracker latencyTracker,
             InputMethodManager inputMethodManager,
             @Main DelayableExecutor mainExecutor,
-            @Main Resources resources) {
+            @Main Resources resources,
+            FalsingCollector falsingCollector) {
         super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback,
-                messageAreaControllerFactory, latencyTracker);
+                messageAreaControllerFactory, latencyTracker, falsingCollector);
         mKeyguardSecurityCallback = keyguardSecurityCallback;
         mInputMethodManager = inputMethodManager;
         mMainExecutor = mainExecutor;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
index 2aaf748..4f48bb4 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
@@ -23,6 +23,7 @@
 import android.os.AsyncTask;
 import android.os.CountDownTimer;
 import android.os.SystemClock;
+import android.view.MotionEvent;
 import android.view.View;
 
 import com.android.internal.util.LatencyTracker;
@@ -35,6 +36,8 @@
 import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
 import com.android.settingslib.Utils;
 import com.android.systemui.R;
+import com.android.systemui.classifier.FalsingClassifier;
+import com.android.systemui.classifier.FalsingCollector;
 
 import java.util.List;
 
@@ -50,6 +53,7 @@
     private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
     private final LockPatternUtils mLockPatternUtils;
     private final LatencyTracker mLatencyTracker;
+    private final FalsingCollector mFalsingCollector;
     private final KeyguardMessageAreaController.Factory mMessageAreaControllerFactory;
 
     private KeyguardMessageAreaController mMessageAreaController;
@@ -102,6 +106,11 @@
 
             final int userId = KeyguardUpdateMonitor.getCurrentUser();
             if (pattern.size() < LockPatternUtils.MIN_PATTERN_REGISTER_FAIL) {
+                // Treat single-sized patterns as erroneous taps.
+                if (pattern.size() == 1) {
+                    mFalsingCollector.updateFalseConfidence(FalsingClassifier.Result.falsed(
+                            0.7, "empty pattern input"));
+                }
                 mLockPatternView.enableInput();
                 onPatternChecked(userId, false, 0, false /* not valid - too short */);
                 return;
@@ -179,11 +188,13 @@
             LockPatternUtils lockPatternUtils,
             KeyguardSecurityCallback keyguardSecurityCallback,
             LatencyTracker latencyTracker,
+            FalsingCollector falsingCollector,
             KeyguardMessageAreaController.Factory messageAreaControllerFactory) {
         super(view, securityMode, keyguardSecurityCallback);
         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
         mLockPatternUtils = lockPatternUtils;
         mLatencyTracker = latencyTracker;
+        mFalsingCollector = falsingCollector;
         mMessageAreaControllerFactory = messageAreaControllerFactory;
         KeyguardMessageArea kma = KeyguardMessageArea.findSecurityMessageDisplay(mView);
         mMessageAreaController = mMessageAreaControllerFactory.create(kma);
@@ -205,6 +216,12 @@
                 KeyguardUpdateMonitor.getCurrentUser()));
         // vibrate mode will be the same for the life of this screen
         mLockPatternView.setTactileFeedbackEnabled(mLockPatternUtils.isTactileFeedbackEnabled());
+        mLockPatternView.setOnTouchListener((v, event) -> {
+            if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
+                mFalsingCollector.avoidGesture();
+            }
+            return false;
+        });
 
         EmergencyButton button = mView.findViewById(R.id.emergency_call_button);
         if (button != null) {
@@ -224,6 +241,7 @@
     protected void onViewDetached() {
         super.onViewDetached();
         mLockPatternView.setOnPatternListener(null);
+        mLockPatternView.setOnTouchListener(null);
         EmergencyButton button = mView.findViewById(R.id.emergency_call_button);
         if (button != null) {
             button.setCallback(null);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
index 4e06491..09fb8ef 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
@@ -164,6 +164,10 @@
         reloadColors();
     }
 
+    NumPadKey[] getButtons() {
+        return mButtons;
+    }
+
     /**
      * By default, the new layout will be enabled. When false, revert to the old style.
      */
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java
index f247948..b156f81 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java
@@ -25,7 +25,6 @@
 import com.android.internal.util.LatencyTracker;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
-import com.android.systemui.Gefingerpoken;
 import com.android.systemui.R;
 import com.android.systemui.classifier.FalsingCollector;
 
@@ -50,19 +49,6 @@
         return false;
     };
 
-    private final Gefingerpoken mGlobalTouchListener = new Gefingerpoken() {
-        @Override
-        public boolean onInterceptTouchEvent(MotionEvent ev) {
-            mFalsingCollector.avoidGesture();
-            return false;
-        }
-
-        @Override
-        public boolean onTouchEvent(MotionEvent ev) {
-            return false;
-        }
-    };
-
     protected KeyguardPinBasedInputViewController(T view,
             KeyguardUpdateMonitor keyguardUpdateMonitor,
             SecurityMode securityMode,
@@ -73,7 +59,7 @@
             LiftToActivateListener liftToActivateListener,
             FalsingCollector falsingCollector) {
         super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback,
-                messageAreaControllerFactory, latencyTracker);
+                messageAreaControllerFactory, latencyTracker, falsingCollector);
         mLiftToActivateListener = liftToActivateListener;
         mFalsingCollector = falsingCollector;
         mPasswordEntry = mView.findViewById(mView.getPasswordTextViewId());
@@ -83,8 +69,14 @@
     protected void onViewAttached() {
         super.onViewAttached();
 
-        mView.addMotionEventListener(mGlobalTouchListener);
-
+        for (NumPadKey button: mView.getButtons()) {
+            button.setOnTouchListener((v, event) -> {
+                if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
+                    mFalsingCollector.avoidGesture();
+                }
+                return false;
+            });
+        }
         mPasswordEntry.setOnKeyListener(mOnKeyListener);
         mPasswordEntry.setUserActivityListener(this::onUserInput);
 
@@ -123,7 +115,10 @@
     @Override
     protected void onViewDetached() {
         super.onViewDetached();
-        mView.removeMotionEventListener(mGlobalTouchListener);
+
+        for (NumPadKey button: mView.getButtons()) {
+            button.setOnTouchListener(null);
+        }
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index a2d7707..eaf8516 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -58,10 +58,12 @@
 import com.android.internal.logging.UiEventLogger;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
+import com.android.systemui.Gefingerpoken;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
 
+import java.util.ArrayList;
 import java.util.List;
 
 public class KeyguardSecurityContainer extends FrameLayout {
@@ -97,6 +99,7 @@
     private final ViewConfiguration mViewConfiguration;
     private final SpringAnimation mSpringAnimation;
     private final VelocityTracker mVelocityTracker = VelocityTracker.obtain();
+    private final List<Gefingerpoken> mMotionEventListeners = new ArrayList<>();
 
     private float mLastTouchY = -1;
     private int mActivePointerId = -1;
@@ -388,6 +391,10 @@
 
     @Override
     public boolean onInterceptTouchEvent(MotionEvent event) {
+        boolean result =  mMotionEventListeners.stream().anyMatch(
+                listener -> listener.onInterceptTouchEvent(event))
+                || super.onInterceptTouchEvent(event);
+
         switch (event.getActionMasked()) {
             case MotionEvent.ACTION_DOWN:
                 int pointerIndex = event.getActionIndex();
@@ -418,12 +425,17 @@
                 mIsDragging = false;
                 break;
         }
-        return false;
+        return result;
     }
 
     @Override
     public boolean onTouchEvent(MotionEvent event) {
         final int action = event.getActionMasked();
+
+        boolean result =  mMotionEventListeners.stream()
+                .anyMatch(listener -> listener.onTouchEvent(event))
+                || super.onTouchEvent(event);
+
         switch (action) {
             case MotionEvent.ACTION_MOVE:
                 mVelocityTracker.addMovement(event);
@@ -469,6 +481,14 @@
         return true;
     }
 
+    void addMotionEventListener(Gefingerpoken listener) {
+        mMotionEventListeners.add(listener);
+    }
+
+    void removeMotionEventListener(Gefingerpoken listener) {
+        mMotionEventListeners.remove(listener);
+    }
+
     private void handleTap(MotionEvent event) {
         // If we're using a fullscreen security mode, skip
         if (!mOneHandedMode) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
index fdab8db..7eac903 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
@@ -33,6 +33,7 @@
 import android.os.UserHandle;
 import android.util.Log;
 import android.util.Slog;
+import android.view.MotionEvent;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.MetricsLogger;
@@ -46,6 +47,8 @@
 import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
 import com.android.keyguard.dagger.KeyguardBouncerScope;
 import com.android.settingslib.utils.ThreadUtils;
+import com.android.systemui.Gefingerpoken;
+import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.shared.system.SysUiStatsLog;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -71,9 +74,44 @@
     private final KeyguardSecurityViewFlipperController mSecurityViewFlipperController;
     private final SecurityCallback mSecurityCallback;
     private final ConfigurationController mConfigurationController;
+    private final KeyguardViewController mKeyguardViewController;
+    private final FalsingManager mFalsingManager;
 
     private SecurityMode mCurrentSecurityMode = SecurityMode.Invalid;
 
+    private final Gefingerpoken mGlobalTouchListener = new Gefingerpoken() {
+        private MotionEvent mTouchDown;
+        @Override
+        public boolean onInterceptTouchEvent(MotionEvent ev) {
+            return false;
+        }
+
+        @Override
+        public boolean onTouchEvent(MotionEvent ev) {
+            // Do just a bit of our own falsing. People should only be tapping on the input, not
+            // swiping.
+            if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
+                if (mTouchDown != null) {
+                    mTouchDown.recycle();
+                    mTouchDown = null;
+                }
+                mTouchDown = MotionEvent.obtain(ev);
+            } else if (mTouchDown != null) {
+                boolean tapResult = mFalsingManager.isFalseTap(true, 0.6);
+                if (tapResult
+                        || ev.getActionMasked() == MotionEvent.ACTION_UP
+                        || ev.getActionMasked() == MotionEvent.ACTION_CANCEL) {
+                    if (tapResult) {
+                        mKeyguardViewController.reset(true);
+                    }
+                    mTouchDown.recycle();
+                    mTouchDown = null;
+                }
+            }
+            return false;
+        }
+    };
+
     private KeyguardSecurityCallback mKeyguardSecurityCallback = new KeyguardSecurityCallback() {
         public void userActivity() {
             if (mSecurityCallback != null) {
@@ -169,7 +207,9 @@
             KeyguardStateController keyguardStateController,
             SecurityCallback securityCallback,
             KeyguardSecurityViewFlipperController securityViewFlipperController,
-            ConfigurationController configurationController) {
+            ConfigurationController configurationController,
+            KeyguardViewController keyguardViewController,
+            FalsingManager falsingManager) {
         super(view);
         mLockPatternUtils = lockPatternUtils;
         mUpdateMonitor = keyguardUpdateMonitor;
@@ -182,6 +222,8 @@
         mAdminSecondaryLockScreenController = adminSecondaryLockScreenControllerFactory.create(
                 mKeyguardSecurityCallback);
         mConfigurationController = configurationController;
+        mKeyguardViewController = keyguardViewController;
+        mFalsingManager = falsingManager;
     }
 
     @Override
@@ -192,12 +234,14 @@
     @Override
     protected void onViewAttached() {
         mView.setSwipeListener(mSwipeListener);
+        mView.addMotionEventListener(mGlobalTouchListener);
         mConfigurationController.addCallback(mConfigurationListener);
     }
 
     @Override
     protected void onViewDetached() {
         mConfigurationController.removeCallback(mConfigurationListener);
+        mView.removeMotionEventListener(mGlobalTouchListener);
     }
 
     /** */
@@ -479,6 +523,8 @@
         private final KeyguardStateController mKeyguardStateController;
         private final KeyguardSecurityViewFlipperController mSecurityViewFlipperController;
         private final ConfigurationController mConfigurationController;
+        private final KeyguardViewController mKeyguardViewController;
+        private final FalsingManager mFalsingManager;
 
         @Inject
         Factory(KeyguardSecurityContainer view,
@@ -491,7 +537,9 @@
                 UiEventLogger uiEventLogger,
                 KeyguardStateController keyguardStateController,
                 KeyguardSecurityViewFlipperController securityViewFlipperController,
-                ConfigurationController configurationController) {
+                ConfigurationController configurationController,
+                KeyguardViewController keyguardViewController,
+                FalsingManager falsingManager) {
             mView = view;
             mAdminSecondaryLockScreenControllerFactory = adminSecondaryLockScreenControllerFactory;
             mLockPatternUtils = lockPatternUtils;
@@ -502,6 +550,8 @@
             mKeyguardStateController = keyguardStateController;
             mSecurityViewFlipperController = securityViewFlipperController;
             mConfigurationController = configurationController;
+            mKeyguardViewController = keyguardViewController;
+            mFalsingManager = falsingManager;
         }
 
         public KeyguardSecurityContainerController create(
@@ -510,7 +560,7 @@
                     mAdminSecondaryLockScreenControllerFactory, mLockPatternUtils,
                     mKeyguardUpdateMonitor, mKeyguardSecurityModel, mMetricsLogger, mUiEventLogger,
                     mKeyguardStateController, securityCallback, mSecurityViewFlipperController,
-                    mConfigurationController);
+                    mConfigurationController, mKeyguardViewController, mFalsingManager);
         }
 
     }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java
index cdbbfe6..b2bf2e6 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java
@@ -78,8 +78,8 @@
             KeyguardSecurityCallback keyguardSecurityCallback,
             KeyguardMessageAreaController.Factory messageAreaControllerFactory,
             LatencyTracker latencyTracker, LiftToActivateListener liftToActivateListener,
-            TelephonyManager telephonyManager,
-            FalsingCollector falsingCollector, boolean isNewLayoutEnabled) {
+            TelephonyManager telephonyManager, FalsingCollector falsingCollector,
+            boolean isNewLayoutEnabled) {
         super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback,
                 messageAreaControllerFactory, latencyTracker, liftToActivateListener,
                 falsingCollector);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java
index 8fff342..620db48 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java
@@ -85,8 +85,8 @@
             KeyguardSecurityCallback keyguardSecurityCallback,
             KeyguardMessageAreaController.Factory messageAreaControllerFactory,
             LatencyTracker latencyTracker, LiftToActivateListener liftToActivateListener,
-            TelephonyManager telephonyManager,
-            FalsingCollector falsingCollector, boolean isNewLayoutEnabled) {
+            TelephonyManager telephonyManager, FalsingCollector falsingCollector,
+            boolean isNewLayoutEnabled) {
         super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback,
                 messageAreaControllerFactory, latencyTracker, liftToActivateListener,
                 falsingCollector);
diff --git a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
index 2040347..e53f5c9 100644
--- a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
@@ -20,7 +20,6 @@
 import static android.hardware.SensorPrivacyManager.Sensors.MICROPHONE;
 import static android.media.AudioManager.ACTION_MICROPHONE_MUTE_CHANGED;
 
-import android.Manifest;
 import android.app.AppOpsManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -43,6 +42,7 @@
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
 import com.android.systemui.Dumpable;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dagger.SysUISingleton;
@@ -370,13 +370,9 @@
     }
 
     // TODO ntmyren: remove after teamfood is finished
-    private boolean shouldShowAppPredictor(String pkgName) {
-        if (!DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY, "permissions_hub_2_enabled",
-                false)) {
-            return false;
-        }
-        return mPackageManager.checkPermission(Manifest.permission.MANAGE_APP_PREDICTIONS, pkgName)
-                == PackageManager.PERMISSION_GRANTED;
+    private boolean showSystemApps() {
+        return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
+                SystemUiDeviceConfigFlags.PROPERTY_PERMISSIONS_HUB_ENABLED, false);
     }
 
     /**
@@ -399,8 +395,8 @@
             return true;
         }
         // TODO ntmyren: Replace this with more robust check if this moves beyond teamfood
-        if ((appOpCode == AppOpsManager.OP_CAMERA && isLocationProvider(packageName))
-                || shouldShowAppPredictor(packageName)
+        if (((showSystemApps() && !packageName.equals("android"))
+                || appOpCode == AppOpsManager.OP_CAMERA && isLocationProvider(packageName))
                 || isSpeechRecognizerUsage(appOpCode, packageName)) {
             return true;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationView.java
index 43ecf67..2036150 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationView.java
@@ -16,57 +16,63 @@
 
 package com.android.systemui.biometrics;
 
-import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.PointF;
 import android.graphics.RectF;
 import android.util.AttributeSet;
 import android.widget.FrameLayout;
 
-import com.android.systemui.doze.DozeReceiver;
-import com.android.systemui.statusbar.phone.StatusBar;
-
 /**
  * Base class for views containing UDFPS animations. Note that this is a FrameLayout so that we
- * can support multiple child views drawing on the same region around the sensor location.
+ * can support multiple child views drawing in the same region around the sensor location.
+ *
+ * - hides animation view when pausing auth
+ * - sends illumination events to fingerprint drawable
+ * - sends sensor rect updates to fingerprint drawable
+ * - optionally can override dozeTimeTick to adjust views for burn-in mitigation
  */
-public abstract class UdfpsAnimationView extends FrameLayout implements DozeReceiver,
-        StatusBar.ExpansionChangedListener {
+abstract class UdfpsAnimationView extends FrameLayout {
 
-    private static final String TAG = "UdfpsAnimationView";
-
-    @Nullable protected abstract UdfpsAnimation getUdfpsAnimation();
-
-    @NonNull private UdfpsView mParent;
-    @NonNull private RectF mSensorRect;
     private int mAlpha;
+    private boolean mPauseAuth;
 
     public UdfpsAnimationView(Context context, @Nullable AttributeSet attrs) {
         super(context, attrs);
-        mSensorRect = new RectF();
-        setWillNotDraw(false);
     }
 
-    @Override
-    protected void onDraw(Canvas canvas) {
-        super.onDraw(canvas);
+    /**
+     * Fingerprint drawable
+     */
+    abstract UdfpsDrawable getDrawable();
 
-        if (getUdfpsAnimation() != null) {
-            final int alpha = mParent.shouldPauseAuth() ? mAlpha : 255;
-            getUdfpsAnimation().setAlpha(alpha);
-            getUdfpsAnimation().draw(canvas);
-        }
+    void onSensorRectUpdated(RectF bounds) {
+        getDrawable().onSensorRectUpdated(bounds);
     }
 
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
+    void onIlluminationStarting() {
+        getDrawable().setIlluminationShowing(true);
+        getDrawable().invalidateSelf();
+    }
 
-        if (getUdfpsAnimation() != null) {
-            getUdfpsAnimation().onDestroy();
+    void onIlluminationStopped() {
+        getDrawable().setIlluminationShowing(false);
+        getDrawable().invalidateSelf();
+    }
+
+    /**
+     * @return true if changed
+     */
+    boolean setPauseAuth(boolean pauseAuth) {
+        if (pauseAuth != mPauseAuth) {
+            mPauseAuth = pauseAuth;
+            updateAlpha();
+            return true;
         }
+        return false;
+    }
+
+    private void updateAlpha() {
+        getDrawable().setAlpha(mPauseAuth ? mAlpha : 255);
     }
 
     private int expansionToAlpha(float expansion) {
@@ -81,76 +87,15 @@
         return (int) ((1 - percent) * 255);
     }
 
-    void onIlluminationStarting() {
-        if (getUdfpsAnimation() == null) {
-            return;
-        }
-
-        getUdfpsAnimation().setIlluminationShowing(true);
-        postInvalidate();
-    }
-
-    void onIlluminationStopped() {
-        if (getUdfpsAnimation() == null) {
-            return;
-        }
-
-        getUdfpsAnimation().setIlluminationShowing(false);
-        postInvalidate();
-    }
-
-    void setParent(@NonNull UdfpsView parent) {
-        mParent = parent;
-    }
-
-    void onSensorRectUpdated(@NonNull RectF sensorRect) {
-        mSensorRect = sensorRect;
-        if (getUdfpsAnimation() != null) {
-            getUdfpsAnimation().onSensorRectUpdated(mSensorRect);
-        }
-    }
-
-    void updateColor() {
-        if (getUdfpsAnimation() != null) {
-            getUdfpsAnimation().updateColor();
-        }
-        postInvalidate();
-    }
-
-    @Override
-    public void dozeTimeTick() {
-        if (getUdfpsAnimation() instanceof DozeReceiver) {
-            ((DozeReceiver) getUdfpsAnimation()).dozeTimeTick();
-        }
-    }
-
-    @Override
     public void onExpansionChanged(float expansion, boolean expanded) {
         mAlpha = expansionToAlpha(expansion);
-        postInvalidate();
-    }
-
-    public int getPaddingX() {
-        if (getUdfpsAnimation() == null) {
-            return 0;
-        }
-        return getUdfpsAnimation().getPaddingX();
-    }
-
-    public int getPaddingY() {
-        if (getUdfpsAnimation() == null) {
-            return 0;
-        }
-        return getUdfpsAnimation().getPaddingY();
+        updateAlpha();
     }
 
     /**
-     * @return the amount of translation needed if the view currently requires the user to touch
-     *         somewhere other than the exact center of the sensor. For example, this can happen
-     *         during guided enrollment.
+     * @return true if handled
      */
-    @NonNull
-    PointF getTouchTranslation() {
-        return new PointF(0, 0);
+    boolean dozeTimeTick() {
+        return false;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.java
new file mode 100644
index 0000000..b6d80ba
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.java
@@ -0,0 +1,167 @@
+/*
+ * 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.biometrics;
+
+import static com.android.systemui.statusbar.StatusBarState.FULLSCREEN_USER_SWITCHER;
+import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
+import static com.android.systemui.statusbar.StatusBarState.SHADE_LOCKED;
+
+import android.annotation.NonNull;
+import android.graphics.PointF;
+import android.graphics.RectF;
+
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.phone.StatusBar;
+import com.android.systemui.util.ViewController;
+
+/**
+ * Handles:
+ * 1. registering for listeners when its view is attached and unregistering on view detached
+ * 2. pausing udfps when fingerprintManager may still be running but we temporarily want to hide
+ * the affordance. this allows us to fade the view in and out nicely (see shouldPauseAuth)
+ * 3. sending events to its view including:
+ *      - illumination events
+ *      - sensor position changes
+ *      - doze time event
+ */
+abstract class UdfpsAnimationViewController<T extends UdfpsAnimationView>
+        extends ViewController<T> {
+    @NonNull final StatusBarStateController mStatusBarStateController;
+    @NonNull final StatusBar mStatusBar;
+
+    private boolean mNotificationShadeExpanded;
+    private int mStatusBarState;
+
+    protected UdfpsAnimationViewController(
+            T view,
+            StatusBarStateController statusBarStateController,
+            StatusBar statusBar) {
+        super(view);
+        mStatusBarStateController = statusBarStateController;
+        mStatusBar = statusBar;
+    }
+
+    @Override
+    protected void onViewAttached() {
+        mStatusBarStateController.addCallback(mStateListener);
+        mStateListener.onStateChanged(mStatusBarStateController.getState());
+        mStatusBar.addExpansionChangedListener(mStatusBarExpansionChangedListener);
+    }
+
+    @Override
+    protected void onViewDetached() {
+        mStatusBarStateController.removeCallback(mStateListener);
+        mStatusBar.removeExpansionChangedListener(mStatusBarExpansionChangedListener);
+    }
+
+    /**
+     * Returns true if the fingerprint manager is running but we want to temporarily pause
+     * authentication.
+     */
+    boolean shouldPauseAuth() {
+        return (mNotificationShadeExpanded && mStatusBarState != KEYGUARD)
+                || mStatusBarState == SHADE_LOCKED
+                || mStatusBarState == FULLSCREEN_USER_SWITCHER;
+    }
+
+    /**
+     * Send pause auth update to our view.
+     */
+    void updatePauseAuth() {
+        if (mView.setPauseAuth(shouldPauseAuth())) {
+            mView.postInvalidate();
+        }
+    }
+
+    /**
+     * Send sensor position change to our view. This rect contains paddingX and paddingY.
+     */
+    void onSensorRectUpdated(RectF sensorRect) {
+        mView.onSensorRectUpdated(sensorRect);
+    }
+
+    /**
+     * Send dozeTimeTick to view in case it wants to handle its burn-in offset.
+     */
+    void dozeTimeTick() {
+        if (mView.dozeTimeTick()) {
+            mView.postInvalidate();
+        }
+    }
+
+    /**
+     * @return the amount of translation needed if the view currently requires the user to touch
+     *         somewhere other than the exact center of the sensor. For example, this can happen
+     *         during guided enrollment.
+     */
+    PointF getTouchTranslation() {
+        return new PointF(0, 0);
+    }
+
+    /**
+     * X-Padding to add to left and right of the sensor rectangle area to increase the size of our
+     * window to draw within.
+     * @return
+     */
+    int getPaddingX() {
+        return 0;
+    }
+
+    /**
+     * Y-Padding to add to top and bottom of the sensor rectangle area to increase the size of our
+     * window to draw within.
+     */
+    int getPaddingY() {
+        return 0;
+    }
+
+    /**
+     * Udfps has started illuminating and the fingerprint manager is working on authenticating.
+     */
+    void onIlluminationStarting() {
+        mView.onIlluminationStarting();
+        mView.postInvalidate();
+    }
+
+    /**
+     * Udfps has stopped illuminating and the fingerprint manager is no longer attempting to
+     * authenticate.
+     */
+    void onIlluminationStopped() {
+        mView.onIlluminationStopped();
+        mView.postInvalidate();
+    }
+
+    private final StatusBar.ExpansionChangedListener mStatusBarExpansionChangedListener =
+            new StatusBar.ExpansionChangedListener() {
+                @Override
+                public void onExpansionChanged(float expansion, boolean expanded) {
+                    mNotificationShadeExpanded = expanded;
+                    mView.onExpansionChanged(expansion, expanded);
+                    updatePauseAuth();
+                }
+            };
+
+    private final StatusBarStateController.StateListener mStateListener =
+            new StatusBarStateController.StateListener() {
+                @Override
+                public void onStateChanged(int newState) {
+                    mStatusBarState = newState;
+                    updatePauseAuth();
+                }
+            };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewEnroll.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewEnroll.java
deleted file mode 100644
index 543df33..0000000
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewEnroll.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.biometrics;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.Context;
-import android.graphics.PointF;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.View;
-
-import com.android.systemui.R;
-
-/**
- * Class that coordinates non-HBM animations during enrollment.
- */
-public class UdfpsAnimationViewEnroll extends UdfpsAnimationView
-        implements UdfpsEnrollHelper.Listener {
-
-    private static final String TAG = "UdfpsAnimationViewEnroll";
-
-    @NonNull private UdfpsAnimationEnroll mUdfpsAnimation;
-    @NonNull private UdfpsProgressBar mProgressBar;
-    @Nullable private UdfpsEnrollHelper mEnrollHelper;
-
-    @NonNull
-    @Override
-    protected UdfpsAnimation getUdfpsAnimation() {
-        return mUdfpsAnimation;
-    }
-
-    public UdfpsAnimationViewEnroll(Context context, @Nullable AttributeSet attrs) {
-        super(context, attrs);
-        mUdfpsAnimation = new UdfpsAnimationEnroll(context);
-    }
-
-    public void setEnrollHelper(@NonNull UdfpsEnrollHelper helper) {
-        mEnrollHelper = helper;
-        mUdfpsAnimation.setEnrollHelper(helper);
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        mProgressBar = findViewById(R.id.progress_bar);
-    }
-
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-
-        if (mEnrollHelper == null) {
-            Log.e(TAG, "Enroll helper is null");
-            return;
-        }
-
-        if (mEnrollHelper.shouldShowProgressBar()) {
-            mProgressBar.setVisibility(View.VISIBLE);
-
-            // Only need enrollment updates if the progress bar is showing :)
-            mEnrollHelper.setListener(this);
-        }
-    }
-
-    @Override
-    public void onEnrollmentProgress(int remaining, int totalSteps) {
-        final int interpolatedProgress = mProgressBar.getMax()
-                * Math.max(0, totalSteps + 1 - remaining) / (totalSteps + 1);
-
-        mProgressBar.setProgress(interpolatedProgress, true);
-    }
-
-    @NonNull
-    @Override
-    PointF getTouchTranslation() {
-        if (!mEnrollHelper.isCenterEnrollmentComplete()) {
-            return new PointF(0, 0);
-        } else {
-            return mEnrollHelper.getNextGuidedEnrollmentPoint();
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewFpmOther.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewFpmOther.java
deleted file mode 100644
index 3d2f5a0..0000000
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewFpmOther.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.biometrics;
-
-import android.content.Context;
-import android.util.AttributeSet;
-
-import androidx.annotation.Nullable;
-
-/**
- * Class that coordinates non-HBM animations during other usage of FingerprintManager (not
- * including Keyguard).
- */
-public class UdfpsAnimationViewFpmOther extends UdfpsAnimationView {
-
-    private final UdfpsAnimationFpmOther mAnimation;
-
-    public UdfpsAnimationViewFpmOther(Context context, @Nullable AttributeSet attrs) {
-        super(context, attrs);
-        mAnimation = new UdfpsAnimationFpmOther(context);
-    }
-
-    @Nullable
-    @Override
-    protected UdfpsAnimation getUdfpsAnimation() {
-        return mAnimation;
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewKeyguard.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewKeyguard.java
deleted file mode 100644
index 7d0b3e5..0000000
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewKeyguard.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.biometrics;
-
-import android.content.Context;
-import android.util.AttributeSet;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
-
-/**
- * Class that coordinates non-HBM animations during keyguard authentication.
- */
-public class UdfpsAnimationViewKeyguard extends UdfpsAnimationView {
-    @Nullable private UdfpsAnimationKeyguard mAnimation;
-
-    public UdfpsAnimationViewKeyguard(Context context, @Nullable AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    void setStatusBarStateController(@NonNull StatusBarStateController statusBarStateController) {
-        if (mAnimation == null) {
-            mAnimation = new UdfpsAnimationKeyguard(getContext(), statusBarStateController);
-            mAnimation.setAnimationView(this);
-        }
-    }
-
-    @Nullable
-    @Override
-    protected UdfpsAnimation getUdfpsAnimation() {
-        return mAnimation;
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewBp.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpView.java
similarity index 67%
rename from packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewBp.java
rename to packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpView.java
index 515b442..70be907 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewBp.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpView.java
@@ -24,19 +24,22 @@
 /**
  * Class that coordinates non-HBM animations during BiometricPrompt.
  *
+ * Currently doesn't draw anything.
+ *
  * Note that {@link AuthBiometricUdfpsView} also shows UDFPS animations. At some point we should
- * de-dupe this if necessary. This will probably happen once the top-level TODO in UdfpsController
- * is completed (inflate operation-specific views, instead of inflating generic udfps_view and
- * adding operation-specific animations to it).
+ * de-dupe this if necessary.
  */
-public class UdfpsAnimationViewBp extends UdfpsAnimationView {
-    public UdfpsAnimationViewBp(Context context, @Nullable AttributeSet attrs) {
+public class UdfpsBpView extends UdfpsAnimationView {
+    private UdfpsFpDrawable mFingerprintDrawable;
+
+    public UdfpsBpView(Context context, @Nullable AttributeSet attrs) {
         super(context, attrs);
+        // Drawable isn't ever added to the view, so we don't currently show anything
+        mFingerprintDrawable = new UdfpsFpDrawable(mContext);
     }
 
-    @Nullable
     @Override
-    protected UdfpsAnimation getUdfpsAnimation() {
-        return null;
+    UdfpsDrawable getDrawable() {
+        return mFingerprintDrawable;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpViewController.java
new file mode 100644
index 0000000..b712c65
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpViewController.java
@@ -0,0 +1,32 @@
+/*
+ * 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.biometrics;
+
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.phone.StatusBar;
+
+/**
+ * Class that coordinates non-HBM animations for biometric prompt.
+ */
+class UdfpsBpViewController extends UdfpsAnimationViewController<UdfpsBpView> {
+    protected UdfpsBpViewController(
+            UdfpsBpView view,
+            StatusBarStateController statusBarStateController,
+            StatusBar statusBar) {
+        super(view, statusBarStateController, statusBar);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index 4b6a8f6..94aeb73 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -31,9 +31,9 @@
 import android.hardware.fingerprint.FingerprintManager;
 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.os.SystemClock;
 import android.util.Log;
 import android.view.Gravity;
 import android.view.LayoutInflater;
@@ -195,17 +195,6 @@
         }
     }
 
-    @VisibleForTesting final StatusBar.ExpansionChangedListener mStatusBarExpansionListener =
-            (expansion, expanded) -> mView.onExpansionChanged(expansion, expanded);
-
-    @VisibleForTesting final StatusBarStateController.StateListener mStatusBarStateListener =
-            new StatusBarStateController.StateListener() {
-                @Override
-                public void onStateChanged(int newState) {
-                    mView.onStateChanged(newState);
-                }
-            };
-
     private static float computePointerSpeed(@NonNull VelocityTracker tracker, int pointerId) {
         final float vx = tracker.getXVelocity(pointerId);
         final float vy = tracker.getYVelocity(pointerId);
@@ -360,10 +349,9 @@
 
     @Override
     public void dozeTimeTick() {
-        if (mView == null) {
-            return;
+        if (mView != null) {
+            mView.dozeTimeTick();
         }
-        mView.dozeTimeTick();
     }
 
     /**
@@ -387,7 +375,8 @@
         }
     }
 
-    private WindowManager.LayoutParams computeLayoutParams(@Nullable UdfpsAnimationView animation) {
+    private WindowManager.LayoutParams computeLayoutParams(
+            @Nullable UdfpsAnimationViewController animation) {
         final int paddingX = animation != null ? animation.getPaddingX() : 0;
         final int paddingY = animation != null ? animation.getPaddingY() : 0;
 
@@ -438,20 +427,13 @@
         mFgExecutor.execute(() -> {
             if (mView == null) {
                 try {
-                    Log.v(TAG, "showUdfpsOverlay | adding window");
-                    // TODO: Eventually we should refactor the code to inflate an
-                    //  operation-specific view here, instead of inflating a generic udfps_view
-                    //  and adding operation-specific animations to it.
+                    Log.v(TAG, "showUdfpsOverlay | adding window reason=" + reason);
                     mView = (UdfpsView) mInflater.inflate(R.layout.udfps_view, null, false);
                     mView.setSensorProperties(mSensorProps);
                     mView.setHbmCallback(this);
-
-                    final UdfpsAnimationView animation = getUdfpsAnimationViewForReason(reason);
-                    mView.setAnimationView(animation);
-
-                    mStatusBar.addExpansionChangedListener(mStatusBarExpansionListener);
-                    mStatusBarStateController.addCallback(mStatusBarStateListener);
-                    mStatusBarStateListener.onStateChanged(mStatusBarStateController.getState());
+                    UdfpsAnimationViewController animation = inflateUdfpsAnimation(reason);
+                    animation.init();
+                    mView.setAnimationViewController(animation);
 
                     mWindowManager.addView(mView, computeLayoutParams(animation));
                     mView.setOnTouchListener(mOnTouchListener);
@@ -464,40 +446,46 @@
         });
     }
 
-    @NonNull
-    private UdfpsAnimationView getUdfpsAnimationViewForReason(int reason) {
-        Log.d(TAG, "getUdfpsAnimationForReason: " + reason);
-
-        final LayoutInflater inflater = LayoutInflater.from(mContext);
-
+    private UdfpsAnimationViewController inflateUdfpsAnimation(int reason) {
         switch (reason) {
             case IUdfpsOverlayController.REASON_ENROLL_FIND_SENSOR:
-            case IUdfpsOverlayController.REASON_ENROLL_ENROLLING: {
-                final UdfpsAnimationViewEnroll view = (UdfpsAnimationViewEnroll)
-                        inflater.inflate(R.layout.udfps_animation_view_enroll, null, false);
-                view.setEnrollHelper(mServerRequest.mEnrollHelper);
-                return view;
-            }
-
-            case IUdfpsOverlayController.REASON_AUTH_BP: {
-                final UdfpsAnimationViewBp view = (UdfpsAnimationViewBp)
-                        inflater.inflate(R.layout.udfps_animation_view_bp, null, false);
-                return view;
-            }
-
-            case IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD: {
-                final UdfpsAnimationViewKeyguard view = (UdfpsAnimationViewKeyguard)
-                        inflater.inflate(R.layout.udfps_animation_view_keyguard, null, false);
-                view.setStatusBarStateController(mStatusBarStateController);
-                return view;
-            }
-
-            case IUdfpsOverlayController.REASON_AUTH_FPM_OTHER: {
-                final UdfpsAnimationViewFpmOther view = (UdfpsAnimationViewFpmOther)
-                        inflater.inflate(R.layout.udfps_animation_view_fpm_other, null, false);
-                return view;
-            }
-
+            case IUdfpsOverlayController.REASON_ENROLL_ENROLLING:
+                UdfpsEnrollView enrollView = (UdfpsEnrollView) mInflater.inflate(
+                        R.layout.udfps_enroll_view, null);
+                mView.addView(enrollView);
+                return new UdfpsEnrollViewController(
+                        enrollView,
+                        mServerRequest.mEnrollHelper,
+                        mStatusBarStateController,
+                        mStatusBar
+                );
+            case IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD:
+                UdfpsKeyguardView keyguardView = (UdfpsKeyguardView)
+                        mInflater.inflate(R.layout.udfps_keyguard_view, null);
+                mView.addView(keyguardView);
+                return new UdfpsKeyguardViewController(
+                        keyguardView,
+                        mStatusBarStateController,
+                        mStatusBar
+                );
+            case IUdfpsOverlayController.REASON_AUTH_BP:
+                // note: empty controller, currently shows no visual affordance
+                UdfpsBpView bpView = (UdfpsBpView) mInflater.inflate(R.layout.udfps_bp_view, null);
+                mView.addView(bpView);
+                return new UdfpsBpViewController(
+                        bpView,
+                        mStatusBarStateController,
+                        mStatusBar
+                );
+            case IUdfpsOverlayController.REASON_AUTH_FPM_OTHER:
+                UdfpsFpmOtherView authOtherView = (UdfpsFpmOtherView)
+                        mInflater.inflate(R.layout.udfps_fpm_other_view, null);
+                mView.addView(authOtherView);
+                return new UdfpsFpmOtherViewController(
+                        authOtherView,
+                        mStatusBarStateController,
+                        mStatusBar
+                );
             default:
                 Log.d(TAG, "Animation for reason " + reason + " not supported yet");
                 return null;
@@ -510,11 +498,9 @@
                 Log.v(TAG, "hideUdfpsOverlay | removing window");
                 // Reset the controller back to its starting state.
                 onFingerUp();
-
-                mStatusBar.removeExpansionChangedListener(mStatusBarExpansionListener);
-                mStatusBarStateController.removeCallback(mStatusBarStateListener);
-
                 mWindowManager.removeView(mView);
+                mView.setOnTouchListener(null);
+                mView.setAnimationViewController(null);
                 mView = null;
             } else {
                 Log.v(TAG, "hideUdfpsOverlay | the overlay is already hidden");
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimation.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDrawable.java
similarity index 70%
rename from packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimation.java
rename to packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDrawable.java
index a51b6fd1..13d31cb 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimation.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDrawable.java
@@ -17,10 +17,10 @@
 package com.android.systemui.biometrics;
 
 import android.content.Context;
+import android.graphics.ColorFilter;
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.graphics.drawable.Drawable;
-import android.view.View;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
@@ -28,24 +28,24 @@
 import com.android.systemui.R;
 
 /**
- * Abstract base class for animations that should be drawn when the finger is not touching the
+ * Abstract base class for drawable displayed when the finger is not touching the
  * sensor area.
  */
-public abstract class UdfpsAnimation extends Drawable {
-    protected abstract void updateColor();
-    protected abstract void onDestroy();
-
+public abstract class UdfpsDrawable extends Drawable {
     @NonNull protected final Context mContext;
     @NonNull protected final Drawable mFingerprintDrawable;
-    @Nullable private View mView;
     private boolean mIlluminationShowing;
 
-    public UdfpsAnimation(@NonNull Context context) {
+    int mAlpha = 255; // 0 - 255
+    public UdfpsDrawable(@NonNull Context context) {
         mContext = context;
         mFingerprintDrawable = context.getResources().getDrawable(R.drawable.ic_fingerprint, null);
         mFingerprintDrawable.mutate();
     }
 
+    /**
+     * @param sensorRect the rect coordinates for the sensor area
+     */
     public void onSensorRectUpdated(@NonNull RectF sensorRect) {
         final int margin =  (int) sensorRect.height() / 8;
 
@@ -56,17 +56,17 @@
         updateFingerprintIconBounds(bounds);
     }
 
+    /**
+     * Bounds for the fingerprint icon
+     */
     protected void updateFingerprintIconBounds(@NonNull Rect bounds) {
         mFingerprintDrawable.setBounds(bounds);
     }
 
     @Override
     public void setAlpha(int alpha) {
-        mFingerprintDrawable.setAlpha(alpha);
-    }
-
-    public void setAnimationView(UdfpsAnimationView view) {
-        mView = view;
+        mAlpha = alpha;
+        mFingerprintDrawable.setAlpha(mAlpha);
     }
 
     boolean isIlluminationShowing() {
@@ -77,23 +77,12 @@
         mIlluminationShowing = showing;
     }
 
-    /**
-     * @return The amount of padding that's needed on each side of the sensor, in pixels.
-     */
-    public int getPaddingX() {
-        return 0;
+    @Override
+    public void setColorFilter(@Nullable ColorFilter colorFilter) {
     }
 
-    /**
-     * @return The amount of padding that's needed on each side of the sensor, in pixels.
-     */
-    public int getPaddingY() {
+    @Override
+    public int getOpacity() {
         return 0;
     }
-
-    protected void postInvalidateView() {
-        if (mView != null) {
-            mView.postInvalidate();
-        }
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationEnroll.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollDrawable.java
similarity index 81%
rename from packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationEnroll.java
rename to packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollDrawable.java
index 015a598..d80e085 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationEnroll.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollDrawable.java
@@ -20,7 +20,6 @@
 import android.content.res.Configuration;
 import android.graphics.Canvas;
 import android.graphics.Color;
-import android.graphics.ColorFilter;
 import android.graphics.Paint;
 import android.graphics.PointF;
 import android.graphics.Rect;
@@ -33,23 +32,23 @@
 import com.android.systemui.R;
 
 /**
- * UDFPS animations that should be shown when enrolling.
+ * UDFPS fingerprint drawable that is shown when enrolling
  */
-public class UdfpsAnimationEnroll extends UdfpsAnimation {
+public class UdfpsEnrollDrawable extends UdfpsDrawable {
     private static final String TAG = "UdfpsAnimationEnroll";
 
     private static final float SHADOW_RADIUS = 5.f;
-    private static final float PROGRESS_BAR_RADIUS = 140.f;
+    static final float PROGRESS_BAR_RADIUS = 140.f;
 
     @NonNull private final Drawable mMovingTargetFpIcon;
     @NonNull private final Paint mSensorPaint;
     @NonNull private final Paint mBlueFill;
-    @NonNull private final Paint mBlueStroke;;
+    @NonNull private final Paint mBlueStroke;
 
     @Nullable private RectF mSensorRect;
     @Nullable private UdfpsEnrollHelper mEnrollHelper;
 
-    UdfpsAnimationEnroll(@NonNull Context context) {
+    UdfpsEnrollDrawable(@NonNull Context context) {
         super(context);
 
         mSensorPaint = new Paint(0 /* flags */);
@@ -72,6 +71,8 @@
         mMovingTargetFpIcon = context.getResources().getDrawable(R.drawable.ic_fingerprint, null);
         mMovingTargetFpIcon.setTint(Color.WHITE);
         mMovingTargetFpIcon.mutate();
+
+        mFingerprintDrawable.setTint(mContext.getColor(R.color.udfps_enroll_icon));
     }
 
     void setEnrollHelper(@NonNull UdfpsEnrollHelper helper) {
@@ -79,16 +80,6 @@
     }
 
     @Override
-    protected void updateColor() {
-        mFingerprintDrawable.setTint(mContext.getColor(R.color.udfps_enroll_icon));
-    }
-
-    @Override
-    protected void onDestroy() {
-
-    }
-
-    @Override
     public void onSensorRectUpdated(@NonNull RectF sensorRect) {
         super.onSensorRectUpdated(sensorRect);
         mSensorRect = sensorRect;
@@ -98,6 +89,7 @@
     protected void updateFingerprintIconBounds(@NonNull Rect bounds) {
         super.updateFingerprintIconBounds(bounds);
         mMovingTargetFpIcon.setBounds(bounds);
+        invalidateSelf();
     }
 
     @Override
@@ -117,7 +109,7 @@
 
         // Draw moving target
         if (mEnrollHelper.isCenterEnrollmentComplete()) {
-            mFingerprintDrawable.setAlpha(64);
+            mFingerprintDrawable.setAlpha(mAlpha == 255 ? 64 : mAlpha);
 
             canvas.save();
             final PointF point = mEnrollHelper.getNextGuidedEnrollmentPoint();
@@ -130,33 +122,16 @@
             mMovingTargetFpIcon.draw(canvas);
             canvas.restore();
         } else {
-            mFingerprintDrawable.setAlpha(255);
+            mFingerprintDrawable.setAlpha(mAlpha);
         }
     }
 
     @Override
-    public int getPaddingX() {
-        return (int) Math.ceil(PROGRESS_BAR_RADIUS);
-    }
-
-    @Override
-    public int getPaddingY() {
-        return (int) Math.ceil(PROGRESS_BAR_RADIUS);
-    }
-
-    @Override
     public void setAlpha(int alpha) {
         super.setAlpha(alpha);
         mSensorPaint.setAlpha(alpha);
-    }
-
-    @Override
-    public void setColorFilter(@Nullable ColorFilter colorFilter) {
-
-    }
-
-    @Override
-    public int getOpacity() {
-        return 0;
+        mBlueFill.setAlpha(alpha);
+        mBlueStroke.setAlpha(alpha);
+        invalidateSelf();
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java
index 667b7a7..98a703f 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java
@@ -21,6 +21,9 @@
 import android.content.Context;
 import android.graphics.PointF;
 import android.hardware.fingerprint.IUdfpsOverlayController;
+import android.os.Build;
+import android.os.UserHandle;
+import android.provider.Settings;
 import android.util.TypedValue;
 
 import java.util.ArrayList;
@@ -32,6 +35,10 @@
 public class UdfpsEnrollHelper {
     private static final String TAG = "UdfpsEnrollHelper";
 
+    private static final String SCALE_OVERRIDE =
+            "com.android.systemui.biometrics.UdfpsEnrollHelper.scale";
+    private static final float SCALE = 0.5f;
+
     // Enroll with two center touches before going to guided enrollment
     private static final int NUM_CENTER_TOUCHES = 2;
 
@@ -39,9 +46,10 @@
         void onEnrollmentProgress(int remaining, int totalSteps);
     }
 
+    @NonNull private final Context mContext;
     // IUdfpsOverlayController reason
     private final int mEnrollReason;
-    private final List<PointF> mGuidedEnrollmentPoints;
+    @NonNull private final List<PointF> mGuidedEnrollmentPoints;
 
     private int mTotalSteps = -1;
     private int mRemainingSteps = -1;
@@ -53,6 +61,7 @@
     @Nullable Listener mListener;
 
     public UdfpsEnrollHelper(@NonNull Context context, int reason) {
+        mContext = context;
         mEnrollReason = reason;
         mGuidedEnrollmentPoints = new ArrayList<>();
 
@@ -100,13 +109,13 @@
 
     }
 
-    void setListener(@NonNull Listener listener) {
+    void setListener(Listener listener) {
         mListener = listener;
 
         // Only notify during setListener if enrollment is already in progress, so the progress
         // bar can be updated. If enrollment has not started yet, the progress bar will be empty
         // anyway.
-        if (mTotalSteps != -1) {
+        if (mListener != null && mTotalSteps != -1) {
             mListener.onEnrollmentProgress(mRemainingSteps, mTotalSteps);
         }
     }
@@ -121,9 +130,15 @@
 
     @NonNull
     PointF getNextGuidedEnrollmentPoint() {
+        float scale = SCALE;
+        if (Build.IS_ENG || Build.IS_USERDEBUG) {
+            scale = Settings.Secure.getFloatForUser(mContext.getContentResolver(),
+                    SCALE_OVERRIDE, SCALE,
+                    UserHandle.USER_CURRENT);
+        }
         final int index = mLocationsEnrolled - NUM_CENTER_TOUCHES;
         final PointF originalPoint = mGuidedEnrollmentPoints
                 .get(index % mGuidedEnrollmentPoints.size());
-        return new PointF(originalPoint.x * 0.5f, originalPoint.y * 0.5f);
+        return new PointF(originalPoint.x * scale, originalPoint.y * scale);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollView.java
new file mode 100644
index 0000000..7985d95
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollView.java
@@ -0,0 +1,53 @@
+/*
+ * 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.biometrics;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.ImageView;
+
+import androidx.annotation.Nullable;
+
+import com.android.systemui.R;
+
+/**
+ * View corresponding with udfps_enroll_view.xml
+ */
+public class UdfpsEnrollView extends UdfpsAnimationView {
+    private final UdfpsEnrollDrawable mFingerprintDrawable;
+    private ImageView mFingerprintView;
+
+    public UdfpsEnrollView(Context context, @Nullable AttributeSet attrs) {
+        super(context, attrs);
+        mFingerprintDrawable = new UdfpsEnrollDrawable(mContext);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        mFingerprintView = findViewById(R.id.udfps_enroll_animation_fp_view);
+        mFingerprintView.setImageDrawable(mFingerprintDrawable);
+    }
+
+    @Override
+    public UdfpsDrawable getDrawable() {
+        return mFingerprintDrawable;
+    }
+
+    void setEnrollHelper(UdfpsEnrollHelper enrollHelper) {
+        mFingerprintDrawable.setEnrollHelper(enrollHelper);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java
new file mode 100644
index 0000000..da8d712
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java
@@ -0,0 +1,92 @@
+/*
+ * 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.biometrics;
+
+import android.annotation.NonNull;
+import android.graphics.PointF;
+import android.view.View;
+
+import com.android.systemui.R;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.phone.StatusBar;
+
+/**
+ * Class that coordinates non-HBM animations during enrollment.
+ */
+public class UdfpsEnrollViewController extends UdfpsAnimationViewController<UdfpsEnrollView> {
+    @NonNull private final UdfpsProgressBar mProgressBar;
+    @NonNull private final UdfpsEnrollHelper mEnrollHelper;
+
+    protected UdfpsEnrollViewController(
+            UdfpsEnrollView view,
+            @NonNull UdfpsEnrollHelper enrollHelper,
+            StatusBarStateController statusBarStateController,
+            StatusBar statusBar) {
+        super(view, statusBarStateController, statusBar);
+        mEnrollHelper = enrollHelper;
+        mProgressBar = mView.findViewById(R.id.progress_bar);
+        mView.setEnrollHelper(mEnrollHelper);
+    }
+
+    @Override
+    protected void onViewAttached() {
+        super.onViewAttached();
+        if (mEnrollHelper.shouldShowProgressBar()) {
+            mProgressBar.setVisibility(View.VISIBLE);
+
+            // Only need enrollment updates if the progress bar is showing :)
+            mEnrollHelper.setListener(mEnrollHelperListener);
+        }
+    }
+
+    @Override
+    protected void onViewDetached() {
+        super.onViewDetached();
+        mEnrollHelper.setListener(null);
+    }
+
+    @NonNull
+    @Override
+    public PointF getTouchTranslation() {
+        if (!mEnrollHelper.isCenterEnrollmentComplete()) {
+            return new PointF(0, 0);
+        } else {
+            return mEnrollHelper.getNextGuidedEnrollmentPoint();
+        }
+    }
+
+    @Override
+    public int getPaddingX() {
+        return (int) Math.ceil(UdfpsEnrollDrawable.PROGRESS_BAR_RADIUS);
+    }
+
+    @Override
+    public int getPaddingY() {
+        return (int) Math.ceil(UdfpsEnrollDrawable.PROGRESS_BAR_RADIUS);
+    }
+
+    private final UdfpsEnrollHelper.Listener mEnrollHelperListener =
+            new UdfpsEnrollHelper.Listener() {
+        @Override
+        public void onEnrollmentProgress(int remaining, int totalSteps) {
+            final int interpolatedProgress = mProgressBar.getMax()
+                    * Math.max(0, totalSteps + 1 - remaining) / (totalSteps + 1);
+
+            mProgressBar.setProgress(interpolatedProgress, true);
+        }
+    };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationFpmOther.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpDrawable.java
similarity index 63%
rename from packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationFpmOther.java
rename to packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpDrawable.java
index ef7a340..09b6fab 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationFpmOther.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpDrawable.java
@@ -18,32 +18,19 @@
 
 import android.content.Context;
 import android.graphics.Canvas;
-import android.graphics.ColorFilter;
 
 import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
 
 /**
- * UDFPS animations that should be shown when authenticating via FingerprintManager, excluding
- * keyguard.
+ * Draws udfps fingerprint if sensor isn't illuminating.
  */
-public class UdfpsAnimationFpmOther extends UdfpsAnimation {
+public class UdfpsFpDrawable extends UdfpsDrawable {
 
-    UdfpsAnimationFpmOther(@NonNull Context context) {
+    UdfpsFpDrawable(@NonNull Context context) {
         super(context);
     }
 
     @Override
-    protected void updateColor() {
-
-    }
-
-    @Override
-    protected void onDestroy() {
-
-    }
-
-    @Override
     public void draw(@NonNull Canvas canvas) {
         if (isIlluminationShowing()) {
             return;
@@ -51,14 +38,4 @@
 
         mFingerprintDrawable.draw(canvas);
     }
-
-    @Override
-    public void setColorFilter(@Nullable ColorFilter colorFilter) {
-
-    }
-
-    @Override
-    public int getOpacity() {
-        return 0;
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmOtherView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmOtherView.java
new file mode 100644
index 0000000..85f1606
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmOtherView.java
@@ -0,0 +1,49 @@
+/*
+ * 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.biometrics;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.ImageView;
+
+import androidx.annotation.Nullable;
+
+import com.android.systemui.R;
+
+/**
+ * View corresponding with udfps_fpm_other_view.xml
+ */
+public class UdfpsFpmOtherView extends UdfpsAnimationView {
+    private final UdfpsFpDrawable mFingerprintDrawable;
+    private ImageView mFingerprintView;
+
+    public UdfpsFpmOtherView(Context context, @Nullable AttributeSet attrs) {
+        super(context, attrs);
+        mFingerprintDrawable = new UdfpsFpDrawable(context);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        mFingerprintView = findViewById(R.id.udfps_fpm_other_fp_view);
+        mFingerprintView.setImageDrawable(mFingerprintDrawable);
+    }
+
+    @Override
+    UdfpsDrawable getDrawable() {
+        return mFingerprintDrawable;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmOtherViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmOtherViewController.java
new file mode 100644
index 0000000..587501b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmOtherViewController.java
@@ -0,0 +1,35 @@
+/*
+ * 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.biometrics;
+
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.phone.StatusBar;
+
+/**
+ * Class that coordinates non-HBM animations for non keyguard, enrollment or biometric prompt
+ * states.
+ *
+ * Currently only shows the fp drawable.
+ */
+class UdfpsFpmOtherViewController extends UdfpsAnimationViewController<UdfpsFpmOtherView> {
+    protected UdfpsFpmOtherViewController(
+            UdfpsFpmOtherView view,
+            StatusBarStateController statusBarStateController,
+            StatusBar statusBar) {
+        super(view, statusBarStateController, statusBar);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationKeyguard.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardDrawable.java
similarity index 63%
rename from packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationKeyguard.java
rename to packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardDrawable.java
index 5f268cf..b0c5da0 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationKeyguard.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardDrawable.java
@@ -21,28 +21,25 @@
 import android.content.Context;
 import android.graphics.Canvas;
 import android.graphics.Color;
-import android.graphics.ColorFilter;
 import android.util.MathUtils;
 
 import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
 
 import com.android.internal.graphics.ColorUtils;
 import com.android.settingslib.Utils;
 import com.android.systemui.R;
 import com.android.systemui.doze.DozeReceiver;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
 
 /**
  * UDFPS animations that should be shown when authenticating on keyguard.
  */
-public class UdfpsAnimationKeyguard extends UdfpsAnimation implements DozeReceiver,
-        StatusBarStateController.StateListener {
+public class UdfpsKeyguardDrawable extends UdfpsDrawable implements DozeReceiver {
 
     private static final String TAG = "UdfpsAnimationKeyguard";
+    private final int mLockScreenColor;
+    private final int mAmbientDisplayColor;
 
     @NonNull private final Context mContext;
-    @NonNull private final StatusBarStateController mStatusBarStateController;
     private final int mMaxBurnInOffsetX;
     private final int mMaxBurnInOffsetY;
 
@@ -51,18 +48,19 @@
     private float mBurnInOffsetX;
     private float mBurnInOffsetY;
 
-    UdfpsAnimationKeyguard(@NonNull Context context,
-            @NonNull StatusBarStateController statusBarStateController) {
+    UdfpsKeyguardDrawable(@NonNull Context context) {
         super(context);
         mContext = context;
-        mStatusBarStateController = statusBarStateController;
 
+        // TODO: move burn-in to view
         mMaxBurnInOffsetX = context.getResources()
                 .getDimensionPixelSize(R.dimen.udfps_burn_in_offset_x);
         mMaxBurnInOffsetY = context.getResources()
                 .getDimensionPixelSize(R.dimen.udfps_burn_in_offset_y);
 
-        statusBarStateController.addCallback(this);
+        mLockScreenColor = Utils.getColorAttrDefaultColor(mContext, R.attr.wallpaperTextColor);
+        mAmbientDisplayColor = Color.WHITE;
+        updateAodPositionAndColor();
     }
 
     private void updateAodPositionAndColor() {
@@ -74,8 +72,10 @@
                 getBurnInOffset(mMaxBurnInOffsetY * 2, false /* xAxis */)
                         - mMaxBurnInOffsetY,
                 mInterpolatedDarkAmount);
-        updateColor();
-        postInvalidateView();
+
+        mFingerprintDrawable.setTint(ColorUtils.blendARGB(mLockScreenColor,
+                mAmbientDisplayColor, mInterpolatedDarkAmount));
+        invalidateSelf();
     }
 
     @Override
@@ -84,44 +84,15 @@
     }
 
     @Override
-    public void onDozeAmountChanged(float linear, float eased) {
-        mInterpolatedDarkAmount = eased;
-        updateAodPositionAndColor();
-    }
-
-    @Override
     public void draw(@NonNull Canvas canvas) {
         if (isIlluminationShowing()) {
             return;
         }
-
-        canvas.save();
-        canvas.translate(mBurnInOffsetX, mBurnInOffsetY);
         mFingerprintDrawable.draw(canvas);
-        canvas.restore();
     }
 
-    @Override
-    public void setColorFilter(@Nullable ColorFilter colorFilter) {
-
-    }
-
-    @Override
-    public int getOpacity() {
-        return 0;
-    }
-
-    @Override
-    protected void updateColor() {
-        final int lockScreenIconColor = Utils.getColorAttrDefaultColor(mContext,
-                R.attr.wallpaperTextColor);
-        final int ambientDisplayIconColor = Color.WHITE;
-        mFingerprintDrawable.setTint(ColorUtils.blendARGB(lockScreenIconColor,
-                ambientDisplayIconColor, mInterpolatedDarkAmount));
-    }
-
-    @Override
-    protected void onDestroy() {
-        mStatusBarStateController.removeCallback(this);
+    void onDozeAmountChanged(float linear, float eased) {
+        mInterpolatedDarkAmount = eased;
+        updateAodPositionAndColor();
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java
new file mode 100644
index 0000000..6a93560
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java
@@ -0,0 +1,60 @@
+/*
+ * 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.biometrics;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.ImageView;
+
+import androidx.annotation.Nullable;
+
+import com.android.systemui.R;
+
+/**
+ * View corresponding with udfps_keyguard_view.xml
+ */
+public class UdfpsKeyguardView extends UdfpsAnimationView {
+    private final UdfpsKeyguardDrawable mFingerprintDrawable;
+    private ImageView mFingerprintView;
+
+    public UdfpsKeyguardView(Context context, @Nullable AttributeSet attrs) {
+        super(context, attrs);
+        mFingerprintDrawable = new UdfpsKeyguardDrawable(mContext);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        mFingerprintView = findViewById(R.id.udfps_keyguard_animation_fp_view);
+        mFingerprintView.setImageDrawable(mFingerprintDrawable);
+    }
+
+    @Override
+    public UdfpsDrawable getDrawable() {
+        return mFingerprintDrawable;
+    }
+
+    @Override
+    public boolean dozeTimeTick() {
+        // TODO: burnin
+        mFingerprintDrawable.dozeTimeTick();
+        return true;
+    }
+
+    void onDozeAmountChanged(float linear, float eased) {
+        mFingerprintDrawable.onDozeAmountChanged(linear, eased);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
new file mode 100644
index 0000000..14bb3fee
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
@@ -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.systemui.biometrics;
+
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.phone.StatusBar;
+
+/**
+ * Class that coordinates non-HBM animations during keyguard authentication.
+ */
+public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<UdfpsKeyguardView> {
+    private boolean mForceShow;
+
+    protected UdfpsKeyguardViewController(
+            UdfpsKeyguardView view,
+            StatusBarStateController statusBarStateController,
+            StatusBar statusBar) {
+        super(view, statusBarStateController, statusBar);
+    }
+
+    @Override
+    protected void onViewAttached() {
+        super.onViewAttached();
+        mStatusBarStateController.addCallback(mStateListener);
+        final float dozeAmount = mStatusBarStateController.getDozeAmount();
+        mStateListener.onDozeAmountChanged(dozeAmount, dozeAmount);
+    }
+
+    @Override
+    protected void onViewDetached() {
+        super.onViewDetached();
+        mStatusBarStateController.removeCallback(mStateListener);
+    }
+
+    /**
+     * Overrides non-force show logic in shouldPauseAuth to still auth.
+     */
+    private void forceShow(boolean forceShow) {
+        if (mForceShow == forceShow) {
+            return;
+        }
+
+        mForceShow = forceShow;
+        updatePauseAuth();
+        // TODO: animate show/hide background protection
+    }
+
+    /**
+     * Returns true if the fingerprint manager is running but we want to temporarily pause
+     * authentication. On the keyguard, we may want to show udfps when the shade
+     * is expanded, so this can be overridden with the forceShow method.
+     */
+    public boolean shouldPauseAuth() {
+        if (mForceShow) {
+            return false;
+        }
+        return super.shouldPauseAuth();
+    }
+
+    private final StatusBarStateController.StateListener mStateListener =
+            new StatusBarStateController.StateListener() {
+        @Override
+        public void onDozeAmountChanged(float linear, float eased) {
+            mView.onDozeAmountChanged(linear, eased);
+        }
+    };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java
index a52bddc..42d0d84 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java
@@ -16,10 +16,6 @@
 
 package com.android.systemui.biometrics;
 
-import static com.android.systemui.statusbar.StatusBarState.FULLSCREEN_USER_SWITCHER;
-import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
-import static com.android.systemui.statusbar.StatusBarState.SHADE_LOCKED;
-
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
@@ -39,15 +35,12 @@
 
 import com.android.systemui.R;
 import com.android.systemui.doze.DozeReceiver;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.phone.StatusBar;
 
 /**
  * A view containing 1) A SurfaceView for HBM, and 2) A normal drawable view for all other
  * animations.
  */
-public class UdfpsView extends FrameLayout implements DozeReceiver, UdfpsIlluminator,
-        StatusBarStateController.StateListener, StatusBar.ExpansionChangedListener {
+public class UdfpsView extends FrameLayout implements DozeReceiver, UdfpsIlluminator {
     private static final String TAG = "UdfpsView";
 
     private static final int DEBUG_TEXT_SIZE_PX = 32;
@@ -56,7 +49,7 @@
     @NonNull private final Paint mDebugTextPaint;
 
     @NonNull private UdfpsSurfaceView mHbmSurfaceView;
-    @Nullable private UdfpsAnimationView mAnimationView;
+    @Nullable private UdfpsAnimationViewController mAnimationViewController;
 
     // Used to obtain the sensor location.
     @NonNull private FingerprintSensorPropertiesInternal mSensorProps;
@@ -64,8 +57,6 @@
     private final float mSensorTouchAreaCoefficient;
     @Nullable private String mDebugMessage;
     private boolean mIlluminationRequested;
-    private int mStatusBarState;
-    private boolean mNotificationShadeExpanded;
 
     public UdfpsView(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -108,15 +99,6 @@
         mSensorProps = properties;
     }
 
-    void setAnimationView(@NonNull UdfpsAnimationView animation) {
-        mAnimationView = animation;
-        animation.setParent(this);
-
-        // TODO: Consider using a ViewStub placeholder to maintain positioning and inflating it
-        //  after the animation type has been decided.
-        addView(animation, 0);
-    }
-
     @Override
     public void setHbmCallback(@Nullable HbmCallback callback) {
         mHbmSurfaceView.setHbmCallback(callback);
@@ -124,45 +106,38 @@
 
     @Override
     public void dozeTimeTick() {
-        if (mAnimationView == null) {
-            return;
-        }
-        mAnimationView.dozeTimeTick();
-    }
-
-    @Override
-    public void onStateChanged(int newState) {
-        mStatusBarState = newState;
-    }
-
-    @Override
-    public void onExpansionChanged(float expansion, boolean expanded) {
-        mNotificationShadeExpanded = expanded;
-
-        if (mAnimationView != null) {
-            mAnimationView.onExpansionChanged(expansion, expanded);
+        if (mAnimationViewController != null) {
+            mAnimationViewController.dozeTimeTick();
         }
     }
 
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         super.onLayout(changed, left, top, right, bottom);
-        mSensorRect.set(0 + mAnimationView.getPaddingX(),
-                0 + mAnimationView.getPaddingY(),
-                2 * mSensorProps.sensorRadius + mAnimationView.getPaddingX(),
-                2 * mSensorProps.sensorRadius + mAnimationView.getPaddingY());
+        int paddingX = mAnimationViewController == null ? 0
+                : mAnimationViewController.getPaddingX();
+        int paddingY = mAnimationViewController == null ? 0
+                : mAnimationViewController.getPaddingY();
+        mSensorRect.set(
+                paddingX,
+                paddingY,
+                2 * mSensorProps.sensorRadius + paddingX,
+                2 * mSensorProps.sensorRadius + paddingY);
 
         mHbmSurfaceView.onSensorRectUpdated(new RectF(mSensorRect));
-        mAnimationView.onSensorRectUpdated(new RectF(mSensorRect));
+        if (mAnimationViewController != null) {
+            mAnimationViewController.onSensorRectUpdated(new RectF(mSensorRect));
+        }
+    }
+
+    void setAnimationViewController(UdfpsAnimationViewController animationViewController) {
+        mAnimationViewController = animationViewController;
     }
 
     @Override
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
         Log.v(TAG, "onAttachedToWindow");
-
-        // Retrieve the colors each time, since it depends on day/night mode
-        mAnimationView.updateColor();
     }
 
     @Override
@@ -188,7 +163,9 @@
 
     boolean isWithinSensorArea(float x, float y) {
         // The X and Y coordinates of the sensor's center.
-        final PointF translation = mAnimationView.getTouchTranslation();
+        final PointF translation = mAnimationViewController == null
+                ? new PointF(0, 0)
+                : mAnimationViewController.getTouchTranslation();
         final float cx = mSensorRect.centerX() + translation.x;
         final float cy = mSensorRect.centerY() + translation.y;
         // Radii along the X and Y axes.
@@ -199,18 +176,7 @@
                 && x < (cx + rx * mSensorTouchAreaCoefficient)
                 && y > (cy - ry * mSensorTouchAreaCoefficient)
                 && y < (cy + ry * mSensorTouchAreaCoefficient)
-                && !shouldPauseAuth();
-    }
-
-    /**
-     * States where UDFPS should temporarily not be authenticating. Instead of completely stopping
-     * authentication which would cause the UDFPS icons to abruptly disappear, do it here by not
-     * sending onFingerDown and smoothly animating away.
-     */
-    boolean shouldPauseAuth() {
-        return (mNotificationShadeExpanded && mStatusBarState != KEYGUARD)
-                || mStatusBarState == SHADE_LOCKED
-                || mStatusBarState == FULLSCREEN_USER_SWITCHER;
+                && !mAnimationViewController.shouldPauseAuth();
     }
 
     boolean isIlluminationRequested() {
@@ -223,7 +189,9 @@
     @Override
     public void startIllumination(@Nullable Runnable onIlluminatedRunnable) {
         mIlluminationRequested = true;
-        mAnimationView.onIlluminationStarting();
+        if (mAnimationViewController != null) {
+            mAnimationViewController.onIlluminationStarting();
+        }
         mHbmSurfaceView.setVisibility(View.VISIBLE);
         mHbmSurfaceView.startIllumination(onIlluminatedRunnable);
     }
@@ -231,7 +199,9 @@
     @Override
     public void stopIllumination() {
         mIlluminationRequested = false;
-        mAnimationView.onIlluminationStopped();
+        if (mAnimationViewController != null) {
+            mAnimationViewController.onIlluminationStopped();
+        }
         mHbmSurfaceView.setVisibility(View.INVISIBLE);
         mHbmSurfaceView.stopIllumination();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java
index 6572ca9..efb7992 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java
@@ -18,7 +18,6 @@
 
 import static com.android.systemui.classifier.FalsingManagerProxy.FALSING_SUCCESS;
 import static com.android.systemui.classifier.FalsingModule.BRIGHT_LINE_GESTURE_CLASSIFERS;
-import static com.android.systemui.classifier.FalsingModule.DOUBLE_TAP_TIMEOUT_MS;
 
 import android.net.Uri;
 import android.os.Build;
@@ -29,11 +28,9 @@
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.systemui.classifier.FalsingDataProvider.SessionListener;
-import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dagger.qualifiers.TestHarness;
 import com.android.systemui.dock.DockManager;
 import com.android.systemui.plugins.FalsingManager;
-import com.android.systemui.util.concurrency.DelayableExecutor;
 import com.android.systemui.util.sensors.ThresholdSensor;
 
 import java.io.FileDescriptor;
@@ -63,14 +60,13 @@
 
     private static final int RECENT_INFO_LOG_SIZE = 40;
     private static final int RECENT_SWIPE_LOG_SIZE = 20;
+    private static final double TAP_CONFIDENCE_THRESHOLD = 0.7;
 
     private final FalsingDataProvider mDataProvider;
     private final DockManager mDockManager;
     private final SingleTapClassifier mSingleTapClassifier;
     private final DoubleTapClassifier mDoubleTapClassifier;
     private final HistoryTracker mHistoryTracker;
-    private final DelayableExecutor mDelayableExecutor;
-    private final long mDoubleTapTimeMs;
     private final boolean mTestHarness;
     private final MetricsLogger mMetricsLogger;
     private int mIsFalseTouchCalls;
@@ -98,19 +94,7 @@
                 @Override
         public void onGestureComplete(long completionTimeMs) {
             if (mPriorResults != null) {
-                // Single taps that may become double taps don't get added right away.
-                if (mClassifyAsSingleTap) {
-                    Collection<FalsingClassifier.Result> singleTapResults = mPriorResults;
-                    mSingleTapHistoryCanceller = mDelayableExecutor.executeDelayed(
-                            () -> {
-                                mSingleTapHistoryCanceller = null;
-                                mHistoryTracker.addResults(singleTapResults, completionTimeMs);
-                            },
-                            mDoubleTapTimeMs);
-                    mClassifyAsSingleTap = false;  // Don't treat things as single taps by default.
-                } else {
-                    mHistoryTracker.addResults(mPriorResults, completionTimeMs);
-                }
+                mHistoryTracker.addResults(mPriorResults, completionTimeMs);
                 mPriorResults = null;
             } else {
                 // Gestures that were not classified get treated as a false.
@@ -123,17 +107,13 @@
     };
 
     private Collection<FalsingClassifier.Result> mPriorResults;
-    private boolean mClassifyAsSingleTap;
-    private Runnable mSingleTapHistoryCanceller;
 
     @Inject
     public BrightLineFalsingManager(FalsingDataProvider falsingDataProvider,
             DockManager dockManager, MetricsLogger metricsLogger,
             @Named(BRIGHT_LINE_GESTURE_CLASSIFERS) Set<FalsingClassifier> classifiers,
             SingleTapClassifier singleTapClassifier, DoubleTapClassifier doubleTapClassifier,
-            HistoryTracker historyTracker, @Main DelayableExecutor delayableExecutor,
-            @Named(DOUBLE_TAP_TIMEOUT_MS) long doubleTapTimeMs,
-            @TestHarness boolean testHarness) {
+            HistoryTracker historyTracker, @TestHarness boolean testHarness) {
         mDataProvider = falsingDataProvider;
         mDockManager = dockManager;
         mMetricsLogger = metricsLogger;
@@ -141,8 +121,6 @@
         mSingleTapClassifier = singleTapClassifier;
         mDoubleTapClassifier = doubleTapClassifier;
         mHistoryTracker = historyTracker;
-        mDelayableExecutor = delayableExecutor;
-        mDoubleTapTimeMs = doubleTapTimeMs;
         mTestHarness = testHarness;
 
         mDataProvider.addSessionListener(mSessionListener);
@@ -158,7 +136,6 @@
     public boolean isFalseTouch(@Classifier.InteractionType int interactionType) {
         boolean result;
 
-        mClassifyAsSingleTap = false;
         mDataProvider.setInteractionType(interactionType);
 
         if (!mTestHarness && !mDataProvider.isJustUnlockedWithFace() && !mDockManager.isDocked()) {
@@ -166,7 +143,7 @@
                     mClassifiers.stream().map(falsingClassifier -> {
                         FalsingClassifier.Result classifierResult =
                                 falsingClassifier.classifyGesture(
-                                        mHistoryTracker.falsePenalty(),
+                                        mHistoryTracker.falseBelief(),
                                         mHistoryTracker.falseConfidence());
                         if (classifierResult.isFalse()) {
                             logInfo(String.format(
@@ -217,9 +194,7 @@
     }
 
     @Override
-    public boolean isFalseTap(boolean robustCheck) {
-        mClassifyAsSingleTap = true;
-
+    public boolean isFalseTap(boolean robustCheck, double falsePenalty) {
         FalsingClassifier.Result singleTapResult =
                 mSingleTapClassifier.isTap(mDataProvider.getRecentMotionEvents());
         mPriorResults = Collections.singleton(singleTapResult);
@@ -233,14 +208,24 @@
             return true;
         }
 
-        // TODO(b/172655679): More heuristics to come. For now, allow touches through if face-authed
         if (robustCheck) {
-            boolean result = !mDataProvider.isJustUnlockedWithFace();
-            mPriorResults = Collections.singleton(
-                    result ? FalsingClassifier.Result.falsed(0.1, "no face detected")
-                            : FalsingClassifier.Result.passed(1));
-
-            return result;
+            if (mDataProvider.isJustUnlockedWithFace()) {
+                // Immediately pass if a face is detected.
+                mPriorResults = Collections.singleton(FalsingClassifier.Result.passed(1));
+                return false;
+            } else if (!isFalseDoubleTap()) {
+                // We must check double tapping before other heuristics. This is because
+                // the double tap will fail if there's only been one tap. We don't want that
+                // failure to be recorded in mPriorResults.
+                return false;
+            } else if (mHistoryTracker.falseBelief() > TAP_CONFIDENCE_THRESHOLD) {
+                mPriorResults = Collections.singleton(
+                        FalsingClassifier.Result.falsed(0, "bad history"));
+                return true;
+            } else {
+                mPriorResults = Collections.singleton(FalsingClassifier.Result.passed(0.1));
+                return false;
+            }
         }
 
         return false;
@@ -248,7 +233,6 @@
 
     @Override
     public boolean isFalseDoubleTap() {
-        mClassifyAsSingleTap = false;
         FalsingClassifier.Result result = mDoubleTapClassifier.classifyGesture();
         mPriorResults = Collections.singleton(result);
         if (result.isFalse()) {
@@ -258,12 +242,6 @@
             if (reason != null) {
                 logInfo(reason);
             }
-        } else {
-            // A valid double tap prevents an invalid single tap from going into history.
-            if (mSingleTapHistoryCanceller != null) {
-                mSingleTapHistoryCanceller.run();
-                mSingleTapHistoryCanceller = null;
-            }
         }
         return result.isFalse();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/DiagonalClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/DiagonalClassifier.java
index bbb9371..ffcdb93 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/DiagonalClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/DiagonalClassifier.java
@@ -62,7 +62,7 @@
                 VERTICAL_ANGLE_RANGE);
     }
 
-    Result calculateFalsingResult(double historyPenalty, double historyConfidence) {
+    Result calculateFalsingResult(double historyBelief, double historyConfidence) {
         float angle = getAngle();
 
         if (angle == Float.MAX_VALUE) {  // Unknown angle
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/DistanceClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/DistanceClassifier.java
index 4cb5aa2..0f121c1 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/DistanceClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/DistanceClassifier.java
@@ -147,7 +147,7 @@
     }
 
     @Override
-    Result calculateFalsingResult(double historyPenalty, double historyConfidence) {
+    Result calculateFalsingResult(double historyBelief, double historyConfidence) {
         return !getPassedFlingThreshold()
                 ? Result.falsed(0.5, getReason()) : Result.passed(0.5);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/DoubleTapClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/DoubleTapClassifier.java
index f7fe14a..baa54a6 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/DoubleTapClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/DoubleTapClassifier.java
@@ -46,14 +46,14 @@
     }
 
     @Override
-    Result calculateFalsingResult(double historyPenalty, double historyConfidence) {
+    Result calculateFalsingResult(double historyBelief, double historyConfidence) {
         List<MotionEvent> secondTapEvents = getRecentMotionEvents();
         List<MotionEvent> firstTapEvents = getPriorMotionEvents();
 
         StringBuilder reason = new StringBuilder();
 
         if (firstTapEvents == null) {
-            return Result.falsed(1, "Only one gesture recorded");
+            return Result.falsed(0, "Only one gesture recorded");
         }
 
         return !isDoubleTap(firstTapEvents, secondTapEvents, reason)
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingClassifier.java
index f40045b..1af5f7c 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingClassifier.java
@@ -124,7 +124,7 @@
      * See also {@link #classifyGesture(double, double)}.
      */
     Result classifyGesture() {
-        return calculateFalsingResult(0, 0);
+        return calculateFalsingResult(0.5, 0);
     }
 
     /**
@@ -135,16 +135,16 @@
      *
      * See also {@link #classifyGesture()}.
      */
-    Result classifyGesture(double historyPenalty, double historyConfidence) {
-        return calculateFalsingResult(historyPenalty, historyConfidence);
+    Result classifyGesture(double historyBelief, double historyConfidence) {
+        return calculateFalsingResult(historyBelief, historyConfidence);
     }
 
     /**
      * Calculate a result based on available data.
      *
-     * When passed a historyConfidence of 0, the history penalty should be wholly ignored.
+     * When passed a historyConfidence of 0, the history belief should be wholly ignored.
      */
-    abstract Result calculateFalsingResult(double historyPenalty, double historyConfidence);
+    abstract Result calculateFalsingResult(double historyBelief, double historyConfidence);
 
     /** */
     public static void logDebug(String msg) {
@@ -164,7 +164,7 @@
     /**
      * A Falsing result that encapsulates the boolean result along with confidence and a reason.
      */
-    static class Result {
+    public static class Result {
         private final boolean mFalsed;
         private final double mConfidence;
         private final String mReason;
@@ -193,14 +193,14 @@
         /**
          * Construct a "falsed" result indicating that a gesture should be treated as accidental.
          */
-        static Result falsed(double confidence, String reason) {
+        public static Result falsed(double confidence, String reason) {
             return new Result(true, confidence, reason);
         }
 
         /**
          * Construct a "passed" result indicating that a gesture should be allowed.
          */
-        static Result passed(double confidence) {
+        public static Result passed(double confidence) {
             return new Result(false, confidence, null);
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollector.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollector.java
index b0bbab3..bb03720 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollector.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollector.java
@@ -120,5 +120,8 @@
 
     /** */
     void cleanup();
+
+    /** */
+    void updateFalseConfidence(FalsingClassifier.Result result);
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java
index 12a0604..939b45a 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java
@@ -153,4 +153,8 @@
     @Override
     public void cleanup() {
     }
+
+    @Override
+    public void updateFalseConfidence(FalsingClassifier.Result result) {
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java
index e08b43b..e090006 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java
@@ -29,6 +29,9 @@
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.util.sensors.ProximitySensor;
 import com.android.systemui.util.sensors.ThresholdSensor;
+import com.android.systemui.util.time.SystemClock;
+
+import java.util.Collections;
 
 import javax.inject.Inject;
 
@@ -42,8 +45,10 @@
     private final FalsingDataProvider mFalsingDataProvider;
     private final FalsingManager mFalsingManager;
     private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+    private final HistoryTracker mHistoryTracker;
     private final ProximitySensor mProximitySensor;
     private final StatusBarStateController mStatusBarStateController;
+    private final SystemClock mSystemClock;
 
     private int mState;
     private boolean mShowingAod;
@@ -80,13 +85,16 @@
 
     @Inject
     FalsingCollectorImpl(FalsingDataProvider falsingDataProvider, FalsingManager falsingManager,
-            KeyguardUpdateMonitor keyguardUpdateMonitor,
-            ProximitySensor proximitySensor, StatusBarStateController statusBarStateController) {
+            KeyguardUpdateMonitor keyguardUpdateMonitor, HistoryTracker historyTracker,
+            ProximitySensor proximitySensor, StatusBarStateController statusBarStateController,
+            SystemClock systemClock) {
         mFalsingDataProvider = falsingDataProvider;
         mFalsingManager = falsingManager;
         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
+        mHistoryTracker = historyTracker;
         mProximitySensor = proximitySensor;
         mStatusBarStateController = statusBarStateController;
+        mSystemClock = systemClock;
 
 
         mProximitySensor.setTag(PROXIMITY_SENSOR_TAG);
@@ -282,6 +290,11 @@
         mStatusBarStateController.removeCallback(mStatusBarStateListener);
     }
 
+    @Override
+    public void updateFalseConfidence(FalsingClassifier.Result result) {
+        mHistoryTracker.addResults(Collections.singleton(result), mSystemClock.uptimeMillis());
+    }
+
     private void updateInteractionType(@Classifier.InteractionType int type) {
         logDebug("InteractionType: " + type);
         mFalsingDataProvider.setInteractionType(type);
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java
index d4d8d06..aac27cb 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java
@@ -76,7 +76,7 @@
     }
 
     @Override
-    public boolean isFalseTap(boolean robustCheck) {
+    public boolean isFalseTap(boolean robustCheck, double falsePenalty) {
         return robustCheck ? mIsFalseRobustTap : mIsFalseTap;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java
index cbec057..e9bb48c 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java
@@ -131,8 +131,8 @@
     }
 
     @Override
-    public boolean isFalseTap(boolean robustCheck) {
-        return mInternalFalsingManager.isFalseTap(robustCheck);
+    public boolean isFalseTap(boolean robustCheck, double falsePenalty) {
+        return mInternalFalsingManager.isFalseTap(robustCheck, falsePenalty);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/HistoryTracker.java b/packages/SystemUI/src/com/android/systemui/classifier/HistoryTracker.java
index 8bd94a1..be48ec4 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/HistoryTracker.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/HistoryTracker.java
@@ -36,12 +36,17 @@
  */
 @SysUISingleton
 public class HistoryTracker {
-    private static final double HISTORY_DECAY = 0.8f;
+    private static final long HISTORY_MAX_AGE_MS = 10000;
+    // A score is decayed discretely every DECAY_INTERVAL_MS.
     private static final long DECAY_INTERVAL_MS = 100;
-    // We expire items once their decay factor is below 0.001.
-    private static final double MINIMUM_SCORE = 0.001;
-    private static final long TOTAL_DECAY_TIME_MS =
-            DECAY_INTERVAL_MS * (long) (Math.log(MINIMUM_SCORE) / Math.log(HISTORY_DECAY));
+    // We expire items once their decay factor is below 0.1.
+    private static final double MINIMUM_SCORE = 0.1;
+    // This magic number is the factor a score is reduced by every DECAY_INTERVAL_MS.
+    // Once a score is HISTORY_MAX_AGE_MS ms old, it will be reduced by being multiplied by
+    // MINIMUM_SCORE. The math below ensures that.
+    private static final double HISTORY_DECAY =
+            Math.pow(10, Math.log10(MINIMUM_SCORE) / HISTORY_MAX_AGE_MS * DECAY_INTERVAL_MS);
+
     private final SystemClock mSystemClock;
 
     DelayQueue<CombinedResult> mResults = new DelayQueue<>();
@@ -54,29 +59,36 @@
     /**
      * Returns how much the HistoryClassifier thinks the past events indicate pocket dialing.
      *
-     * A result of 0 means that all prior gestures succeeded or there is no data to
-     * calculate a score with. Use {@link #falseConfidence()} to differentiate between the
-     * two cases.
+     * A result close to 0.5 means that prior data is inconclusive (inconsistent, lacking
+     * confidence, or simply lacking in quantity).
      *
-     * A result of 1 means that all prior gestures were very obviously false. The current gesture
-     * might be valid, but it should have a high-bar to be classified as such.
+     * A result close to 0 means that prior gestures indicate a success.
+     *
+     * A result close to 1 means that prior gestures were very obviously false.
+     *
+     * The current gesture might be different than what is reported by this method, but there should
+     * be a high-bar to be classified differently.
      *
      * See also {@link #falseConfidence()}.
      */
-    double falsePenalty() {
+    double falseBelief() {
         //noinspection StatementWithEmptyBody
         while (mResults.poll() != null) {
             // Empty out the expired results.
         }
 
         if (mResults.isEmpty()) {
-            return 0;
+            return 0.5;
         }
 
         long nowMs = mSystemClock.uptimeMillis();
+        // Get our Bayes on.
         return mResults.stream()
                 .map(result -> result.getDecayedScore(nowMs))
-                .reduce(0.0, Double::sum) / mResults.size();
+                .reduce(0.5,
+                        (prior, measurement) ->
+                                (prior * measurement)
+                                        / (prior * measurement + (1 - prior) * (1 - measurement)));
     }
 
     /**
@@ -91,7 +103,7 @@
      * A result of 1 means that there are ample, fresh data to act upon that is all consistent
      * with each other.
      *
-     * See als {@link #falsePenalty()}.
+     * See als {@link #falseBelief()}.
      */
     double falseConfidence() {
         //noinspection StatementWithEmptyBody
@@ -126,6 +138,15 @@
 
         finalScore /= results.size();
 
+        // Never add a 0 or  1, else Bayes breaks down (a 0 and a 1 together results in NaN). In
+        // other words,  you shouldn't need Bayes if you have 100% confidence one way or another.
+        // Instead, make the number ever so slightly smaller so that our math never breaks.
+        if (finalScore == 1) {
+            finalScore = 0.99999;
+        } else if (finalScore == 0) {
+            finalScore = 0.00001;
+        }
+
         //noinspection StatementWithEmptyBody
         while (mResults.poll() != null) {
             // Empty out the expired results.
@@ -147,15 +168,17 @@
         private final double mScore;
 
         CombinedResult(long uptimeMillis, double score) {
-            mExpiryMs = uptimeMillis + TOTAL_DECAY_TIME_MS;
+            mExpiryMs = uptimeMillis + HISTORY_MAX_AGE_MS;
             mScore = score;
         }
 
         double getDecayedScore(long nowMs) {
             long remainingTimeMs = mExpiryMs - nowMs;
-            long decayedTimeMs = TOTAL_DECAY_TIME_MS - remainingTimeMs;
+            long decayedTimeMs = HISTORY_MAX_AGE_MS - remainingTimeMs;
             double timeIntervals = (double) decayedTimeMs / DECAY_INTERVAL_MS;
-            return mScore * Math.pow(HISTORY_DECAY, timeIntervals);
+
+            // Score should decay towards 0.5.
+            return (mScore - 0.5) * Math.pow(HISTORY_DECAY, timeIntervals) + 0.5;
         }
 
         double getScore() {
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/PointerCountClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/PointerCountClassifier.java
index cd399fe..77d2d42 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/PointerCountClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/PointerCountClassifier.java
@@ -56,7 +56,7 @@
     }
 
     @Override
-    Result calculateFalsingResult(double historyPenalty, double historyConfidence) {
+    Result calculateFalsingResult(double historyBelief, double historyConfidence) {
         int interactionType = getInteractionType();
         int allowedPointerCount =
                 (interactionType == QUICK_SETTINGS || interactionType == NOTIFICATION_DRAG_DOWN)
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.java
index 9ee8598..6e97857 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.java
@@ -112,7 +112,7 @@
     }
 
     @Override
-    Result calculateFalsingResult(double historyPenalty, double historyConfidence) {
+    Result calculateFalsingResult(double historyBelief, double historyConfidence) {
         if (getInteractionType() == QUICK_SETTINGS) {
             return Result.passed(0);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/SingleTapClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/SingleTapClassifier.java
index f2622ec..4dd20cc 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/SingleTapClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/SingleTapClassifier.java
@@ -39,12 +39,15 @@
     }
 
     @Override
-    Result calculateFalsingResult(double historyPenalty, double historyConfidence) {
+    Result calculateFalsingResult(double historyBelief, double historyConfidence) {
         return isTap(getRecentMotionEvents());
     }
 
     /** Given a list of {@link android.view.MotionEvent}'s, returns true if the look like a tap. */
     public Result isTap(List<MotionEvent> motionEvents) {
+        if (motionEvents.isEmpty()) {
+            return Result.falsed(0, "no motion events");
+        }
         float downX = motionEvents.get(0).getX();
         float downY = motionEvents.get(0).getY();
 
@@ -59,7 +62,7 @@
             } else if (Math.abs(event.getY() - downY) >= mTouchSlop) {
                 reason = "dY too big for a tap: "
                         + Math.abs(event.getY() - downY)
-                        + "vs "
+                        + " vs "
                         + mTouchSlop;
                 return Result.falsed(0.5, reason);
             }
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/TypeClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/TypeClassifier.java
index d470d62..4e032ea 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/TypeClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/TypeClassifier.java
@@ -38,7 +38,7 @@
     }
 
     @Override
-    Result calculateFalsingResult(double historyPenalty, double historyConfidence) {
+    Result calculateFalsingResult(double historyBelief, double historyConfidence) {
         boolean vertical = isVertical();
         boolean up = isUp();
         boolean right = isRight();
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/ZigZagClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/ZigZagClassifier.java
index 2bfb218..2058257 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/ZigZagClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/ZigZagClassifier.java
@@ -84,7 +84,7 @@
     }
 
     @Override
-    Result calculateFalsingResult(double historyPenalty, double historyConfidence) {
+    Result calculateFalsingResult(double historyBelief, double historyConfidence) {
         List<MotionEvent> motionEvents = getRecentMotionEvents();
         // Rotate horizontal gestures to be horizontal between their first and last point.
         // Rotate vertical gestures to be vertical between their first and last point.
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
index 8f79de5..ed3d5ec 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
@@ -34,7 +34,7 @@
 import com.android.wm.shell.pip.Pip;
 import com.android.wm.shell.splitscreen.SplitScreen;
 import com.android.wm.shell.startingsurface.StartingSurface;
-import com.android.wm.shell.transition.RemoteTransitions;
+import com.android.wm.shell.transition.ShellTransitions;
 
 import java.util.Optional;
 
@@ -87,7 +87,7 @@
         Builder setShellCommandHandler(Optional<ShellCommandHandler> shellDump);
 
         @BindsInstance
-        Builder setTransitions(RemoteTransitions t);
+        Builder setTransitions(ShellTransitions t);
 
         @BindsInstance
         Builder setStartingSurface(Optional<StartingSurface> s);
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
index 1b77d1c..bbd95b4 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
@@ -33,7 +33,7 @@
 import com.android.wm.shell.pip.Pip;
 import com.android.wm.shell.splitscreen.SplitScreen;
 import com.android.wm.shell.startingsurface.StartingSurface;
-import com.android.wm.shell.transition.RemoteTransitions;
+import com.android.wm.shell.transition.ShellTransitions;
 
 import java.util.Optional;
 
@@ -98,7 +98,7 @@
     Optional<TaskViewFactory> getTaskViewFactory();
 
     @WMSingleton
-    RemoteTransitions getTransitions();
+    ShellTransitions getTransitions();
 
     @WMSingleton
     Optional<StartingSurface> getStartingSurface();
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
index 5536237..b471659 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
@@ -211,6 +211,7 @@
     private Locale mLocale;
     private int mLayoutDirection;
 
+    private boolean mAllowForceNavBarHandleOpaque;
     private boolean mForceNavBarHandleOpaque;
     private boolean mIsCurrentUserSetup;
 
@@ -333,13 +334,23 @@
                 // If the current user is not yet setup, then don't update any button alphas
                 return;
             }
+            if (QuickStepContract.isLegacyMode(mNavBarMode)) {
+                // Don't allow the bar buttons to be affected by the alpha
+                return;
+            }
+
             ButtonDispatcher buttonDispatcher = null;
             boolean forceVisible = false;
-            if (QuickStepContract.isSwipeUpMode(mNavBarMode)) {
-                buttonDispatcher = mNavigationBarView.getBackButton();
-            } else if (QuickStepContract.isGesturalMode(mNavBarMode)) {
-                forceVisible = mForceNavBarHandleOpaque;
+            if (QuickStepContract.isGesturalMode(mNavBarMode)) {
+                // Disallow home handle animations when in gestural
+                animate = false;
+                forceVisible = mAllowForceNavBarHandleOpaque && mForceNavBarHandleOpaque;
                 buttonDispatcher = mNavigationBarView.getHomeHandle();
+                if (getBarTransitions() != null) {
+                    getBarTransitions().setBackgroundOverrideAlpha(alpha);
+                }
+            } else if (QuickStepContract.isSwipeUpMode(mNavBarMode)) {
+                buttonDispatcher = mNavigationBarView.getBackButton();
             }
             if (buttonDispatcher != null) {
                 buttonDispatcher.setVisibility(
@@ -506,6 +517,8 @@
         // Respect the latest disabled-flags.
         mCommandQueue.recomputeDisableFlags(mDisplayId, false);
 
+        mAllowForceNavBarHandleOpaque = mContext.getResources().getBoolean(
+                R.bool.allow_force_nav_bar_handle_opaque);
         mForceNavBarHandleOpaque = DeviceConfig.getBoolean(
                 DeviceConfig.NAMESPACE_SYSTEMUI,
                 NAV_BAR_HANDLE_FORCE_OPAQUE,
@@ -1468,6 +1481,12 @@
     @Override
     public void onNavigationModeChanged(int mode) {
         mNavBarMode = mode;
+        if (!QuickStepContract.isGesturalMode(mode)) {
+            // Reset the override alpha
+            if (getBarTransitions() != null) {
+                getBarTransitions().setBackgroundOverrideAlpha(1f);
+            }
+        }
         updateScreenPinningGestures();
 
         if (!canShowSecondaryHandle()) {
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
index 4491cc1..0bfd065 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
@@ -212,6 +212,14 @@
         createNavigationBar(display, null /* savedState */, null /* result */);
     }
 
+    @Override
+    public void setNavigationBarLumaSamplingEnabled(int displayId, boolean enable) {
+        final NavigationBarView navigationBarView = getNavigationBarView(displayId);
+        if (navigationBarView != null) {
+            navigationBarView.setNavigationBarLumaSamplingEnabled(enable);
+        }
+    }
+
     /**
      * Recreates the navigation bar for the given display.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarTransitions.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarTransitions.java
index 61e1d61..fbc7c92 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarTransitions.java
@@ -36,6 +36,7 @@
 import com.android.systemui.statusbar.phone.BarTransitions;
 import com.android.systemui.statusbar.phone.LightBarTransitionsController;
 
+import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -135,6 +136,10 @@
         mBarBackground.setFrame(frame);
     }
 
+    void setBackgroundOverrideAlpha(float alpha) {
+        mBarBackground.setOverrideAlpha(alpha);
+    }
+
     @Override
     protected boolean isLightsOut(int mode) {
         return super.isLightsOut(mode) || (mAllowAutoDimWallpaperNotVisible && mAutoDim
@@ -230,4 +235,17 @@
     public void removeDarkIntensityListener(DarkIntensityListener listener) {
         mDarkIntensityListeners.remove(listener);
     }
+
+    public void dump(PrintWriter pw) {
+        pw.println("NavigationBarTransitions:");
+        pw.println("  mMode: " + getMode());
+        pw.println("  mAlwaysOpaque: " + isAlwaysOpaque());
+        pw.println("  mAllowAutoDimWallpaperNotVisible: " + mAllowAutoDimWallpaperNotVisible);
+        pw.println("  mWallpaperVisible: " + mWallpaperVisible);
+        pw.println("  mLightsOut: " + mLightsOut);
+        pw.println("  mAutoDim: " + mAutoDim);
+        pw.println("  bg overrideAlpha: " + mBarBackground.getOverrideAlpha());
+        pw.println("  bg color: " + mBarBackground.getColor());
+        pw.println("  bg frame: " + mBarBackground.getFrame());
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
index 35d5ca9..091b17d 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
@@ -1158,6 +1158,8 @@
             int frameHeight = getResources().getDimensionPixelSize(
                     com.android.internal.R.dimen.navigation_bar_frame_height);
             mBarTransitions.setBackgroundFrame(new Rect(0, frameHeight - height, w, h));
+        } else {
+            mBarTransitions.setBackgroundFrame(null);
         }
 
         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
@@ -1331,6 +1333,7 @@
         if (mNavigationInflaterView != null) {
             mNavigationInflaterView.dump(pw);
         }
+        mBarTransitions.dump(pw);
         mContextualButtonGroup.dump(pw);
         mRecentsOnboarding.dump(pw);
         mRegionSamplingHelper.dump(pw);
@@ -1397,4 +1400,12 @@
     private final Consumer<Rect> mPipListener = bounds -> post(() -> {
         mEdgeBackGestureHandler.setPipStashExclusionBounds(bounds);
     });
+
+    void setNavigationBarLumaSamplingEnabled(boolean enable) {
+        if (enable) {
+            mRegionSamplingHelper.start(mSamplingBounds);
+        } else {
+            mRegionSamplingHelper.stop();
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogController.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogController.kt
index 03c1843..f87ea7c 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogController.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogController.kt
@@ -214,9 +214,7 @@
 
     private fun filterType(type: PrivacyType?): PrivacyType? {
         return type?.let {
-            if (privacyItemController.allIndicatorsAvailable) {
-                it
-            } else if ((it == PrivacyType.TYPE_CAMERA || it == PrivacyType.TYPE_MICROPHONE) &&
+            if ((it == PrivacyType.TYPE_CAMERA || it == PrivacyType.TYPE_MICROPHONE) &&
                     privacyItemController.micCameraAvailable) {
                 it
             } else if (it == PrivacyType.TYPE_LOCATION && privacyItemController.locationAvailable) {
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt
index 1e04516..03d6154 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt
@@ -68,8 +68,6 @@
             addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)
         }
         const val TAG = "PrivacyItemController"
-        private const val ALL_INDICATORS =
-                SystemUiDeviceConfigFlags.PROPERTY_PERMISSIONS_HUB_ENABLED
         private const val MIC_CAMERA = SystemUiDeviceConfigFlags.PROPERTY_MIC_CAMERA_ENABLED
         private const val LOCATION = SystemUiDeviceConfigFlags.PROPERTY_LOCATION_INDICATORS_ENABLED
         private const val DEFAULT_ALL_INDICATORS = false
@@ -83,11 +81,6 @@
         @Synchronized get() = field.toList() // Returns a shallow copy of the list
         @Synchronized set
 
-    private fun isAllIndicatorsEnabled(): Boolean {
-        return deviceConfigProxy.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
-                ALL_INDICATORS, DEFAULT_ALL_INDICATORS)
-    }
-
     private fun isMicCameraEnabled(): Boolean {
         return deviceConfigProxy.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
                 MIC_CAMERA, DEFAULT_MIC_CAMERA)
@@ -120,34 +113,29 @@
         uiExecutor.execute(notifyChanges)
     }
 
-    var allIndicatorsAvailable = isAllIndicatorsEnabled()
-        private set
     var micCameraAvailable = isMicCameraEnabled()
         private set
     var locationAvailable = isLocationEnabled()
 
+    var allIndicatorsAvailable = micCameraAvailable && locationAvailable
+
     private val devicePropertiesChangedListener =
             object : DeviceConfig.OnPropertiesChangedListener {
         override fun onPropertiesChanged(properties: DeviceConfig.Properties) {
             if (DeviceConfig.NAMESPACE_PRIVACY.equals(properties.getNamespace()) &&
-                    (properties.keyset.contains(ALL_INDICATORS) ||
-                            properties.keyset.contains(MIC_CAMERA) ||
+                    (properties.keyset.contains(MIC_CAMERA) ||
                             properties.keyset.contains(LOCATION))) {
 
                 // Running on the ui executor so can iterate on callbacks
-                if (properties.keyset.contains(ALL_INDICATORS)) {
-                    allIndicatorsAvailable = properties.getBoolean(ALL_INDICATORS,
-                            DEFAULT_ALL_INDICATORS)
-                    callbacks.forEach { it.get()?.onFlagAllChanged(allIndicatorsAvailable) }
-                }
-
                 if (properties.keyset.contains(MIC_CAMERA)) {
                     micCameraAvailable = properties.getBoolean(MIC_CAMERA, DEFAULT_MIC_CAMERA)
+                    allIndicatorsAvailable = micCameraAvailable && locationAvailable
                     callbacks.forEach { it.get()?.onFlagMicCameraChanged(micCameraAvailable) }
                 }
 
                 if (properties.keyset.contains(LOCATION)) {
                     locationAvailable = properties.getBoolean(LOCATION, DEFAULT_LOCATION)
+                    allIndicatorsAvailable = micCameraAvailable && locationAvailable
                     callbacks.forEach { it.get()?.onFlagLocationChanged(locationAvailable) }
                 }
                 internalUiExecutor.updateListeningState()
@@ -163,8 +151,7 @@
             active: Boolean
         ) {
             // Check if we care about this code right now
-            if (!allIndicatorsAvailable &&
-                    (code in OPS_LOCATION && !locationAvailable)) {
+            if (code in OPS_LOCATION && !locationAvailable) {
                 return
             }
             val userId = UserHandle.getUserId(uid)
@@ -231,7 +218,7 @@
      */
     private fun setListeningState() {
         val listen = !callbacks.isEmpty() and
-                (allIndicatorsAvailable || micCameraAvailable || locationAvailable)
+                (micCameraAvailable || locationAvailable)
         if (listening == listen) return
         listening = listen
         if (listening) {
@@ -338,7 +325,7 @@
             AppOpsManager.OP_RECORD_AUDIO -> PrivacyType.TYPE_MICROPHONE
             else -> return null
         }
-        if (type == PrivacyType.TYPE_LOCATION && (!allIndicatorsAvailable && !locationAvailable)) {
+        if (type == PrivacyType.TYPE_LOCATION && !locationAvailable) {
             return null
         }
         val app = PrivacyApplication(appOpItem.packageName, appOpItem.uid)
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/television/TvOngoingPrivacyChip.java b/packages/SystemUI/src/com/android/systemui/privacy/television/TvOngoingPrivacyChip.java
index 0fa7b59..5ab7bd8 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/television/TvOngoingPrivacyChip.java
+++ b/packages/SystemUI/src/com/android/systemui/privacy/television/TvOngoingPrivacyChip.java
@@ -88,7 +88,6 @@
     private boolean mViewAndWindowAdded;
     private ObjectAnimator mAnimator;
 
-    private boolean mAllIndicatorsFlagEnabled;
     private boolean mMicCameraIndicatorFlagEnabled;
     private boolean mLocationIndicatorEnabled;
     private List<PrivacyItem> mPrivacyItems;
@@ -111,12 +110,10 @@
         mIconMarginStart = Math.round(res.getDimension(R.dimen.privacy_chip_icon_margin));
         mIconSize = res.getDimensionPixelSize(R.dimen.privacy_chip_icon_size);
 
-        mAllIndicatorsFlagEnabled = privacyItemController.getAllIndicatorsAvailable();
         mMicCameraIndicatorFlagEnabled = privacyItemController.getMicCameraAvailable();
         mLocationIndicatorEnabled = privacyItemController.getLocationAvailable();
 
         if (DEBUG) {
-            Log.d(TAG, "allIndicators: " + mAllIndicatorsFlagEnabled);
             Log.d(TAG, "micCameraIndicators: " + mMicCameraIndicatorFlagEnabled);
             Log.d(TAG, "locationIndicators: " + mLocationIndicatorEnabled);
         }
@@ -135,12 +132,6 @@
     }
 
     @Override
-    public void onFlagAllChanged(boolean flag) {
-        if (DEBUG) Log.d(TAG, "all indicators enabled: " + flag);
-        mAllIndicatorsFlagEnabled = flag;
-    }
-
-    @Override
     public void onFlagMicCameraChanged(boolean flag) {
         if (DEBUG) Log.d(TAG, "mic/camera indicators enabled: " + flag);
         mMicCameraIndicatorFlagEnabled = flag;
@@ -155,8 +146,8 @@
     private void updateUI() {
         if (DEBUG) Log.d(TAG, mPrivacyItems.size() + " privacy items");
 
-        if ((mMicCameraIndicatorFlagEnabled || mAllIndicatorsFlagEnabled
-                || mLocationIndicatorEnabled) && !mPrivacyItems.isEmpty()) {
+        if ((mMicCameraIndicatorFlagEnabled || mLocationIndicatorEnabled)
+                && !mPrivacyItems.isEmpty()) {
             if (mState == STATE_NOT_SHOWN || mState == STATE_DISAPPEARING) {
                 showIndicator();
             } else {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
index fe76668..b8823e1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
@@ -14,6 +14,8 @@
 
 package com.android.systemui.qs;
 
+import android.animation.TimeInterpolator;
+import android.animation.ValueAnimator;
 import android.util.Log;
 import android.view.View;
 import android.view.View.OnAttachStateChangeListener;
@@ -35,6 +37,7 @@
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.List;
 import java.util.concurrent.Executor;
 
 import javax.inject.Inject;
@@ -77,6 +80,9 @@
     // This animates fading of SecurityFooter and media divider
     private TouchAnimator mAllPagesDelayedAnimator;
     private TouchAnimator mBrightnessAnimator;
+    private HeightExpansionAnimator mQQSTileHeightAnimator;
+    private HeightExpansionAnimator mOtherTilesExpandAnimator;
+
     private boolean mNeedsAnimatorUpdate = false;
 
     private boolean mOnKeyguard;
@@ -161,7 +167,7 @@
     @Override
     public void onViewAttachedToWindow(View v) {
         mTunerService.addTunable(this, ALLOW_FANCY_ANIMATION,
-                MOVE_FULL_ROWS, QuickQSPanel.NUM_QUICK_TILES);
+                MOVE_FULL_ROWS);
     }
 
     @Override
@@ -179,9 +185,6 @@
             }
         } else if (MOVE_FULL_ROWS.equals(key)) {
             mFullRows = TunerService.parseIntegerSwitch(newValue, true);
-        } else if (QuickQSPanel.NUM_QUICK_TILES.equals(key)) {
-            mNumQuickTiles = QuickQSPanel.parseNumTiles(newValue);
-            clearAnimationState();
         }
         updateAnimators();
     }
@@ -209,6 +212,10 @@
         clearAnimationState();
         mAllViews.clear();
         mQuickQsViews.clear();
+        mQQSTileHeightAnimator = null;
+        mOtherTilesExpandAnimator = null;
+
+        mNumQuickTiles = mQuickQsPanel.getNumQuickTiles();
 
         QSTileLayout tileLayout = mQsPanelController.getTileLayout();
         mAllViews.add((View) tileLayout);
@@ -218,6 +225,9 @@
                 + mQs.getHeader().getPaddingBottom();
         firstPageBuilder.addFloat(tileLayout, "translationY", heightDiff, 0);
 
+        boolean qsSideLabelsEnabled = mFeatureFlags.isQSLabelsEnabled();
+        int qqsTileHeight = 0;
+
         for (QSTile tile : tiles) {
             QSTileView tileView = mQsPanelController.getTileView(tile);
             if (tileView == null) {
@@ -237,22 +247,47 @@
                 getRelativePosition(loc1, quickTileView.getIcon().getIconView(), view);
                 getRelativePosition(loc2, tileIcon, view);
                 final int xDiff = loc2[0] - loc1[0];
-                final int yDiff = loc2[1] - loc1[1];
-
+                int yDiff = loc2[1] - loc1[1];
 
                 if (count < tileLayout.getNumVisibleTiles()) {
+                    getRelativePosition(loc1, quickTileView, view);
+                    getRelativePosition(loc2, tileView, view);
+                    int yOffset = qsSideLabelsEnabled ? loc2[1] - loc1[1] : 0;
                     // Move the quick tile right from its location to the new one.
-                    translationXBuilder.addFloat(quickTileView, "translationX", 0, xDiff);
-                    translationYBuilder.addFloat(quickTileView, "translationY", 0, yDiff);
-
-                    // Counteract the parent translation on the tile. So we have a static base to
-                    // animate the label position off from.
-                    //firstPageBuilder.addFloat(tileView, "translationY", mQsPanel.getHeight(), 0);
+                    View v = qsSideLabelsEnabled ? quickTileView.getIcon() : quickTileView;
+                    translationXBuilder.addFloat(v, "translationX", 0, xDiff);
+                    translationYBuilder.addFloat(v, "translationY", 0, yDiff - yOffset);
+                    mAllViews.add(v);
 
                     // Move the real tile from the quick tile position to its final
                     // location.
-                    translationXBuilder.addFloat(tileView, "translationX", -xDiff, 0);
-                    translationYBuilder.addFloat(tileView, "translationY", -yDiff, 0);
+                    v = qsSideLabelsEnabled ? tileIcon : tileView;
+                    translationXBuilder.addFloat(v, "translationX", -xDiff, 0);
+                    translationYBuilder.addFloat(v, "translationY", -yDiff + yOffset, 0);
+
+                    if (qsSideLabelsEnabled) {
+                        translationYBuilder.addFloat(quickTileView, "translationY", 0, yOffset);
+                        translationYBuilder.addFloat(tileView, "translationY", -yOffset, 0);
+
+                        if (mQQSTileHeightAnimator == null) {
+                            mQQSTileHeightAnimator = new HeightExpansionAnimator(this,
+                                    quickTileView.getHeight(), tileView.getHeight());
+                            qqsTileHeight = quickTileView.getHeight();
+                        }
+
+                        mQQSTileHeightAnimator.addView(quickTileView);
+                        View qqsLabelContainer = quickTileView.getLabelContainer();
+                        View qsLabelContainer = tileView.getLabelContainer();
+
+                        getRelativePosition(loc1, qqsLabelContainer, view);
+                        getRelativePosition(loc2, qsLabelContainer, view);
+                        yDiff = loc2[1] - loc1[1] - yOffset;
+
+                        translationYBuilder.addFloat(qqsLabelContainer, "translationY", 0, yDiff);
+                        translationYBuilder.addFloat(qsLabelContainer, "translationY", -yDiff, 0);
+                        mAllViews.add(qqsLabelContainer);
+                        mAllViews.add(qsLabelContainer);
+                    }
 
                 } else { // These tiles disappear when expanding
                     firstPageBuilder.addFloat(quickTileView, "alpha", 1, 0);
@@ -265,7 +300,7 @@
                             translationX);
                 }
 
-                if (mFeatureFlags.isQSLabelsEnabled()) {
+                if (qsSideLabelsEnabled) {
                     mQuickQsViews.add(tileView);
                 } else {
                     mQuickQsViews.add(tileView.getIconWithBackground());
@@ -278,9 +313,29 @@
 
                 mAllViews.add(tileIcon);
             } else {
-                firstPageBuilder.addFloat(tileView, "alpha", 0, 1);
-                firstPageBuilder.addFloat(tileView, "translationY", -heightDiff, 0);
+                if (!qsSideLabelsEnabled) {
+                    firstPageBuilder.addFloat(tileView, "alpha", 0, 1);
+                    firstPageBuilder.addFloat(tileView, "translationY", -heightDiff, 0);
+                } else {
+                    // Pretend there's a corresponding QQS tile (for the position) that we are
+                    // expanding from.
+                    SideLabelTileLayout qqsLayout =
+                            (SideLabelTileLayout) mQuickQsPanel.getTileLayout();
+                    getRelativePosition(loc1, qqsLayout, view);
+                    getRelativePosition(loc2, tileView, view);
+                    int diff = loc2[1] - (loc1[1] + qqsLayout.getPhantomTopPosition(count));
+                    translationYBuilder.addFloat(tileView, "translationY", -diff, 0);
+                    if (mOtherTilesExpandAnimator == null) {
+                        mOtherTilesExpandAnimator =
+                                new HeightExpansionAnimator(
+                                        this, qqsTileHeight, tileView.getHeight());
+                    }
+                    mOtherTilesExpandAnimator.addView(tileView);
+                    tileView.setClipChildren(true);
+                    tileView.setClipToPadding(true);
+                }
             }
+
             mAllViews.add(tileView);
             count++;
         }
@@ -303,7 +358,7 @@
                     .build();
             // Fade in the tiles/labels as we reach the final position.
             Builder builder = new Builder()
-                    .setStartDelay(EXPANDED_TILE_DELAY)
+                    .setStartDelay(qsSideLabelsEnabled ? 0 : EXPANDED_TILE_DELAY)
                     .addFloat(tileLayout, "alpha", 0, 1);
             mFirstPageDelayedAnimator = builder.build();
 
@@ -331,6 +386,12 @@
             translationYBuilder.setInterpolator(interpolatorBuilder.getYInterpolator());
             mTranslationXAnimator = translationXBuilder.build();
             mTranslationYAnimator = translationYBuilder.build();
+            if (mQQSTileHeightAnimator != null) {
+                mQQSTileHeightAnimator.setInterpolator(interpolatorBuilder.getYInterpolator());
+            }
+            if (mOtherTilesExpandAnimator != null) {
+                mOtherTilesExpandAnimator.setInterpolator(interpolatorBuilder.getYInterpolator());
+            }
         }
         mNonfirstPageAnimator = new TouchAnimator.Builder()
                 .addFloat(mQuickQsPanel, "alpha", 1, 0)
@@ -404,6 +465,12 @@
             if (mBrightnessAnimator != null) {
                 mBrightnessAnimator.setPosition(position);
             }
+            if (mQQSTileHeightAnimator != null) {
+                mQQSTileHeightAnimator.setPosition(position);
+            }
+            if (mOtherTilesExpandAnimator != null) {
+                mOtherTilesExpandAnimator.setPosition(position);
+            }
         } else {
             mNonfirstPageAnimator.setPosition(position);
             mNonfirstPageDelayedAnimator.setPosition(position);
@@ -446,6 +513,16 @@
             v.setAlpha(1);
             v.setTranslationX(0);
             v.setTranslationY(0);
+            if (v instanceof SideLabelTileLayout) {
+                ((SideLabelTileLayout) v).setClipChildren(false);
+                ((SideLabelTileLayout) v).setClipToPadding(false);
+            }
+        }
+        if (mQQSTileHeightAnimator != null) {
+            mQQSTileHeightAnimator.resetViewsHeights();
+        }
+        if (mOtherTilesExpandAnimator != null) {
+            mOtherTilesExpandAnimator.resetViewsHeights();
         }
         final int N2 = mQuickQsViews.size();
         for (int i = 0; i < N2; i++) {
@@ -483,4 +560,61 @@
         updateAnimators();
         setCurrentPosition();
     };
+
+    static class HeightExpansionAnimator {
+        private final List<View> mViews = new ArrayList<>();
+        private final ValueAnimator mAnimator;
+        private final TouchAnimator.Listener mListener;
+
+        private final ValueAnimator.AnimatorUpdateListener mUpdateListener =
+                new ValueAnimator.AnimatorUpdateListener() {
+            float mLastT = -1;
+            @Override
+            public void onAnimationUpdate(ValueAnimator valueAnimator) {
+                float t = valueAnimator.getAnimatedFraction();
+                if (t == 0f) {
+                    mListener.onAnimationAtStart();
+                } else if (t == 1f) {
+                    mListener.onAnimationAtEnd();
+                } else if (mLastT <= 0 || mLastT == 1) {
+                    mListener.onAnimationStarted();
+                }
+                mLastT = t;
+                final int viewCount = mViews.size();
+                int height = (Integer) valueAnimator.getAnimatedValue();
+                for (int i = 0; i < viewCount; i++) {
+                    View v = mViews.get(i);
+                    v.setBottom(v.getTop() + height);
+                }
+            }
+        };
+
+        HeightExpansionAnimator(TouchAnimator.Listener listener, int startHeight, int endHeight) {
+            mListener = listener;
+            mAnimator = ValueAnimator.ofInt(startHeight, endHeight);
+            mAnimator.setRepeatCount(ValueAnimator.INFINITE);
+            mAnimator.setRepeatMode(ValueAnimator.REVERSE);
+            mAnimator.addUpdateListener(mUpdateListener);
+        }
+
+        void addView(View v) {
+            mViews.add(v);
+        }
+
+        void setInterpolator(TimeInterpolator interpolator) {
+            mAnimator.setInterpolator(interpolator);
+        }
+
+        void setPosition(float position) {
+            mAnimator.setCurrentFraction(position);
+        }
+
+        void resetViewsHeights() {
+            final int viewsCount = mViews.size();
+            for (int i = 0; i < viewsCount; i++) {
+                View v = mViews.get(i);
+                v.setBottom(v.getTop() + v.getMeasuredHeight());
+            }
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index ed308ae..7c9f0b0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -430,6 +430,7 @@
         mFooter.setExpansion(onKeyguardAndExpanded ? 1 : expansion);
         mQSPanelController.setRevealExpansion(expansion);
         mQSPanelController.getTileLayout().setExpansion(expansion);
+        mQuickQSPanelController.getTileLayout().setExpansion(expansion);
         mQSPanelScrollView.setTranslationY(translationScaleY * heightDiff);
         if (fullyCollapsed) {
             mQSPanelScrollView.setScrollY(0);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index ff9b912..c794a21 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -315,7 +315,7 @@
         int tileBg = getResources().getDimensionPixelSize(R.dimen.qs_tile_background_size);
         mFooterMarginStartHorizontal = getResources().getDimensionPixelSize(
                 R.dimen.qs_footer_horizontal_margin);
-        mVisualTilePadding = (int) ((tileSize - tileBg) / 2.0f);
+        mVisualTilePadding = mSideLabels ? 0 : (int) ((tileSize - tileBg) / 2.0f);
         updatePadding();
 
         updatePageIndicator();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index f51d7ef..e7828c3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -348,19 +348,20 @@
     }
 
     static class QQSSideLabelTileLayout extends SideLabelTileLayout {
+
         QQSSideLabelTileLayout(Context context) {
             super(context, null);
             setClipChildren(false);
             setClipToPadding(false);
             LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT,
                     LayoutParams.WRAP_CONTENT);
-            lp.gravity = Gravity.CENTER_HORIZONTAL;
             setLayoutParams(lp);
             setMaxColumns(4);
         }
 
         @Override
         public boolean updateResources() {
+            mCellHeightResId = R.dimen.qs_quick_tile_size;
             boolean b = super.updateResources();
             mMaxAllowedRows = 2;
             return b;
@@ -379,5 +380,38 @@
             updateMaxRows(10000, mRecords.size());
             super.onMeasure(widthMeasureSpec, heightMeasureSpec);
         }
+
+        @Override
+        public void setListening(boolean listening, UiEventLogger uiEventLogger) {
+            boolean startedListening = !mListening && listening;
+            super.setListening(listening, uiEventLogger);
+            if (startedListening) {
+                // getNumVisibleTiles() <= mRecords.size()
+                for (int i = 0; i < getNumVisibleTiles(); i++) {
+                    QSTile tile = mRecords.get(i).tile;
+                    uiEventLogger.logWithInstanceId(QSEvent.QQS_TILE_VISIBLE, 0,
+                            tile.getMetricsSpec(), tile.getInstanceId());
+                }
+            }
+        }
+
+        @Override
+        public void setExpansion(float expansion) {
+            if (expansion > 0f && expansion < 1f) {
+                return;
+            }
+            boolean selected = expansion == 0f;
+            // Expansion == 0f is when QQS is fully showing (as opposed to 1f, which is QS). At this
+            // point we want them to be selected so the tiles will marquee (but not at other points
+            // of expansion.
+            // We set it as not important while we change this, so setting each tile as selected
+            // will not cause them to announce themselves until the user has actually selected the
+            // item.
+            setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
+            for (int i = 0; i < getChildCount(); i++) {
+                getChildAt(i).setSelected(selected);
+            }
+            setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_AUTO);
+        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
index 671f8f7..fee56b9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
@@ -99,7 +99,7 @@
                 break;
             }
         }
-        super.setTiles(tiles, !mQSLabelFlag);
+        super.setTiles(tiles, /* collapsedView */ true);
     }
 
     /** */
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
index e3c39aa..eedcdab 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
@@ -97,7 +97,6 @@
 
     private boolean mListening;
     private AlarmClockInfo mNextAlarm;
-    private boolean mAllIndicatorsEnabled;
     private boolean mMicCameraIndicatorsEnabled;
     private boolean mLocationIndicatorsEnabled;
     private boolean mPrivacyChipLogged;
@@ -151,14 +150,6 @@
         }
 
         @Override
-        public void onFlagAllChanged(boolean flag) {
-            if (mAllIndicatorsEnabled != flag) {
-                mAllIndicatorsEnabled = flag;
-                update();
-            }
-        }
-
-        @Override
         public void onFlagMicCameraChanged(boolean flag) {
             if (mMicCameraIndicatorsEnabled != flag) {
                 mMicCameraIndicatorsEnabled = flag;
@@ -270,7 +261,6 @@
         mRingerContainer.setOnClickListener(mOnClickListener);
         mPrivacyChip.setOnClickListener(mOnClickListener);
 
-        mAllIndicatorsEnabled = mPrivacyItemController.getAllIndicatorsAvailable();
         mMicCameraIndicatorsEnabled = mPrivacyItemController.getMicCameraAvailable();
         mLocationIndicatorsEnabled = mPrivacyItemController.getLocationAvailable();
 
@@ -321,7 +311,6 @@
             mNextAlarmController.addCallback(mNextAlarmChangeCallback);
             mLifecycle.setCurrentState(Lifecycle.State.RESUMED);
             // Get the most up to date info
-            mAllIndicatorsEnabled = mPrivacyItemController.getAllIndicatorsAvailable();
             mMicCameraIndicatorsEnabled = mPrivacyItemController.getMicCameraAvailable();
             mLocationIndicatorsEnabled = mPrivacyItemController.getLocationAvailable();
             mPrivacyItemController.addCallback(mPICCallback);
@@ -353,13 +342,13 @@
     private List<String> getIgnoredIconSlots() {
         ArrayList<String> ignored = new ArrayList<>();
         if (getChipEnabled()) {
-            if (mAllIndicatorsEnabled || mMicCameraIndicatorsEnabled) {
+            if (mMicCameraIndicatorsEnabled) {
                 ignored.add(mView.getResources().getString(
                         com.android.internal.R.string.status_bar_camera));
                 ignored.add(mView.getResources().getString(
                         com.android.internal.R.string.status_bar_microphone));
             }
-            if (mAllIndicatorsEnabled || mLocationIndicatorsEnabled) {
+            if (mLocationIndicatorsEnabled) {
                 ignored.add(mView.getResources().getString(
                         com.android.internal.R.string.status_bar_location));
             }
@@ -368,7 +357,7 @@
     }
 
     private boolean getChipEnabled() {
-        return mMicCameraIndicatorsEnabled || mLocationIndicatorsEnabled || mAllIndicatorsEnabled;
+        return mMicCameraIndicatorsEnabled || mLocationIndicatorsEnabled;
     }
 
     private boolean isZenOverridingRinger() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/SideLabelTileLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/SideLabelTileLayout.kt
index 52f111e7..0ebadfd 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/SideLabelTileLayout.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/SideLabelTileLayout.kt
@@ -33,4 +33,15 @@
     override fun isFull(): Boolean {
         return mRecords.size >= maxTiles()
     }
+
+    /**
+     * Return the position from the top of the layout of the tile with this index.
+     *
+     * This will return a position even for indices that go beyond [maxTiles], continuing the rows
+     * beyond that.
+     */
+    fun getPhantomTopPosition(index: Int): Int {
+        val row = index / mColumns
+        return getRowTop(row)
+    }
 }
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
index c1ce4a5..9e0aa5a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
@@ -25,6 +25,7 @@
 
     protected int mColumns;
     protected int mCellWidth;
+    protected int mCellHeightResId = R.dimen.qs_tile_height;
     protected int mCellHeight;
     protected int mMaxCellHeight;
     protected int mCellMarginHorizontal;
@@ -118,7 +119,7 @@
         final Resources res = mContext.getResources();
         mResourceColumns = Math.max(1, res.getInteger(R.integer.quick_settings_num_columns));
         updateColumns();
-        mMaxCellHeight = mContext.getResources().getDimensionPixelSize(R.dimen.qs_tile_height);
+        mMaxCellHeight = mContext.getResources().getDimensionPixelSize(mCellHeightResId);
         mCellMarginHorizontal = res.getDimensionPixelSize(R.dimen.qs_tile_margin_horizontal);
         mCellMarginVertical= res.getDimensionPixelSize(R.dimen.qs_tile_margin_vertical);
         mCellMarginTop = res.getDimensionPixelSize(R.dimen.qs_tile_margin_top);
@@ -235,7 +236,7 @@
         layoutTileRecords(mRecords.size());
     }
 
-    private int getRowTop(int row) {
+    protected int getRowTop(int row) {
         return row * (mCellHeight + mCellMarginVertical) + mCellMarginTop;
     }
 
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 f8c0dd4..7977b49 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileViewHorizontal.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileViewHorizontal.kt
@@ -14,7 +14,7 @@
 class CustomizeTileViewHorizontal(
     context: Context,
     icon: QSIconView
-) : QSTileViewHorizontal(context, icon),
+) : QSTileViewHorizontal(context, icon, collapsed = false),
     TileAdapter.CustomizeView {
 
     private var showAppLabel = false
@@ -27,6 +27,7 @@
 
     override fun handleStateChanged(state: QSTile.State) {
         super.handleStateChanged(state)
+        mShowRippleEffect = false
         mSecondLine.visibility = if (showAppLabel) View.VISIBLE else View.GONE
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
index 56d06eb..1699a34 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
@@ -51,6 +51,7 @@
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.qs.QSTile.State;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.QSHost;
@@ -95,6 +96,7 @@
             QSHost host,
             Looper backgroundLooper,
             Handler mainHandler,
+            FalsingManager falsingManager,
             MetricsLogger metricsLogger,
             StatusBarStateController statusBarStateController,
             ActivityStarter activityStarter,
@@ -102,8 +104,8 @@
             String action,
             Context userContext
     ) {
-        super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
-                activityStarter, qsLogger);
+        super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
+                statusBarStateController, activityStarter, qsLogger);
         mWindowManager = WindowManagerGlobal.getWindowManagerService();
         mComponent = ComponentName.unflattenFromString(action);
         mTile = new Tile();
@@ -450,6 +452,7 @@
         final Lazy<QSHost> mQSHostLazy;
         final Looper mBackgroundLooper;
         final Handler mMainHandler;
+        private final FalsingManager mFalsingManager;
         final MetricsLogger mMetricsLogger;
         final StatusBarStateController mStatusBarStateController;
         final ActivityStarter mActivityStarter;
@@ -463,6 +466,7 @@
                 Lazy<QSHost> hostLazy,
                 @Background Looper backgroundLooper,
                 @Main Handler mainHandler,
+                FalsingManager falsingManager,
                 MetricsLogger metricsLogger,
                 StatusBarStateController statusBarStateController,
                 ActivityStarter activityStarter,
@@ -471,6 +475,7 @@
             mQSHostLazy = hostLazy;
             mBackgroundLooper = backgroundLooper;
             mMainHandler = mainHandler;
+            mFalsingManager = falsingManager;
             mMetricsLogger = metricsLogger;
             mStatusBarStateController = statusBarStateController;
             mActivityStarter = activityStarter;
@@ -496,6 +501,7 @@
                     mQSHostLazy.get(),
                     mBackgroundLooper,
                     mMainHandler,
+                    mFalsingManager,
                     mMetricsLogger,
                     mStatusBarStateController,
                     mActivityStarter,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
index 9e5fe73..29b9e64 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
@@ -248,10 +248,10 @@
     public QSTileView createTileView(QSTile tile, boolean collapsedView) {
         Context context = new ContextThemeWrapper(mQsHostLazy.get().getContext(), R.style.qs_theme);
         QSIconView icon = tile.createTileView(context);
-        if (collapsedView) {
+        if (mSideLabels) {
+            return new QSTileViewHorizontal(context, icon, collapsedView);
+        } else if (collapsedView) {
             return new QSTileBaseView(context, icon, collapsedView);
-        } else if (mSideLabels) {
-            return new QSTileViewHorizontal(context, icon);
         } else {
             return new com.android.systemui.qs.tileimpl.QSTileView(context, icon);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java
index 33ca7d6..a45b1319 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java
@@ -58,13 +58,13 @@
     private static final int ICON_MASK_ID = com.android.internal.R.string.config_icon_mask;
     protected final Handler mHandler = new H();
     private final int[] mLocInScreen = new int[2];
-    private final FrameLayout mIconFrame;
+    protected final FrameLayout mIconFrame;
     protected QSIconView mIcon;
     protected RippleDrawable mRipple;
     protected Drawable mTileBackground;
     private String mAccessibilityClass;
     private boolean mTileState;
-    private boolean mCollapsedView;
+    protected boolean mCollapsedView;
     protected boolean mShowRippleEffect = true;
     private float mStrokeWidthActive;
     private float mStrokeWidthInactive;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
index 5a81676..f9d1def 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
@@ -58,6 +58,7 @@
 import com.android.systemui.Dumpable;
 import com.android.systemui.Prefs;
 import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.qs.DetailAdapter;
 import com.android.systemui.plugins.qs.QSIconView;
 import com.android.systemui.plugins.qs.QSTile;
@@ -103,6 +104,7 @@
     private final StatusBarStateController mStatusBarStateController;
     protected final ActivityStarter mActivityStarter;
     private final UiEventLogger mUiEventLogger;
+    private final FalsingManager mFalsingManager;
     private final QSLogger mQSLogger;
     private volatile int mReadyState;
 
@@ -159,6 +161,7 @@
             QSHost host,
             Looper backgroundLooper,
             Handler mainHandler,
+            FalsingManager falsingManager,
             MetricsLogger metricsLogger,
             StatusBarStateController statusBarStateController,
             ActivityStarter activityStarter,
@@ -171,6 +174,7 @@
 
         mUiHandler = mainHandler;
         mHandler = new H(backgroundLooper);
+        mFalsingManager = falsingManager;
         mQSLogger = qsLogger;
         mMetricsLogger = metricsLogger;
         mStatusBarStateController = statusBarStateController;
@@ -608,7 +612,9 @@
                                 mContext, mEnforcedAdmin);
                         mActivityStarter.postStartActivityDismissingKeyguard(intent, 0);
                     } else {
-                        handleClick();
+                        if (!mFalsingManager.isFalseTap(true, 0.1)) {
+                            handleClick();
+                        }
                     }
                 } else if (msg.what == SECONDARY_CLICK) {
                     name = "handleSecondaryClick";
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java
index b59326a..c7ed89b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java
@@ -26,6 +26,8 @@
 import android.widget.ImageView;
 import android.widget.TextView;
 
+import androidx.annotation.Nullable;
+
 import com.android.settingslib.Utils;
 import com.android.systemui.FontSizeUtils;
 import com.android.systemui.R;
@@ -116,7 +118,8 @@
         }
     }
 
-    private boolean shouldLabelBeSingleLine() {
+    protected boolean shouldLabelBeSingleLine() {
+        if (mCollapsedView) return true;
         if (mLabel.getLineCount() > mMaxLabelLines) {
             return true;
         } else if (!TextUtils.isEmpty(mSecondLine.getText())
@@ -138,14 +141,14 @@
             } else {
                 labelColor = mColorLabelUnavailable;
             }
-            mLabel.setTextColor(labelColor);
+            changeLabelColor(labelColor);
             mState = state.state;
             mLabel.setText(state.label);
         }
         if (!Objects.equals(mSecondLine.getText(), state.secondaryLabel)) {
             mSecondLine.setText(state.secondaryLabel);
-            mSecondLine.setVisibility(TextUtils.isEmpty(state.secondaryLabel) ? View.GONE
-                    : View.VISIBLE);
+            mSecondLine.setVisibility(TextUtils.isEmpty(state.secondaryLabel) || mCollapsedView
+                    ? View.GONE : View.VISIBLE);
         }
         boolean dualTarget = mDualTargetAllowed && state.dualTarget;
         handleExpand(dualTarget);
@@ -160,6 +163,10 @@
         mPadLock.setVisibility(state.disabledByPolicy ? View.VISIBLE : View.GONE);
     }
 
+    protected void changeLabelColor(ColorStateList color) {
+        mLabel.setTextColor(color);
+    }
+
     protected void handleExpand(boolean dualTarget) {
         mExpandIndicator.setVisibility(dualTarget ? View.VISIBLE : View.GONE);
         mExpandSpace.setVisibility(dualTarget ? View.VISIBLE : View.GONE);
@@ -178,4 +185,10 @@
     public TextView getAppLabel() {
         return mSecondLine;
     }
+
+    @Nullable
+    @Override
+    public View getLabelContainer() {
+        return mLabelContainer;
+    }
 }
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 328c2c3..32285cf 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,7 @@
 import android.content.res.ColorStateList
 import android.graphics.Color
 import android.graphics.drawable.Drawable
-import android.graphics.drawable.ShapeDrawable
-import android.graphics.drawable.shapes.RoundRectShape
+import android.graphics.drawable.RippleDrawable
 import android.service.quicksettings.Tile.STATE_ACTIVE
 import android.view.Gravity
 import android.widget.LinearLayout
@@ -32,25 +31,31 @@
 import com.android.systemui.plugins.qs.QSTile
 import com.android.systemui.qs.tileimpl.QSTileImpl.getColorForState
 
-// 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) {
+    icon: QSIconView,
+    collapsed: Boolean
+) : QSTileView(context, icon, collapsed) {
 
-    protected var backgroundDrawable: ShapeDrawable? = null
+    protected var colorBackgroundDrawable: Drawable? = null
     private var paintColor = Color.WHITE
     private var paintAnimator: ValueAnimator? = null
+    private var labelAnimator: ValueAnimator? = null
 
     init {
         orientation = HORIZONTAL
+        gravity = Gravity.CENTER_VERTICAL or Gravity.START
         mDualTargetAllowed = false
+        val padding = context.resources.getDimensionPixelSize(R.dimen.qs_tile_side_label_padding)
+        setPadding(padding, paddingTop, padding, paddingBottom)
+
         mBg.setImageDrawable(null)
+        mIconFrame.removeAllViews()
+        removeView(mIconFrame)
+        val iconSize = context.resources.getDimensionPixelSize(R.dimen.qs_icon_size)
+        addView(mIcon, 0, LayoutParams(iconSize, iconSize))
+
         mColorLabelActive = ColorStateList.valueOf(getColorForState(getContext(), STATE_ACTIVE))
-        mMaxLabelLines = 3
     }
 
     override fun createLabel() {
@@ -61,65 +66,112 @@
                 removeRule(RelativeLayout.ALIGN_PARENT_TOP)
             }
         }
+        mLabelContainer.setPadding(0, 0, 0, 0)
+        (mLabelContainer.layoutParams as MarginLayoutParams).apply {
+            marginStart = context.resources.getDimensionPixelSize(R.dimen.qs_label_container_margin)
+        }
         mLabel.gravity = Gravity.START
         mLabel.textDirection = TEXT_DIRECTION_LOCALE
         mSecondLine.gravity = Gravity.START
         mSecondLine.textDirection = TEXT_DIRECTION_LOCALE
-        val padding = context.resources.getDimensionPixelSize(R.dimen.qs_tile_side_label_padding)
-        mLabelContainer.setPaddingRelative(0, padding, padding, padding)
+
         (mLabelContainer.layoutParams as LayoutParams).gravity =
             Gravity.CENTER_VERTICAL or Gravity.START
+        if (mCollapsedView) {
+            mSecondLine.visibility = GONE
+        }
+    }
+
+    override fun shouldLabelBeSingleLine(): Boolean {
+        return true
     }
 
     override fun updateRippleSize() {
     }
 
     override fun newTileBackground(): Drawable? {
-        backgroundDrawable = ShapeDrawable(RoundRectShape(RADII, null, null))
-        return backgroundDrawable
+        val ripple = mContext.getDrawable(R.drawable.qs_tile_background) as RippleDrawable
+        colorBackgroundDrawable = ripple.findDrawableByLayerId(R.id.background)
+        return ripple
     }
 
     override fun setClickable(clickable: Boolean) {
         super.setClickable(clickable)
-        background = mTileBackground
+        background = if (clickable && mShowRippleEffect) {
+            mTileBackground
+        } else {
+            colorBackgroundDrawable
+        }
     }
 
     override fun handleStateChanged(state: QSTile.State) {
         super.handleStateChanged(state)
-        mSecondLine.setTextColor(mLabel.textColors)
         mLabelContainer.background = null
 
         val allowAnimations = animationsEnabled() && paintColor != Color.WHITE
         val newColor = getCircleColor(state.state)
         if (allowAnimations) {
-            animateToNewState(newColor)
+            animateBackground(newColor)
         } else {
             if (newColor != paintColor) {
-                clearAnimator()
-                backgroundDrawable?.setTintList(ColorStateList.valueOf(newColor))
+                clearBackgroundAnimator()
+                colorBackgroundDrawable?.setTintList(ColorStateList.valueOf(newColor))?.also {
+                    paintColor = newColor
+                }
                 paintColor = newColor
             }
         }
     }
 
-    private fun animateToNewState(newColor: Int) {
-        if (newColor != paintColor) {
-            clearAnimator()
-            paintAnimator = ValueAnimator.ofArgb(paintColor, newColor)
+    private fun animateBackground(newBackgroundColor: Int) {
+        if (newBackgroundColor != paintColor) {
+            clearBackgroundAnimator()
+            paintAnimator = ValueAnimator.ofArgb(paintColor, newBackgroundColor)
                 .setDuration(QSIconViewImpl.QS_ANIM_LENGTH).apply {
                     addUpdateListener { animation: ValueAnimator ->
                         val c = animation.animatedValue as Int
-                        backgroundDrawable?.setTintList(ColorStateList.valueOf(c))
-                        paintColor = c
+                        colorBackgroundDrawable?.setTintList(ColorStateList.valueOf(c))?.also {
+                            paintColor = c
+                        }
                     }
                     start()
                 }
         }
     }
 
-    private fun clearAnimator() {
+    override fun changeLabelColor(color: ColorStateList) {
+        val allowAnimations = animationsEnabled()
+        val currentColor = mLabel.textColors.defaultColor
+        if (currentColor != color.defaultColor) {
+            clearLabelAnimator()
+            if (allowAnimations) {
+                labelAnimator = ValueAnimator.ofArgb(currentColor, color.defaultColor)
+                    .setDuration(QSIconViewImpl.QS_ANIM_LENGTH).apply {
+                        addUpdateListener {
+                            setLabelsColor(ColorStateList.valueOf(it.animatedValue as Int))
+                        }
+                        start()
+                }
+            } else {
+                setLabelsColor(color)
+            }
+        }
+    }
+
+    private fun setLabelsColor(color: ColorStateList) {
+        mLabel.setTextColor(color)
+        if (!mCollapsedView) {
+            mSecondLine.setTextColor(color)
+        }
+    }
+
+    private fun clearBackgroundAnimator() {
         paintAnimator?.cancel()?.also { paintAnimator = null }
     }
 
+    private fun clearLabelAnimator() {
+        labelAnimator?.cancel()?.also { labelAnimator = null }
+    }
+
     override fun handleExpand(dualTarget: Boolean) {}
 }
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
index b848590..07abb90 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
@@ -38,6 +38,7 @@
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.qs.QSTile.BooleanState;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.GlobalSetting;
@@ -63,6 +64,7 @@
             QSHost host,
             @Background Looper backgroundLooper,
             @Main Handler mainHandler,
+            FalsingManager falsingManager,
             MetricsLogger metricsLogger,
             StatusBarStateController statusBarStateController,
             ActivityStarter activityStarter,
@@ -70,8 +72,8 @@
             BroadcastDispatcher broadcastDispatcher,
             Lazy<ConnectivityManager> lazyConnectivityManager
     ) {
-        super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
-                activityStarter, qsLogger);
+        super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
+                statusBarStateController, activityStarter, qsLogger);
         mBroadcastDispatcher = broadcastDispatcher;
         mLazyConnectivityManager = lazyConnectivityManager;
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/AlarmTile.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/AlarmTile.kt
index dede627..2945c6b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/AlarmTile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/AlarmTile.kt
@@ -15,6 +15,7 @@
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.plugins.FalsingManager
 import com.android.systemui.plugins.qs.QSTile
 import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.qs.QSHost
@@ -30,6 +31,7 @@
     host: QSHost,
     @Background backgroundLooper: Looper,
     @Main mainHandler: Handler,
+    falsingManager: FalsingManager,
     metricsLogger: MetricsLogger,
     statusBarStateController: StatusBarStateController,
     activityStarter: ActivityStarter,
@@ -41,6 +43,7 @@
     host,
     backgroundLooper,
     mainHandler,
+    falsingManager,
     metricsLogger,
     statusBarStateController,
     activityStarter,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java
index bf3e4be..49d3ff9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java
@@ -29,6 +29,7 @@
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.qs.QSTile.BooleanState;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.QSHost;
@@ -59,6 +60,7 @@
             QSHost host,
             @Background Looper backgroundLooper,
             @Main Handler mainHandler,
+            FalsingManager falsingManager,
             MetricsLogger metricsLogger,
             StatusBarStateController statusBarStateController,
             ActivityStarter activityStarter,
@@ -66,8 +68,8 @@
             BatteryController batteryController,
             SecureSettings secureSettings
     ) {
-        super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
-                activityStarter, qsLogger);
+        super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
+                statusBarStateController, activityStarter, qsLogger);
         mBatteryController = batteryController;
         mBatteryController.observe(getLifecycle(), this);
         int currentUser = host.getUserContext().getUserId();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index 1424244..56df4d8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -42,6 +42,7 @@
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.qs.DetailAdapter;
 import com.android.systemui.plugins.qs.QSTile.BooleanState;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -70,14 +71,15 @@
             QSHost host,
             @Background Looper backgroundLooper,
             @Main Handler mainHandler,
+            FalsingManager falsingManager,
             MetricsLogger metricsLogger,
             StatusBarStateController statusBarStateController,
             ActivityStarter activityStarter,
             QSLogger qsLogger,
             BluetoothController bluetoothController
     ) {
-        super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
-                activityStarter, qsLogger);
+        super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
+                statusBarStateController, activityStarter, qsLogger);
         mController = bluetoothController;
         mDetailAdapter = (BluetoothDetailAdapter) createDetailAdapter();
         mController.observe(getLifecycle(), mCallback);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CameraToggleTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CameraToggleTile.java
index 70287cd..0d73a5a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CameraToggleTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CameraToggleTile.java
@@ -21,7 +21,6 @@
 
 import static com.android.systemui.DejankUtils.whitelistIpcs;
 
-import android.hardware.SensorPrivacyManager;
 import android.hardware.SensorPrivacyManager.Sensors.Sensor;
 import android.os.Handler;
 import android.os.Looper;
@@ -35,6 +34,7 @@
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.QSHost;
 import com.android.systemui.qs.logging.QSLogger;
@@ -50,13 +50,15 @@
             @Background Looper backgroundLooper,
             @Main Handler mainHandler,
             MetricsLogger metricsLogger,
+            FalsingManager falsingManager,
             StatusBarStateController statusBarStateController,
             ActivityStarter activityStarter,
             QSLogger qsLogger,
             IndividualSensorPrivacyController sensorPrivacyController,
             KeyguardStateController keyguardStateController) {
-        super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
-                activityStarter, qsLogger, sensorPrivacyController, keyguardStateController);
+        super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
+                statusBarStateController, activityStarter, qsLogger, sensorPrivacyController,
+                keyguardStateController);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
index f03ce2c..fa99eed 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
@@ -40,6 +40,7 @@
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.qs.DetailAdapter;
 import com.android.systemui.plugins.qs.QSTile.BooleanState;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -81,6 +82,7 @@
             QSHost host,
             @Background Looper backgroundLooper,
             @Main Handler mainHandler,
+            FalsingManager falsingManager,
             MetricsLogger metricsLogger,
             StatusBarStateController statusBarStateController,
             ActivityStarter activityStarter,
@@ -90,8 +92,8 @@
             NetworkController networkController,
             HotspotController hotspotController
     ) {
-        super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
-                activityStarter, qsLogger);
+        super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
+                statusBarStateController, activityStarter, qsLogger);
         mController = castController;
         mDetailAdapter = new CastDetailAdapter();
         mKeyguard = keyguardStateController;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
index 6a574d1..8cc6ff2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
@@ -45,6 +45,7 @@
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.qs.DetailAdapter;
 import com.android.systemui.plugins.qs.QSIconView;
 import com.android.systemui.plugins.qs.QSTile.SignalState;
@@ -76,14 +77,15 @@
             QSHost host,
             @Background Looper backgroundLooper,
             @Main Handler mainHandler,
+            FalsingManager falsingManager,
             MetricsLogger metricsLogger,
             StatusBarStateController statusBarStateController,
             ActivityStarter activityStarter,
             QSLogger qsLogger,
             NetworkController networkController
     ) {
-        super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
-                activityStarter, qsLogger);
+        super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
+                statusBarStateController, activityStarter, qsLogger);
         mController = networkController;
         mDataController = mController.getMobileDataController();
         mDetailAdapter = new CellularDetailAdapter();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
index a6d9604..ca7cf83 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
@@ -32,6 +32,7 @@
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.qs.QSTile.BooleanState;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.QSHost;
@@ -60,6 +61,7 @@
             QSHost host,
             @Background Looper backgroundLooper,
             @Main Handler mainHandler,
+            FalsingManager falsingManager,
             MetricsLogger metricsLogger,
             StatusBarStateController statusBarStateController,
             ActivityStarter activityStarter,
@@ -67,8 +69,8 @@
             UserTracker userTracker,
             SecureSettings secureSettings
     ) {
-        super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
-                activityStarter, qsLogger);
+        super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
+                statusBarStateController, activityStarter, qsLogger);
 
         mSetting = new SecureSetting(secureSettings, mHandler,
                 Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, userTracker.getUserId()) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java
index 85f1245..61376f0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java
@@ -29,6 +29,7 @@
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.qs.QSTile.BooleanState;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.QSHost;
@@ -49,14 +50,15 @@
             QSHost host,
             @Background Looper backgroundLooper,
             @Main Handler mainHandler,
+            FalsingManager falsingManager,
             MetricsLogger metricsLogger,
             StatusBarStateController statusBarStateController,
             ActivityStarter activityStarter,
             QSLogger qsLogger,
             DataSaverController dataSaverController
     ) {
-        super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
-                activityStarter, qsLogger);
+        super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
+                statusBarStateController, activityStarter, qsLogger);
         mDataSaverController = dataSaverController;
         mDataSaverController.observe(getLifecycle(), this);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt
index 257d6a7..a74a50e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt
@@ -33,6 +33,7 @@
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.plugins.FalsingManager
 import com.android.systemui.plugins.qs.QSTile
 import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.qs.QSHost
@@ -47,6 +48,7 @@
     host: QSHost,
     @Background backgroundLooper: Looper,
     @Main mainHandler: Handler,
+    falsingManager: FalsingManager,
     metricsLogger: MetricsLogger,
     statusBarStateController: StatusBarStateController,
     activityStarter: ActivityStarter,
@@ -58,6 +60,7 @@
         host,
         backgroundLooper,
         mainHandler,
+        falsingManager,
         metricsLogger,
         statusBarStateController,
         activityStarter,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
index 7ec2691..4b96cf3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@@ -54,6 +54,7 @@
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.qs.DetailAdapter;
 import com.android.systemui.plugins.qs.QSTile.BooleanState;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -87,6 +88,7 @@
             QSHost host,
             @Background Looper backgroundLooper,
             @Main Handler mainHandler,
+            FalsingManager falsingManager,
             MetricsLogger metricsLogger,
             StatusBarStateController statusBarStateController,
             ActivityStarter activityStarter,
@@ -94,8 +96,8 @@
             ZenModeController zenModeController,
             @Main SharedPreferences sharedPreferences
     ) {
-        super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
-                activityStarter, qsLogger);
+        super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
+                statusBarStateController, activityStarter, qsLogger);
         mController = zenModeController;
         mSharedPreferences = sharedPreferences;
         mDetailAdapter = new DndDetailAdapter();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
index cd45082..31a98db 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
@@ -30,6 +30,7 @@
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.qs.QSTile.BooleanState;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.QSHost;
@@ -51,14 +52,15 @@
             QSHost host,
             @Background Looper backgroundLooper,
             @Main Handler mainHandler,
+            FalsingManager falsingManager,
             MetricsLogger metricsLogger,
             StatusBarStateController statusBarStateController,
             ActivityStarter activityStarter,
             QSLogger qsLogger,
             FlashlightController flashlightController
     ) {
-        super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
-                activityStarter, qsLogger);
+        super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
+                statusBarStateController, activityStarter, qsLogger);
         mFlashlightController = flashlightController;
         mFlashlightController.observe(getLifecycle(), this);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
index a45d94a..4e0f634 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
@@ -32,6 +32,7 @@
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.qs.QSTile.BooleanState;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.QSHost;
@@ -57,6 +58,7 @@
             QSHost host,
             @Background Looper backgroundLooper,
             @Main Handler mainHandler,
+            FalsingManager falsingManager,
             MetricsLogger metricsLogger,
             StatusBarStateController statusBarStateController,
             ActivityStarter activityStarter,
@@ -64,8 +66,8 @@
             HotspotController hotspotController,
             DataSaverController dataSaverController
     ) {
-        super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
-                activityStarter, qsLogger);
+        super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
+                statusBarStateController, activityStarter, qsLogger);
         mHotspotController = hotspotController;
         mDataSaverController = dataSaverController;
         mHotspotController.observe(this, mCallbacks);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java
index e1a1fd2..14a3fc0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java
@@ -40,9 +40,9 @@
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.qs.QSIconView;
 import com.android.systemui.plugins.qs.QSTile;
-import com.android.systemui.plugins.qs.QSTile.Icon;
 import com.android.systemui.plugins.qs.QSTile.SignalState;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.AlphaControlledSignalTileView;
@@ -80,14 +80,15 @@
             QSHost host,
             @Background Looper backgroundLooper,
             @Main Handler mainHandler,
+            FalsingManager falsingManager,
             MetricsLogger metricsLogger,
             StatusBarStateController statusBarStateController,
             ActivityStarter activityStarter,
             QSLogger qsLogger,
             NetworkController networkController
     ) {
-        super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
-                activityStarter, qsLogger);
+        super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
+                statusBarStateController, activityStarter, qsLogger);
         mController = networkController;
         mDataController = mController.getMobileDataController();
         mController.observe(getLifecycle(), mSignalCallback);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
index d502d06..830a1fd 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
@@ -30,6 +30,7 @@
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.qs.QSTile.BooleanState;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.QSHost;
@@ -55,6 +56,7 @@
             QSHost host,
             @Background Looper backgroundLooper,
             @Main Handler mainHandler,
+            FalsingManager falsingManager,
             MetricsLogger metricsLogger,
             StatusBarStateController statusBarStateController,
             ActivityStarter activityStarter,
@@ -62,8 +64,8 @@
             LocationController locationController,
             KeyguardStateController keyguardStateController
     ) {
-        super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
-                activityStarter, qsLogger);
+        super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
+                statusBarStateController, activityStarter, qsLogger);
         mController = locationController;
         mKeyguard = keyguardStateController;
         mController.observe(this, mCallback);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/MicrophoneToggleTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/MicrophoneToggleTile.java
index e9b712d..b8d8792 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/MicrophoneToggleTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/MicrophoneToggleTile.java
@@ -21,7 +21,6 @@
 
 import static com.android.systemui.DejankUtils.whitelistIpcs;
 
-import android.hardware.SensorPrivacyManager;
 import android.hardware.SensorPrivacyManager.Sensors.Sensor;
 import android.os.Handler;
 import android.os.Looper;
@@ -35,6 +34,7 @@
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.QSHost;
 import com.android.systemui.qs.logging.QSLogger;
@@ -50,13 +50,15 @@
             @Background Looper backgroundLooper,
             @Main Handler mainHandler,
             MetricsLogger metricsLogger,
+            FalsingManager falsingManager,
             StatusBarStateController statusBarStateController,
             ActivityStarter activityStarter,
             QSLogger qsLogger,
             IndividualSensorPrivacyController sensorPrivacyController,
             KeyguardStateController keyguardStateController) {
-        super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
-                activityStarter, qsLogger, sensorPrivacyController, keyguardStateController);
+        super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
+                statusBarStateController, activityStarter, qsLogger, sensorPrivacyController,
+                keyguardStateController);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java
index 63e27796..6ac2f9ae 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java
@@ -36,6 +36,7 @@
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.qs.QSTile.BooleanState;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.QSHost;
@@ -60,14 +61,15 @@
             QSHost host,
             @Background Looper backgroundLooper,
             @Main Handler mainHandler,
+            FalsingManager falsingManager,
             MetricsLogger metricsLogger,
             StatusBarStateController statusBarStateController,
             ActivityStarter activityStarter,
             QSLogger qsLogger,
             BroadcastDispatcher broadcastDispatcher
     ) {
-        super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
-                activityStarter, qsLogger);
+        super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
+                statusBarStateController, activityStarter, qsLogger);
         mBroadcastDispatcher = broadcastDispatcher;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java
index d8548de..5369086 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java
@@ -40,6 +40,7 @@
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.qs.QSTile.BooleanState;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.QSHost;
@@ -78,6 +79,7 @@
             QSHost host,
             @Background Looper backgroundLooper,
             @Main Handler mainHandler,
+            FalsingManager falsingManager,
             MetricsLogger metricsLogger,
             StatusBarStateController statusBarStateController,
             ActivityStarter activityStarter,
@@ -86,8 +88,8 @@
             ColorDisplayManager colorDisplayManager,
             NightDisplayListenerModule.Builder nightDisplayListenerBuilder
     ) {
-        super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
-                activityStarter, qsLogger);
+        super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
+                statusBarStateController, activityStarter, qsLogger);
         mLocationController = locationController;
         mManager = colorDisplayManager;
         mNightDisplayListenerBuilder = nightDisplayListenerBuilder;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java
index aec7b9a..479be65 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java
@@ -30,6 +30,7 @@
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.qs.QSTile;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.QSHost;
@@ -57,13 +58,14 @@
             QSHost host,
             @Background Looper backgroundLooper,
             @Main Handler mainHandler,
+            FalsingManager falsingManager,
             MetricsLogger metricsLogger,
             StatusBarStateController statusBarStateController,
             ActivityStarter activityStarter,
             QSLogger qsLogger
     ) {
-        super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
-                activityStarter, qsLogger);
+        super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
+                statusBarStateController, activityStarter, qsLogger);
         mReduceBrightColorsController = reduceBrightColorsController;
         mReduceBrightColorsController.observe(getLifecycle(), this);
         mIsAvailable = isAvailable;
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 c46cc4f..173cc05 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
@@ -31,6 +31,7 @@
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.qs.QSTile.BooleanState;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.QSHost;
@@ -52,14 +53,15 @@
             QSHost host,
             @Background Looper backgroundLooper,
             @Main Handler mainHandler,
+            FalsingManager falsingManager,
             MetricsLogger metricsLogger,
             StatusBarStateController statusBarStateController,
             ActivityStarter activityStarter,
             QSLogger qsLogger,
             RotationLockController rotationLockController
     ) {
-        super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
-                activityStarter, qsLogger);
+        super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
+                statusBarStateController, activityStarter, qsLogger);
         mController = rotationLockController;
         mController.observe(this, mCallback);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java
index 0f0a9a2..6845dc5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java
@@ -29,6 +29,7 @@
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.qs.QSTile;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.QSHost;
@@ -55,6 +56,7 @@
             QSHost host,
             @Background Looper backgroundLooper,
             @Main Handler mainHandler,
+            FalsingManager falsingManager,
             MetricsLogger metricsLogger,
             StatusBarStateController statusBarStateController,
             ActivityStarter activityStarter,
@@ -62,8 +64,8 @@
             RecordingController controller,
             KeyguardDismissUtil keyguardDismissUtil
     ) {
-        super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
-                activityStarter, qsLogger);
+        super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
+                statusBarStateController, activityStarter, qsLogger);
         mController = controller;
         mController.observe(this, mCallback);
         mKeyguardDismissUtil = keyguardDismissUtil;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyToggleTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyToggleTile.java
index 0c582bd..a492330 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyToggleTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyToggleTile.java
@@ -29,6 +29,7 @@
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.qs.QSTile;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.QSHost;
@@ -59,14 +60,15 @@
     protected SensorPrivacyToggleTile(QSHost host,
             @Background Looper backgroundLooper,
             @Main Handler mainHandler,
+            FalsingManager falsingManager,
             MetricsLogger metricsLogger,
             StatusBarStateController statusBarStateController,
             ActivityStarter activityStarter,
             QSLogger qsLogger,
             IndividualSensorPrivacyController sensorPrivacyController,
             KeyguardStateController keyguardStateController) {
-        super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
-                activityStarter, qsLogger);
+        super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
+                statusBarStateController, activityStarter, qsLogger);
         mSensorPrivacyController = sensorPrivacyController;
         mKeyguard = keyguardStateController;
         mSensorPrivacyController.observe(getLifecycle(), this);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java
index 78975a47..0ef5bc8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java
@@ -32,6 +32,7 @@
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.qs.QSTile;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.QSHost;
@@ -66,6 +67,7 @@
             QSHost host,
             @Background Looper backgroundLooper,
             @Main Handler mainHandler,
+            FalsingManager falsingManager,
             MetricsLogger metricsLogger,
             StatusBarStateController statusBarStateController,
             ActivityStarter activityStarter,
@@ -74,8 +76,8 @@
             BatteryController batteryController,
             LocationController locationController
     ) {
-        super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
-                activityStarter, qsLogger);
+        super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
+                statusBarStateController, activityStarter, qsLogger);
         mBatteryController = batteryController;
         mUiModeManager = host.getUserContext().getSystemService(UiModeManager.class);
         mLocationController = locationController;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java
index a6cddd3..2590f37 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java
@@ -28,6 +28,7 @@
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.qs.DetailAdapter;
 import com.android.systemui.plugins.qs.QSTile;
 import com.android.systemui.plugins.qs.QSTile.State;
@@ -51,6 +52,7 @@
             QSHost host,
             @Background Looper backgroundLooper,
             @Main Handler mainHandler,
+            FalsingManager falsingManager,
             MetricsLogger metricsLogger,
             StatusBarStateController statusBarStateController,
             ActivityStarter activityStarter,
@@ -58,8 +60,8 @@
             UserSwitcherController userSwitcherController,
             UserInfoController userInfoController
     ) {
-        super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
-                activityStarter, qsLogger);
+        super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
+                statusBarStateController, activityStarter, qsLogger);
         mUserSwitcherController = userSwitcherController;
         mUserInfoController = userInfoController;
         mUserInfoController.observe(getLifecycle(), this);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
index 341e67c..dab68ed 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -37,6 +37,7 @@
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.qs.DetailAdapter;
 import com.android.systemui.plugins.qs.QSIconView;
 import com.android.systemui.plugins.qs.QSTile;
@@ -77,6 +78,7 @@
             QSHost host,
             @Background Looper backgroundLooper,
             @Main Handler mainHandler,
+            FalsingManager falsingManager,
             MetricsLogger metricsLogger,
             StatusBarStateController statusBarStateController,
             ActivityStarter activityStarter,
@@ -84,8 +86,8 @@
             NetworkController networkController,
             AccessPointController accessPointController
     ) {
-        super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
-                activityStarter, qsLogger);
+        super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
+                statusBarStateController, activityStarter, qsLogger);
         mController = networkController;
         mWifiController = accessPointController;
         mDetailAdapter = (WifiDetailAdapter) createDetailAdapter();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
index 5235b6d..c88a002 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
@@ -29,6 +29,7 @@
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.qs.QSTile.BooleanState;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.QSHost;
@@ -50,14 +51,15 @@
             QSHost host,
             @Background Looper backgroundLooper,
             @Main Handler mainHandler,
+            FalsingManager falsingManager,
             MetricsLogger metricsLogger,
             StatusBarStateController statusBarStateController,
             ActivityStarter activityStarter,
             QSLogger qsLogger,
             ManagedProfileController managedProfileController
     ) {
-        super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
-                activityStarter, qsLogger);
+        super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
+                statusBarStateController, activityStarter, qsLogger);
         mProfileController = managedProfileController;
         mProfileController.observe(getLifecycle(), this);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index a87bfd8..b0a3f43 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -25,6 +25,11 @@
 
 import static com.android.internal.accessibility.common.ShortcutConstants.CHOOSER_PACKAGE_NAME;
 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_INPUT_MONITOR;
+import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_ONE_HANDED;
+import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_PIP;
+import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_SHELL_TRANSITIONS;
+import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_SPLIT_SCREEN;
+import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_STARTING_WINDOW;
 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SUPPORTS_WINDOW_CORNERS;
 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SYSUI_PROXY;
 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_WINDOW_CORNER_RADIUS;
@@ -35,15 +40,12 @@
 
 import android.annotation.FloatRange;
 import android.app.ActivityTaskManager;
-import android.app.PendingIntent;
-import android.app.PictureInPictureParams;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.ServiceConnection;
-import android.content.pm.ActivityInfo;
 import android.graphics.Bitmap;
 import android.graphics.Insets;
 import android.graphics.Rect;
@@ -57,14 +59,12 @@
 import android.os.PatternMatcher;
 import android.os.RemoteException;
 import android.os.UserHandle;
-import android.util.ArraySet;
 import android.util.Log;
 import android.view.InputMonitor;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.Surface;
 import android.view.accessibility.AccessibilityManager;
-import android.window.IRemoteTransition;
 
 import androidx.annotation.NonNull;
 
@@ -83,15 +83,11 @@
 import com.android.systemui.recents.OverviewProxyService.OverviewProxyListener;
 import com.android.systemui.settings.CurrentUserTracker;
 import com.android.systemui.shared.recents.IOverviewProxy;
-import com.android.systemui.shared.recents.IPinnedStackAnimationListener;
-import com.android.systemui.shared.recents.ISplitScreenListener;
-import com.android.systemui.shared.recents.IStartingWindowListener;
 import com.android.systemui.shared.recents.ISystemUiProxy;
 import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.shared.system.InputMonitorCompat;
 import com.android.systemui.shared.system.QuickStepContract;
-import com.android.systemui.shared.system.RemoteTransitionCompat;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.NotificationShadeWindowController;
 import com.android.systemui.statusbar.phone.StatusBar;
@@ -103,7 +99,7 @@
 import com.android.wm.shell.pip.PipAnimationController;
 import com.android.wm.shell.splitscreen.SplitScreen;
 import com.android.wm.shell.startingsurface.StartingSurface;
-import com.android.wm.shell.transition.RemoteTransitions;
+import com.android.wm.shell.transition.ShellTransitions;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -111,7 +107,6 @@
 import java.util.List;
 import java.util.Optional;
 import java.util.function.BiConsumer;
-import java.util.function.Consumer;
 
 import javax.inject.Inject;
 
@@ -151,12 +146,11 @@
     private final ScreenshotHelper mScreenshotHelper;
     private final Optional<OneHanded> mOneHandedOptional;
     private final CommandQueue mCommandQueue;
-    private final RemoteTransitions mShellTransitions;
+    private final ShellTransitions mShellTransitions;
     private final Optional<StartingSurface> mStartingSurface;
 
     private Region mActiveNavBarRegion;
 
-    private IPinnedStackAnimationListener mIPinnedStackAnimationListener;
     private IOverviewProxy mOverviewProxy;
     private int mConnectionBackoffAttempts;
     private boolean mBound;
@@ -169,8 +163,6 @@
     private float mWindowCornerRadius;
     private boolean mSupportsRoundedCornersOnWindows;
     private int mNavBarMode = NAV_BAR_MODE_3BUTTON;
-    private final ArraySet<IRemoteTransition> mRemoteTransitions = new ArraySet<>();
-    private IStartingWindowListener mIStartingWindowListener;
 
     @VisibleForTesting
     public ISystemUiProxy mSysUiProxy = new ISystemUiProxy.Stub() {
@@ -294,11 +286,6 @@
         }
 
         @Override
-        public void setBackButtonAlpha(float alpha, boolean animate) {
-            setNavBarButtonAlpha(alpha, animate);
-        }
-
-        @Override
         public void onAssistantProgress(@FloatRange(from = 0.0, to = 1.0) float progress) {
             if (!verifyCaller("onAssistantProgress")) {
                 return;
@@ -388,20 +375,6 @@
         }
 
         @Override
-        public void setShelfHeight(boolean visible, int shelfHeight) {
-            if (!verifyCaller("setShelfHeight")) {
-                return;
-            }
-            final long token = Binder.clearCallingIdentity();
-            try {
-                mPipOptional.ifPresent(
-                        pip -> pip.setShelfHeight(visible, shelfHeight));
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        @Override
         public void handleImageAsScreenshot(Bitmap screenImage, Rect locationInScreen,
                 Insets visibleInsets, int taskId) {
             // Deprecated
@@ -429,36 +402,6 @@
         }
 
         @Override
-        public void setPinnedStackAnimationListener(IPinnedStackAnimationListener listener) {
-            if (!verifyCaller("setPinnedStackAnimationListener")) {
-                return;
-            }
-            mIPinnedStackAnimationListener = listener;
-            final long token = Binder.clearCallingIdentity();
-            try {
-                mPipOptional.ifPresent(
-                        pip -> pip.setPinnedStackAnimationListener(mPinnedStackAnimationCallback));
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        @Override
-        public void setStartingWindowListener(IStartingWindowListener listener) {
-            if (!verifyCaller("setStartingWindowListener")) {
-                return;
-            }
-            mIStartingWindowListener = listener;
-            final long token = Binder.clearCallingIdentity();
-            try {
-                mStartingSurface.ifPresent(s ->
-                        s.setStartingWindowListener(mStartingWindowListener));
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        @Override
         public void onQuickSwitchToNewTask(@Surface.Rotation int rotation) {
             if (!verifyCaller("onQuickSwitchToNewTask")) {
                 return;
@@ -472,32 +415,6 @@
         }
 
         @Override
-        public void startOneHandedMode() {
-            if (!verifyCaller("startOneHandedMode")) {
-                return;
-            }
-            final long token = Binder.clearCallingIdentity();
-            try {
-                mOneHandedOptional.ifPresent(oneHanded -> oneHanded.startOneHanded());
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        @Override
-        public void stopOneHandedMode()  {
-            if (!verifyCaller("stopOneHandedMode")) {
-                return;
-            }
-            final long token = Binder.clearCallingIdentity();
-            try {
-                mOneHandedOptional.ifPresent(oneHanded -> oneHanded.stopOneHanded());
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        @Override
         public void handleImageBundleAsScreenshot(Bundle screenImageBundle, Rect locationInScreen,
                 Insets visibleInsets, Task.TaskKey task) {
             mScreenshotHelper.provideScreenshot(
@@ -525,190 +442,6 @@
             }
         }
 
-        @Override
-        public Rect startSwipePipToHome(ComponentName componentName, ActivityInfo activityInfo,
-                PictureInPictureParams pictureInPictureParams,
-                int launcherRotation, int shelfHeight) {
-            if (!verifyCaller("startSwipePipToHome")) {
-                return null;
-            }
-            final long binderToken = Binder.clearCallingIdentity();
-            try {
-                return mPipOptional.map(pip ->
-                        pip.startSwipePipToHome(componentName, activityInfo,
-                                pictureInPictureParams, launcherRotation, shelfHeight))
-                        .orElse(null);
-            } finally {
-                Binder.restoreCallingIdentity(binderToken);
-            }
-        }
-
-        @Override
-        public void stopSwipePipToHome(ComponentName componentName, Rect destinationBounds) {
-            if (!verifyCaller("stopSwipePipToHome")) {
-                return;
-            }
-            final long binderToken = Binder.clearCallingIdentity();
-            try {
-                mPipOptional.ifPresent(pip -> pip.stopSwipePipToHome(
-                        componentName, destinationBounds));
-            } finally {
-                Binder.restoreCallingIdentity(binderToken);
-            }
-        }
-
-        @Override
-        public void registerRemoteTransition(RemoteTransitionCompat remoteTransition) {
-            if (!verifyCaller("registerRemoteTransition")) return;
-            final long binderToken = Binder.clearCallingIdentity();
-            try {
-                mRemoteTransitions.add(remoteTransition.getTransition());
-                mShellTransitions.registerRemote(
-                        remoteTransition.getFilter(), remoteTransition.getTransition());
-            } finally {
-                Binder.restoreCallingIdentity(binderToken);
-            }
-        }
-
-        @Override
-        public void unregisterRemoteTransition(RemoteTransitionCompat remoteTransition) {
-            if (!verifyCaller("registerRemoteTransition")) return;
-            final long binderToken = Binder.clearCallingIdentity();
-            try {
-                mRemoteTransitions.remove(remoteTransition.getTransition());
-                mShellTransitions.unregisterRemote(remoteTransition.getTransition());
-            } finally {
-                Binder.restoreCallingIdentity(binderToken);
-            }
-        }
-
-        @Override
-        public void registerSplitScreenListener(ISplitScreenListener listener) {
-            if (!verifyCaller("registerSplitScreenListener")) {
-                return;
-            }
-            mISplitScreenListener = listener;
-            final long token = Binder.clearCallingIdentity();
-            try {
-                mSplitScreenOptional.ifPresent(
-                        s -> s.registerSplitScreenListener(mSplitScreenListener));
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        @Override
-        public void unregisterSplitScreenListener(ISplitScreenListener listener) {
-            if (!verifyCaller("unregisterSplitScreenListener")) {
-                return;
-            }
-            mISplitScreenListener = null;
-            final long token = Binder.clearCallingIdentity();
-            try {
-                mSplitScreenOptional.ifPresent(
-                        s -> s.unregisterSplitScreenListener(mSplitScreenListener));
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        @Override
-        public void setSideStageVisibility(boolean visible) {
-            if (!verifyCaller("setSideStageVisibility")) {
-                return;
-            }
-            final long token = Binder.clearCallingIdentity();
-            try {
-                mSplitScreenOptional.ifPresent(s -> s.setSideStageVisibility(visible));
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        @Override
-        public void exitSplitScreen() {
-            if (!verifyCaller("exitSplitScreen")) {
-                return;
-            }
-            final long token = Binder.clearCallingIdentity();
-            try {
-                mSplitScreenOptional.ifPresent(s -> s.exitSplitScreen());
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        @Override
-        public void exitSplitScreenOnHide(boolean exitSplitScreenOnHide) {
-            if (!verifyCaller("exitSplitScreenOnHide")) {
-                return;
-            }
-            final long token = Binder.clearCallingIdentity();
-            try {
-                mSplitScreenOptional.ifPresent(s -> s.exitSplitScreenOnHide(exitSplitScreenOnHide));
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        @Override
-        public void startTask(int taskId, int stage, int position, Bundle options) {
-            if (!verifyCaller("startTask")) {
-                return;
-            }
-            final long token = Binder.clearCallingIdentity();
-            try {
-                mSplitScreenOptional.ifPresent(
-                        s -> s.startTask(taskId, stage, position, options));
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        @Override
-        public void startShortcut(String packageName, String shortcutId, int stage, int position,
-                Bundle options, UserHandle user) {
-            if (!verifyCaller("startShortcut")) {
-                return;
-            }
-            final long token = Binder.clearCallingIdentity();
-            try {
-                mSplitScreenOptional.ifPresent(s ->
-                        s.startShortcut(packageName, shortcutId, stage, position, options, user));
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        @Override
-        public void startIntent(PendingIntent intent, Intent fillInIntent,
-                int stage, int position, Bundle options) {
-            if (!verifyCaller("startIntent")) {
-                return;
-            }
-            final long token = Binder.clearCallingIdentity();
-            try {
-                mSplitScreenOptional.ifPresent(s ->
-                        s.startIntent(intent, mContext, fillInIntent, stage, position, options));
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        @Override
-        public void removeFromSideStage(int taskId) {
-            if (!verifyCaller("removeFromSideStage")) {
-                return;
-            }
-            final long token = Binder.clearCallingIdentity();
-            try {
-                mSplitScreenOptional.ifPresent(
-                        s -> s.removeFromSideStage(taskId));
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
         private boolean verifyCaller(String reason) {
             final int callerId = Binder.getCallingUserHandle().getIdentifier();
             if (callerId != mCurrentBoundedUserId) {
@@ -762,6 +495,22 @@
             params.putBinder(KEY_EXTRA_SYSUI_PROXY, mSysUiProxy.asBinder());
             params.putFloat(KEY_EXTRA_WINDOW_CORNER_RADIUS, mWindowCornerRadius);
             params.putBoolean(KEY_EXTRA_SUPPORTS_WINDOW_CORNERS, mSupportsRoundedCornersOnWindows);
+
+            mPipOptional.ifPresent((pip) -> params.putBinder(
+                    KEY_EXTRA_SHELL_PIP,
+                    pip.createExternalInterface().asBinder()));
+            mSplitScreenOptional.ifPresent((splitscreen) -> params.putBinder(
+                    KEY_EXTRA_SHELL_SPLIT_SCREEN,
+                    splitscreen.createExternalInterface().asBinder()));
+            mOneHandedOptional.ifPresent((onehanded) -> params.putBinder(
+                    KEY_EXTRA_SHELL_ONE_HANDED,
+                    onehanded.createExternalInterface().asBinder()));
+            params.putBinder(KEY_EXTRA_SHELL_SHELL_TRANSITIONS,
+                    mShellTransitions.createExternalInterface().asBinder());
+            mStartingSurface.ifPresent((startingwindow) -> params.putBinder(
+                    KEY_EXTRA_SHELL_STARTING_WINDOW,
+                    startingwindow.createExternalInterface().asBinder()));
+
             try {
                 mOverviewProxy.onInitialize(params);
             } catch (RemoteException e) {
@@ -801,42 +550,11 @@
     private final StatusBarWindowCallback mStatusBarWindowCallback = this::onStatusBarStateChanged;
     private final BiConsumer<Rect, Rect> mSplitScreenBoundsChangeListener =
             this::notifySplitScreenBoundsChanged;
-    private final Consumer<Boolean> mPinnedStackAnimationCallback =
-            this::notifyPinnedStackAnimationStarted;
-
-    private final BiConsumer<Integer, Integer> mStartingWindowListener =
-            this::notifyTaskLaunching;
 
     // This is the death handler for the binder from the launcher service
     private final IBinder.DeathRecipient mOverviewServiceDeathRcpt
             = this::cleanupAfterDeath;
 
-    private ISplitScreenListener mISplitScreenListener;
-    private final SplitScreen.SplitScreenListener mSplitScreenListener =
-            new SplitScreen.SplitScreenListener() {
-        @Override
-        public void onStagePositionChanged(int stage, int position) {
-            try {
-                if (mISplitScreenListener != null) {
-                    mISplitScreenListener.onStagePositionChanged(stage, position);
-                }
-            } catch (RemoteException e) {
-                Log.e(TAG_OPS, "onStagePositionChanged", e);
-            }
-        }
-
-        @Override
-        public void onTaskStageChanged(int taskId, int stage, boolean visible) {
-            try {
-                if (mISplitScreenListener != null) {
-                    mISplitScreenListener.onTaskStageChanged(taskId, stage, visible);
-                }
-            } catch (RemoteException e) {
-                Log.e(TAG_OPS, "onTaskStageChanged", e);
-            }
-        }
-    };
-
     @SuppressWarnings("OptionalUsedAsFieldOrParameterType")
     @Inject
     public OverviewProxyService(Context context, CommandQueue commandQueue,
@@ -849,7 +567,7 @@
             Optional<Lazy<StatusBar>> statusBarOptionalLazy,
             Optional<OneHanded> oneHandedOptional,
             BroadcastDispatcher broadcastDispatcher,
-            RemoteTransitions shellTransitions,
+            ShellTransitions shellTransitions,
             Optional<StartingSurface> startingSurface) {
         super(broadcastDispatcher);
         mContext = context;
@@ -966,29 +684,6 @@
         }
     }
 
-    private void notifyPinnedStackAnimationStarted(Boolean isAnimationStarted) {
-        if (mIPinnedStackAnimationListener == null) {
-            return;
-        }
-        try {
-            mIPinnedStackAnimationListener.onPinnedStackAnimationStarted();
-        } catch (RemoteException e) {
-            Log.e(TAG_OPS, "Failed to call onPinnedStackAnimationStarted()", e);
-        }
-    }
-
-    private void notifyTaskLaunching(int taskId, int supportedType) {
-        if (mIStartingWindowListener == null) {
-            return;
-        }
-
-        try {
-            mIStartingWindowListener.onTaskLaunching(taskId, supportedType);
-        } catch (RemoteException e) {
-            Log.e(TAG_OPS, "Failed to call notifyTaskLaunching()", e);
-        }
-    }
-
     private void onStatusBarStateChanged(boolean keyguardShowing, boolean keyguardOccluded,
             boolean bouncerShowing) {
         mSysUiState.setFlag(SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING,
@@ -1032,12 +727,6 @@
         // Clean up the minimized state if launcher dies
         mLegacySplitScreenOptional.ifPresent(
                 splitScreen -> splitScreen.setMinimized(false));
-
-        // Clean up any registered remote transitions
-        for (int i = mRemoteTransitions.size() - 1; i >= 0; --i) {
-            mShellTransitions.unregisterRemote(mRemoteTransitions.valueAt(i));
-        }
-        mRemoteTransitions.clear();
     }
 
     public void startConnectionToCurrentUser() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index c4fa6df..0599039 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -141,6 +141,7 @@
     private static final int MSG_HANDLE_WINDOW_MANAGER_LOGGING_COMMAND = 57 << MSG_SHIFT;
     //TODO(b/169175022) Update name and when feature name is locked.
     private static final int MSG_EMERGENCY_ACTION_LAUNCH_GESTURE      = 58 << MSG_SHIFT;
+    private static final int MSG_SET_NAVIGATION_BAR_LUMA_SAMPLING_ENABLED = 59 << MSG_SHIFT;
 
     public static final int FLAG_EXCLUDE_NONE = 0;
     public static final int FLAG_EXCLUDE_SEARCH_PANEL = 1 << 0;
@@ -369,6 +370,11 @@
          * Handles a window manager shell logging command.
          */
         default void handleWindowManagerLoggingCommand(String[] args, ParcelFileDescriptor outFd) {}
+
+        /**
+         * @see IStatusBar#setNavigationBarLumaSamplingEnabled(int, boolean)
+         */
+        default void setNavigationBarLumaSamplingEnabled(int displayId, boolean enable) {}
     }
 
     public CommandQueue(Context context) {
@@ -1019,6 +1025,14 @@
     }
 
     @Override
+    public void setNavigationBarLumaSamplingEnabled(int displayId, boolean enable) {
+        synchronized (mLock) {
+            mHandler.obtainMessage(MSG_SET_NAVIGATION_BAR_LUMA_SAMPLING_ENABLED, displayId,
+                    enable ? 1 : 0).sendToTarget();
+        }
+    }
+
+    @Override
     public void passThroughShellCommand(String[] args, ParcelFileDescriptor pfd) {
         final FileOutputStream fos = new FileOutputStream(pfd.getFileDescriptor());
         final PrintWriter pw = new PrintWriter(fos);
@@ -1400,6 +1414,12 @@
                     }
                     args.recycle();
                     break;
+                case MSG_SET_NAVIGATION_BAR_LUMA_SAMPLING_ENABLED:
+                    for (int i = 0; i < mCallbacks.size(); i++) {
+                        mCallbacks.get(i).setNavigationBarLumaSamplingEnabled(msg.arg1,
+                                msg.arg2 != 0);
+                    }
+                    break;
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
index 2b194ba..f65ae0c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
@@ -337,6 +337,7 @@
         } else {
             header.reapply(getContext(), mNotificationHeader);
         }
+        mNotificationHeaderWrapper.setExpanded(mChildrenExpanded);
         mNotificationHeaderWrapper.onContentUpdated(mContainingNotification);
         if (mNotificationHeaderWrapper instanceof NotificationHeaderViewWrapper) {
             NotificationHeaderViewWrapper headerWrapper =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
index e6731e6..c60bbc5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
@@ -166,6 +166,7 @@
 
         private int mGradientAlpha;
         private int mColor;
+        private float mOverrideAlpha = 1f;
         private PorterDuffColorFilter mTintFilter;
         private Paint mPaint = new Paint();
 
@@ -195,6 +196,23 @@
             mFrame = frame;
         }
 
+        public void setOverrideAlpha(float overrideAlpha) {
+            mOverrideAlpha = overrideAlpha;
+            invalidateSelf();
+        }
+
+        public float getOverrideAlpha() {
+            return mOverrideAlpha;
+        }
+
+        public int getColor() {
+            return mColor;
+        }
+
+        public Rect getFrame() {
+            return mFrame;
+        }
+
         @Override
         public void setAlpha(int alpha) {
             // noop
@@ -296,11 +314,13 @@
                 mGradient.setAlpha(mGradientAlpha);
                 mGradient.draw(canvas);
             }
+
             if (Color.alpha(mColor) > 0) {
                 mPaint.setColor(mColor);
                 if (mTintFilter != null) {
                     mPaint.setColorFilter(mTintFilter);
                 }
+                mPaint.setAlpha((int) (Color.alpha(mColor) * mOverrideAlpha));
                 if (mFrame != null) {
                     canvas.drawRect(mFrame, mPaint);
                 } else {
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 626162d..ca6e53d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -575,8 +575,8 @@
             FeatureFlags featureFlags) {
         super(view, falsingManager, dozeLog, keyguardStateController,
                 (SysuiStatusBarStateController) statusBarStateController, vibratorHelper,
-                latencyTracker, flingAnimationUtilsBuilder.get(), statusBarTouchableRegionManager,
-                ambientState);
+                statusBarKeyguardViewManager, latencyTracker, flingAnimationUtilsBuilder.get(),
+                statusBarTouchableRegionManager, ambientState);
         mView = view;
         mMetricsLogger = metricsLogger;
         mActivityManager = activityManager;
@@ -1348,7 +1348,6 @@
         super.flingToHeight(vel, expand, target, collapseSpeedUpFactor, expandBecauseOfFalsing);
     }
 
-
     private boolean onQsIntercept(MotionEvent event) {
         int pointerIndex = event.findPointerIndex(mTrackingPointer);
         if (pointerIndex < 0) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationTapHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationTapHelper.java
index 50c8e2e..66df936 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationTapHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationTapHelper.java
@@ -64,7 +64,7 @@
                 mTrackTouch = event.getY() <= maxTouchableHeight;
                 break;
             case MotionEvent.ACTION_MOVE:
-                if (mTrackTouch && mFalsingManager.isFalseTap(false)) {
+                if (mTrackTouch && mFalsingManager.isFalseTap(false, 0)) {
                     makeInactive();
                     mTrackTouch = false;
                 }
@@ -78,10 +78,10 @@
 
                 // 1) See if we have confidence that we can activate after a single tap.
                 // 2) Else, see if it looks like a tap at all and check for a double-tap.
-                if (!mFalsingManager.isFalseTap(true)) {
+                if (!mFalsingManager.isFalseTap(true, 0)) {
                     makeInactive();
                     return mDoubleTapListener.onDoubleTap();
-                } else if (!mFalsingManager.isFalseTap(false)) {
+                } else if (!mFalsingManager.isFalseTap(false, 0)) {
                     if (mSlideBackListener != null && mSlideBackListener.onSlideBack()) {
                         return true;
                     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
index b6ed3e5..3ac6937 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
@@ -167,6 +167,7 @@
     private boolean mIgnoreXTouchSlop;
     private boolean mExpandLatencyTracking;
     private final PanelView mView;
+    private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
     protected final Resources mResources;
     protected final KeyguardStateController mKeyguardStateController;
     protected final SysuiStatusBarStateController mStatusBarStateController;
@@ -235,12 +236,14 @@
             FalsingManager falsingManager, DozeLog dozeLog,
             KeyguardStateController keyguardStateController,
             SysuiStatusBarStateController statusBarStateController, VibratorHelper vibratorHelper,
+            StatusBarKeyguardViewManager statusBarKeyguardViewManager,
             LatencyTracker latencyTracker,
             FlingAnimationUtils.Builder flingAnimationUtilsBuilder,
             StatusBarTouchableRegionManager statusBarTouchableRegionManager,
             AmbientState ambientState) {
         mAmbientState = ambientState;
         mView = view;
+        mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
         mView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
             @Override
             public void onViewAttachedToWindow(View v) {
@@ -1391,8 +1394,13 @@
 
                 case MotionEvent.ACTION_UP:
                 case MotionEvent.ACTION_CANCEL:
-                    addMovement(event);
-                    endMotionEvent(event, x, y, false /* forceCancel */);
+                    if (mStatusBarKeyguardViewManager.isBouncerShowing()
+                            && mFalsingManager.isFalseTap(true, 0.5)) {
+                        endMotionEvent(event, x, y, true /* forceCancel */);
+                    } else {
+                        addMovement(event);
+                        endMotionEvent(event, x, y, false /* forceCancel */);
+                    }
                     InteractionJankMonitor monitor = InteractionJankMonitor.getInstance();
                     if (event.getActionMasked() == MotionEvent.ACTION_UP) {
                         monitor.end(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index d537241..f1405de 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -675,8 +675,7 @@
 
         mIconController.setIconVisibility(mSlotCamera, showCamera);
         mIconController.setIconVisibility(mSlotMicrophone, showMicrophone);
-        if (mPrivacyItemController.getAllIndicatorsAvailable()
-                || mPrivacyItemController.getLocationAvailable()) {
+        if (mPrivacyItemController.getLocationAvailable()) {
             mIconController.setIconVisibility(mSlotLocation, showLocation);
         }
         mPrivacyLogger.logStatusBarIconsVisible(showCamera, showMicrophone,  showLocation);
@@ -684,8 +683,7 @@
 
     @Override
     public void onLocationActiveChanged(boolean active) {
-        if (!mPrivacyItemController.getAllIndicatorsAvailable()
-                && !mPrivacyItemController.getLocationAvailable()) {
+        if (!mPrivacyItemController.getLocationAvailable()) {
             updateLocationFromController();
         }
     }
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 5083e33..01ada0f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -76,7 +76,7 @@
  * Manages creating, showing, hiding and resetting the keyguard within the status bar. Calls back
  * via {@link ViewMediatorCallback} to poke the wake lock and report that the keyguard is done,
  * which is in turn, reported to this class by the current
- * {@link com.android.keyguard.KeyguardViewBase}.
+ * {@link com.android.keyguard.KeyguardViewController}.
  */
 @SysUISingleton
 public class StatusBarKeyguardViewManager implements RemoteInputController.Callback,
diff --git a/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java b/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java
index ba58ed2..5cd3e57 100644
--- a/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java
@@ -52,6 +52,7 @@
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.qs.QSTile;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.QSHost;
@@ -408,14 +409,15 @@
                 QSHost host,
                 @Background Looper backgroundLooper,
                 @Main Handler mainHandler,
+                FalsingManager falsingManager,
                 MetricsLogger metricsLogger,
                 StatusBarStateController statusBarStateController,
                 ActivityStarter activityStarter,
                 QSLogger qsLogger,
                 GarbageMonitor monitor
         ) {
-            super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
-                    activityStarter, qsLogger);
+            super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
+                    statusBarStateController, activityStarter, qsLogger);
             gm = monitor;
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
index a123269..1d18750 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
@@ -81,7 +81,7 @@
 import com.android.wm.shell.splitscreen.SplitScreenController;
 import com.android.wm.shell.startingsurface.StartingSurface;
 import com.android.wm.shell.startingsurface.StartingWindowController;
-import com.android.wm.shell.transition.RemoteTransitions;
+import com.android.wm.shell.transition.ShellTransitions;
 import com.android.wm.shell.transition.Transitions;
 
 import java.util.Optional;
@@ -399,8 +399,8 @@
 
     @WMSingleton
     @Provides
-    static RemoteTransitions provideRemoteTransitions(Transitions transitions) {
-        return Transitions.asRemoteTransitions(transitions);
+    static ShellTransitions provideRemoteTransitions(Transitions transitions) {
+        return transitions.asRemoteTransitions();
     }
 
     @WMSingleton
@@ -480,8 +480,8 @@
     @WMSingleton
     @Provides
     static StartingWindowController provideStartingWindowController(Context context,
-            @ShellSplashscreenThread ShellExecutor executor) {
-        return new StartingWindowController(context, executor);
+            @ShellAnimationThread ShellExecutor executor, TransactionPool pool) {
+        return new StartingWindowController(context, executor, pool);
     }
 
     //
@@ -509,27 +509,33 @@
 
     @WMSingleton
     @Provides
-    static ShellInit provideShellInit(DisplayImeController displayImeController,
+    static ShellInit provideShellInit(ShellInitImpl impl) {
+        return impl.asShellInit();
+    }
+
+    @WMSingleton
+    @Provides
+    static ShellInitImpl provideShellInitImpl(DisplayImeController displayImeController,
             DragAndDropController dragAndDropController,
             ShellTaskOrganizer shellTaskOrganizer,
             Optional<LegacySplitScreenController> legacySplitScreenOptional,
             Optional<SplitScreenController> splitScreenOptional,
             Optional<AppPairsController> appPairsOptional,
-            Optional<StartingSurface> startingSurface,
             Optional<PipTouchHandler> pipTouchHandlerOptional,
             FullscreenTaskListener fullscreenTaskListener,
             Transitions transitions,
+            StartingWindowController startingWindow,
             @ShellMainThread ShellExecutor mainExecutor) {
-        return ShellInitImpl.create(displayImeController,
+        return new ShellInitImpl(displayImeController,
                 dragAndDropController,
                 shellTaskOrganizer,
                 legacySplitScreenOptional,
                 splitScreenOptional,
                 appPairsOptional,
-                startingSurface,
                 pipTouchHandlerOptional,
                 fullscreenTaskListener,
                 transitions,
+                startingWindow,
                 mainExecutor);
     }
 
@@ -539,7 +545,13 @@
      */
     @WMSingleton
     @Provides
-    static Optional<ShellCommandHandler> provideShellCommandHandler(
+    static Optional<ShellCommandHandler> provideShellCommandHandler(ShellCommandHandlerImpl impl) {
+        return Optional.of(impl.asShellCommandHandler());
+    }
+
+    @WMSingleton
+    @Provides
+    static ShellCommandHandlerImpl provideShellCommandHandlerImpl(
             ShellTaskOrganizer shellTaskOrganizer,
             Optional<LegacySplitScreenController> legacySplitScreenOptional,
             Optional<SplitScreenController> splitScreenOptional,
@@ -548,8 +560,8 @@
             Optional<HideDisplayCutoutController> hideDisplayCutout,
             Optional<AppPairsController> appPairsOptional,
             @ShellMainThread ShellExecutor mainExecutor) {
-        return Optional.of(ShellCommandHandlerImpl.create(shellTaskOrganizer,
+        return new ShellCommandHandlerImpl(shellTaskOrganizer,
                 legacySplitScreenOptional, splitScreenOptional, pipOptional, oneHandedOptional,
-                hideDisplayCutout, appPairsOptional, mainExecutor));
+                hideDisplayCutout, appPairsOptional, mainExecutor);
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java
index c2ade81..0cf343c 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java
@@ -36,6 +36,8 @@
 import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.classifier.FalsingCollector;
+import com.android.systemui.classifier.FalsingCollectorFake;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -69,6 +71,7 @@
     private KeyguardMessageAreaController mKeyguardMessageAreaController;
     @Mock
     private LatencyTracker mLatencyTracker;
+    private final FalsingCollector mFalsingCollector = new FalsingCollectorFake();
 
     private KeyguardAbsKeyInputViewController mKeyguardAbsKeyInputViewController;
 
@@ -84,7 +87,7 @@
                 .thenReturn(mKeyguardMessageArea);
         mKeyguardAbsKeyInputViewController = new KeyguardAbsKeyInputViewController(mAbsKeyInputView,
                 mKeyguardUpdateMonitor, mSecurityMode, mLockPatternUtils, mKeyguardSecurityCallback,
-                mKeyguardMessageAreaControllerFactory, mLatencyTracker) {
+                mKeyguardMessageAreaControllerFactory, mLatencyTracker, mFalsingCollector) {
             @Override
             void resetState() {
             }
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt
index c69ec1a..fc93ded 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt
@@ -24,6 +24,8 @@
 import com.android.internal.widget.LockPatternView
 import com.android.systemui.R
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.classifier.FalsingCollector
+import com.android.systemui.classifier.FalsingCollectorFake
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -48,6 +50,7 @@
     private lateinit var mKeyguardSecurityCallback: KeyguardSecurityCallback
     @Mock
     private lateinit var mLatencyTracker: LatencyTracker
+    private var mFalsingCollector: FalsingCollector = FalsingCollectorFake()
     @Mock
     private lateinit
     var mKeyguardMessageAreaControllerFactory: KeyguardMessageAreaController.Factory
@@ -72,7 +75,7 @@
                 .thenReturn(mKeyguardMessageAreaController)
         mKeyguardPatternViewController = KeyguardPatternViewController(mKeyguardPatternView,
         mKeyguardUpdateMonitor, mSecurityMode, mLockPatternUtils, mKeyguardSecurityCallback,
-                mLatencyTracker, mKeyguardMessageAreaControllerFactory)
+                mLatencyTracker, mFalsingCollector, mKeyguardMessageAreaControllerFactory)
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java
index 31cc7bb..33a0dcd0 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java
@@ -33,6 +33,7 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.classifier.FalsingCollector;
 import com.android.systemui.classifier.FalsingCollectorFake;
+import com.android.systemui.classifier.SingleTapClassifier;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -69,9 +70,12 @@
     private LiftToActivateListener mLiftToactivateListener;
     private FalsingCollector mFalsingCollector = new FalsingCollectorFake();
     @Mock
+    private SingleTapClassifier mSingleTapClassifier;
+    @Mock
     private View mDeleteButton;
     @Mock
     private View mOkButton;
+    private NumPadKey[] mButtons = new NumPadKey[]{};
 
     private KeyguardPinBasedInputViewController mKeyguardPinViewController;
 
@@ -83,6 +87,7 @@
         when(mPinBasedInputView.getPasswordTextViewId()).thenReturn(1);
         when(mPinBasedInputView.findViewById(1)).thenReturn(mPasswordEntry);
         when(mPinBasedInputView.isAttachedToWindow()).thenReturn(true);
+        when(mPinBasedInputView.getButtons()).thenReturn(mButtons);
         when(mPinBasedInputView.findViewById(R.id.keyguard_message_area))
                 .thenReturn(mKeyguardMessageArea);
         when(mPinBasedInputView.findViewById(R.id.delete_button))
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
index b03dc94..49ba646 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
@@ -34,6 +34,8 @@
 import com.android.internal.widget.LockPatternUtils;
 import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.classifier.FalsingManagerFake;
+import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 
@@ -83,6 +85,9 @@
     private KeyguardSecurityViewFlipperController mKeyguardSecurityViewFlipperController;
     @Mock
     private ConfigurationController mConfigurationController;
+    @Mock
+    private KeyguardViewController mKeyguardViewController;
+    private FalsingManager mFalsingManager = new FalsingManagerFake();
 
     private KeyguardSecurityContainerController mKeyguardSecurityContainerController;
 
@@ -96,7 +101,8 @@
                 mView,  mAdminSecondaryLockScreenControllerFactory, mLockPatternUtils,
                 mKeyguardUpdateMonitor, mKeyguardSecurityModel, mMetricsLogger, mUiEventLogger,
                 mKeyguardStateController, mKeyguardSecurityViewFlipperController,
-                mConfigurationController).create(mSecurityCallback);
+                mConfigurationController, mKeyguardViewController, mFalsingManager)
+                .create(mSecurityCallback);
     }
 
     @Test
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 0768618..d6f4958 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -246,20 +246,4 @@
         // THEN the illumination is hidden
         verify(mUdfpsView).stopIllumination();
     }
-
-    @Test
-    public void registersAndUnregistersViewForCallbacks() throws RemoteException {
-        mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
-                IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD, mUdfpsOverlayControllerCallback);
-        mFgExecutor.runAllReady();
-        verify(mStatusBarStateController).addCallback(mUdfpsController.mStatusBarStateListener);
-        verify(mStatusBar).addExpansionChangedListener(
-                mUdfpsController.mStatusBarExpansionListener);
-
-        mOverlayController.hideUdfpsOverlay(TEST_UDFPS_SENSOR_ID);
-        mFgExecutor.runAllReady();
-        verify(mStatusBarStateController).removeCallback(mUdfpsController.mStatusBarStateListener);
-        verify(mStatusBar).removeExpansionChangedListener(
-                mUdfpsController.mStatusBarExpansionListener);
-    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
new file mode 100644
index 0000000..480b335
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.biometrics;
+
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper.RunWithLooper;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.phone.StatusBar;
+
+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.List;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
+public class UdfpsKeyguardViewControllerTest extends SysuiTestCase {
+    // Dependencies
+    @Mock
+    private UdfpsKeyguardView mView;
+    @Mock
+    private StatusBarStateController mStatusBarStateController;
+    @Mock
+    private StatusBar mStatusBar;
+
+    private UdfpsKeyguardViewController mController;
+
+    // Capture listeners so that they can be used to send events
+    @Captor private ArgumentCaptor<StatusBarStateController.StateListener> mStateListenerCaptor;
+    private StatusBarStateController.StateListener mParentListener;
+    private StatusBarStateController.StateListener mDozeListener;
+
+    @Captor private ArgumentCaptor<StatusBar.ExpansionChangedListener> mExpansionListenerCaptor;
+    private StatusBar.ExpansionChangedListener mExpansionListener;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mController = new UdfpsKeyguardViewController(
+                mView,
+                mStatusBarStateController,
+                mStatusBar);
+    }
+
+    @Test
+    public void testRegistersExpansionChangedListenerOnAttached() {
+        mController.onViewAttached();
+        captureExpansionListener();
+    }
+
+    @Test
+    public void testRegistersStatusBarStateListenersOnAttached() {
+        mController.onViewAttached();
+        captureStatusBarStateListeners();
+    }
+
+    @Test
+    public void testViewControllerQueriesSBStateOnAttached() {
+        mController.onViewAttached();
+        verify(mStatusBarStateController).getState();
+        verify(mStatusBarStateController).getDozeAmount();
+
+        final float dozeAmount = .88f;
+        when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE_LOCKED);
+        when(mStatusBarStateController.getDozeAmount()).thenReturn(dozeAmount);
+        captureStatusBarStateListeners();
+
+        mController.onViewAttached();
+        verify(mView).setPauseAuth(true);
+        verify(mView).onDozeAmountChanged(dozeAmount, dozeAmount);
+    }
+
+    @Test
+    public void testListenersUnregisteredOnDetached() {
+        mController.onViewAttached();
+        captureStatusBarStateListeners();
+        captureExpansionListener();
+        mController.onViewDetached();
+
+        verify(mStatusBarStateController).removeCallback(mParentListener);
+        verify(mStatusBarStateController).removeCallback(mDozeListener);
+        verify(mStatusBar).removeExpansionChangedListener(mExpansionListener);
+    }
+
+    @Test
+    public void testDozeEventsSentToView() {
+        mController.onViewAttached();
+        captureStatusBarStateListeners();
+
+        final float linear = .55f;
+        final float eased = .65f;
+        mDozeListener.onDozeAmountChanged(linear, eased);
+
+        verify(mView).onDozeAmountChanged(linear, eased);
+    }
+
+    private void captureStatusBarStateListeners() {
+        verify(mStatusBarStateController, times(2)).addCallback(mStateListenerCaptor.capture());
+        List<StatusBarStateController.StateListener> stateListeners =
+                mStateListenerCaptor.getAllValues();
+        mParentListener = stateListeners.get(0);
+        mDozeListener = stateListeners.get(1);
+    }
+
+    private void captureExpansionListener() {
+        verify(mStatusBar).addExpansionChangedListener(mExpansionListenerCaptor.capture());
+        mExpansionListener = mExpansionListenerCaptor.getValue();
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java
index 5709ce30..b232850 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java
@@ -21,10 +21,7 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyCollection;
 import static org.mockito.ArgumentMatchers.anyDouble;
-import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -93,7 +90,7 @@
         when(mFalsingDataProvider.getRecentMotionEvents()).thenReturn(mMotionEventList);
         mBrightLineFalsingManager = new BrightLineFalsingManager(mFalsingDataProvider, mDockManager,
                 mMetricsLogger, mClassifiers, mSingleTapClassfier, mDoubleTapClassifier,
-                mHistoryTracker, mFakeExecutor, DOUBLE_TAP_TIMEOUT_MS, false);
+                mHistoryTracker, false);
 
 
         ArgumentCaptor<GestureCompleteListener> gestureCompleteListenerCaptor =
@@ -161,25 +158,27 @@
     public void testIsFalseTap_BasicCheck() {
         when(mSingleTapClassfier.isTap(mMotionEventList)).thenReturn(mFalsedResult);
 
-        assertThat(mBrightLineFalsingManager.isFalseTap(false)).isTrue();
+        assertThat(mBrightLineFalsingManager.isFalseTap(false, 0)).isTrue();
 
         when(mSingleTapClassfier.isTap(mMotionEventList)).thenReturn(mPassedResult);
 
-        assertThat(mBrightLineFalsingManager.isFalseTap(false)).isFalse();
+        assertThat(mBrightLineFalsingManager.isFalseTap(false, 0)).isFalse();
     }
 
     @Test
     public void testIsFalseTap_RobustCheck_NoFaceAuth() {
         when(mSingleTapClassfier.isTap(mMotionEventList)).thenReturn(mPassedResult);
+        when(mDoubleTapClassifier.classifyGesture()).thenReturn(mFalsedResult);
+        when(mHistoryTracker.falseBelief()).thenReturn(1.0);
         mFalsingDataProvider.setJustUnlockedWithFace(false);
-        assertThat(mBrightLineFalsingManager.isFalseTap(true)).isTrue();
+        assertThat(mBrightLineFalsingManager.isFalseTap(true, 0)).isTrue();
     }
 
     @Test
     public void testIsFalseTap_RobustCheck_FaceAuth() {
         when(mSingleTapClassfier.isTap(mMotionEventList)).thenReturn(mPassedResult);
         when(mFalsingDataProvider.isJustUnlockedWithFace()).thenReturn(true);
-        assertThat(mBrightLineFalsingManager.isFalseTap(true)).isFalse();
+        assertThat(mBrightLineFalsingManager.isFalseTap(true, 0)).isFalse();
     }
 
     @Test
@@ -203,43 +202,29 @@
     @Test
     public void testHistory_singleTap() {
         // When trying to classify single taps, we don't immediately add results to history.
-        mBrightLineFalsingManager.isFalseTap(false);
+        mBrightLineFalsingManager.isFalseTap(false, 0);
         mGestureCompleteListener.onGestureComplete(1000);
-
-        verify(mHistoryTracker, never()).addResults(any(), anyLong());
-
-        mFakeExecutor.advanceClockToNext();
-        mFakeExecutor.runAllReady();
-
         verify(mHistoryTracker).addResults(anyCollection(), eq(1000L));
     }
 
     @Test
     public void testHistory_multipleSingleTaps() {
         // When trying to classify single taps, we don't immediately add results to history.
-        mBrightLineFalsingManager.isFalseTap(false);
+        mBrightLineFalsingManager.isFalseTap(false, 0);
         mGestureCompleteListener.onGestureComplete(1000);
-        mBrightLineFalsingManager.isFalseTap(false);
+        mBrightLineFalsingManager.isFalseTap(false, 0);
         mGestureCompleteListener.onGestureComplete(2000);
-
-        verify(mHistoryTracker, never()).addResults(any(), anyLong());
-
-        mFakeExecutor.advanceClockToNext();
-        mFakeExecutor.runNextReady();
         verify(mHistoryTracker).addResults(anyCollection(), eq(1000L));
-        reset(mHistoryTracker);
-        mFakeExecutor.advanceClockToNext();
-        mFakeExecutor.runNextReady();
         verify(mHistoryTracker).addResults(anyCollection(), eq(2000L));
     }
 
     @Test
     public void testHistory_doubleTap() {
         // When trying to classify single taps, we don't immediately add results to history.
-        mBrightLineFalsingManager.isFalseTap(false);
+        mBrightLineFalsingManager.isFalseTap(false, 0);
         mGestureCompleteListener.onGestureComplete(1000);
         // Before checking for double tap, we may check for single-tap on the second gesture.
-        mBrightLineFalsingManager.isFalseTap(false);
+        mBrightLineFalsingManager.isFalseTap(false, 0);
         mBrightLineFalsingManager.isFalseDoubleTap();
         mGestureCompleteListener.onGestureComplete(2000);
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingCollectorImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingCollectorImplTest.java
index 23ef865..dc79b88 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingCollectorImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingCollectorImplTest.java
@@ -36,6 +36,7 @@
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.util.sensors.ProximitySensor;
 import com.android.systemui.util.sensors.ThresholdSensor;
+import com.android.systemui.util.time.FakeSystemClock;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -56,6 +57,8 @@
     @Mock
     private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
     @Mock
+    private HistoryTracker mHistoryTracker;
+    @Mock
     private ProximitySensor mProximitySensor;
     @Mock
     private SysuiStatusBarStateController mStatusBarStateController;
@@ -67,7 +70,8 @@
         when(mStatusBarStateController.getState()).thenReturn(StatusBarState.KEYGUARD);
 
         mFalsingCollector = new FalsingCollectorImpl(mFalsingDataProvider, mFalsingManager,
-                mKeyguardUpdateMonitor, mProximitySensor, mStatusBarStateController);
+                mKeyguardUpdateMonitor, mHistoryTracker, mProximitySensor,
+                mStatusBarStateController, new FakeSystemClock());
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/HistoryTrackerTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/HistoryTrackerTest.java
index 01cce35..bb7545f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/HistoryTrackerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/HistoryTrackerTest.java
@@ -48,14 +48,14 @@
 
     @Test
     public void testNoDataNoPenalty() {
-        assertThat(mHistoryTracker.falsePenalty()).isEqualTo(0);
+        assertThat(mHistoryTracker.falseBelief()).isEqualTo(0.5);
         assertThat(mHistoryTracker.falseConfidence()).isEqualTo(0);
     }
 
     @Test
     public void testOneResultFullConfidence() {
         addResult(true, 1);
-        assertThat(mHistoryTracker.falsePenalty()).isEqualTo(1);
+        assertThat(mHistoryTracker.falseBelief()).isWithin(0.001).of(1);
         assertThat(mHistoryTracker.falseConfidence()).isEqualTo(1);
     }
 
@@ -64,8 +64,8 @@
         addResult(true, 1);
         addResult(false, 1);
 
-        assertThat(mHistoryTracker.falsePenalty()).isEqualTo(0.5);
-        assertThat(mHistoryTracker.falseConfidence()).isEqualTo(0.5);
+        assertThat(mHistoryTracker.falseBelief()).isWithin(0.001).of(0.5);
+        assertThat(mHistoryTracker.falseConfidence()).isWithin(0.001).of(0.5);
     }
 
     @Test
@@ -73,20 +73,20 @@
         addResult(true, 1);
         addResult(true, 0);
 
-        assertThat(mHistoryTracker.falsePenalty()).isEqualTo(0.75);
-        assertThat(mHistoryTracker.falseConfidence()).isEqualTo(.75);
+        assertThat(mHistoryTracker.falseBelief()).isWithin(0.001).of(1);
+        assertThat(mHistoryTracker.falseConfidence()).isWithin(0.001).of(.75);
     }
 
     @Test
     public void testDecay() {
         addResult(true, 1);
 
-        assertThat(mHistoryTracker.falsePenalty()).isEqualTo(1);
+        assertThat(mHistoryTracker.falseBelief()).isWithin(0.001).of(1);
         assertThat(mHistoryTracker.falseConfidence()).isEqualTo(1);
 
-        mSystemClock.advanceTime(1000);
+        mSystemClock.advanceTime(9999);
 
-        assertThat(mHistoryTracker.falsePenalty()).isWithin(0.01).of(0.1);
+        assertThat(mHistoryTracker.falseBelief()).isWithin(0.005).of(0.55);
         assertThat(mHistoryTracker.falseConfidence()).isEqualTo(1);
     }
 
@@ -96,25 +96,25 @@
         mSystemClock.advanceTime(1000);
         addResult(false, .5);
 
-        assertThat(mHistoryTracker.falsePenalty()).isWithin(0.01).of(0.17);
-        assertThat(mHistoryTracker.falseConfidence()).isEqualTo(0.625);
+        assertThat(mHistoryTracker.falseBelief()).isWithin(0.01).of(0.74);
+        assertThat(mHistoryTracker.falseConfidence()).isWithin(0.001).of(0.625);
     }
 
     @Test
     public void testCompleteDecay() {
         addResult(true, 1);
 
-        assertThat(mHistoryTracker.falsePenalty()).isEqualTo(1);
+        assertThat(mHistoryTracker.falseBelief()).isWithin(0.001).of(1);
         assertThat(mHistoryTracker.falseConfidence()).isEqualTo(1);
 
-        mSystemClock.advanceTime(2999);
+        mSystemClock.advanceTime(9999);
 
-        assertThat(mHistoryTracker.falsePenalty()).isGreaterThan(0);
+        assertThat(mHistoryTracker.falseBelief()).isGreaterThan(0);
         assertThat(mHistoryTracker.falseConfidence()).isEqualTo(1);
 
         mSystemClock.advanceTime(1);
 
-        assertThat(mHistoryTracker.falsePenalty()).isEqualTo(0);
+        assertThat(mHistoryTracker.falseBelief()).isEqualTo(0.5);
         assertThat(mHistoryTracker.falseConfidence()).isEqualTo(0);
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarViewModelTest.kt
index 1f9862c..3d4425c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarViewModelTest.kt
@@ -35,6 +35,7 @@
 
 import org.junit.After
 import org.junit.Before
+import org.junit.Ignore
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.ArgumentCaptor
@@ -49,7 +50,7 @@
 
 @SmallTest
 @RunWith(AndroidTestingRunner::class)
-@TestableLooper.RunWithLooper
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
 public class SeekBarViewModelTest : SysuiTestCase() {
 
     private lateinit var viewModel: SeekBarViewModel
@@ -124,6 +125,7 @@
     }
 
     @Test
+    @Ignore
     fun updateDurationWithPlayback() {
         // GIVEN that the duration is contained within the metadata
         val duration = 12000L
@@ -146,6 +148,7 @@
     }
 
     @Test
+    @Ignore
     fun updateDurationWithoutPlayback() {
         // GIVEN that the duration is contained within the metadata
         val duration = 12000L
@@ -204,6 +207,7 @@
     }
 
     @Test
+    @Ignore
     fun updateDurationNoMetadata() {
         // GIVEN that the metadata is null
         whenever(mockController.getMetadata()).thenReturn(null)
@@ -235,6 +239,7 @@
     }
 
     @Test
+    @Ignore
     fun updateSeekAvailable() {
         // GIVEN that seek is included in actions
         val state = PlaybackState.Builder().run {
@@ -249,6 +254,7 @@
     }
 
     @Test
+    @Ignore
     fun updateSeekNotAvailable() {
         // GIVEN that seek is not included in actions
         val state = PlaybackState.Builder().run {
@@ -303,6 +309,7 @@
     }
 
     @Test
+    @Ignore
     fun onSeekProgressWithSeekStarting() {
         val pos = 42L
         with(viewModel) {
@@ -314,6 +321,7 @@
     }
 
     @Test
+    @Ignore
     fun onProgressChangedFromUser() {
         // WHEN user starts dragging the seek bar
         val pos = 42
@@ -614,6 +622,7 @@
     }
 
     @Test
+    @Ignore
     fun clearSeekBar() {
         // GIVEN that the duration is contained within the metadata
         val metadata = MediaMetadata.Builder().run {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerTest.kt
index 072f7b8..791dd12 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerTest.kt
@@ -395,9 +395,8 @@
         `when`(permissionManager.indicatorAppOpUsageData).thenReturn(
                 listOf(usage_camera, usage_location, usage_microphone)
         )
-        `when`(privacyItemController.micCameraAvailable).thenReturn(false)
-        `when`(privacyItemController.locationAvailable).thenReturn(false)
-        `when`(privacyItemController.allIndicatorsAvailable).thenReturn(true)
+        `when`(privacyItemController.micCameraAvailable).thenReturn(true)
+        `when`(privacyItemController.locationAvailable).thenReturn(true)
 
         controller.showDialog(context)
         exhaustExecutors()
@@ -422,7 +421,6 @@
         )
         `when`(privacyItemController.micCameraAvailable).thenReturn(false)
         `when`(privacyItemController.locationAvailable).thenReturn(false)
-        `when`(privacyItemController.allIndicatorsAvailable).thenReturn(false)
 
         controller.showDialog(context)
         exhaustExecutors()
@@ -525,7 +523,6 @@
 
         `when`(privacyItemController.locationAvailable).thenReturn(true)
         `when`(privacyItemController.micCameraAvailable).thenReturn(true)
-        `when`(privacyItemController.allIndicatorsAvailable).thenReturn(false)
 
         `when`(userTracker.userProfiles).thenReturn(listOf(
                 UserInfo(USER_ID, "", 0),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerFlagsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerFlagsTest.kt
index 132bee0..f991e71 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerFlagsTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerFlagsTest.kt
@@ -37,7 +37,6 @@
 import org.mockito.ArgumentCaptor
 import org.mockito.Mock
 import org.mockito.Mockito
-import org.mockito.Mockito.anyBoolean
 import org.mockito.Mockito.atLeastOnce
 import org.mockito.Mockito.never
 import org.mockito.Mockito.verify
@@ -51,8 +50,6 @@
         fun <T> eq(value: T): T = Mockito.eq(value) ?: value
         fun <T> any(): T = Mockito.any<T>()
 
-        private const val ALL_INDICATORS =
-                SystemUiDeviceConfigFlags.PROPERTY_PERMISSIONS_HUB_ENABLED
         private const val MIC_CAMERA = SystemUiDeviceConfigFlags.PROPERTY_MIC_CAMERA_ENABLED
         private const val LOCATION = SystemUiDeviceConfigFlags.PROPERTY_LOCATION_INDICATORS_ENABLED
     }
@@ -96,11 +93,6 @@
     }
 
     @Test
-    fun testNotListeningAllByDefault() {
-        assertFalse(privacyItemController.allIndicatorsAvailable)
-    }
-
-    @Test
     fun testMicCameraListeningByDefault() {
         assertTrue(privacyItemController.micCameraAvailable)
     }
@@ -111,10 +103,8 @@
         executor.runAllReady()
 
         verify(callback).onFlagMicCameraChanged(false)
-        verify(callback, never()).onFlagAllChanged(anyBoolean())
 
         assertFalse(privacyItemController.micCameraAvailable)
-        assertFalse(privacyItemController.allIndicatorsAvailable)
     }
 
     @Test
@@ -127,26 +117,15 @@
     }
 
     @Test
-    fun testAllChanged() {
-        changeAll(true)
-        executor.runAllReady()
-
-        verify(callback).onFlagAllChanged(true)
-        verify(callback, never()).onFlagMicCameraChanged(anyBoolean())
-
-        assertTrue(privacyItemController.allIndicatorsAvailable)
-    }
-
-    @Test
     fun testBothChanged() {
         changeAll(true)
         changeMicCamera(false)
         executor.runAllReady()
 
-        verify(callback, atLeastOnce()).onFlagAllChanged(true)
+        verify(callback, atLeastOnce()).onFlagLocationChanged(true)
         verify(callback, atLeastOnce()).onFlagMicCameraChanged(false)
 
-        assertTrue(privacyItemController.allIndicatorsAvailable)
+        assertTrue(privacyItemController.locationAvailable)
         assertFalse(privacyItemController.micCameraAvailable)
     }
 
@@ -186,28 +165,6 @@
     }
 
     @Test
-    fun testSomeListening_stillListening() {
-        // Mic and camera are true by default
-        changeAll(true)
-        executor.runAllReady()
-        changeAll(false)
-        executor.runAllReady()
-
-        verify(appOpsController, never()).removeCallback(any(), any())
-    }
-
-    @Test
-    fun testAllDeleted_micCameraFalse_stopListening() {
-        changeMicCamera(false)
-        changeAll(true)
-        executor.runAllReady()
-        changeAll(null)
-        executor.runAllReady()
-
-        verify(appOpsController).removeCallback(any(), any())
-    }
-
-    @Test
     fun testMicDeleted_stillListening() {
         changeMicCamera(true)
         executor.runAllReady()
@@ -219,7 +176,10 @@
 
     private fun changeMicCamera(value: Boolean?) = changeProperty(MIC_CAMERA, value)
     private fun changeLocation(value: Boolean?) = changeProperty(LOCATION, value)
-    private fun changeAll(value: Boolean?) = changeProperty(ALL_INDICATORS, value)
+    private fun changeAll(value: Boolean?) {
+        changeMicCamera(value)
+        changeLocation(value)
+    }
 
     private fun changeProperty(name: String, value: Boolean?) {
         deviceConfigProxy.setProperty(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt
index 7ca468e..b87c7a6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt
@@ -43,7 +43,6 @@
 import org.junit.Assert.assertThat
 import org.junit.Assert.assertTrue
 import org.junit.Before
-import org.junit.Ignore
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.ArgumentCaptor
@@ -72,8 +71,8 @@
         val TEST_UID = CURRENT_USER_ID * UserHandle.PER_USER_RANGE
         const val TEST_PACKAGE_NAME = "test"
 
-        private const val ALL_INDICATORS =
-                SystemUiDeviceConfigFlags.PROPERTY_PERMISSIONS_HUB_ENABLED
+        private const val LOCATION_INDICATOR =
+                SystemUiDeviceConfigFlags.PROPERTY_LOCATION_INDICATORS_ENABLED
         private const val MIC_CAMERA = SystemUiDeviceConfigFlags.PROPERTY_MIC_CAMERA_ENABLED
         fun <T> capture(argumentCaptor: ArgumentCaptor<T>): T = argumentCaptor.capture()
         fun <T> eq(value: T): T = Mockito.eq(value) ?: value
@@ -119,7 +118,8 @@
         deviceConfigProxy = DeviceConfigProxyFake()
 
         // Listen to everything by default
-        changeAll(true)
+        changeMicCamera(true)
+        changeLocation(true)
 
         `when`(userTracker.userProfiles).thenReturn(listOf(UserInfo(CURRENT_USER_ID, "", 0)))
 
@@ -259,9 +259,8 @@
     }
 
     @Test
-    @Ignore // TODO(b/168209929)
     fun testNotListeningWhenIndicatorsDisabled() {
-        changeAll(false)
+        changeLocation(false)
         changeMicCamera(false)
         privacyItemController.addCallback(callback)
         executor.runAllReady()
@@ -271,7 +270,7 @@
 
     @Test
     fun testNotSendingLocationWhenOnlyMicCamera() {
-        changeAll(false)
+        changeLocation(false)
         changeMicCamera(true)
         executor.runAllReady()
 
@@ -294,7 +293,7 @@
                 .`when`(appOpsController).getActiveAppOpsForUser(anyInt())
 
         privacyItemController.addCallback(callback)
-        changeAll(false)
+        changeLocation(false)
         changeMicCamera(true)
         executor.runAllReady()
         reset(callback) // Clean callback
@@ -521,7 +520,7 @@
     }
 
     private fun changeMicCamera(value: Boolean?) = changeProperty(MIC_CAMERA, value)
-    private fun changeAll(value: Boolean?) = changeProperty(ALL_INDICATORS, value)
+    private fun changeLocation(value: Boolean?) = changeProperty(LOCATION_INDICATOR, value)
 
     private fun changeProperty(name: String, value: Boolean?) {
         deviceConfigProxy.setProperty(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
index cfef5be..2ca8082 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
@@ -49,6 +49,7 @@
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.classifier.FalsingManagerFake;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.qs.QSFactory;
@@ -360,6 +361,7 @@
                     host,
                     mLooper.getLooper(),
                     new Handler(mLooper.getLooper()),
+                    new FalsingManagerFake(),
                     mock(MetricsLogger.class),
                     mock(StatusBarStateController.class),
                     mock(ActivityStarter.class),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt
index 97a8459..4948c2b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt
@@ -148,7 +148,7 @@
 
     @Test
     fun testIgnoredSlotsOnAttached_noIndicators() {
-        setPrivacyController(false, false, false)
+        setPrivacyController(micCamera = false, location = false)
 
         controller.init()
 
@@ -160,7 +160,7 @@
 
     @Test
     fun testIgnoredSlotsOnAttached_onlyMicCamera() {
-        setPrivacyController(false, true, false)
+        setPrivacyController(micCamera = true, location = false)
 
         controller.init()
 
@@ -177,7 +177,7 @@
 
     @Test
     fun testIgnoredSlotsOnAttached_onlyLocation() {
-        setPrivacyController(false, false, true)
+        setPrivacyController(micCamera = false, location = true)
 
         controller.init()
 
@@ -192,26 +192,7 @@
 
     @Test
     fun testIgnoredSlotsOnAttached_locationMicCamera() {
-        setPrivacyController(false, true, true)
-
-        controller.init()
-
-        val captor = argumentCaptor<List<String>>()
-        verify(iconContainer).setIgnoredSlots(capture(captor))
-
-        val cameraString = mContext.resources.getString(
-                com.android.internal.R.string.status_bar_camera)
-        val micString = mContext.resources.getString(
-                com.android.internal.R.string.status_bar_microphone)
-        val locationString = mContext.resources.getString(
-                com.android.internal.R.string.status_bar_location)
-
-        assertThat(captor.value).containsExactly(cameraString, micString, locationString)
-    }
-
-    @Test
-    fun testIgnoredSlotsOnAttached_all() {
-        setPrivacyController(true, false, false)
+        setPrivacyController(micCamera = true, location = true)
 
         controller.init()
 
@@ -248,8 +229,7 @@
         `when`(view.findViewById<Clock>(R.id.clock)).thenReturn(clock)
     }
 
-    private fun setPrivacyController(all: Boolean, micCamera: Boolean, location: Boolean) {
-        `when`(privacyItemController.allIndicatorsAvailable).thenReturn(all)
+    private fun setPrivacyController(micCamera: Boolean, location: Boolean) {
         `when`(privacyItemController.micCameraAvailable).thenReturn(micCamera)
         `when`(privacyItemController.locationAvailable).thenReturn(location)
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt
index 3aa40de..b1c3d1d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt
@@ -32,6 +32,7 @@
 import android.view.IWindowManager
 import com.android.internal.logging.MetricsLogger
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.classifier.FalsingManagerFake
 import com.android.systemui.plugins.ActivityStarter
 import com.android.systemui.plugins.qs.QSTile
 import com.android.systemui.plugins.statusbar.StatusBarStateController
@@ -103,6 +104,7 @@
                 { tileHost },
                 testableLooper.looper,
                 Handler(testableLooper.looper),
+                FalsingManagerFake(),
                 metricsLogger,
                 statusBarStateController,
                 activityStarter,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
index 61a0d6c..937ab1c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
@@ -26,6 +26,8 @@
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_STATUS_BAR_STATE;
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_ACTION;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotEquals;
@@ -55,7 +57,9 @@
 import com.android.internal.logging.UiEventLogger;
 import com.android.internal.logging.testing.UiEventLoggerFake;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.classifier.FalsingManagerFake;
 import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.qs.QSTile;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.QSEvent;
@@ -90,6 +94,7 @@
     private QSTileHost mHost;
     @Mock
     private MetricsLogger mMetricsLogger;
+    private final FalsingManagerFake mFalsingManager = new FalsingManagerFake();
     @Mock
     private StatusBarStateController mStatusBarStateController;
     @Mock
@@ -112,7 +117,7 @@
 
         Handler mainHandler = new Handler(mTestableLooper.getLooper());
 
-        mTile = new TileImpl(mHost, mTestableLooper.getLooper(), mainHandler,
+        mTile = new TileImpl(mHost, mTestableLooper.getLooper(), mainHandler, mFalsingManager,
                 mMetricsLogger, mStatusBarStateController, mActivityStarter, mQsLogger);
         mTile.setTileSpec(SPEC);
     }
@@ -144,6 +149,19 @@
     }
 
     @Test
+    public void testClick_falsing() {
+        mFalsingManager.setFalseRobustTap(true);
+        mTile.click();
+        mTestableLooper.processAllMessages();
+        assertThat(mTile.mClicked).isFalse();
+
+        mFalsingManager.setFalseRobustTap(false);
+        mTile.click();
+        mTestableLooper.processAllMessages();
+        assertThat(mTile.mClicked).isTrue();
+    }
+
+    @Test
     public void testSecondaryClick_Metrics() {
         mTile.secondaryClick();
         verify(mMetricsLogger).write(argThat(new TileLogMatcher(ACTION_QS_SECONDARY_CLICK)));
@@ -360,17 +378,20 @@
     }
 
     private static class TileImpl extends QSTileImpl<QSTile.BooleanState> {
+        boolean mClicked;
+
         protected TileImpl(
                 QSHost host,
                 Looper backgroundLooper,
                 Handler mainHandler,
+                FalsingManager falsingManager,
                 MetricsLogger metricsLogger,
                 StatusBarStateController statusBarStateController,
                 ActivityStarter activityStarter,
                 QSLogger qsLogger
         ) {
-            super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
-                    activityStarter, qsLogger);
+            super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
+                    statusBarStateController, activityStarter, qsLogger);
             getState().state = Tile.STATE_ACTIVE;
         }
 
@@ -381,7 +402,7 @@
 
         @Override
         protected void handleClick() {
-
+            mClicked = true;
         }
 
         @Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/AlarmTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/AlarmTileTest.kt
index a9d10e9..9674a60 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/AlarmTileTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/AlarmTileTest.kt
@@ -10,6 +10,7 @@
 import com.android.internal.logging.MetricsLogger
 import com.android.internal.logging.UiEventLogger
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.classifier.FalsingManagerFake
 import com.android.systemui.plugins.ActivityStarter
 import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.qs.QSHost
@@ -73,6 +74,7 @@
             qsHost,
             testableLooper.looper,
             Handler(testableLooper.looper),
+            FalsingManagerFake(),
             metricsLogger,
             statusBarStateController,
             activityStarter,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BatterySaverTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BatterySaverTileTest.kt
index bcfc835..f17bd56 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BatterySaverTileTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BatterySaverTileTest.kt
@@ -24,6 +24,7 @@
 import androidx.test.filters.SmallTest
 import com.android.internal.logging.MetricsLogger
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.classifier.FalsingManagerFake
 import com.android.systemui.plugins.ActivityStarter
 import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.qs.QSHost
@@ -79,6 +80,7 @@
                 qsHost,
                 testableLooper.looper,
                 Handler(testableLooper.looper),
+                FalsingManagerFake(),
                 metricsLogger,
                 statusBarStateController,
                 activityStarter,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java
index 1c29a81..7d39361 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java
@@ -37,6 +37,7 @@
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.classifier.FalsingManagerFake;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.QSTileHost;
@@ -101,6 +102,7 @@
                 mHost,
                 mTestableLooper.getLooper(),
                 new Handler(mTestableLooper.getLooper()),
+                new FalsingManagerFake(),
                 mMetricsLogger,
                 mStatusBarStateController,
                 mActivityStarter,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DeviceControlsTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DeviceControlsTileTest.kt
index 9363b248..9fe5687 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DeviceControlsTileTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DeviceControlsTileTest.kt
@@ -28,6 +28,7 @@
 import com.android.internal.logging.MetricsLogger
 import com.android.internal.logging.UiEventLogger
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.classifier.FalsingManagerFake
 import com.android.systemui.controls.ControlsServiceInfo
 import com.android.systemui.controls.controller.ControlsController
 import com.android.systemui.controls.dagger.ControlsComponent
@@ -323,6 +324,7 @@
                 qsHost,
                 testableLooper.looper,
                 Handler(testableLooper.looper),
+                FalsingManagerFake(),
                 metricsLogger,
                 statusBarStateController,
                 activityStarter,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/NfcTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/NfcTileTest.java
index b37ac4a..99d028c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/NfcTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/NfcTileTest.java
@@ -33,6 +33,7 @@
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.classifier.FalsingManagerFake;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.QSTileHost;
@@ -84,6 +85,7 @@
                 mHost,
                 mTestableLooper.getLooper(),
                 new Handler(mTestableLooper.getLooper()),
+                new FalsingManagerFake(),
                 mMetricsLogger,
                 mStatusBarStateController,
                 mActivityStarter,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java
index 880c290..6032e51 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java
@@ -33,6 +33,7 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.classifier.FalsingManagerFake;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.QSTileHost;
@@ -82,6 +83,7 @@
                 mHost,
                 mTestableLooper.getLooper(),
                 new Handler(mTestableLooper.getLooper()),
+                new FalsingManagerFake(),
                 mMetricsLogger,
                 mStatusBarStateController,
                 mActivityStarter,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java
index 6b54791..2215433 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java
@@ -33,6 +33,7 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.classifier.FalsingManagerFake;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.QSTileHost;
@@ -81,6 +82,7 @@
                 mHost,
                 mTestableLooper.getLooper(),
                 new Handler(mTestableLooper.getLooper()),
+                new FalsingManagerFake(),
                 mMetricsLogger,
                 mStatusBarStateController,
                 mActivityStarter,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.java b/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.java
deleted file mode 100644
index 25104b8..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.java
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.recents;
-
-import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.content.pm.PackageManager;
-import android.os.RemoteException;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableContext;
-import android.testing.TestableLooper;
-
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.model.SysUiState;
-import com.android.systemui.navigationbar.NavigationBarController;
-import com.android.systemui.navigationbar.NavigationModeController;
-import com.android.systemui.shared.recents.IPinnedStackAnimationListener;
-import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.NotificationShadeWindowController;
-import com.android.systemui.statusbar.phone.StatusBar;
-import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
-import com.android.wm.shell.pip.Pip;
-import com.android.wm.shell.splitscreen.SplitScreen;
-import com.android.wm.shell.startingsurface.StartingSurface;
-import com.android.wm.shell.transition.RemoteTransitions;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.util.Optional;
-
-import dagger.Lazy;
-
-/**
- * Unit tests for {@link com.android.systemui.recents.OverviewProxyService}
- */
-@SmallTest
-@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
-public class OverviewProxyServiceTest extends SysuiTestCase {
-    private OverviewProxyService mSpiedOverviewProxyService;
-    private TestableContext mSpiedContext;
-
-    @Mock private BroadcastDispatcher mMockBroadcastDispatcher;
-    @Mock private CommandQueue mMockCommandQueue;
-    @Mock private Lazy<NavigationBarController> mMockNavBarControllerLazy;
-    @Mock private IPinnedStackAnimationListener mMockPinnedStackAnimationListener;
-    @Mock private NavigationModeController mMockNavModeController;
-    @Mock private NotificationShadeWindowController mMockStatusBarWinController;
-    @Mock private Optional<Pip> mMockPipOptional;
-    @Mock private Optional<LegacySplitScreen> mMockLegacySplitScreenOptional;
-    @Mock private Optional<SplitScreen> mMockSplitScreenOptional;
-    @Mock private Optional<Lazy<StatusBar>> mMockStatusBarOptionalLazy;
-    @Mock private Optional<com.android.wm.shell.onehanded.OneHanded> mMockOneHandedOptional;
-    @Mock private PackageManager mPackageManager;
-    @Mock private SysUiState mMockSysUiState;
-    @Mock private RemoteTransitions mMockTransitions;
-    @Mock private Optional<StartingSurface> mStartingSurface;
-
-    @Before
-    public void setUp() throws RemoteException {
-        MockitoAnnotations.initMocks(this);
-
-        mSpiedContext = spy(mContext);
-
-        when(mPackageManager.hasSystemFeature(FEATURE_PICTURE_IN_PICTURE)).thenReturn(false);
-        when(mSpiedContext.getPackageManager()).thenReturn(mPackageManager);
-
-        mSpiedOverviewProxyService = spy(new OverviewProxyService(mSpiedContext, mMockCommandQueue,
-                mMockNavBarControllerLazy, mMockNavModeController, mMockStatusBarWinController,
-                mMockSysUiState, mMockPipOptional, mMockLegacySplitScreenOptional,
-                mMockSplitScreenOptional, mMockStatusBarOptionalLazy, mMockOneHandedOptional,
-                mMockBroadcastDispatcher, mMockTransitions, mStartingSurface));
-    }
-
-    @Test
-    public void testNonPipDevice_shouldNotNotifySwipeToHomeFinished() throws RemoteException {
-        mSpiedOverviewProxyService.mSysUiProxy.notifySwipeToHomeFinished();
-
-        verify(mMockPipOptional, never()).ifPresent(any());
-    }
-
-    @Test
-    public void testNonPipDevice_shouldNotSetPinnedStackAnimationListener() throws RemoteException {
-        mSpiedOverviewProxyService.mSysUiProxy.setPinnedStackAnimationListener(
-                mMockPinnedStackAnimationListener);
-
-        verify(mMockPipOptional, never()).ifPresent(any());
-    }
-
-    @Test
-    public void testNonPipDevice_shouldNotSetShelfHeight() throws RemoteException {
-        mSpiedOverviewProxyService.mSysUiProxy.setShelfHeight(true /* visible */,
-                100 /* shelfHeight */);
-
-        verify(mMockPipOptional, never()).ifPresent(any());
-    }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
index 2917dfa..8ec03d7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
@@ -476,4 +476,11 @@
         waitForIdleSync();
         verify(mCallbacks).requestWindowMagnificationConnection(true);
     }
+
+    @Test
+    public void testSetEnableNavigationBarLumaSampling() {
+        mCommandQueue.setNavigationBarLumaSamplingEnabled(1, true);
+        waitForIdleSync();
+        verify(mCallbacks).setNavigationBarLumaSamplingEnabled(eq(1), eq(true));
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
index a844d09..a60baa5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
@@ -45,6 +45,7 @@
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.NotificationRemoteInputManager;
 import com.android.systemui.statusbar.RemoteInputController;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
@@ -86,6 +87,7 @@
                 mRemoteInputQuickSettingsDisabler);
         mDependency.injectTestDependency(LightBarController.class,
                 mLightBarController);
+        mDependency.injectMockDependency(NotificationRemoteInputManager.class);
 
         mReceiver = new BlockingQueueIntentReceiver();
         mContext.registerReceiver(mReceiver, new IntentFilter(TEST_ACTION), null,
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 0eb7daf..b00689b 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -98,7 +98,6 @@
         ":platform-compat-overrides",
         ":display-device-config",
         ":display-layout-config",
-        ":cec-config",
         ":device-state-config",
         "java/com/android/server/EventLogTags.logtags",
         "java/com/android/server/am/EventLogTags.logtags",
@@ -119,7 +118,6 @@
     ],
 
     required: [
-        "cec_config.xml",
         "gps_debug.conf",
         "protolog.conf.json.gz",
     ],
@@ -185,11 +183,6 @@
 }
 
 prebuilt_etc {
-    name: "cec_config.xml",
-    src: "java/com/android/server/hdmi/cec_config.xml",
-}
-
-prebuilt_etc {
     name: "gps_debug.conf",
     src: "java/com/android/server/location/gnss/gps_debug.conf",
 }
diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java
index bb4bbd5..1e608f5 100644
--- a/services/core/java/com/android/server/BatteryService.java
+++ b/services/core/java/com/android/server/BatteryService.java
@@ -918,19 +918,7 @@
                 int opts = parseOptions(shell);
                 getContext().enforceCallingOrSelfPermission(
                         android.Manifest.permission.DEVICE_POWER, null);
-                if (!mUpdatesStopped) {
-                    copy(mLastHealthInfo, mHealthInfo);
-                }
-                mHealthInfo.chargerAcOnline = false;
-                mHealthInfo.chargerUsbOnline = false;
-                mHealthInfo.chargerWirelessOnline = false;
-                final long ident = Binder.clearCallingIdentity();
-                try {
-                    mUpdatesStopped = true;
-                    processValuesFromShellLocked(pw, opts);
-                } finally {
-                    Binder.restoreCallingIdentity(ident);
-                }
+                unplugBattery(/* forceUpdate= */ (opts & OPTION_FORCE_UPDATE) != 0, pw);
             } break;
             case "set": {
                 int opts = parseOptions(shell);
@@ -990,7 +978,8 @@
                         final long ident = Binder.clearCallingIdentity();
                         try {
                             mUpdatesStopped = true;
-                            processValuesFromShellLocked(pw, opts);
+                            processValuesLocked(
+                                    /* forceUpdate= */ (opts & OPTION_FORCE_UPDATE) != 0, pw);
                         } finally {
                             Binder.restoreCallingIdentity(ident);
                         }
@@ -1004,30 +993,12 @@
                 int opts = parseOptions(shell);
                 getContext().enforceCallingOrSelfPermission(
                         android.Manifest.permission.DEVICE_POWER, null);
-                final long ident = Binder.clearCallingIdentity();
-                try {
-                    if (mUpdatesStopped) {
-                        mUpdatesStopped = false;
-                        copy(mHealthInfo, mLastHealthInfo);
-                        processValuesFromShellLocked(pw, opts);
-                    }
-                } finally {
-                    Binder.restoreCallingIdentity(ident);
-                }
-                if (mBatteryInputSuspended) {
-                    PowerProperties.battery_input_suspended(false);
-                    mBatteryInputSuspended = false;
-                }
+                resetBattery(/* forceUpdate= */ (opts & OPTION_FORCE_UPDATE) != 0, pw);
             } break;
             case "suspend_input": {
-                if (!Build.IS_DEBUGGABLE) {
-                    throw new SecurityException(
-                            "battery suspend_input is only supported on debuggable builds");
-                }
                 getContext().enforceCallingOrSelfPermission(
                         android.Manifest.permission.DEVICE_POWER, null);
-                PowerProperties.battery_input_suspended(true);
-                mBatteryInputSuspended = true;
+                suspendBatteryInput();
             } break;
             default:
                 return shell.handleDefaultCommands(cmd);
@@ -1035,9 +1006,59 @@
         return 0;
     }
 
-    private void processValuesFromShellLocked(PrintWriter pw, int opts) {
-        processValuesLocked((opts & OPTION_FORCE_UPDATE) != 0);
-        if ((opts & OPTION_FORCE_UPDATE) != 0) {
+    private void setChargerAcOnline(boolean online, boolean forceUpdate) {
+        if (!mUpdatesStopped) {
+            copy(mLastHealthInfo, mHealthInfo);
+        }
+        mHealthInfo.chargerAcOnline = online;
+        mUpdatesStopped = true;
+        Binder.withCleanCallingIdentity(() -> processValuesLocked(forceUpdate));
+    }
+
+    private void setBatteryLevel(int level, boolean forceUpdate) {
+        if (!mUpdatesStopped) {
+            copy(mLastHealthInfo, mHealthInfo);
+        }
+        mHealthInfo.batteryLevel = level;
+        mUpdatesStopped = true;
+        Binder.withCleanCallingIdentity(() -> processValuesLocked(forceUpdate));
+    }
+
+    private void unplugBattery(boolean forceUpdate, PrintWriter pw) {
+        if (!mUpdatesStopped) {
+            copy(mLastHealthInfo, mHealthInfo);
+        }
+        mHealthInfo.chargerAcOnline = false;
+        mHealthInfo.chargerUsbOnline = false;
+        mHealthInfo.chargerWirelessOnline = false;
+        mUpdatesStopped = true;
+        Binder.withCleanCallingIdentity(() -> processValuesLocked(forceUpdate, pw));
+    }
+
+    private void resetBattery(boolean forceUpdate, @Nullable PrintWriter pw) {
+        if (mUpdatesStopped) {
+            mUpdatesStopped = false;
+            copy(mHealthInfo, mLastHealthInfo);
+            Binder.withCleanCallingIdentity(() -> processValuesLocked(forceUpdate, pw));
+        }
+        if (mBatteryInputSuspended) {
+            PowerProperties.battery_input_suspended(false);
+            mBatteryInputSuspended = false;
+        }
+    }
+
+    private void suspendBatteryInput() {
+        if (!Build.IS_DEBUGGABLE) {
+            throw new SecurityException(
+                    "battery suspend_input is only supported on debuggable builds");
+        }
+        PowerProperties.battery_input_suspended(true);
+        mBatteryInputSuspended = true;
+    }
+
+    private void processValuesLocked(boolean forceUpdate, @Nullable PrintWriter pw) {
+        processValuesLocked(forceUpdate);
+        if (pw != null && forceUpdate) {
             pw.println(mSequence);
         }
     }
@@ -1363,6 +1384,41 @@
                 return mInvalidCharger;
             }
         }
+
+        @Override
+        public void setChargerAcOnline(boolean online, boolean forceUpdate) {
+            getContext().enforceCallingOrSelfPermission(
+                    android.Manifest.permission.DEVICE_POWER, /* message= */ null);
+            BatteryService.this.setChargerAcOnline(online, forceUpdate);
+        }
+
+        @Override
+        public void setBatteryLevel(int level, boolean forceUpdate) {
+            getContext().enforceCallingOrSelfPermission(
+                    android.Manifest.permission.DEVICE_POWER, /* message= */ null);
+            BatteryService.this.setBatteryLevel(level, forceUpdate);
+        }
+
+        @Override
+        public void unplugBattery(boolean forceUpdate) {
+            getContext().enforceCallingOrSelfPermission(
+                    android.Manifest.permission.DEVICE_POWER, /* message= */ null);
+            BatteryService.this.unplugBattery(forceUpdate, /* printWriter= */ null);
+        }
+
+        @Override
+        public void resetBattery(boolean forceUpdate) {
+            getContext().enforceCallingOrSelfPermission(
+                    android.Manifest.permission.DEVICE_POWER, /* message= */ null);
+            BatteryService.this.resetBattery(forceUpdate, /* printWriter= */ null);
+        }
+
+        @Override
+        public void suspendBatteryInput() {
+            getContext().enforceCallingOrSelfPermission(
+                    android.Manifest.permission.DEVICE_POWER, /* message= */ null);
+            BatteryService.this.suspendBatteryInput();
+        }
     }
 
     /**
@@ -1539,6 +1595,8 @@
                             if (Objects.equals(newService, oldService)) return;
 
                             Slog.i(TAG, "health: new instance registered " + mInstanceName);
+                            // #init() may be called with null callback. Skip null callbacks.
+                            if (mCallback == null) return;
                             mCallback.onRegistration(oldService, newService, mInstanceName);
                         } catch (NoSuchElementException | RemoteException ex) {
                             Slog.e(TAG, "health: Cannot get instance '" + mInstanceName
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 72d32636..b4fcaee 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -85,6 +85,7 @@
 import android.net.ConnectivityDiagnosticsManager.ConnectivityReport;
 import android.net.ConnectivityDiagnosticsManager.DataStallReport;
 import android.net.ConnectivityManager;
+import android.net.ConnectivityManager.NetworkCallback;
 import android.net.DataStallReportParcelable;
 import android.net.DnsResolverServiceManager;
 import android.net.ICaptivePortal;
@@ -189,7 +190,6 @@
 import com.android.connectivity.aidl.INetworkAgent;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.AsyncChannel;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.LocationPermissionChecker;
 import com.android.internal.util.MessageUtils;
@@ -345,8 +345,7 @@
     private String mCurrentTcpBufferSizes;
 
     private static final SparseArray<String> sMagicDecoderRing = MessageUtils.findMessageNames(
-            new Class[] { AsyncChannel.class, ConnectivityService.class, NetworkAgent.class,
-                    NetworkAgentInfo.class });
+            new Class[] { ConnectivityService.class, NetworkAgent.class, NetworkAgentInfo.class });
 
     private enum ReapUnvalidatedNetworks {
         // Tear down networks that have no chance (e.g. even if validated) of becoming
@@ -1108,7 +1107,8 @@
         mNetworkRanker = new NetworkRanker();
         final NetworkRequest defaultInternetRequest = createDefaultRequest();
         mDefaultRequest = new NetworkRequestInfo(
-                defaultInternetRequest, null, new Binder(),
+                defaultInternetRequest, null,
+                new Binder(), NetworkCallback.FLAG_INCLUDE_LOCATION_INFO,
                 null /* attributionTags */);
         mNetworkRequests.put(defaultInternetRequest, mDefaultRequest);
         mDefaultNetworkRequests.add(mDefaultRequest);
@@ -1358,7 +1358,9 @@
 
         if (enable) {
             handleRegisterNetworkRequest(new NetworkRequestInfo(
-                    networkRequest, null, new Binder(),
+                    networkRequest, null,
+                    new Binder(),
+                    NetworkCallback.FLAG_INCLUDE_LOCATION_INFO,
                     null /* attributionTags */));
         } else {
             handleReleaseNetworkRequest(networkRequest, Process.SYSTEM_UID,
@@ -1719,8 +1721,8 @@
                 result.put(
                         nai.network,
                         createWithLocationInfoSanitizedIfNecessaryWhenParceled(
-                                nc, mDeps.getCallingUid(), callingPackageName,
-                                callingAttributionTag));
+                                nc, false /* includeLocationSensitiveInfo */,
+                                mDeps.getCallingUid(), callingPackageName, callingAttributionTag));
             }
         }
 
@@ -1733,7 +1735,9 @@
                     result.put(
                             network,
                             createWithLocationInfoSanitizedIfNecessaryWhenParceled(
-                                    nc, mDeps.getCallingUid(), callingPackageName,
+                                    nc,
+                                    false /* includeLocationSensitiveInfo */,
+                                    mDeps.getCallingUid(), callingPackageName,
                                     callingAttributionTag));
                 }
             }
@@ -1815,6 +1819,7 @@
         enforceAccessPermission();
         return createWithLocationInfoSanitizedIfNecessaryWhenParceled(
                 getNetworkCapabilitiesInternal(network),
+                false /* includeLocationSensitiveInfo */,
                 mDeps.getCallingUid(), callingPackageName, callingAttributionTag);
     }
 
@@ -1848,8 +1853,8 @@
     @VisibleForTesting
     @Nullable
     NetworkCapabilities createWithLocationInfoSanitizedIfNecessaryWhenParceled(
-            @Nullable NetworkCapabilities nc, int callerUid, @NonNull String callerPkgName,
-            @Nullable String callingAttributionTag) {
+            @Nullable NetworkCapabilities nc, boolean includeLocationSensitiveInfo,
+            int callerUid, @NonNull String callerPkgName, @Nullable String callingAttributionTag) {
         if (nc == null) {
             return null;
         }
@@ -1857,7 +1862,9 @@
         final NetworkCapabilities newNc;
         // Avoid doing location permission check if the transport info has no location sensitive
         // data.
-        if (nc.getTransportInfo() != null && nc.getTransportInfo().hasLocationSensitiveFields()) {
+        if (includeLocationSensitiveInfo
+                && nc.getTransportInfo() != null
+                && nc.getTransportInfo().hasLocationSensitiveFields()) {
             hasLocationPermission =
                     hasLocationPermission(callerUid, callerPkgName, callingAttributionTag);
             newNc = new NetworkCapabilities(nc, hasLocationPermission);
@@ -1874,6 +1881,16 @@
             // Owner UIDs already checked above. No need to re-check.
             return newNc;
         }
+        // If the caller does not want location sensitive data & target SDK >= S, then mask info.
+        // Else include the owner UID iff the caller has location permission to provide backwards
+        // compatibility for older apps.
+        if (!includeLocationSensitiveInfo
+                && isTargetSdkAtleast(
+                        Build.VERSION_CODES.S, callerUid, callerPkgName)) {
+            newNc.setOwnerUid(INVALID_UID);
+            return newNc;
+        }
+
         if (hasLocationPermission == null) {
             // Location permission not checked yet, check now for masking owner UID.
             hasLocationPermission =
@@ -2892,22 +2909,6 @@
             super(looper);
         }
 
-        private boolean maybeHandleAsyncChannelMessage(Message msg) {
-            switch (msg.what) {
-                default:
-                    return false;
-                case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: {
-                    handleAsyncChannelHalfConnect(msg);
-                    break;
-                }
-                case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
-                    handleAsyncChannelDisconnected(msg);
-                    break;
-                }
-            }
-            return true;
-        }
-
         private void maybeHandleNetworkAgentMessage(Message msg) {
             final Pair<NetworkAgentInfo, Object> arg = (Pair<NetworkAgentInfo, Object>) msg.obj;
             final NetworkAgentInfo nai = arg.first;
@@ -3199,8 +3200,7 @@
 
         @Override
         public void handleMessage(Message msg) {
-            if (!maybeHandleAsyncChannelMessage(msg)
-                    && !maybeHandleNetworkMonitorMessage(msg)
+            if (!maybeHandleNetworkMonitorMessage(msg)
                     && !maybeHandleNetworkAgentInfoMessage(msg)) {
                 maybeHandleNetworkAgentMessage(msg);
             }
@@ -3464,21 +3464,6 @@
         return false;
     }
 
-    private void handleAsyncChannelHalfConnect(Message msg) {
-        ensureRunningOnConnectivityServiceThread();
-        if (mNetworkProviderInfos.containsKey(msg.replyTo)) {
-            if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
-                if (VDBG) log("NetworkFactory connected");
-                // Finish setting up the full connection
-                NetworkProviderInfo npi = mNetworkProviderInfos.get(msg.replyTo);
-                sendAllRequestsToProvider(npi);
-            } else {
-                loge("Error connecting NetworkFactory");
-                mNetworkProviderInfos.remove(msg.obj);
-            }
-        }
-    }
-
     private void handleNetworkAgentRegistered(Message msg) {
         final NetworkAgentInfo nai = (NetworkAgentInfo) msg.obj;
         if (!mNetworkAgentInfos.contains(nai)) {
@@ -3509,14 +3494,6 @@
         }
     }
 
-    // This is a no-op if it's called with a message designating a provider that has
-    // already been destroyed, because its reference will not be found in the relevant
-    // maps.
-    private void handleAsyncChannelDisconnected(Message msg) {
-        NetworkProviderInfo npi = mNetworkProviderInfos.remove(msg.replyTo);
-        if (DBG && npi != null) log("unregisterNetworkFactory for " + npi.name);
-    }
-
     // Destroys a network, remove references to it from the internal state managed by
     // ConnectivityService, free its interfaces and clean up.
     // Must be called on the Handler thread.
@@ -5159,8 +5136,8 @@
         private final IBinder.DeathRecipient mDeathRecipient;
         public final int providerId;
 
-        NetworkProviderInfo(String name, Messenger messenger, AsyncChannel asyncChannel,
-                int providerId, @NonNull IBinder.DeathRecipient deathRecipient) {
+        NetworkProviderInfo(String name, Messenger messenger, int providerId,
+                @NonNull IBinder.DeathRecipient deathRecipient) {
             this.name = name;
             this.messenger = messenger;
             this.providerId = providerId;
@@ -5254,6 +5231,7 @@
         private final IBinder mBinder;
         final int mPid;
         final int mUid;
+        final @NetworkCallback.Flag int mCallbackFlags;
         @Nullable
         final String mCallingAttributionTag;
         // In order to preserve the mapping of NetworkRequest-to-callback when apps register
@@ -5301,17 +5279,26 @@
             mPid = getCallingPid();
             mUid = mDeps.getCallingUid();
             mNetworkRequestCounter.incrementCountOrThrow(mUid);
+            /**
+             * Location sensitive data not included in pending intent. Only included in
+             * {@link NetworkCallback}.
+             */
+            mCallbackFlags = NetworkCallback.FLAG_NONE;
             mCallingAttributionTag = callingAttributionTag;
         }
 
         NetworkRequestInfo(@NonNull final NetworkRequest r, @Nullable final Messenger m,
-                @Nullable final IBinder binder, @Nullable String callingAttributionTag) {
-            this(Collections.singletonList(r), r, m, binder, callingAttributionTag);
+                @Nullable final IBinder binder,
+                @NetworkCallback.Flag int callbackFlags,
+                @Nullable String callingAttributionTag) {
+            this(Collections.singletonList(r), r, m, binder, callbackFlags, callingAttributionTag);
         }
 
         NetworkRequestInfo(@NonNull final List<NetworkRequest> r,
                 @NonNull final NetworkRequest requestForCallback, @Nullable final Messenger m,
-                @Nullable final IBinder binder, @Nullable String callingAttributionTag) {
+                @Nullable final IBinder binder,
+                @NetworkCallback.Flag int callbackFlags,
+                @Nullable String callingAttributionTag) {
             super();
             ensureAllNetworkRequestsHaveType(r);
             mRequests = initializeRequests(r);
@@ -5322,6 +5309,7 @@
             mUid = mDeps.getCallingUid();
             mPendingIntent = null;
             mNetworkRequestCounter.incrementCountOrThrow(mUid);
+            mCallbackFlags = callbackFlags;
             mCallingAttributionTag = callingAttributionTag;
 
             try {
@@ -5363,6 +5351,7 @@
             mUid = nri.mUid;
             mPendingIntent = nri.mPendingIntent;
             mNetworkRequestCounter.incrementCountOrThrow(mUid);
+            mCallbackFlags = nri.mCallbackFlags;
             mCallingAttributionTag = nri.mCallingAttributionTag;
         }
 
@@ -5412,7 +5401,8 @@
                     + " callback request Id: "
                     + mNetworkRequestForCallback.requestId
                     + " " + mRequests
-                    + (mPendingIntent == null ? "" : " to trigger " + mPendingIntent);
+                    + (mPendingIntent == null ? "" : " to trigger " + mPendingIntent)
+                    + "callback flags: " + mCallbackFlags;
         }
     }
 
@@ -5496,13 +5486,13 @@
         }
     }
 
-    private boolean checkUnsupportedStartingFrom(int version, String callingPackageName) {
-        final UserHandle user = UserHandle.getUserHandleForUid(mDeps.getCallingUid());
+    private boolean isTargetSdkAtleast(int version, int callingUid,
+            @NonNull String callingPackageName) {
+        final UserHandle user = UserHandle.getUserHandleForUid(callingUid);
         final PackageManager pm =
                 mContext.createContextAsUser(user, 0 /* flags */).getPackageManager();
         try {
-            final int callingVersion = pm.getApplicationInfo(
-                    callingPackageName, 0 /* flags */).targetSdkVersion;
+            final int callingVersion = pm.getTargetSdkVersion(callingPackageName);
             if (callingVersion < version) return false;
         } catch (PackageManager.NameNotFoundException e) { }
         return true;
@@ -5511,10 +5501,11 @@
     @Override
     public NetworkRequest requestNetwork(NetworkCapabilities networkCapabilities,
             int reqTypeInt, Messenger messenger, int timeoutMs, IBinder binder,
-            int legacyType, @NonNull String callingPackageName,
+            int legacyType, int callbackFlags, @NonNull String callingPackageName,
             @Nullable String callingAttributionTag) {
         if (legacyType != TYPE_NONE && !checkNetworkStackPermission()) {
-            if (checkUnsupportedStartingFrom(Build.VERSION_CODES.M, callingPackageName)) {
+            if (isTargetSdkAtleast(Build.VERSION_CODES.M, mDeps.getCallingUid(),
+                    callingPackageName)) {
                 throw new SecurityException("Insufficient permissions to specify legacy type");
             }
         }
@@ -5576,7 +5567,7 @@
         final NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, legacyType,
                 nextNetworkRequestId(), reqType);
         final NetworkRequestInfo nri = getNriToRegister(
-                networkRequest, messenger, binder, callingAttributionTag);
+                networkRequest, messenger, binder, callbackFlags, callingAttributionTag);
         if (DBG) log("requestNetwork for " + nri);
 
         // For TRACK_SYSTEM_DEFAULT callbacks, the capabilities have been modified since they were
@@ -5611,6 +5602,7 @@
      */
     private NetworkRequestInfo getNriToRegister(@NonNull final NetworkRequest nr,
             @Nullable final Messenger msgr, @Nullable final IBinder binder,
+            @NetworkCallback.Flag int callbackFlags,
             @Nullable String callingAttributionTag) {
         final List<NetworkRequest> requests;
         if (NetworkRequest.Type.TRACK_DEFAULT == nr.type) {
@@ -5619,7 +5611,8 @@
         } else {
             requests = Collections.singletonList(nr);
         }
-        return new NetworkRequestInfo(requests, nr, msgr, binder, callingAttributionTag);
+        return new NetworkRequestInfo(
+                requests, nr, msgr, binder, callbackFlags, callingAttributionTag);
     }
 
     private void enforceNetworkRequestPermissions(NetworkCapabilities networkCapabilities,
@@ -5745,8 +5738,9 @@
 
     @Override
     public NetworkRequest listenForNetwork(NetworkCapabilities networkCapabilities,
-            Messenger messenger, IBinder binder, @NonNull String callingPackageName,
-            @Nullable String callingAttributionTag) {
+            Messenger messenger, IBinder binder,
+            @NetworkCallback.Flag int callbackFlags,
+            @NonNull String callingPackageName, @NonNull String callingAttributionTag) {
         final int callingUid = mDeps.getCallingUid();
         if (!hasWifiNetworkListenPermission(networkCapabilities)) {
             enforceAccessPermission();
@@ -5767,7 +5761,8 @@
         NetworkRequest networkRequest = new NetworkRequest(nc, TYPE_NONE, nextNetworkRequestId(),
                 NetworkRequest.Type.LISTEN);
         NetworkRequestInfo nri =
-                new NetworkRequestInfo(networkRequest, messenger, binder, callingAttributionTag);
+                new NetworkRequestInfo(networkRequest, messenger, binder, callbackFlags,
+                        callingAttributionTag);
         if (VDBG) log("listenForNetwork for " + nri);
 
         mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_LISTENER, nri));
@@ -5836,8 +5831,7 @@
     public int registerNetworkProvider(Messenger messenger, String name) {
         enforceNetworkFactoryOrSettingsPermission();
         NetworkProviderInfo npi = new NetworkProviderInfo(name, messenger,
-                null /* asyncChannel */, nextNetworkProviderId(),
-                () -> unregisterNetworkProvider(messenger));
+                nextNetworkProviderId(), () -> unregisterNetworkProvider(messenger));
         mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_PROVIDER, npi));
         return npi.providerId;
     }
@@ -7101,6 +7095,8 @@
         if (notificationType != ConnectivityManager.CALLBACK_UNAVAIL) {
             putParcelable(bundle, networkAgent.network);
         }
+        final boolean includeLocationSensitiveInfo =
+                (nri.mCallbackFlags & NetworkCallback.FLAG_INCLUDE_LOCATION_INFO) != 0;
         switch (notificationType) {
             case ConnectivityManager.CALLBACK_AVAILABLE: {
                 final NetworkCapabilities nc =
@@ -7109,7 +7105,8 @@
                 putParcelable(
                         bundle,
                         createWithLocationInfoSanitizedIfNecessaryWhenParceled(
-                                nc, nri.mUid, nrForCallback.getRequestorPackageName(),
+                                nc, includeLocationSensitiveInfo, nri.mUid,
+                                nrForCallback.getRequestorPackageName(),
                                 nri.mCallingAttributionTag));
                 putParcelable(bundle, linkPropertiesRestrictedForCallerPermissions(
                         networkAgent.linkProperties, nri.mPid, nri.mUid));
@@ -7129,7 +7126,8 @@
                 putParcelable(
                         bundle,
                         createWithLocationInfoSanitizedIfNecessaryWhenParceled(
-                                netCap, nri.mUid, nrForCallback.getRequestorPackageName(),
+                                netCap, includeLocationSensitiveInfo, nri.mUid,
+                                nrForCallback.getRequestorPackageName(),
                                 nri.mCallingAttributionTag));
                 break;
             }
diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java
index 81d4b9d..4c3c6ef 100644
--- a/services/core/java/com/android/server/IpSecService.java
+++ b/services/core/java/com/android/server/IpSecService.java
@@ -56,6 +56,7 @@
 import android.system.OsConstants;
 import android.text.TextUtils;
 import android.util.Log;
+import android.util.Range;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
@@ -756,13 +757,9 @@
         }
     }
 
-    // These values have been reserved in NetIdManager
-    @VisibleForTesting static final int TUN_INTF_NETID_START = 0xFC00;
-
-    public static final int TUN_INTF_NETID_RANGE = 0x0400;
-
     private final SparseBooleanArray mTunnelNetIds = new SparseBooleanArray();
-    private int mNextTunnelNetIdIndex = 0;
+    final Range<Integer> mNetIdRange = ConnectivityManager.getIpSecNetIdRange();
+    private int mNextTunnelNetId = mNetIdRange.getLower();
 
     /**
      * Reserves a netId within the range of netIds allocated for IPsec tunnel interfaces
@@ -775,11 +772,13 @@
      */
     @VisibleForTesting
     int reserveNetId() {
+        final int range = mNetIdRange.getUpper() - mNetIdRange.getLower() + 1;
         synchronized (mTunnelNetIds) {
-            for (int i = 0; i < TUN_INTF_NETID_RANGE; i++) {
-                int index = mNextTunnelNetIdIndex;
-                int netId = index + TUN_INTF_NETID_START;
-                if (++mNextTunnelNetIdIndex >= TUN_INTF_NETID_RANGE) mNextTunnelNetIdIndex = 0;
+            for (int i = 0; i < range; i++) {
+                final int netId = mNextTunnelNetId;
+                if (++mNextTunnelNetId > mNetIdRange.getUpper()) {
+                    mNextTunnelNetId = mNetIdRange.getLower();
+                }
                 if (!mTunnelNetIds.get(netId)) {
                     mTunnelNetIds.put(netId, true);
                     return netId;
diff --git a/services/core/java/com/android/server/NetIdManager.java b/services/core/java/com/android/server/NetIdManager.java
index 097fb3a..61925c8 100644
--- a/services/core/java/com/android/server/NetIdManager.java
+++ b/services/core/java/com/android/server/NetIdManager.java
@@ -17,6 +17,7 @@
 package com.android.server;
 
 import android.annotation.NonNull;
+import android.net.ConnectivityManager;
 import android.util.SparseBooleanArray;
 
 import com.android.internal.annotations.GuardedBy;
@@ -31,7 +32,7 @@
     // Sequence number for Networks; keep in sync with system/netd/NetworkController.cpp
     public static final int MIN_NET_ID = 100; // some reserved marks
     // Top IDs reserved by IpSecService
-    public static final int MAX_NET_ID = 65535 - IpSecService.TUN_INTF_NETID_RANGE;
+    public static final int MAX_NET_ID = ConnectivityManager.getIpSecNetIdRange().getLower() - 1;
 
     @GuardedBy("mNetIdInUse")
     private final SparseBooleanArray mNetIdInUse = new SparseBooleanArray();
diff --git a/services/core/java/com/android/server/OWNERS b/services/core/java/com/android/server/OWNERS
index e12586b..c983600 100644
--- a/services/core/java/com/android/server/OWNERS
+++ b/services/core/java/com/android/server/OWNERS
@@ -18,6 +18,7 @@
 
 per-file *Alarm* = file:/apex/jobscheduler/OWNERS
 per-file *AppOp* = file:/core/java/android/permission/OWNERS
+per-file *Battery* = file:/BATTERY_STATS_OWNERS
 per-file *Bluetooth* = file:/core/java/android/bluetooth/OWNERS
 per-file *Gnss* = file:/services/core/java/com/android/server/location/OWNERS
 per-file *Location* = file:/services/core/java/com/android/server/location/OWNERS
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index a9904ba..5adbdff 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -318,7 +318,8 @@
 
     private int[] mDataEnabledReason;
 
-    private Map<Integer, Long> mAllowedNetworkTypesList;
+    private int[] mAllowedNetworkTypeReason;
+    private long[] mAllowedNetworkTypeValue;
 
     /**
      * Per-phone map of precise data connection state. The key of the map is the pair of transport
@@ -383,7 +384,8 @@
     private boolean isPrivilegedPhoneStatePermissionRequired(Set<Integer> events) {
         return events.contains(TelephonyCallback.EVENT_SRVCC_STATE_CHANGED)
                 || events.contains(TelephonyCallback.EVENT_VOICE_ACTIVATION_STATE_CHANGED)
-                || events.contains(TelephonyCallback.EVENT_RADIO_POWER_STATE_CHANGED);
+                || events.contains(TelephonyCallback.EVENT_RADIO_POWER_STATE_CHANGED)
+                || events.contains(TelephonyCallback.EVENT_ALLOWED_NETWORK_TYPE_LIST_CHANGED);
     }
 
     private static final int MSG_USER_SWITCHED = 1;
@@ -527,6 +529,8 @@
         mTelephonyDisplayInfos = copyOf(mTelephonyDisplayInfos, mNumPhones);
         mIsDataEnabled= copyOf(mIsDataEnabled, mNumPhones);
         mDataEnabledReason = copyOf(mDataEnabledReason, mNumPhones);
+        mAllowedNetworkTypeReason = copyOf(mAllowedNetworkTypeReason, mNumPhones);
+        mAllowedNetworkTypeValue = copyOf(mAllowedNetworkTypeValue, mNumPhones);
 
         // ds -> ss switch.
         if (mNumPhones < oldNumPhones) {
@@ -571,6 +575,8 @@
             mIsDataEnabled[i] = false;
             mDataEnabledReason[i] = TelephonyManager.DATA_ENABLED_REASON_USER;
             mPhysicalChannelConfigs.add(i, new PhysicalChannelConfig.Builder().build());
+            mAllowedNetworkTypeReason[i] = -1;
+            mAllowedNetworkTypeValue[i] = -1;
         }
     }
 
@@ -630,9 +636,11 @@
         mBarringInfo = new ArrayList<>();
         mTelephonyDisplayInfos = new TelephonyDisplayInfo[numPhones];
         mPhysicalChannelConfigs = new ArrayList<>();
-        mAllowedNetworkTypesList = new HashMap<>();
+        mAllowedNetworkTypeReason = new int[numPhones];
+        mAllowedNetworkTypeValue = new long[numPhones];
         mIsDataEnabled = new boolean[numPhones];
         mDataEnabledReason = new int[numPhones];
+
         for (int i = 0; i < numPhones; i++) {
             mCallState[i] =  TelephonyManager.CALL_STATE_IDLE;
             mDataActivity[i] = TelephonyManager.DATA_ACTIVITY_NONE;
@@ -665,6 +673,8 @@
             mIsDataEnabled[i] = false;
             mDataEnabledReason[i] = TelephonyManager.DATA_ENABLED_REASON_USER;
             mPhysicalChannelConfigs.add(i, new PhysicalChannelConfig.Builder().build());
+            mAllowedNetworkTypeReason[i] = -1;
+            mAllowedNetworkTypeValue[i] = -1;
         }
 
         mAppOps = mContext.getSystemService(AppOpsManager.class);
@@ -1172,14 +1182,6 @@
                         remove(r.binder);
                     }
                 }
-                if (events.contains(
-                        TelephonyCallback.EVENT_ALLOWED_NETWORK_TYPE_LIST_CHANGED)) {
-                    try {
-                        r.callback.onAllowedNetworkTypesChanged(mAllowedNetworkTypesList);
-                    } catch (RemoteException ex) {
-                        remove(r.binder);
-                    }
-                }
             }
         }
     }
@@ -2454,18 +2456,19 @@
      *
      * @param phoneId the phone id.
      * @param subId the subId.
-     * @param allowedNetworkTypesList Map associating all allowed network type reasons with reason's
-     *                                allowed network type values.
+     * @param reason the allowed network type reason.
+     * @param allowedNetworkType the allowed network type value.
      */
-    public void notifyAllowedNetworkTypesChanged(int phoneId, int subId,
-            Map allowedNetworkTypesList) {
+    public void notifyAllowedNetworkTypesChanged(int phoneId, int subId, int reason,
+            long allowedNetworkType) {
         if (!checkNotifyPermission("notifyAllowedNetworkTypesChanged()")) {
             return;
         }
 
         synchronized (mRecords) {
             if (validatePhoneId(phoneId)) {
-                mAllowedNetworkTypesList = allowedNetworkTypesList;
+                mAllowedNetworkTypeReason[phoneId] = reason;
+                mAllowedNetworkTypeValue[phoneId] = allowedNetworkType;
 
                 for (Record r : mRecords) {
                     if (r.matchTelephonyCallbackEvent(
@@ -2473,10 +2476,12 @@
                             && idMatch(r.subId, subId, phoneId)) {
                         try {
                             if (VDBG) {
-                                log("notifyAllowedNetworkTypesChanged: AllowedNetworkTypesList= "
-                                        + mAllowedNetworkTypesList.toString());
+                                log("notifyAllowedNetworkTypesChanged: reason= " + reason
+                                        + ", allowed network type:"
+                                        + TelephonyManager.convertNetworkTypeBitmaskToString(
+                                        allowedNetworkType));
                             }
-                            r.callback.onAllowedNetworkTypesChanged(mAllowedNetworkTypesList);
+                            r.callback.onAllowedNetworkTypesChanged(reason, allowedNetworkType);
                         } catch (RemoteException ex) {
                             mRemoveList.add(r.binder);
                         }
@@ -2531,6 +2536,8 @@
                 pw.println("mTelephonyDisplayInfo=" + mTelephonyDisplayInfos[i]);
                 pw.println("mIsDataEnabled=" + mIsDataEnabled);
                 pw.println("mDataEnabledReason=" + mDataEnabledReason);
+                pw.println("mAllowedNetworkTypeReason=" + mAllowedNetworkTypeReason[i]);
+                pw.println("mAllowedNetworkTypeValue=" + mAllowedNetworkTypeValue[i]);
                 pw.decreaseIndent();
             }
             pw.println("mCarrierNetworkChangeState=" + mCarrierNetworkChangeState);
diff --git a/services/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java
index cd3892d..140f24f 100644
--- a/services/core/java/com/android/server/VcnManagementService.java
+++ b/services/core/java/com/android/server/VcnManagementService.java
@@ -666,6 +666,10 @@
             @NonNull IVcnUnderlyingNetworkPolicyListener listener) {
         requireNonNull(listener, "listener was null");
 
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.NETWORK_FACTORY,
+                "Must have permission NETWORK_FACTORY to unregister a policy listener");
+
         Binder.withCleanCallingIdentity(() -> {
             synchronized (mLock) {
                 PolicyListenerBinderDeath listenerBinderDeath =
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 68c4a73..673749c 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -1841,7 +1841,7 @@
                     ServiceState stracker = r.getTracker();
                     if (stracker != null) {
                         stracker.setForeground(false, mAm.mProcessStats.getMemFactorLocked(),
-                                r.lastActivity);
+                                SystemClock.uptimeMillis());
                     }
                 }
                 if (alreadyStartedOp) {
@@ -1863,7 +1863,7 @@
                 ServiceState stracker = r.getTracker();
                 if (stracker != null) {
                     stracker.setForeground(false, mAm.mProcessStats.getMemFactorLocked(),
-                            r.lastActivity);
+                            SystemClock.uptimeMillis());
                 }
                 mAm.mAppOpsService.finishOperation(
                         AppOpsManager.getToken(mAm.mAppOpsService),
@@ -3765,6 +3765,7 @@
             }
         }
 
+        final long now = SystemClock.uptimeMillis();
         // Check to see if the service had been started as foreground, but being
         // brought down before actually showing a notification.  That is not allowed.
         if (r.fgRequired) {
@@ -3774,8 +3775,7 @@
             r.fgWaiting = false;
             ServiceState stracker = r.getTracker();
             if (stracker != null) {
-                stracker.setForeground(false, mAm.mProcessStats.getMemFactorLocked(),
-                        r.lastActivity);
+                stracker.setForeground(false, mAm.mProcessStats.getMemFactorLocked(), now);
             }
             mAm.mAppOpsService.finishOperation(AppOpsManager.getToken(mAm.mAppOpsService),
                     AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName, null);
@@ -3834,8 +3834,7 @@
             decActiveForegroundAppLocked(smap, r);
             ServiceState stracker = r.getTracker();
             if (stracker != null) {
-                stracker.setForeground(false, mAm.mProcessStats.getMemFactorLocked(),
-                        r.lastActivity);
+                stracker.setForeground(false, mAm.mProcessStats.getMemFactorLocked(), now);
             }
             mAm.mAppOpsService.finishOperation(
                     AppOpsManager.getToken(mAm.mAppOpsService),
@@ -3902,7 +3901,6 @@
         }
 
         int memFactor = mAm.mProcessStats.getMemFactorLocked();
-        long now = SystemClock.uptimeMillis();
         if (r.tracker != null) {
             r.tracker.setStarted(false, memFactor, now);
             r.tracker.setBound(false, memFactor, now);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 8ea6194..06a1abb 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -44,11 +44,11 @@
 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.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;
 import static android.os.IServiceManager.DUMP_FLAG_PROTO;
+import static android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
 import static android.os.PowerWhitelistManager.REASON_SYSTEM_ALLOW_LISTED;
 import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
 import static android.os.Process.BLUETOOTH_UID;
@@ -273,6 +273,9 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.os.WorkSource;
+import android.os.incremental.IIncrementalService;
+import android.os.incremental.IncrementalManager;
+import android.os.incremental.IncrementalMetrics;
 import android.os.storage.IStorageManager;
 import android.os.storage.StorageManager;
 import android.provider.DeviceConfig;
@@ -7697,18 +7700,32 @@
      */
     void handleApplicationCrashInner(String eventType, ProcessRecord r, String processName,
             ApplicationErrorReport.CrashInfo crashInfo) {
-        boolean isPackageLoading = false;
+        boolean isIncremental = false;
+        float loadingProgress = 1;
+        long millisSinceOldestPendingRead = 0;
         // Notify package manager service to possibly update package state
         if (r != null && r.info != null && r.info.packageName != null) {
+            final String codePath = r.info.getCodePath();
             mPackageManagerInt.notifyPackageCrashOrAnr(r.info.packageName);
             IncrementalStatesInfo incrementalStatesInfo =
                     mPackageManagerInt.getIncrementalStatesInfo(r.info.packageName, r.uid,
                             r.userId);
-            isPackageLoading = incrementalStatesInfo.isLoading();
-            if (isPackageLoading) {
-                // Report in the main log that the package is still loading
-                Slog.e(TAG, "App crashed when package " + r.info.packageName + " is "
-                        + ((int) (incrementalStatesInfo.getProgress() * 100)) + "% loaded.");
+            if (incrementalStatesInfo != null) {
+                loadingProgress = incrementalStatesInfo.getProgress();
+            }
+            isIncremental = IncrementalManager.isIncrementalPath(codePath);
+            if (isIncremental) {
+                // Report in the main log about the incremental package
+                Slog.e(TAG, "App crashed on incremental package " + r.info.packageName
+                        + " which is " + ((int) (loadingProgress * 100)) + "% loaded.");
+                final IBinder incrementalService = ServiceManager.getService(
+                        Context.INCREMENTAL_SERVICE);
+                if (incrementalService != null) {
+                    final IncrementalManager incrementalManager = new IncrementalManager(
+                            IIncrementalService.Stub.asInterface(incrementalService));
+                    IncrementalMetrics metrics = incrementalManager.getMetrics(codePath);
+                    millisSinceOldestPendingRead = metrics.getMillisSinceOldestPendingRead();
+                }
             }
         }
 
@@ -7737,7 +7754,7 @@
                 processName.equals("system_server") ? ServerProtoEnums.SYSTEM_SERVER
                         : (r != null) ? r.getProcessClassEnum()
                                       : ServerProtoEnums.ERROR_SOURCE_UNKNOWN,
-                isPackageLoading
+                isIncremental, loadingProgress, millisSinceOldestPendingRead
         );
 
         final int relaunchReason = r == null ? RELAUNCH_REASON_NONE
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index dbfa7f3..6b9fc07 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -32,6 +32,7 @@
 import android.net.INetworkManagementEventObserver;
 import android.net.Network;
 import android.net.NetworkCapabilities;
+import android.os.BatteryManagerInternal;
 import android.os.BatteryStats;
 import android.os.BatteryStatsInternal;
 import android.os.BatteryUsageStats;
@@ -184,6 +185,8 @@
                 }
             };
 
+    private BatteryManagerInternal mBatteryManagerInternal;
+
     private void populatePowerEntityMaps() {
         PowerEntity[] entities = mPowerStatsInternal.getPowerEntityInfo();
         if (entities == null) {
@@ -370,6 +373,7 @@
                 Slog.e(TAG, "Could not register PowerStatsInternal");
             }
         }
+        mBatteryManagerInternal = LocalServices.getService(BatteryManagerInternal.class);
 
         Watchdog.getInstance().addMonitor(this);
 
@@ -2715,4 +2719,44 @@
             });
         }
     }
+
+    /**
+     * Sets battery AC charger to enabled/disabled, and freezes the battery state.
+     */
+    @Override
+    public void setChargerAcOnline(boolean online, boolean forceUpdate) {
+        mBatteryManagerInternal.setChargerAcOnline(online, forceUpdate);
+    }
+
+    /**
+     * Sets battery level, and freezes the battery state.
+     */
+    @Override
+    public void setBatteryLevel(int level, boolean forceUpdate) {
+        mBatteryManagerInternal.setBatteryLevel(level, forceUpdate);
+    }
+
+    /**
+     * Unplugs battery, and freezes the battery state.
+     */
+    @Override
+    public void unplugBattery(boolean forceUpdate) {
+        mBatteryManagerInternal.unplugBattery(forceUpdate);
+    }
+
+    /**
+     * Unfreezes battery state, returning to current hardware values.
+     */
+    @Override
+    public void resetBattery(boolean forceUpdate) {
+        mBatteryManagerInternal.resetBattery(forceUpdate);
+    }
+
+    /**
+     * Suspend charging even if plugged in.
+     */
+    @Override
+    public void suspendBatteryInput() {
+        mBatteryManagerInternal.suspendBatteryInput();
+    }
 }
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 81c4c86..e79f096 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -1416,7 +1416,7 @@
             }
         }
         if (!skip && info.activityInfo.applicationInfo.uid != Process.SYSTEM_UID &&
-            r.requiredPermissions != null && r.requiredPermissions.length > 0) {
+                r.requiredPermissions != null && r.requiredPermissions.length > 0) {
             for (int i = 0; i < r.requiredPermissions.length; i++) {
                 String requiredPermission = r.requiredPermissions[i];
                 try {
@@ -1424,7 +1424,7 @@
                             checkPermission(requiredPermission,
                                     info.activityInfo.applicationInfo.packageName,
                                     UserHandle
-                                            .getUserId(info.activityInfo.applicationInfo.uid));
+                                    .getUserId(info.activityInfo.applicationInfo.uid));
                 } catch (RemoteException e) {
                     perm = PackageManager.PERMISSION_DENIED;
                 }
@@ -1439,36 +1439,18 @@
                     break;
                 }
                 int appOp = AppOpsManager.permissionToOpCode(requiredPermission);
-                if (appOp != AppOpsManager.OP_NONE && appOp != r.appOp
-                        && mService.getAppOpsManager().noteOpNoThrow(appOp,
-                        info.activityInfo.applicationInfo.uid, info.activityInfo.packageName,
-                        null /* default featureId */,
-                        "Broadcast delivered to " + info.activityInfo.name)
-                        != AppOpsManager.MODE_ALLOWED) {
-                    Slog.w(TAG, "Appop Denial: receiving "
-                            + r.intent + " to "
-                            + component.flattenToShortString()
-                            + " requires appop " + AppOpsManager.permissionToOp(
-                            requiredPermission)
-                            + " due to sender " + r.callerPackage
-                            + " (uid " + r.callingUid + ")");
-                    skip = true;
-                    break;
+                if (appOp != AppOpsManager.OP_NONE && appOp != r.appOp) {
+                    if (!noteOpForManifestReceiver(appOp, r, info, component)) {
+                        skip = true;
+                        break;
+                    }
                 }
             }
         }
-        if (!skip && r.appOp != AppOpsManager.OP_NONE
-                && mService.getAppOpsManager().noteOpNoThrow(r.appOp,
-                info.activityInfo.applicationInfo.uid, info.activityInfo.packageName,
-                null  /* default featureId */, "Broadcast delivered to " + info.activityInfo.name)
-                != AppOpsManager.MODE_ALLOWED) {
-            Slog.w(TAG, "Appop Denial: receiving "
-                    + r.intent + " to "
-                    + component.flattenToShortString()
-                    + " requires appop " + AppOpsManager.opToName(r.appOp)
-                    + " due to sender " + r.callerPackage
-                    + " (uid " + r.callingUid + ")");
-            skip = true;
+        if (!skip && r.appOp != AppOpsManager.OP_NONE) {
+            if (!noteOpForManifestReceiver(r.appOp, r, info, component)) {
+                skip = true;
+            }
         }
         boolean isSingleton = false;
         try {
@@ -1717,6 +1699,40 @@
         mPendingBroadcastRecvIndex = recIdx;
     }
 
+    private boolean noteOpForManifestReceiver(int appOp, BroadcastRecord r, ResolveInfo info,
+            ComponentName component) {
+        if (info.activityInfo.attributionTags == null) {
+            return noteOpForManifestReceiverInner(appOp, r, info, component, null);
+        } else {
+            // Attribution tags provided, noteOp each tag
+            for (String tag : info.activityInfo.attributionTags) {
+                if (!noteOpForManifestReceiverInner(appOp, r, info, component, tag)) {
+                    return false;
+                }
+            }
+            return true;
+        }
+    }
+
+    private boolean noteOpForManifestReceiverInner(int appOp, BroadcastRecord r, ResolveInfo info,
+            ComponentName component, String tag) {
+        if (mService.getAppOpsManager().noteOpNoThrow(appOp,
+                    info.activityInfo.applicationInfo.uid,
+                    info.activityInfo.packageName,
+                    tag,
+                    "Broadcast delivered to " + info.activityInfo.name)
+                != AppOpsManager.MODE_ALLOWED) {
+            Slog.w(TAG, "Appop Denial: receiving "
+                    + r.intent + " to "
+                    + component.flattenToShortString()
+                    + " requires appop " + AppOpsManager.opToName(appOp)
+                    + " due to sender " + r.callerPackage
+                    + " (uid " + r.callingUid + ")");
+            return false;
+        }
+        return true;
+    }
+
     private void maybeAddAllowBackgroundActivityStartsToken(ProcessRecord proc, BroadcastRecord r) {
         if (r == null || proc == null || !r.allowBackgroundActivityStarts) {
             return;
diff --git a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
index d03a47a..93f30cc 100644
--- a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
+++ b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
@@ -26,12 +26,18 @@
 import android.app.ApplicationErrorReport;
 import android.app.ApplicationExitInfo;
 import android.content.ComponentName;
+import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IncrementalStatesInfo;
 import android.content.pm.PackageManagerInternal;
+import android.os.IBinder;
 import android.os.Message;
 import android.os.Process;
+import android.os.ServiceManager;
 import android.os.SystemClock;
+import android.os.incremental.IIncrementalService;
+import android.os.incremental.IncrementalManager;
+import android.os.incremental.IncrementalMetrics;
 import android.provider.Settings;
 import android.util.EventLog;
 import android.util.Slog;
@@ -294,14 +300,31 @@
         }
 
         // Check if package is still being loaded
-        boolean isPackageLoading = false;
+        boolean isIncremental = false;
+        float loadingProgress = 1;
+        long millisSinceOldestPendingRead = 0;
         final PackageManagerInternal packageManagerInternal = mService.getPackageManagerInternal();
         if (aInfo != null && aInfo.packageName != null) {
             IncrementalStatesInfo incrementalStatesInfo =
                     packageManagerInternal.getIncrementalStatesInfo(
                             aInfo.packageName, mApp.uid, mApp.userId);
             if (incrementalStatesInfo != null) {
-                isPackageLoading = incrementalStatesInfo.isLoading();
+                loadingProgress = incrementalStatesInfo.getProgress();
+            }
+            final String codePath = aInfo.getCodePath();
+            isIncremental = IncrementalManager.isIncrementalPath(codePath);
+            if (isIncremental) {
+                // Report in the main log that the incremental package is still loading
+                Slog.e(TAG, "App crashed on incremental package " + aInfo.packageName
+                        + " which is " + ((int) (loadingProgress * 100)) + "% loaded.");
+                final IBinder incrementalService = ServiceManager.getService(
+                        Context.INCREMENTAL_SERVICE);
+                if (incrementalService != null) {
+                    final IncrementalManager incrementalManager = new IncrementalManager(
+                            IIncrementalService.Stub.asInterface(incrementalService));
+                    IncrementalMetrics metrics = incrementalManager.getMetrics(codePath);
+                    millisSinceOldestPendingRead = metrics.getMillisSinceOldestPendingRead();
+                }
             }
         }
 
@@ -322,10 +345,8 @@
             info.append("Parent: ").append(parentShortComponentName).append("\n");
         }
 
-        if (isPackageLoading) {
-            // Report in the main log that the package is still loading
-            final float loadingProgress = packageManagerInternal.getIncrementalStatesInfo(
-                    aInfo.packageName, mApp.uid, mApp.userId).getProgress();
+        if (isIncremental) {
+            // Report in the main log about the incremental package
             info.append("Package is ").append((int) (loadingProgress * 100)).append("% loaded.\n");
         }
 
@@ -412,7 +433,8 @@
                         ? FrameworkStatsLog.ANROCCURRED__FOREGROUND_STATE__FOREGROUND
                         : FrameworkStatsLog.ANROCCURRED__FOREGROUND_STATE__BACKGROUND,
                 mApp.getProcessClassEnum(),
-                (mApp.info != null) ? mApp.info.packageName : "", isPackageLoading);
+                (mApp.info != null) ? mApp.info.packageName : "",
+                isIncremental, loadingProgress, millisSinceOldestPendingRead);
         final ProcessRecord parentPr = parentProcess != null
                 ? (ProcessRecord) parentProcess.mOwner : null;
         mService.addErrorToDropBox("anr", mApp, mApp.processName, activityShortComponentName,
diff --git a/services/core/java/com/android/server/app/GameManagerSettings.java b/services/core/java/com/android/server/app/GameManagerSettings.java
index 3e32380..2982545 100644
--- a/services/core/java/com/android/server/app/GameManagerSettings.java
+++ b/services/core/java/com/android/server/app/GameManagerSettings.java
@@ -137,6 +137,11 @@
     boolean readPersistentDataLocked() {
         mGameModes.clear();
 
+        if (!mSettingsFile.exists()) {
+            Slog.v(GameManagerService.TAG, "Settings file doesn't exists, skip reading");
+            return false;
+        }
+
         try {
             final FileInputStream str = mSettingsFile.openRead();
 
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 6614e06..1122f7f 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -2098,26 +2098,28 @@
         ensureHistoricalOpRequestIsValid(uid, packageName, attributionTag, opNames, filter,
                 beginTimeMillis, endTimeMillis, flags);
         Objects.requireNonNull(callback, "callback cannot be null");
-
         ActivityManagerInternal ami = LocalServices.getService(ActivityManagerInternal.class);
-        boolean isCallerInstrumented = ami.isUidCurrentlyInstrumented(Binder.getCallingUid());
-        boolean isCallerSystem = Binder.getCallingPid() == Process.myPid();
-        boolean isCallerPermissionController;
-        try {
-            isCallerPermissionController = pm.getPackageUid(
-                    mContext.getPackageManager().getPermissionControllerPackageName(), 0)
-                    == Binder.getCallingUid();
-        } catch (PackageManager.NameNotFoundException doesNotHappen) {
-            return;
-        }
+        boolean isSelfRequest = (filter & FILTER_BY_UID) != 0 && uid == Binder.getCallingUid();
+        if (!isSelfRequest) {
+            boolean isCallerInstrumented = ami.isUidCurrentlyInstrumented(Binder.getCallingUid());
+            boolean isCallerSystem = Binder.getCallingPid() == Process.myPid();
+            boolean isCallerPermissionController;
+            try {
+                isCallerPermissionController = pm.getPackageUid(
+                        mContext.getPackageManager().getPermissionControllerPackageName(), 0)
+                        == Binder.getCallingUid();
+            } catch (PackageManager.NameNotFoundException doesNotHappen) {
+                return;
+            }
 
-        if (!isCallerSystem && !isCallerInstrumented && !isCallerPermissionController) {
-            mHandler.post(() -> callback.sendResult(new Bundle()));
-            return;
-        }
+            if (!isCallerSystem && !isCallerInstrumented && !isCallerPermissionController) {
+                mHandler.post(() -> callback.sendResult(new Bundle()));
+                return;
+            }
 
-        mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
-                Binder.getCallingPid(), Binder.getCallingUid(), "getHistoricalOps");
+            mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
+                    Binder.getCallingPid(), Binder.getCallingUid(), "getHistoricalOps");
+        }
 
         final String[] opNamesArray = (opNames != null)
                 ? opNames.toArray(new String[opNames.size()]) : null;
diff --git a/services/core/java/com/android/server/appop/DiscreteRegistry.java b/services/core/java/com/android/server/appop/DiscreteRegistry.java
index ed62abc..2b0157c 100644
--- a/services/core/java/com/android/server/appop/DiscreteRegistry.java
+++ b/services/core/java/com/android/server/appop/DiscreteRegistry.java
@@ -49,8 +49,6 @@
 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;
@@ -85,6 +83,8 @@
     private static final String TAG = DiscreteRegistry.class.getSimpleName();
 
     private static final long TIMELINE_HISTORY_CUTOFF = Duration.ofHours(24).toMillis();
+    private static final long TIMELINE_QUANTIZATION = Duration.ofMinutes(1).toMillis();
+
     private static final String TAG_HISTORY = "h";
     private static final String ATTR_VERSION = "v";
     private static final int CURRENT_VERSION = 1;
@@ -107,6 +107,8 @@
     private static final String ATTR_UID_STATE = "us";
     private static final String ATTR_FLAGS = "f";
 
+    private static final int OP_FLAGS_DISCRETE = OP_FLAG_SELF | OP_FLAG_TRUSTED_PROXIED;
+
     // Lock for read/write access to on disk state
     private final Object mOnDiskLock = new Object();
 
@@ -119,6 +121,9 @@
     @GuardedBy("mInMemoryLock")
     private DiscreteOps mDiscreteOps;
 
+    @GuardedBy("mOnDiskLock")
+    private DiscreteOps mCachedOps = null;
+
     DiscreteRegistry(Object inMemoryLock) {
         mInMemoryLock = inMemoryLock;
         mDiscreteAccessDir = new File(new File(Environment.getDataSystemDirectory(), "appops"),
@@ -173,23 +178,25 @@
                     }
                 }
             }
-        }
-        DiscreteOps discreteOps;
-        synchronized (mInMemoryLock) {
-            discreteOps = mDiscreteOps;
-            mDiscreteOps = new DiscreteOps();
-        }
-        if (discreteOps.isEmpty()) {
-            return;
-        }
-        long currentTimeStamp = Instant.now().toEpochMilli();
-        try {
-            final File file = new File(mDiscreteAccessDir, currentTimeStamp + TIMELINE_FILE_SUFFIX);
-            discreteOps.writeToFile(file);
-        } catch (Throwable t) {
-            Slog.e(TAG,
-                    "Error writing timeline state: " + t.getMessage() + " "
-                            + Arrays.toString(t.getStackTrace()));
+            DiscreteOps discreteOps;
+            synchronized (mInMemoryLock) {
+                discreteOps = mDiscreteOps;
+                mDiscreteOps = new DiscreteOps();
+                mCachedOps = null;
+            }
+            if (discreteOps.isEmpty()) {
+                return;
+            }
+            long currentTimeStamp = Instant.now().toEpochMilli();
+            try {
+                final File file = new File(mDiscreteAccessDir,
+                        currentTimeStamp + TIMELINE_FILE_SUFFIX);
+                discreteOps.writeToFile(file);
+            } catch (Throwable t) {
+                Slog.e(TAG,
+                        "Error writing timeline state: " + t.getMessage() + " "
+                                + Arrays.toString(t.getStackTrace()));
+            }
         }
     }
 
@@ -197,25 +204,33 @@
             long endTimeMillis, @AppOpsManager.HistoricalOpsRequestFilter int filter, int uidFilter,
             @Nullable String packageNameFilter, @Nullable String[] opNamesFilter,
             @Nullable String attributionTagFilter, @AppOpsManager.OpFlags int flagsFilter) {
-        writeAndClearAccessHistory();
-        DiscreteOps discreteOps = new DiscreteOps();
-        readDiscreteOpsFromDisk(discreteOps, beginTimeMillis, endTimeMillis, filter, uidFilter,
-                packageNameFilter, opNamesFilter, attributionTagFilter, flagsFilter);
+        DiscreteOps discreteOps = getAndCacheDiscreteOps();
+        discreteOps.filter(beginTimeMillis, endTimeMillis, filter, uidFilter, packageNameFilter,
+                opNamesFilter, attributionTagFilter, flagsFilter);
         discreteOps.applyToHistoricalOps(result);
         return;
     }
 
-    private void readDiscreteOpsFromDisk(DiscreteOps discreteOps, long beginTimeMillis,
-            long endTimeMillis, @AppOpsManager.HistoricalOpsRequestFilter int filter, int uidFilter,
-            @Nullable String packageNameFilter, @Nullable String[] opNamesFilter,
-            @Nullable String attributionTagFilter, @AppOpsManager.OpFlags int flagsFilter) {
+    private DiscreteOps getAndCacheDiscreteOps() {
+        DiscreteOps discreteOps = new DiscreteOps();
+
         synchronized (mOnDiskLock) {
-            long historyBeginTimeMillis = Instant.now().minus(TIMELINE_HISTORY_CUTOFF,
-                    ChronoUnit.MILLIS).toEpochMilli();
-            if (historyBeginTimeMillis > endTimeMillis) {
-                return;
+            synchronized (mInMemoryLock) {
+                discreteOps.merge(mDiscreteOps);
             }
-            beginTimeMillis = max(beginTimeMillis, historyBeginTimeMillis);
+            if (mCachedOps == null) {
+                mCachedOps = new DiscreteOps();
+                readDiscreteOpsFromDisk(mCachedOps);
+            }
+            discreteOps.merge(mCachedOps);
+        }
+        return discreteOps;
+    }
+
+    private void readDiscreteOpsFromDisk(DiscreteOps discreteOps) {
+        synchronized (mOnDiskLock) {
+            long beginTimeMillis = Instant.now().minus(TIMELINE_HISTORY_CUTOFF,
+                    ChronoUnit.MILLIS).toEpochMilli();
 
             final File[] files = mDiscreteAccessDir.listFiles();
             if (files != null && files.length > 0) {
@@ -229,8 +244,7 @@
                     if (timestamp < beginTimeMillis) {
                         continue;
                     }
-                    discreteOps.readFromFile(f, beginTimeMillis, endTimeMillis, filter, uidFilter,
-                            packageNameFilter, opNamesFilter, attributionTagFilter, flagsFilter);
+                    discreteOps.readFromFile(f, beginTimeMillis);
                 }
             }
         }
@@ -251,15 +265,11 @@
             @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 discreteOps = getAndCacheDiscreteOps();
+        String[] opNamesFilter = dumpOp == OP_NONE ? null
+                : new String[]{AppOpsManager.opToPublicName(dumpOp)};
+        discreteOps.filter(0, Instant.now().toEpochMilli(), filter, uidFilter, packageNameFilter,
+                opNamesFilter, attributionTagFilter, OP_FLAGS_ALL);
         discreteOps.dump(pw, sdf, date, prefix, nDiscreteOps);
     }
 
@@ -270,7 +280,7 @@
         if (!isDiscreteUid(uid)) {
             return false;
         }
-        if ((flags & (OP_FLAG_SELF | OP_FLAG_TRUSTED_PROXIED)) == 0) {
+        if ((flags & (OP_FLAGS_DISCRETE)) == 0) {
             return false;
         }
         return true;
@@ -298,6 +308,19 @@
             mUids = new ArrayMap<>();
         }
 
+        boolean isEmpty() {
+            return mUids.isEmpty();
+        }
+
+        void merge(DiscreteOps other) {
+            int nUids = other.mUids.size();
+            for (int i = 0; i < nUids; i++) {
+                int uid = other.mUids.keyAt(i);
+                DiscreteUidOps uidOps = other.mUids.valueAt(i);
+                getOrCreateDiscreteUidOps(uid).merge(uidOps);
+            }
+        }
+
         void addDiscreteAccess(int op, int uid, @NonNull String packageName,
                 @Nullable String attributionTag, @AppOpsManager.OpFlags int flags,
                 @AppOpsManager.UidState int uidState, long accessTime, long accessDuration) {
@@ -305,6 +328,25 @@
                     uidState, accessTime, accessDuration);
         }
 
+        private void filter(long beginTimeMillis, long endTimeMillis,
+                @AppOpsManager.HistoricalOpsRequestFilter int filter, int uidFilter,
+                @Nullable String packageNameFilter, @Nullable String[] opNamesFilter,
+                @Nullable String attributionTagFilter, @AppOpsManager.OpFlags int flagsFilter) {
+            if ((filter & FILTER_BY_UID) != 0) {
+                ArrayMap<Integer, DiscreteUidOps> uids = new ArrayMap<>();
+                uids.put(uidFilter, getOrCreateDiscreteUidOps(uidFilter));
+                mUids = uids;
+            }
+            int nUids = mUids.size();
+            for (int i = nUids - 1; i >= 0; i--) {
+                mUids.valueAt(i).filter(beginTimeMillis, endTimeMillis, filter, packageNameFilter,
+                        opNamesFilter, attributionTagFilter, flagsFilter);
+                if (mUids.valueAt(i).isEmpty()) {
+                    mUids.removeAt(i);
+                }
+            }
+        }
+
         private void applyToHistoricalOps(AppOpsManager.HistoricalOps result) {
             int nUids = mUids.size();
             for (int i = 0; i < nUids; i++) {
@@ -353,14 +395,7 @@
             return result;
         }
 
-        boolean isEmpty() {
-            return mUids.isEmpty();
-        }
-
-        private void readFromFile(File f, long beginTimeMillis, long endTimeMillis,
-                @AppOpsManager.HistoricalOpsRequestFilter int filter,
-                int uidFilter, @Nullable String packageNameFilter, @Nullable String[] opNamesFilter,
-                @Nullable String attributionTagFilter, @AppOpsManager.OpFlags int flagsFilter) {
+        private void readFromFile(File f, long beginTimeMillis) {
             try {
                 FileInputStream stream = new FileInputStream(f);
                 TypedXmlPullParser parser = Xml.resolvePullParser(stream);
@@ -377,12 +412,7 @@
                 while (XmlUtils.nextElementWithin(parser, depth)) {
                     if (TAG_UID.equals(parser.getName())) {
                         int uid = parser.getAttributeInt(null, ATTR_UID, -1);
-                        if ((filter & FILTER_BY_UID) != 0 && uid != uidFilter) {
-                            continue;
-                        }
-                        getOrCreateDiscreteUidOps(uid).deserialize(parser, beginTimeMillis,
-                                endTimeMillis, filter, packageNameFilter, opNamesFilter,
-                                attributionTagFilter, flagsFilter);
+                        getOrCreateDiscreteUidOps(uid).deserialize(parser, beginTimeMillis);
                     }
                 }
             } catch (Throwable t) {
@@ -400,6 +430,38 @@
             mPackages = new ArrayMap<>();
         }
 
+        boolean isEmpty() {
+            return mPackages.isEmpty();
+        }
+
+        void merge(DiscreteUidOps other) {
+            int nPackages = other.mPackages.size();
+            for (int i = 0; i < nPackages; i++) {
+                String packageName = other.mPackages.keyAt(i);
+                DiscretePackageOps p = other.mPackages.valueAt(i);
+                getOrCreateDiscretePackageOps(packageName).merge(p);
+            }
+        }
+
+        private void filter(long beginTimeMillis, long endTimeMillis,
+                @AppOpsManager.HistoricalOpsRequestFilter int filter,
+                @Nullable String packageNameFilter, @Nullable String[] opNamesFilter,
+                @Nullable String attributionTagFilter, @AppOpsManager.OpFlags int flagsFilter) {
+            if ((filter & FILTER_BY_PACKAGE_NAME) != 0) {
+                ArrayMap<String, DiscretePackageOps> packages = new ArrayMap<>();
+                packages.put(packageNameFilter, getOrCreateDiscretePackageOps(packageNameFilter));
+                mPackages = packages;
+            }
+            int nPackages = mPackages.size();
+            for (int i = nPackages - 1; i >= 0; i--) {
+                mPackages.valueAt(i).filter(beginTimeMillis, endTimeMillis, filter, opNamesFilter,
+                        attributionTagFilter, flagsFilter);
+                if (mPackages.valueAt(i).isEmpty()) {
+                    mPackages.removeAt(i);
+                }
+            }
+        }
+
         void addDiscreteAccess(int op, @NonNull String packageName, @Nullable String attributionTag,
                 @AppOpsManager.OpFlags int flags, @AppOpsManager.UidState int uidState,
                 long accessTime, long accessDuration) {
@@ -445,22 +507,12 @@
             }
         }
 
-        void deserialize(TypedXmlPullParser parser, long beginTimeMillis,
-                long endTimeMillis, @AppOpsManager.HistoricalOpsRequestFilter int filter,
-                @Nullable String packageNameFilter,
-                @Nullable String[] opNamesFilter, @Nullable String attributionTagFilter,
-                @AppOpsManager.OpFlags int flagsFilter) throws Exception {
+        void deserialize(TypedXmlPullParser parser, long beginTimeMillis) throws Exception {
             int depth = parser.getDepth();
             while (XmlUtils.nextElementWithin(parser, depth)) {
                 if (TAG_PACKAGE.equals(parser.getName())) {
                     String packageName = parser.getAttributeValue(null, ATTR_PACKAGE_NAME);
-                    if ((filter & FILTER_BY_PACKAGE_NAME) != 0
-                            && !packageName.equals(packageNameFilter)) {
-                        continue;
-                    }
-                    getOrCreateDiscretePackageOps(packageName).deserialize(parser, beginTimeMillis,
-                            endTimeMillis, filter, opNamesFilter, attributionTagFilter,
-                            flagsFilter);
+                    getOrCreateDiscretePackageOps(packageName).deserialize(parser, beginTimeMillis);
                 }
             }
         }
@@ -473,6 +525,10 @@
             mPackageOps = new ArrayMap<>();
         }
 
+        boolean isEmpty() {
+            return mPackageOps.isEmpty();
+        }
+
         void addDiscreteAccess(int op, @Nullable String attributionTag,
                 @AppOpsManager.OpFlags int flags, @AppOpsManager.UidState int uidState,
                 long accessTime, long accessDuration) {
@@ -480,6 +536,35 @@
                     accessDuration);
         }
 
+        void merge(DiscretePackageOps other) {
+            int nOps = other.mPackageOps.size();
+            for (int i = 0; i < nOps; i++) {
+                int opId = other.mPackageOps.keyAt(i);
+                DiscreteOp op = other.mPackageOps.valueAt(i);
+                getOrCreateDiscreteOp(opId).merge(op);
+            }
+        }
+
+        private void filter(long beginTimeMillis, long endTimeMillis,
+                @AppOpsManager.HistoricalOpsRequestFilter int filter,
+                @Nullable String[] opNamesFilter, @Nullable String attributionTagFilter,
+                @AppOpsManager.OpFlags int flagsFilter) {
+            int nOps = mPackageOps.size();
+            for (int i = nOps - 1; i >= 0; i--) {
+                int opId = mPackageOps.keyAt(i);
+                if ((filter & FILTER_BY_OP_NAMES) != 0 && !ArrayUtils.contains(opNamesFilter,
+                        AppOpsManager.opToPublicName(opId))) {
+                    mPackageOps.removeAt(i);
+                    continue;
+                }
+                mPackageOps.valueAt(i).filter(beginTimeMillis, endTimeMillis, filter,
+                        attributionTagFilter, flagsFilter);
+                if (mPackageOps.valueAt(i).isEmpty()) {
+                    mPackageOps.removeAt(i);
+                }
+            }
+        }
+
         private DiscreteOp getOrCreateDiscreteOp(int op) {
             DiscreteOp result = mPackageOps.get(op);
             if (result == null) {
@@ -519,20 +604,12 @@
             }
         }
 
-        void deserialize(TypedXmlPullParser parser, long beginTimeMillis, long endTimeMillis,
-                @AppOpsManager.HistoricalOpsRequestFilter int filter,
-                @Nullable String[] opNamesFilter, @Nullable String attributionTagFilter,
-                @AppOpsManager.OpFlags int flagsFilter) throws Exception {
+        void deserialize(TypedXmlPullParser parser, long beginTimeMillis) throws Exception {
             int depth = parser.getDepth();
             while (XmlUtils.nextElementWithin(parser, depth)) {
                 if (TAG_OP.equals(parser.getName())) {
                     int op = parser.getAttributeInt(null, ATTR_OP_ID);
-                    if ((filter & FILTER_BY_OP_NAMES) != 0 && !ArrayUtils.contains(opNamesFilter,
-                            AppOpsManager.opToPublicName(op))) {
-                        continue;
-                    }
-                    getOrCreateDiscreteOp(op).deserialize(parser, beginTimeMillis, endTimeMillis,
-                            filter, attributionTagFilter, flagsFilter);
+                    getOrCreateDiscreteOp(op).deserialize(parser, beginTimeMillis);
                 }
             }
         }
@@ -545,31 +622,66 @@
             mAttributedOps = new ArrayMap<>();
         }
 
+        boolean isEmpty() {
+            return mAttributedOps.isEmpty();
+        }
+
+        void merge(DiscreteOp other) {
+            int nTags = other.mAttributedOps.size();
+            for (int i = 0; i < nTags; i++) {
+                String tag = other.mAttributedOps.keyAt(i);
+                List<DiscreteOpEvent> otherEvents = other.mAttributedOps.valueAt(i);
+                List<DiscreteOpEvent> events = getOrCreateDiscreteOpEventsList(tag);
+                mAttributedOps.put(tag, stableListMerge(events, otherEvents));
+            }
+        }
+
+        private void filter(long beginTimeMillis, long endTimeMillis,
+                @AppOpsManager.HistoricalOpsRequestFilter int filter,
+                @Nullable String attributionTagFilter, @AppOpsManager.OpFlags int flagsFilter) {
+            if ((filter & FILTER_BY_ATTRIBUTION_TAG) != 0) {
+                ArrayMap<String, List<DiscreteOpEvent>> attributedOps = new ArrayMap<>();
+                attributedOps.put(attributionTagFilter,
+                        getOrCreateDiscreteOpEventsList(attributionTagFilter));
+                mAttributedOps = attributedOps;
+            }
+
+            int nTags = mAttributedOps.size();
+            for (int i = nTags - 1; i >= 0; i--) {
+                String tag = mAttributedOps.keyAt(i);
+                List<DiscreteOpEvent> list = mAttributedOps.valueAt(i);
+                list = filterEventsList(list, beginTimeMillis, endTimeMillis, flagsFilter);
+                mAttributedOps.put(tag, list);
+                if (list.size() == 0) {
+                    mAttributedOps.removeAt(i);
+                }
+            }
+        }
+
         void addDiscreteAccess(@Nullable String attributionTag,
                 @AppOpsManager.OpFlags int flags, @AppOpsManager.UidState int uidState,
                 long accessTime, long accessDuration) {
             List<DiscreteOpEvent> attributedOps = getOrCreateDiscreteOpEventsList(
                     attributionTag);
-            accessTime = Instant.ofEpochMilli(accessTime).truncatedTo(
-                    ChronoUnit.MINUTES).toEpochMilli();
+            accessTime = accessTime / TIMELINE_QUANTIZATION * TIMELINE_QUANTIZATION;
 
             int nAttributedOps = attributedOps.size();
-            for (int i = nAttributedOps - 1; i >= 0; i--) {
-                DiscreteOpEvent previousOp = attributedOps.get(i);
-                if (i == nAttributedOps - 1 && previousOp.mNoteTime == accessTime
-                        && accessDuration > -1) {
-                    // existing event with updated duration
-                    attributedOps.remove(i);
-                    break;
-                }
+            int i = nAttributedOps;
+            for (; i > 0; i--) {
+                DiscreteOpEvent previousOp = attributedOps.get(i - 1);
                 if (previousOp.mNoteTime < accessTime) {
                     break;
                 }
                 if (previousOp.mOpFlag == flags && previousOp.mUidState == uidState) {
-                    return;
+                    if (accessDuration != previousOp.mNoteDuration
+                            && accessDuration > TIMELINE_QUANTIZATION) {
+                        break;
+                    } else {
+                        return;
+                    }
                 }
             }
-            attributedOps.add(new DiscreteOpEvent(accessTime, accessDuration, uidState, flags));
+            attributedOps.add(i, new DiscreteOpEvent(accessTime, accessDuration, uidState, flags));
         }
 
         private List<DiscreteOpEvent> getOrCreateDiscreteOpEventsList(String attributionTag) {
@@ -633,18 +745,11 @@
             }
         }
 
-        void deserialize(TypedXmlPullParser parser, long beginTimeMillis, long endTimeMillis,
-                @AppOpsManager.HistoricalOpsRequestFilter int filter,
-                @Nullable String attributionTagFilter,
-                @AppOpsManager.OpFlags int flagsFilter) throws Exception {
+        void deserialize(TypedXmlPullParser parser, long beginTimeMillis) throws Exception {
             int outerDepth = parser.getDepth();
             while (XmlUtils.nextElementWithin(parser, outerDepth)) {
                 if (TAG_TAG.equals(parser.getName())) {
                     String attributionTag = parser.getAttributeValue(null, ATTR_TAG);
-                    if ((filter & FILTER_BY_ATTRIBUTION_TAG) != 0 && !attributionTag.equals(
-                            attributionTagFilter)) {
-                        continue;
-                    }
                     List<DiscreteOpEvent> events = getOrCreateDiscreteOpEventsList(
                             attributionTag);
                     int innerDepth = parser.getDepth();
@@ -655,11 +760,7 @@
                                     -1);
                             int uidState = parser.getAttributeInt(null, ATTR_UID_STATE);
                             int opFlags = parser.getAttributeInt(null, ATTR_FLAGS);
-                            if ((flagsFilter & opFlags) == 0) {
-                                continue;
-                            }
-                            if ((noteTime + noteDuration < beginTimeMillis
-                                    && noteTime > endTimeMillis)) {
+                            if (noteTime + noteDuration < beginTimeMillis) {
                                 continue;
                             }
                             DiscreteOpEvent event = new DiscreteOpEvent(noteTime, noteDuration,
@@ -715,5 +816,41 @@
             out.attributeInt(null, ATTR_FLAGS, mOpFlag);
         }
     }
+
+    private static List<DiscreteOpEvent> stableListMerge(List<DiscreteOpEvent> a,
+            List<DiscreteOpEvent> b) {
+        int nA = a.size();
+        int nB = b.size();
+        int i = 0;
+        int k = 0;
+        List<DiscreteOpEvent> result = new ArrayList<>(nA + nB);
+        while (i < nA || k < nB) {
+            if (i == nA) {
+                result.add(b.get(k++));
+            } else if (k == nB) {
+                result.add(a.get(i++));
+            } else if (a.get(i).mNoteTime < b.get(k).mNoteTime) {
+                result.add(a.get(i++));
+            } else {
+                result.add(b.get(k++));
+            }
+        }
+        return result;
+    }
+
+    private static List<DiscreteOpEvent> filterEventsList(List<DiscreteOpEvent> list,
+            long beginTimeMillis, long endTimeMillis, @AppOpsManager.OpFlags int flagsFilter) {
+        int n = list.size();
+        List<DiscreteOpEvent> result = new ArrayList<>(n);
+        for (int i = 0; i < n; i++) {
+            DiscreteOpEvent event = list.get(i);
+            if ((event.mOpFlag & flagsFilter) != 0
+                    && event.mNoteTime + event.mNoteDuration > beginTimeMillis
+                    && event.mNoteTime < endTimeMillis) {
+                result.add(event);
+            }
+        }
+        return result;
+    }
 }
 
diff --git a/services/core/java/com/android/server/appop/HistoricalRegistry.java b/services/core/java/com/android/server/appop/HistoricalRegistry.java
index 22d628b..4435c47 100644
--- a/services/core/java/com/android/server/appop/HistoricalRegistry.java
+++ b/services/core/java/com/android/server/appop/HistoricalRegistry.java
@@ -532,7 +532,7 @@
                         System.currentTimeMillis()).increaseAccessDuration(op, uid, packageName,
                         attributionTag, uidState, flags, increment);
                 mDiscreteRegistry.recordDiscreteAccess(uid, packageName, op, attributionTag,
-                        flags, uidState, increment, eventStartTime);
+                        flags, uidState, eventStartTime, increment);
             }
         }
     }
@@ -795,7 +795,7 @@
     private static boolean isApiEnabled() {
         return Binder.getCallingUid() == Process.myUid()
                 || DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
-                PROPERTY_PERMISSIONS_HUB_ENABLED, false);
+                PROPERTY_PERMISSIONS_HUB_ENABLED, true);
     }
 
     private static final class Persistence {
diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java
index e0d1375..6712c54 100644
--- a/services/core/java/com/android/server/clipboard/ClipboardService.java
+++ b/services/core/java/com/android/server/clipboard/ClipboardService.java
@@ -950,34 +950,36 @@
         }
         clipboard.mNotifiedUids.put(uid, true);
 
-        // Retrieve the app label of the source of the clip data
-        CharSequence sourceAppLabel = null;
-        if (clipboard.mPrimaryClipPackage != null) {
-            try {
-                sourceAppLabel = mPm.getApplicationLabel(mPm.getApplicationInfoAsUser(
-                        clipboard.mPrimaryClipPackage, 0, userId));
-            } catch (PackageManager.NameNotFoundException e) {
-                // leave label as null
+        Binder.withCleanCallingIdentity(() -> {
+            // Retrieve the app label of the source of the clip data
+            CharSequence sourceAppLabel = null;
+            if (clipboard.mPrimaryClipPackage != null) {
+                try {
+                    sourceAppLabel = mPm.getApplicationLabel(mPm.getApplicationInfoAsUser(
+                            clipboard.mPrimaryClipPackage, 0, userId));
+                } catch (PackageManager.NameNotFoundException e) {
+                    // leave label as null
+                }
             }
-        }
 
-        try {
-            CharSequence callingAppLabel = mPm.getApplicationLabel(
-                    mPm.getApplicationInfoAsUser(callingPackage, 0, userId));
-            String message;
-            if (sourceAppLabel != null) {
-                message = getContext().getString(
-                        R.string.pasted_from_app, callingAppLabel, sourceAppLabel);
-            } else {
-                message = getContext().getString(R.string.pasted_from_clipboard, callingAppLabel);
+            try {
+                CharSequence callingAppLabel = mPm.getApplicationLabel(
+                        mPm.getApplicationInfoAsUser(callingPackage, 0, userId));
+                String message;
+                if (sourceAppLabel != null) {
+                    message = getContext().getString(
+                            R.string.pasted_from_app, callingAppLabel, sourceAppLabel);
+                } else {
+                    message = getContext().getString(
+                            R.string.pasted_from_clipboard, callingAppLabel);
+                }
+                Slog.i(TAG, message);
+                Toast.makeText(
+                        getContext(), UiThread.get().getLooper(), message, Toast.LENGTH_SHORT)
+                        .show();
+            } catch (PackageManager.NameNotFoundException e) {
+                // do nothing
             }
-            Slog.i(TAG, message);
-            Binder.withCleanCallingIdentity(() ->
-                    Toast.makeText(getContext(), UiThread.get().getLooper(), message,
-                            Toast.LENGTH_SHORT)
-                            .show());
-        } catch (PackageManager.NameNotFoundException e) {
-            // do nothing
-        }
+        });
     }
 }
diff --git a/services/core/java/com/android/server/compat/CompatChange.java b/services/core/java/com/android/server/compat/CompatChange.java
index 5cf478a..ae9b001 100644
--- a/services/core/java/com/android/server/compat/CompatChange.java
+++ b/services/core/java/com/android/server/compat/CompatChange.java
@@ -28,6 +28,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 
+import com.android.internal.compat.AndroidBuildClassifier;
 import com.android.internal.compat.CompatibilityChangeInfo;
 import com.android.internal.compat.OverrideAllowedState;
 import com.android.server.compat.config.Change;
@@ -55,7 +56,7 @@
      * A change ID to be used only in the CTS test for this SystemApi
      */
     @ChangeId
-    @EnabledSince(targetSdkVersion = 1235) // Needs to be > test APK targetSdkVersion.
+    @EnabledSince(targetSdkVersion = 31) // Needs to be > test APK targetSdkVersion.
     static final long CTS_SYSTEM_API_CHANGEID = 149391281; // This is a bug id.
 
     /**
@@ -233,7 +234,7 @@
      * @param app Info about the app in question
      * @return {@code true} if the change should be enabled for the package.
      */
-    boolean isEnabled(ApplicationInfo app) {
+    boolean isEnabled(ApplicationInfo app, AndroidBuildClassifier buildClassifier) {
         if (app == null) {
             return defaultValue();
         }
@@ -244,7 +245,13 @@
             return false;
         }
         if (getEnableSinceTargetSdk() != -1) {
-            return app.targetSdkVersion >= getEnableSinceTargetSdk();
+            // If the change is gated by a platform version newer than the one currently installed
+            // on the device, disregard the app's target sdk version.
+            int compareSdk = Math.min(app.targetSdkVersion, buildClassifier.platformTargetSdk());
+            if (compareSdk != app.targetSdkVersion) {
+                compareSdk = app.targetSdkVersion;
+            }
+            return compareSdk >= getEnableSinceTargetSdk();
         }
         return true;
     }
diff --git a/services/core/java/com/android/server/compat/CompatConfig.java b/services/core/java/com/android/server/compat/CompatConfig.java
index 2c053b4..ef86f42 100644
--- a/services/core/java/com/android/server/compat/CompatConfig.java
+++ b/services/core/java/com/android/server/compat/CompatConfig.java
@@ -74,12 +74,14 @@
     private final LongSparseArray<CompatChange> mChanges = new LongSparseArray<>();
 
     private final OverrideValidatorImpl mOverrideValidator;
+    private final AndroidBuildClassifier mAndroidBuildClassifier;
     private Context mContext;
     private File mOverridesFile;
 
     @VisibleForTesting
     CompatConfig(AndroidBuildClassifier androidBuildClassifier, Context context) {
         mOverrideValidator = new OverrideValidatorImpl(androidBuildClassifier, context, this);
+        mAndroidBuildClassifier = androidBuildClassifier;
         mContext = context;
     }
 
@@ -133,7 +135,7 @@
         synchronized (mChanges) {
             for (int i = 0; i < mChanges.size(); ++i) {
                 CompatChange c = mChanges.valueAt(i);
-                if (!c.isEnabled(app)) {
+                if (!c.isEnabled(app, mAndroidBuildClassifier)) {
                     disabled.add(c.getId());
                 }
             }
@@ -175,7 +177,7 @@
                 // we know nothing about this change: default behaviour is enabled.
                 return true;
             }
-            return c.isEnabled(app);
+            return c.isEnabled(app, mAndroidBuildClassifier);
         }
     }
 
@@ -475,7 +477,7 @@
         synchronized (mChanges) {
             for (int i = 0; i < mChanges.size(); ++i) {
                 CompatChange c = mChanges.valueAt(i);
-                if (c.isEnabled(applicationInfo)) {
+                if (c.isEnabled(applicationInfo, mAndroidBuildClassifier)) {
                     enabled.add(c.getId());
                 } else {
                     disabled.add(c.getId());
diff --git a/services/core/java/com/android/server/compat/OverrideValidatorImpl.java b/services/core/java/com/android/server/compat/OverrideValidatorImpl.java
index fe5b4a9..aa66a1a 100644
--- a/services/core/java/com/android/server/compat/OverrideValidatorImpl.java
+++ b/services/core/java/com/android/server/compat/OverrideValidatorImpl.java
@@ -22,6 +22,7 @@
 import static com.android.internal.compat.OverrideAllowedState.DISABLED_NOT_DEBUGGABLE;
 import static com.android.internal.compat.OverrideAllowedState.DISABLED_TARGET_SDK_TOO_HIGH;
 import static com.android.internal.compat.OverrideAllowedState.LOGGING_ONLY_CHANGE;
+import static com.android.internal.compat.OverrideAllowedState.PLATFORM_TOO_OLD;
 
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
@@ -85,6 +86,9 @@
         if (debuggableBuild) {
             return new OverrideAllowedState(ALLOWED, -1, -1);
         }
+        if (maxTargetSdk >= mAndroidBuildClassifier.platformTargetSdk()) {
+            return new OverrideAllowedState(PLATFORM_TOO_OLD, -1, maxTargetSdk);
+        }
         PackageManager packageManager = mContext.getPackageManager();
         if (packageManager == null) {
             throw new IllegalStateException("No PackageManager!");
diff --git a/services/core/java/com/android/server/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java
index d17753f..2be39aa 100644
--- a/services/core/java/com/android/server/compat/PlatformCompat.java
+++ b/services/core/java/com/android/server/compat/PlatformCompat.java
@@ -66,18 +66,22 @@
     private final Context mContext;
     private final ChangeReporter mChangeReporter;
     private final CompatConfig mCompatConfig;
+    private final AndroidBuildClassifier mBuildClassifier;
 
     public PlatformCompat(Context context) {
         mContext = context;
         mChangeReporter = new ChangeReporter(ChangeReporter.SOURCE_SYSTEM_SERVER);
-        mCompatConfig = CompatConfig.create(new AndroidBuildClassifier(), mContext);
+        mBuildClassifier = new AndroidBuildClassifier();
+        mCompatConfig = CompatConfig.create(mBuildClassifier, mContext);
     }
 
     @VisibleForTesting
-    PlatformCompat(Context context, CompatConfig compatConfig) {
+    PlatformCompat(Context context, CompatConfig compatConfig,
+                   AndroidBuildClassifier buildClassifier) {
         mContext = context;
         mChangeReporter = new ChangeReporter(ChangeReporter.SOURCE_SYSTEM_SERVER);
         mCompatConfig = compatConfig;
+        mBuildClassifier = buildClassifier;
 
         registerPackageReceiver(context);
     }
@@ -392,7 +396,8 @@
             return false;
         }
         if (change.getEnableSinceTargetSdk() > 0) {
-            return change.getEnableSinceTargetSdk() >= Build.VERSION_CODES.Q;
+            return change.getEnableSinceTargetSdk() >= Build.VERSION_CODES.Q
+                && change.getEnableSinceTargetSdk() <= mBuildClassifier.platformTargetSdk();
         }
         return true;
     }
diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
index 9411e33..488677a 100644
--- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java
+++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
@@ -31,14 +31,17 @@
 import static com.android.net.module.util.CollectionUtils.toIntArray;
 
 import android.annotation.NonNull;
+import android.content.BroadcastReceiver;
 import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.PackageManagerInternal;
 import android.net.INetd;
 import android.net.UidRange;
+import android.net.Uri;
 import android.os.Build;
 import android.os.RemoteException;
 import android.os.ServiceSpecificException;
@@ -54,7 +57,6 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.net.module.util.CollectionUtils;
-import com.android.server.LocalServices;
 
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -71,7 +73,7 @@
  *
  * @hide
  */
-public class PermissionMonitor implements PackageManagerInternal.PackageListObserver {
+public class PermissionMonitor {
     private static final String TAG = "PermissionMonitor";
     private static final boolean DBG = true;
     protected static final Boolean SYSTEM = Boolean.TRUE;
@@ -83,6 +85,7 @@
     private final SystemConfigManager mSystemConfigManager;
     private final INetd mNetd;
     private final Dependencies mDeps;
+    private final Context mContext;
 
     @GuardedBy("this")
     private final Set<UserHandle> mUsers = new HashSet<>();
@@ -102,6 +105,25 @@
     @GuardedBy("this")
     private final Set<Integer> mAllApps = new HashSet<>();
 
+    private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            final String action = intent.getAction();
+            final int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
+            final Uri packageData = intent.getData();
+            final String packageName =
+                    packageData != null ? packageData.getSchemeSpecificPart() : null;
+
+            if (Intent.ACTION_PACKAGE_ADDED.equals(action)) {
+                onPackageAdded(packageName, uid);
+            } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
+                onPackageRemoved(packageName, uid);
+            } else {
+                Log.wtf(TAG, "received unexpected intent: " + action);
+            }
+        }
+    };
+
     /**
      * Dependencies of PermissionMonitor, for injection in tests.
      */
@@ -127,6 +149,7 @@
         mSystemConfigManager = context.getSystemService(SystemConfigManager.class);
         mNetd = netd;
         mDeps = deps;
+        mContext = context;
     }
 
     // Intended to be called only once at startup, after the system is ready. Installs a broadcast
@@ -134,12 +157,14 @@
     public synchronized void startMonitoring() {
         log("Monitoring");
 
-        PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
-        if (pmi != null) {
-            pmi.getPackageList(this);
-        } else {
-            loge("failed to get the PackageManagerInternal service");
-        }
+        final IntentFilter intentFilter = new IntentFilter();
+        intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
+        intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+        intentFilter.addDataScheme("package");
+        mContext.createContextAsUser(UserHandle.ALL, 0 /* flags */).registerReceiver(
+                mIntentReceiver, intentFilter, null /* broadcastPermission */,
+                null /* scheduler */);
+
         List<PackageInfo> apps = mPackageManager.getInstalledPackages(GET_PERMISSIONS
                 | MATCH_ANY_USER);
         if (apps == null) {
@@ -347,9 +372,10 @@
      *
      * @hide
      */
-    @Override
     public synchronized void onPackageAdded(@NonNull final String packageName, final int uid) {
-        sendPackagePermissionsForUid(uid, getPermissionForUid(uid));
+        // TODO: Netd is using appId for checking traffic permission. Correct the methods that are
+        //  using appId instead of uid actually
+        sendPackagePermissionsForUid(UserHandle.getAppId(uid), getPermissionForUid(uid));
 
         // If multiple packages share a UID (cf: android:sharedUserId) and ask for different
         // permissions, don't downgrade (i.e., if it's already SYSTEM, leave it as is).
@@ -384,9 +410,10 @@
      *
      * @hide
      */
-    @Override
     public synchronized void onPackageRemoved(@NonNull final String packageName, final int uid) {
-        sendPackagePermissionsForUid(uid, getPermissionForUid(uid));
+        // TODO: Netd is using appId for checking traffic permission. Correct the methods that are
+        //  using appId instead of uid actually
+        sendPackagePermissionsForUid(UserHandle.getAppId(uid), getPermissionForUid(uid));
 
         // If the newly-removed package falls within some VPN's uid range, update Netd with it.
         // This needs to happen before the mApps update below, since removeBypassingUids() depends
@@ -432,19 +459,6 @@
         }
     }
 
-    /**
-     * Called when a package is changed.
-     *
-     * @param packageName The name of the changed package.
-     * @param uid The uid of the changed package.
-     *
-     * @hide
-     */
-    @Override
-    public synchronized void onPackageChanged(@NonNull final String packageName, final int uid) {
-        sendPackagePermissionsForUid(uid, getPermissionForUid(uid));
-    }
-
     private static int getNetdPermissionMask(String[] requestedPermissions,
                                              int[] requestedPermissionsFlags) {
         int permissions = 0;
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index 027b9af..0e71496 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -791,12 +791,13 @@
     public SyncAdapterType[] getSyncAdapterTypesAsUser(int userId) {
         enforceCrossUserPermission(userId,
                 "no permission to read sync settings for user " + userId);
+        final int callingUid = Binder.getCallingUid();
         // This makes it so that future permission checks will be in the context of this
         // process rather than the caller's process. We will restore this before returning.
         final long identityToken = clearCallingIdentity();
         try {
             SyncManager syncManager = getSyncManager();
-            return syncManager.getSyncAdapterTypes(userId);
+            return syncManager.getSyncAdapterTypes(callingUid, userId);
         } finally {
             restoreCallingIdentity(identityToken);
         }
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index df87012..ac7e01e 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -89,6 +89,7 @@
 import android.os.UserManager;
 import android.os.WorkSource;
 import android.provider.Settings;
+import android.text.TextUtils;
 import android.text.format.TimeMigrationUtils;
 import android.util.EventLog;
 import android.util.Log;
@@ -1257,16 +1258,19 @@
                 syncExemptionFlag, callingUid, callingPid, callingPackage);
     }
 
-    public SyncAdapterType[] getSyncAdapterTypes(int userId) {
+    public SyncAdapterType[] getSyncAdapterTypes(int callingUid, int userId) {
         final Collection<RegisteredServicesCache.ServiceInfo<SyncAdapterType>> serviceInfos;
         serviceInfos = mSyncAdapters.getAllServices(userId);
-        SyncAdapterType[] types = new SyncAdapterType[serviceInfos.size()];
-        int i = 0;
+        final List<SyncAdapterType> types = new ArrayList<>(serviceInfos.size());
         for (RegisteredServicesCache.ServiceInfo<SyncAdapterType> serviceInfo : serviceInfos) {
-            types[i] = serviceInfo.type;
-            ++i;
+            final String packageName = serviceInfo.type.getPackageName();
+            if (!TextUtils.isEmpty(packageName) && mPackageManagerInternal.filterAppAccess(
+                    packageName, callingUid, userId)) {
+                continue;
+            }
+            types.add(serviceInfo.type);
         }
-        return types;
+        return types.toArray(new SyncAdapterType[] {});
     }
 
     public String[] getSyncAdapterPackagesForAuthorityAsUser(String authority, int userId) {
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 174d4b2..96a7416 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -1128,7 +1128,7 @@
             recordTopInsetLocked(display);
         }
         addDisplayPowerControllerLocked(display);
-        mDisplayStates.append(displayId, Display.STATE_OFF);
+        mDisplayStates.append(displayId, Display.STATE_UNKNOWN);
         mDisplayBrightnesses.append(displayId, display.getDisplayInfoLocked().brightnessDefault);
 
         DisplayManagerGlobal.invalidateLocalDisplayInfoCaches();
@@ -1204,16 +1204,15 @@
         DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
         if ((info.flags & DisplayDeviceInfo.FLAG_NEVER_BLANK) == 0) {
             final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(device);
-            final int state;
             final int displayId = display.getDisplayIdLocked();
+            final int state = mDisplayStates.get(displayId);
 
-            if (display.isEnabled()) {
-                state = mDisplayStates.get(displayId);
-            } else {
-                state = Display.STATE_OFF;
+            // Only send a request for display state if the display state has already been
+            // initialized by DisplayPowercontroller.
+            if (state != Display.STATE_UNKNOWN) {
+                final float brightness = mDisplayBrightnesses.get(displayId);
+                return device.requestDisplayStateLocked(state, brightness);
             }
-            final float brightness = mDisplayBrightnesses.get(displayId);
-            return device.requestDisplayStateLocked(state, brightness);
         }
         return null;
     }
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 0117326..7b107b85 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -982,7 +982,8 @@
             mWaitingForNegativeProximity = false;
             mIgnoreProximityUntilChanged = false;
         }
-        if (mScreenOffBecauseOfProximity) {
+
+        if (!mLogicalDisplay.isEnabled() || mScreenOffBecauseOfProximity) {
             state = Display.STATE_OFF;
         }
 
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index d88896c..aaec89a 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -682,7 +682,10 @@
                                     || oldState == Display.STATE_ON_SUSPEND) {
                                 setDisplayState(Display.STATE_ON);
                                 currentState = Display.STATE_ON;
-                            } else {
+
+                            // If UNKNOWN, we still want to set the initial display state,
+                            // otherwise, return early.
+                            } else if (oldState != Display.STATE_UNKNOWN) {
                                 return; // old state and new state is off
                             }
                         }
diff --git a/services/core/java/com/android/server/graphics/fonts/FontManagerService.java b/services/core/java/com/android/server/graphics/fonts/FontManagerService.java
index 06adce8..2b7d207 100644
--- a/services/core/java/com/android/server/graphics/fonts/FontManagerService.java
+++ b/services/core/java/com/android/server/graphics/fonts/FontManagerService.java
@@ -31,6 +31,7 @@
 import android.os.ShellCallback;
 import android.system.ErrnoException;
 import android.text.FontConfig;
+import android.text.TextUtils;
 import android.util.AndroidException;
 import android.util.IndentingPrintWriter;
 import android.util.Slog;
@@ -66,6 +67,8 @@
 
     @Override
     public FontConfig getFontConfig() {
+        getContext().enforceCallingPermission(Manifest.permission.UPDATE_FONTS,
+                "UPDATE_FONTS permission required.");
         return getSystemFontConfig();
     }
 
@@ -148,10 +151,24 @@
 
     /* package */ static class OtfFontFileParser implements UpdatableFontDir.FontFileParser {
         @Override
-        public String getPostScriptName(File file) throws IOException {
+        public String getCanonicalFileName(File file) throws IOException {
             ByteBuffer buffer = mmap(file);
             try {
-                return FontFileUtil.getPostScriptName(buffer, 0);
+                String psName = FontFileUtil.getPostScriptName(buffer, 0);
+                int isType1Font = FontFileUtil.isPostScriptType1Font(buffer, 0);
+                int isCollection = FontFileUtil.isCollectionFont(buffer);
+
+                if (TextUtils.isEmpty(psName) || isType1Font == -1 || isCollection == -1) {
+                    return null;
+                }
+
+                String extension;
+                if (isCollection == 1) {
+                    extension = isType1Font == 1 ? ".otc" : ".ttc";
+                } else {
+                    extension = isType1Font == 1 ? ".otf" : ".ttf";
+                }
+                return psName + extension;
             } finally {
                 NioUtils.freeDirectBuffer(buffer);
             }
diff --git a/services/core/java/com/android/server/graphics/fonts/UpdatableFontDir.java b/services/core/java/com/android/server/graphics/fonts/UpdatableFontDir.java
index 86dbe86..4f95d27 100644
--- a/services/core/java/com/android/server/graphics/fonts/UpdatableFontDir.java
+++ b/services/core/java/com/android/server/graphics/fonts/UpdatableFontDir.java
@@ -56,14 +56,12 @@
 
     private static final String TAG = "UpdatableFontDir";
     private static final String RANDOM_DIR_PREFIX = "~~";
-    // TODO: Support .otf
-    private static final String ALLOWED_EXTENSION = ".ttf";
 
     private static final String CONFIG_XML_FILE = "/data/fonts/config/config.xml";
 
     /** Interface to mock font file access in tests. */
     interface FontFileParser {
-        String getPostScriptName(File file) throws IOException;
+        String getCanonicalFileName(File file) throws IOException;
 
         long getRevision(File file) throws IOException;
     }
@@ -321,20 +319,20 @@
                         FontManager.RESULT_ERROR_VERIFICATION_FAILURE,
                         "Failed to setup fs-verity.", e);
             }
-            String postScriptName;
+            String canonicalFileName;
             try {
-                postScriptName = mParser.getPostScriptName(tempNewFontFile);
+                canonicalFileName = mParser.getCanonicalFileName(tempNewFontFile);
             } catch (IOException e) {
                 throw new SystemFontException(
                         FontManager.RESULT_ERROR_INVALID_FONT_FILE,
                         "Failed to read PostScript name from font file", e);
             }
-            if (postScriptName == null) {
+            if (canonicalFileName == null) {
                 throw new SystemFontException(
                         FontManager.RESULT_ERROR_INVALID_FONT_NAME,
                         "Failed to read PostScript name from font file");
             }
-            File newFontFile = new File(newDir, postScriptName + ALLOWED_EXTENSION);
+            File newFontFile = new File(newDir, canonicalFileName);
             if (!mFsverityUtil.rename(tempNewFontFile, newFontFile)) {
                 throw new SystemFontException(
                         FontManager.RESULT_ERROR_FAILED_TO_WRITE_FONT_FILE,
@@ -380,20 +378,38 @@
         return dir;
     }
 
+    private FontFileInfo lookupFontFileInfo(File file) {
+        String name = file.getName();
+
+        if (!name.endsWith(".ttf") && !name.endsWith(".otf") && !name.endsWith(".ttc")
+                && !name.endsWith(".otc")) {
+            return null;
+        }
+        String key = name.substring(0, name.length() - 4);
+        return mFontFileInfoMap.get(key);
+    }
+
+    private void putFontFileInfo(FontFileInfo info) {
+        String name = info.getFile().getName();
+        // The file name in FontFileInfo is already validated. Thus, just strip last 4 chars.
+        String key = name.substring(0, name.length() - 4);
+        mFontFileInfoMap.put(key, info);
+    }
+
     /**
      * Add the given {@link FontFileInfo} to {@link #mFontFileInfoMap} if its font revision is
      * higher than the currently used font file (either in {@link #mFontFileInfoMap} or {@link
      * #mPreinstalledFontDirs}).
      */
     private boolean addFileToMapIfNewer(FontFileInfo fontFileInfo, boolean deleteOldFile) {
-        String name = fontFileInfo.getFile().getName();
-        FontFileInfo existingInfo = mFontFileInfoMap.get(name);
+        FontFileInfo existingInfo = lookupFontFileInfo(fontFileInfo.getFile());
         final boolean shouldAddToMap;
         if (existingInfo == null) {
             // We got a new updatable font. We need to check if it's newer than preinstalled fonts.
             // Note that getPreinstalledFontRevision() returns -1 if there is no preinstalled font
             // with 'name'.
-            shouldAddToMap = getPreinstalledFontRevision(name) < fontFileInfo.getRevision();
+            long preInstalledRev = getPreinstalledFontRevision(fontFileInfo.getFile().getName());
+            shouldAddToMap = preInstalledRev < fontFileInfo.getRevision();
         } else {
             shouldAddToMap = existingInfo.getRevision() < fontFileInfo.getRevision();
         }
@@ -401,7 +417,7 @@
             if (deleteOldFile && existingInfo != null) {
                 FileUtils.deleteContentsAndDir(existingInfo.getRandomizedFontDir());
             }
-            mFontFileInfoMap.put(name, fontFileInfo);
+            putFontFileInfo(fontFileInfo);
         } else {
             if (deleteOldFile) {
                 FileUtils.deleteContentsAndDir(fontFileInfo.getRandomizedFontDir());
@@ -464,15 +480,18 @@
      */
     private boolean validateFontFileName(File file) {
         String fileName = file.getName();
-        String postScriptName = getPostScriptName(file);
-        return (postScriptName + ALLOWED_EXTENSION).equals(fileName);
+        String canonicalFileName = getCanonicalFileName(file);
+        if (canonicalFileName == null) {
+            return false;
+        }
+        return canonicalFileName.equals(fileName);
     }
 
     /** Returns the PostScript name of the given font file, or null. */
     @Nullable
-    private String getPostScriptName(File file) {
+    private String getCanonicalFileName(File file) {
         try {
-            return mParser.getPostScriptName(file);
+            return mParser.getCanonicalFileName(file);
         } catch (IOException e) {
             Slog.e(TAG, "Failed to read font file", e);
             return null;
@@ -514,7 +533,7 @@
         List<FontConfig.Font> fontList = fontFamily.getFontList();
         for (int i = 0; i < fontList.size(); i++) {
             FontConfig.Font font = fontList.get(i);
-            FontFileInfo info = mFontFileInfoMap.get(font.getFile().getName());
+            FontFileInfo info = lookupFontFileInfo(font.getFile());
             if (info == null) {
                 return null;
             }
@@ -537,8 +556,9 @@
 
     Map<String, File> getFontFileMap() {
         Map<String, File> map = new ArrayMap<>();
-        for (Map.Entry<String, FontFileInfo> entry : mFontFileInfoMap.entrySet()) {
-            map.put(entry.getKey(), entry.getValue().getFile());
+        for (int i = 0; i < mFontFileInfoMap.size(); ++i) {
+            File file = mFontFileInfoMap.valueAt(i).getFile();
+            map.put(file.getName(), file);
         }
         return map;
     }
diff --git a/services/core/java/com/android/server/hdmi/DeviceSelectAction.java b/services/core/java/com/android/server/hdmi/DeviceSelectAction.java
index c23e2e6..947ee24 100644
--- a/services/core/java/com/android/server/hdmi/DeviceSelectAction.java
+++ b/services/core/java/com/android/server/hdmi/DeviceSelectAction.java
@@ -97,11 +97,16 @@
 
     @Override
     public boolean start() {
-      // Wake-up on <Set Stream Path> was not mandatory before CEC 2.0.
-      // The message is re-sent at the end of the action for devices that don't support 2.0.
-      sendSetStreamPath();
-        int targetPowerStatus = localDevice().mService.getHdmiCecNetwork()
-                .getCecDeviceInfo(getTargetAddress()).getDevicePowerStatus();
+        // Wake-up on <Set Stream Path> was not mandatory before CEC 2.0.
+        // The message is re-sent at the end of the action for devices that don't support 2.0.
+        sendSetStreamPath();
+        int targetPowerStatus = HdmiControlManager.POWER_STATUS_UNKNOWN;
+        HdmiDeviceInfo targetDevice = localDevice().mService.getHdmiCecNetwork().getCecDeviceInfo(
+                getTargetAddress());
+        if (targetDevice != null) {
+            targetPowerStatus = targetDevice.getDevicePowerStatus();
+        }
+
         if (!mIsCec20 || targetPowerStatus == HdmiControlManager.POWER_STATUS_UNKNOWN) {
             queryDevicePowerStatus();
         } else if (targetPowerStatus == HdmiControlManager.POWER_STATUS_ON) {
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecConfig.java b/services/core/java/com/android/server/hdmi/HdmiCecConfig.java
index 624af30..6fbb26c 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecConfig.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecConfig.java
@@ -35,33 +35,19 @@
 import android.os.UserHandle;
 import android.provider.Settings.Global;
 import android.util.ArrayMap;
-import android.util.Slog;
 
+import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ConcurrentUtils;
-import com.android.server.hdmi.cec.config.CecSettings;
-import com.android.server.hdmi.cec.config.Setting;
-import com.android.server.hdmi.cec.config.Value;
-import com.android.server.hdmi.cec.config.XmlParser;
 
-import org.xmlpull.v1.XmlPullParserException;
-
-import java.io.BufferedInputStream;
-import java.io.ByteArrayInputStream;
 import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
 import java.util.ArrayList;
-import java.util.HashSet;
+import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map.Entry;
-import java.util.Set;
 import java.util.concurrent.Executor;
 
-import javax.xml.datatype.DatatypeConfigurationException;
-
 /**
  * The {@link HdmiCecConfig} class is used for getting information about
  * available HDMI CEC settings.
@@ -74,6 +60,10 @@
     private static final String SHARED_PREFS_DIR = "shared_prefs";
     private static final String SHARED_PREFS_NAME = "cec_config.xml";
 
+    private static final int STORAGE_SYSPROPS = 0;
+    private static final int STORAGE_GLOBAL_SETTINGS = 1;
+    private static final int STORAGE_SHARED_PREFS = 2;
+
     @IntDef({
         STORAGE_SYSPROPS,
         STORAGE_GLOBAL_SETTINGS,
@@ -81,10 +71,6 @@
     })
     private @interface Storage {}
 
-    private static final int STORAGE_SYSPROPS = 0;
-    private static final int STORAGE_GLOBAL_SETTINGS = 1;
-    private static final int STORAGE_SHARED_PREFS = 2;
-
     private static final String VALUE_TYPE_STRING = "string";
     private static final String VALUE_TYPE_INT = "int";
 
@@ -96,8 +82,6 @@
 
     @NonNull private final Context mContext;
     @NonNull private final StorageAdapter mStorageAdapter;
-    @Nullable private final CecSettings mSystemConfig;
-    @Nullable private final CecSettings mVendorOverride;
 
     private final Object mLock = new Object();
 
@@ -107,6 +91,18 @@
 
     private SettingsObserver mSettingsObserver;
 
+    private LinkedHashMap<String, Setting> mSettings = new LinkedHashMap<>();
+
+    /**
+     * Exception thrown when the CEC Configuration setup verification fails.
+     * This usually means a settings lacks default value or storage/storage key.
+     */
+    public static class VerificationException extends RuntimeException {
+        public VerificationException(String message) {
+            super(message);
+        }
+    }
+
     /**
      * Listener used to get notifications when value of a setting changes.
      */
@@ -202,91 +198,297 @@
         }
     }
 
+    private class Value {
+        private final String mStringValue;
+        private final Integer mIntValue;
+
+        Value(@NonNull String value) {
+            mStringValue = value;
+            mIntValue = null;
+        }
+
+        Value(@NonNull Integer value) {
+            mStringValue = null;
+            mIntValue = value;
+        }
+
+        String getStringValue() {
+            return mStringValue;
+        }
+
+        Integer getIntValue() {
+            return mIntValue;
+        }
+    }
+
+    private class Setting {
+        @NonNull private final Context mContext;
+        @NonNull private final @CecSettingName String mName;
+        private final boolean mUserConfigurable;
+
+        private Value mDefaultValue = null;
+        private List<Value> mAllowedValues = new ArrayList<>();
+
+        Setting(@NonNull Context context,
+                @NonNull @CecSettingName String name,
+                int userConfResId) {
+            mContext = context;
+            mName = name;
+            mUserConfigurable = mContext.getResources().getBoolean(userConfResId);
+        }
+
+        public @CecSettingName String getName() {
+            return mName;
+        }
+
+        public @ValueType String getValueType() {
+            return getDefaultValue().getStringValue() != null
+                    ? VALUE_TYPE_STRING
+                    : VALUE_TYPE_INT;
+        }
+
+        public Value getDefaultValue() {
+            if (mDefaultValue == null) {
+                throw new VerificationException("Invalid CEC setup for '"
+                    + this.getName() + "' setting. "
+                    + "Setting has no default value.");
+            }
+            return mDefaultValue;
+        }
+
+        public boolean getUserConfigurable() {
+            return mUserConfigurable;
+        }
+
+        private void registerValue(@NonNull Value value,
+                                   int allowedResId, int defaultResId) {
+            if (mContext.getResources().getBoolean(allowedResId)) {
+                mAllowedValues.add(value);
+                if (mContext.getResources().getBoolean(defaultResId)) {
+                    if (mDefaultValue != null) {
+                        throw new VerificationException("Invalid CEC setup for '"
+                            + this.getName() + "' setting. "
+                            + "Setting already has a default value.");
+                    }
+                    mDefaultValue = value;
+                }
+            }
+        }
+
+        public void registerValue(@NonNull String value, int allowedResId,
+                                  int defaultResId) {
+            registerValue(new Value(value), allowedResId, defaultResId);
+        }
+
+        public void registerValue(int value, int allowedResId,
+                                  int defaultResId) {
+            registerValue(new Value(value), allowedResId, defaultResId);
+        }
+
+
+        public List<Value> getAllowedValues() {
+            return mAllowedValues;
+        }
+    }
+
     @VisibleForTesting
     HdmiCecConfig(@NonNull Context context,
-                  @NonNull StorageAdapter storageAdapter,
-                  @Nullable CecSettings systemConfig,
-                  @Nullable CecSettings vendorOverride) {
+                  @NonNull StorageAdapter storageAdapter) {
         mContext = context;
         mStorageAdapter = storageAdapter;
-        mSystemConfig = systemConfig;
-        mVendorOverride = vendorOverride;
-        if (mSystemConfig == null) {
-            Slog.i(TAG, "CEC system configuration XML missing.");
-        }
-        if (mVendorOverride == null) {
-            Slog.i(TAG, "CEC OEM configuration override XML missing.");
-        }
+
+        Setting hdmiCecEnabled = registerSetting(
+                HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
+                R.bool.config_cecHdmiCecEnabled_userConfigurable);
+        hdmiCecEnabled.registerValue(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED,
+                R.bool.config_cecHdmiCecControlEnabled_allowed,
+                R.bool.config_cecHdmiCecControlEnabled_default);
+        hdmiCecEnabled.registerValue(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED,
+                R.bool.config_cecHdmiCecControlDisabled_allowed,
+                R.bool.config_cecHdmiCecControlDisabled_default);
+
+        Setting hdmiCecVersion = registerSetting(
+                HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
+                R.bool.config_cecHdmiCecVersion_userConfigurable);
+        hdmiCecVersion.registerValue(HdmiControlManager.HDMI_CEC_VERSION_1_4_B,
+                R.bool.config_cecHdmiCecVersion14b_allowed,
+                R.bool.config_cecHdmiCecVersion14b_default);
+        hdmiCecVersion.registerValue(HdmiControlManager.HDMI_CEC_VERSION_2_0,
+                R.bool.config_cecHdmiCecVersion20_allowed,
+                R.bool.config_cecHdmiCecVersion20_default);
+
+        Setting powerControlMode = registerSetting(
+                HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE,
+                R.bool.config_cecSendStandbyOnSleep_userConfigurable);
+        powerControlMode.registerValue(HdmiControlManager.POWER_CONTROL_MODE_TV,
+                R.bool.config_cecPowerControlModeTv_allowed,
+                R.bool.config_cecPowerControlModeTv_default);
+        powerControlMode.registerValue(HdmiControlManager.POWER_CONTROL_MODE_BROADCAST,
+                R.bool.config_cecPowerControlModeBroadcast_allowed,
+                R.bool.config_cecPowerControlModeBroadcast_default);
+        powerControlMode.registerValue(HdmiControlManager.POWER_CONTROL_MODE_NONE,
+                R.bool.config_cecPowerControlModeNone_allowed,
+                R.bool.config_cecPowerControlModeNone_default);
+
+        Setting powerStateChangeOnActiveSourceLost = registerSetting(
+                HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST,
+                R.bool.config_cecPowerStateChangeOnActiveSourceLost_userConfigurable);
+        powerStateChangeOnActiveSourceLost.registerValue(
+                HdmiControlManager.POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_NONE,
+                R.bool.config_cecPowerStateChangeOnActiveSourceLostNone_allowed,
+                R.bool.config_cecPowerStateChangeOnActiveSourceLostNone_default);
+        powerStateChangeOnActiveSourceLost.registerValue(
+                HdmiControlManager.POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_STANDBY_NOW,
+                R.bool.config_cecPowerStateChangeOnActiveSourceLostStandbyNow_allowed,
+                R.bool.config_cecPowerStateChangeOnActiveSourceLostStandbyNow_default);
+
+        Setting systemAudioModeMuting = registerSetting(
+                HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING,
+                R.bool.config_cecSystemAudioModeMuting_userConfigurable);
+        systemAudioModeMuting.registerValue(HdmiControlManager.SYSTEM_AUDIO_MODE_MUTING_ENABLED,
+                R.bool.config_cecSystemAudioModeMutingEnabled_allowed,
+                R.bool.config_cecSystemAudioModeMutingEnabled_default);
+        systemAudioModeMuting.registerValue(HdmiControlManager.SYSTEM_AUDIO_MODE_MUTING_DISABLED,
+                R.bool.config_cecSystemAudioModeMutingDisabled_allowed,
+                R.bool.config_cecSystemAudioModeMutingDisabled_default);
+
+        Setting volumeControlMode = registerSetting(
+                HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE,
+                R.bool.config_cecVolumeControlMode_userConfigurable);
+        volumeControlMode.registerValue(HdmiControlManager.VOLUME_CONTROL_ENABLED,
+                R.bool.config_cecVolumeControlModeEnabled_allowed,
+                R.bool.config_cecVolumeControlModeEnabled_default);
+        volumeControlMode.registerValue(HdmiControlManager.VOLUME_CONTROL_DISABLED,
+                R.bool.config_cecVolumeControlModeDisabled_allowed,
+                R.bool.config_cecVolumeControlModeDisabled_default);
+
+        Setting tvWakeOnOneTouchPlay = registerSetting(
+                HdmiControlManager.CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY,
+                R.bool.config_cecTvWakeOnOneTouchPlay_userConfigurable);
+        tvWakeOnOneTouchPlay.registerValue(HdmiControlManager.TV_WAKE_ON_ONE_TOUCH_PLAY_ENABLED,
+                R.bool.config_cecTvWakeOnOneTouchPlayEnabled_allowed,
+                R.bool.config_cecTvWakeOnOneTouchPlayEnabled_default);
+        tvWakeOnOneTouchPlay.registerValue(HdmiControlManager.TV_WAKE_ON_ONE_TOUCH_PLAY_DISABLED,
+                R.bool.config_cecTvWakeOnOneTouchPlayDisabled_allowed,
+                R.bool.config_cecTvWakeOnOneTouchPlayDisabled_default);
+
+        Setting tvSendStandbyOnSleep = registerSetting(
+                HdmiControlManager.CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP,
+                R.bool.config_cecTvSendStandbyOnSleep_userConfigurable);
+        tvSendStandbyOnSleep.registerValue(HdmiControlManager.TV_SEND_STANDBY_ON_SLEEP_ENABLED,
+                R.bool.config_cecTvSendStandbyOnSleepEnabled_allowed,
+                R.bool.config_cecTvSendStandbyOnSleepEnabled_default);
+        tvSendStandbyOnSleep.registerValue(HdmiControlManager.TV_SEND_STANDBY_ON_SLEEP_DISABLED,
+                R.bool.config_cecTvSendStandbyOnSleepDisabled_allowed,
+                R.bool.config_cecTvSendStandbyOnSleepDisabled_default);
+
+        Setting rcProfileTv = registerSetting(
+                HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_TV,
+                R.bool.config_cecRcProfileTv_userConfigurable);
+        rcProfileTv.registerValue(HdmiControlManager.RC_PROFILE_TV_NONE,
+                R.bool.config_cecRcProfileTvNone_allowed,
+                R.bool.config_cecRcProfileTvNone_default);
+        rcProfileTv.registerValue(HdmiControlManager.RC_PROFILE_TV_ONE,
+                R.bool.config_cecRcProfileTvOne_allowed,
+                R.bool.config_cecRcProfileTvOne_default);
+        rcProfileTv.registerValue(HdmiControlManager.RC_PROFILE_TV_TWO,
+                R.bool.config_cecRcProfileTvTwo_allowed,
+                R.bool.config_cecRcProfileTvTwo_default);
+        rcProfileTv.registerValue(HdmiControlManager.RC_PROFILE_TV_THREE,
+                R.bool.config_cecRcProfileTvThree_allowed,
+                R.bool.config_cecRcProfileTvThree_default);
+        rcProfileTv.registerValue(HdmiControlManager.RC_PROFILE_TV_FOUR,
+                R.bool.config_cecRcProfileTvFour_allowed,
+                R.bool.config_cecRcProfileTvFour_default);
+
+        Setting rcProfileSourceRootMenu = registerSetting(
+                HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_ROOT_MENU,
+                R.bool.config_cecRcProfileSourceRootMenu_userConfigurable);
+        rcProfileSourceRootMenu.registerValue(
+                HdmiControlManager.RC_PROFILE_SOURCE_ROOT_MENU_HANDLED,
+                R.bool.config_cecRcProfileSourceRootMenuHandled_allowed,
+                R.bool.config_cecRcProfileSourceRootMenuHandled_default);
+        rcProfileSourceRootMenu.registerValue(
+                HdmiControlManager.RC_PROFILE_SOURCE_ROOT_MENU_NOT_HANDLED,
+                R.bool.config_cecRcProfileSourceRootMenuNotHandled_allowed,
+                R.bool.config_cecRcProfileSourceRootMenuNotHandled_default);
+
+        Setting rcProfileSourceSetupMenu = registerSetting(
+                HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_SETUP_MENU,
+                R.bool.config_cecRcProfileSourceSetupMenu_userConfigurable);
+        rcProfileSourceSetupMenu.registerValue(
+                HdmiControlManager.RC_PROFILE_SOURCE_SETUP_MENU_HANDLED,
+                R.bool.config_cecRcProfileSourceSetupMenuHandled_allowed,
+                R.bool.config_cecRcProfileSourceSetupMenuHandled_default);
+        rcProfileSourceSetupMenu.registerValue(
+                HdmiControlManager.RC_PROFILE_SOURCE_SETUP_MENU_NOT_HANDLED,
+                R.bool.config_cecRcProfileSourceSetupMenuNotHandled_allowed,
+                R.bool.config_cecRcProfileSourceSetupMenuNotHandled_default);
+
+        Setting rcProfileSourceContentsMenu = registerSetting(
+                HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_CONTENTS_MENU,
+                R.bool.config_cecRcProfileSourceContentsMenu_userConfigurable);
+        rcProfileSourceContentsMenu.registerValue(
+                HdmiControlManager.RC_PROFILE_SOURCE_CONTENTS_MENU_HANDLED,
+                R.bool.config_cecRcProfileSourceContentsMenuHandled_allowed,
+                R.bool.config_cecRcProfileSourceContentsMenuHandled_default);
+        rcProfileSourceContentsMenu.registerValue(
+                HdmiControlManager.RC_PROFILE_SOURCE_CONTENTS_MENU_NOT_HANDLED,
+                R.bool.config_cecRcProfileSourceContentsMenuNotHandled_allowed,
+                R.bool.config_cecRcProfileSourceContentsMenuNotHandled_default);
+
+        Setting rcProfileSourceTopMenu = registerSetting(
+                HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_TOP_MENU,
+                R.bool.config_cecRcProfileSourceTopMenu_userConfigurable);
+        rcProfileSourceTopMenu.registerValue(
+                HdmiControlManager.RC_PROFILE_SOURCE_TOP_MENU_HANDLED,
+                R.bool.config_cecRcProfileSourceTopMenuHandled_allowed,
+                R.bool.config_cecRcProfileSourceTopMenuHandled_default);
+        rcProfileSourceTopMenu.registerValue(
+                HdmiControlManager.RC_PROFILE_SOURCE_TOP_MENU_NOT_HANDLED,
+                R.bool.config_cecRcProfileSourceTopMenuNotHandled_allowed,
+                R.bool.config_cecRcProfileSourceTopMenuNotHandled_default);
+
+        Setting rcProfileSourceMediaContextSensitiveMenu = registerSetting(
+                HdmiControlManager
+                    .CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_MEDIA_CONTEXT_SENSITIVE_MENU,
+                R.bool.config_cecRcProfileSourceMediaContextSensitiveMenu_userConfigurable);
+        rcProfileSourceMediaContextSensitiveMenu.registerValue(
+                HdmiControlManager.RC_PROFILE_SOURCE_MEDIA_CONTEXT_SENSITIVE_MENU_HANDLED,
+                R.bool.config_cecRcProfileSourceMediaContextSensitiveMenuHandled_allowed,
+                R.bool.config_cecRcProfileSourceMediaContextSensitiveMenuHandled_default);
+        rcProfileSourceMediaContextSensitiveMenu.registerValue(
+                HdmiControlManager.RC_PROFILE_SOURCE_MEDIA_CONTEXT_SENSITIVE_MENU_NOT_HANDLED,
+                R.bool.config_cecRcProfileSourceMediaContextSensitiveMenuNotHandled_allowed,
+                R.bool.config_cecRcProfileSourceMediaContextSensitiveMenuNotHandled_default);
+
+        verifySettings();
     }
 
     HdmiCecConfig(@NonNull Context context) {
-        this(context, new StorageAdapter(context),
-             readSettingsFromFile(Environment.buildPath(Environment.getRootDirectory(),
-                                                        ETC_DIR, CONFIG_FILE)),
-             readSettingsFromFile(Environment.buildPath(Environment.getVendorDirectory(),
-                                                        ETC_DIR, CONFIG_FILE)));
+        this(context, new StorageAdapter(context));
     }
 
-    @Nullable
-    private static CecSettings readSettingsFromFile(@NonNull File file) {
-        if (!file.exists()) {
-            return null;
-        }
-        if (!file.isFile()) {
-            Slog.e(TAG, "CEC configuration is not a file: " + file + ", skipping.");
-            return null;
-        }
-        try (InputStream in = new BufferedInputStream(new FileInputStream(file))) {
-            return XmlParser.read(in);
-        } catch (IOException | DatatypeConfigurationException | XmlPullParserException e) {
-            Slog.e(TAG, "Encountered an error while reading/parsing CEC config file: " + file, e);
-        }
-        return null;
+    private Setting registerSetting(@NonNull @CecSettingName String name,
+                               int userConfResId) {
+        Setting setting = new Setting(mContext, name, userConfResId);
+        mSettings.put(name, setting);
+        return setting;
     }
 
-    @NonNull
-    @VisibleForTesting
-    static HdmiCecConfig createFromStrings(@NonNull Context context,
-                                           @NonNull StorageAdapter storageAdapter,
-                                           @Nullable String productConfigXml,
-                                           @Nullable String vendorOverrideXml) {
-        CecSettings productConfig = null;
-        CecSettings vendorOverride = null;
-        try {
-            if (productConfigXml != null) {
-                productConfig = XmlParser.read(
-                        new ByteArrayInputStream(productConfigXml.getBytes()));
-            }
-            if (vendorOverrideXml != null) {
-                vendorOverride = XmlParser.read(
-                        new ByteArrayInputStream(vendorOverrideXml.getBytes()));
-            }
-        } catch (IOException | DatatypeConfigurationException | XmlPullParserException e) {
-            Slog.e(TAG, "Encountered an error while reading/parsing CEC config strings", e);
+    private void verifySettings() {
+        for (Setting setting: mSettings.values()) {
+            // This will throw an exception when a setting
+            // doesn't have a default value assigned.
+            setting.getDefaultValue();
+            getStorage(setting);
+            getStorageKey(setting);
         }
-        return new HdmiCecConfig(context, storageAdapter, productConfig, vendorOverride);
     }
 
     @Nullable
     private Setting getSetting(@NonNull String name) {
-        if (mSystemConfig == null) {
-            return null;
-        }
-        if (mVendorOverride != null) {
-            // First read from the vendor override.
-            for (Setting setting : mVendorOverride.getSetting()) {
-                if (setting.getName().equals(name)) {
-                    return setting;
-                }
-            }
-        }
-        // If not found, try the system config.
-        for (Setting setting : mSystemConfig.getSetting()) {
-            if (setting.getName().equals(name)) {
-                return setting;
-            }
-        }
-        return null;
+        return mSettings.containsKey(name) ? mSettings.get(name) : null;
     }
 
     @Storage
@@ -322,7 +524,7 @@
                     .CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_MEDIA_CONTEXT_SENSITIVE_MENU:
                 return STORAGE_SHARED_PREFS;
             default:
-                throw new RuntimeException("Invalid CEC setting '" + setting.getName()
+                throw new VerificationException("Invalid CEC setting '" + setting.getName()
                         + "' storage.");
         }
     }
@@ -359,7 +561,7 @@
                     .CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_MEDIA_CONTEXT_SENSITIVE_MENU:
                 return setting.getName();
             default:
-                throw new RuntimeException("Invalid CEC setting '" + setting.getName()
+                throw new VerificationException("Invalid CEC setting '" + setting.getName()
                     + "' storage key.");
         }
     }
@@ -396,10 +598,6 @@
         }
     }
 
-    private int getIntValue(@NonNull Value value) {
-        return Integer.decode(value.getIntValue());
-    }
-
     private void notifyGlobalSettingChanged(String setting) {
         switch (setting) {
             case Global.HDMI_CONTROL_ENABLED:
@@ -533,41 +731,20 @@
      * Returns a list of all settings based on the XML metadata.
      */
     public @CecSettingName List<String> getAllSettings() {
-        if (mSystemConfig == null) {
-            return new ArrayList<String>();
-        }
-        List<String> allSettings = new ArrayList<String>();
-        for (Setting setting : mSystemConfig.getSetting()) {
-            allSettings.add(setting.getName());
-        }
-        return allSettings;
+        return new ArrayList<>(mSettings.keySet());
     }
 
     /**
      * Returns a list of user-modifiable settings based on the XML metadata.
      */
     public @CecSettingName List<String> getUserSettings() {
-        if (mSystemConfig == null) {
-            return new ArrayList<String>();
-        }
-        Set<String> userSettings = new HashSet<String>();
-        // First read from the system config.
-        for (Setting setting : mSystemConfig.getSetting()) {
+        List<String> settings = new ArrayList<>();
+        for (Setting setting: mSettings.values()) {
             if (setting.getUserConfigurable()) {
-                userSettings.add(setting.getName());
+                settings.add(setting.getName());
             }
         }
-        if (mVendorOverride != null) {
-            // Next either add or remove based on the vendor override.
-            for (Setting setting : mVendorOverride.getSetting()) {
-                if (setting.getUserConfigurable()) {
-                    userSettings.add(setting.getName());
-                } else {
-                    userSettings.remove(setting.getName());
-                }
-            }
-        }
-        return new ArrayList(userSettings);
+        return settings;
     }
 
     /**
@@ -607,7 +784,7 @@
                     + "' is not a string-type setting.");
         }
         List<String> allowedValues = new ArrayList<String>();
-        for (Value allowedValue : setting.getAllowedValues().getValue()) {
+        for (Value allowedValue : setting.getAllowedValues()) {
             allowedValues.add(allowedValue.getStringValue());
         }
         return allowedValues;
@@ -626,8 +803,8 @@
                     + "' is not a string-type setting.");
         }
         List<Integer> allowedValues = new ArrayList<Integer>();
-        for (Value allowedValue : setting.getAllowedValues().getValue()) {
-            allowedValues.add(getIntValue(allowedValue));
+        for (Value allowedValue : setting.getAllowedValues()) {
+            allowedValues.add(allowedValue.getIntValue());
         }
         return allowedValues;
     }
@@ -659,7 +836,7 @@
             throw new IllegalArgumentException("Setting '" + name
                     + "' is not a string-type setting.");
         }
-        return getIntValue(getSetting(name).getDefaultValue());
+        return getSetting(name).getDefaultValue().getIntValue();
     }
 
     /**
@@ -691,7 +868,7 @@
                     + "' is not a int-type setting.");
         }
         HdmiLogger.debug("Getting CEC setting value '" + name + "'.");
-        String defaultValue = Integer.toString(getIntValue(setting.getDefaultValue()));
+        String defaultValue = Integer.toString(setting.getDefaultValue().getIntValue());
         String value = retrieveValue(setting, defaultValue);
         return Integer.parseInt(value);
     }
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
index d8914b3..bdc4e66 100755
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
@@ -500,7 +500,8 @@
 
         HdmiDeviceInfo cecDeviceInfo = mService.getHdmiCecNetwork().getCecDeviceInfo(address);
         // If no non-default display name is available for the device, request the devices OSD name.
-        if (cecDeviceInfo.getDisplayName().equals(HdmiUtils.getDefaultDeviceName(address))) {
+        if (cecDeviceInfo != null && cecDeviceInfo.getDisplayName().equals(
+                HdmiUtils.getDefaultDeviceName(address))) {
             mService.sendCecCommand(
                     HdmiCecMessageBuilder.buildGiveOsdNameCommand(mAddress, address));
         }
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 7235a92..90d6433 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -30,6 +30,7 @@
 import static android.hardware.hdmi.HdmiControlManager.TIMER_RECORDING_TYPE_DIGITAL;
 import static android.hardware.hdmi.HdmiControlManager.TIMER_RECORDING_TYPE_EXTERNAL;
 
+import android.annotation.Nullable;
 import android.hardware.hdmi.HdmiControlManager;
 import android.hardware.hdmi.HdmiDeviceInfo;
 import android.hardware.hdmi.HdmiPortInfo;
@@ -1147,6 +1148,7 @@
                 && getAvrDeviceInfo() != null;
     }
 
+    @Nullable
     @ServiceThreadOnly
     HdmiDeviceInfo getAvrDeviceInfo() {
         assertRunOnServiceThread();
@@ -1157,6 +1159,7 @@
         return getSafeAvrDeviceInfo() != null;
     }
 
+    @Nullable
     HdmiDeviceInfo getSafeAvrDeviceInfo() {
         return mService.getHdmiCecNetwork().getSafeCecDeviceInfo(Constants.ADDR_AUDIO_SYSTEM);
     }
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java b/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java
index b748ae0..7ceaa95 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java
@@ -185,6 +185,12 @@
         mLocalDevices.clear();
     }
 
+    /**
+     * Get the device info of a local device or a device in the CEC network by a device id.
+     * @param id id of the device to get
+     * @return the device with the given id, or {@code null}
+     */
+    @Nullable
     public HdmiDeviceInfo getDeviceInfo(int id) {
         return mDeviceInfos.get(id);
     }
@@ -717,6 +723,7 @@
      * @return {@link HdmiDeviceInfo} matched with the given {@code logicalAddress}.
      * Returns null if no logical address matched
      */
+    @Nullable
     HdmiDeviceInfo getSafeCecDeviceInfo(int logicalAddress) {
         for (HdmiDeviceInfo info : mSafeAllDeviceInfos) {
             if (info.isCecDevice() && info.getLogicalAddress() == logicalAddress) {
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 115cafed..e6e2f96 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -988,6 +988,7 @@
         return mCecController.getVendorId();
     }
 
+    @Nullable
     @ServiceThreadOnly
     HdmiDeviceInfo getDeviceInfo(int logicalAddress) {
         assertRunOnServiceThread();
diff --git a/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java b/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java
index 73ecbe0..9d2db94 100644
--- a/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java
+++ b/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java
@@ -16,6 +16,7 @@
 package com.android.server.hdmi;
 
 import android.hardware.hdmi.HdmiControlManager;
+import android.hardware.hdmi.HdmiDeviceInfo;
 import android.hardware.hdmi.HdmiPlaybackClient.OneTouchPlayCallback;
 import android.hardware.hdmi.IHdmiControlCallback;
 import android.util.Slog;
@@ -62,8 +63,7 @@
             Slog.e(TAG, "Wrong arguments");
             return null;
         }
-        return new OneTouchPlayAction(source, targetAddress,
-                callback);
+        return new OneTouchPlayAction(source, targetAddress, callback);
     }
 
     private OneTouchPlayAction(HdmiCecLocalDevice localDevice, int targetAddress,
@@ -71,8 +71,8 @@
         this(localDevice, targetAddress, callback,
                 localDevice.getDeviceInfo().getCecVersion()
                         >= HdmiControlManager.HDMI_CEC_VERSION_2_0
-                        && localDevice.mService.getHdmiCecNetwork().getCecDeviceInfo(
-                        targetAddress).getCecVersion() >= HdmiControlManager.HDMI_CEC_VERSION_2_0);
+                        && getTargetCecVersion(localDevice, targetAddress)
+                        >= HdmiControlManager.HDMI_CEC_VERSION_2_0);
     }
 
     @VisibleForTesting
@@ -88,9 +88,9 @@
         // Because only source device can create this action, it's safe to cast.
         mSource = source();
         sendCommand(HdmiCecMessageBuilder.buildTextViewOn(getSourceAddress(), mTargetAddress));
-        boolean targetOnBefore = localDevice().mService.getHdmiCecNetwork()
-                .getCecDeviceInfo(mTargetAddress).getDevicePowerStatus()
-                == HdmiControlManager.POWER_STATUS_ON;
+
+        boolean targetOnBefore = getTargetDevicePowerStatus(mSource, mTargetAddress,
+                HdmiControlManager.POWER_STATUS_UNKNOWN) == HdmiControlManager.POWER_STATUS_ON;
         broadcastActiveSource();
         // If the device is not an audio system itself, request the connected audio system to
         // turn on.
@@ -98,8 +98,8 @@
             sendCommand(HdmiCecMessageBuilder.buildSystemAudioModeRequest(getSourceAddress(),
                     Constants.ADDR_AUDIO_SYSTEM, getSourcePath(), true));
         }
-        int targetPowerStatus = localDevice().mService.getHdmiCecNetwork()
-                .getCecDeviceInfo(mTargetAddress).getDevicePowerStatus();
+        int targetPowerStatus = getTargetDevicePowerStatus(mSource, mTargetAddress,
+                HdmiControlManager.POWER_STATUS_UNKNOWN);
         if (!mIsCec20 || targetPowerStatus == HdmiControlManager.POWER_STATUS_UNKNOWN) {
             queryDevicePowerStatus();
         } else if (targetPowerStatus == HdmiControlManager.POWER_STATUS_ON) {
@@ -179,4 +179,23 @@
         return sendStandbyOnSleep.equals(HdmiControlManager.POWER_CONTROL_MODE_BROADCAST);
     }
 
+    private static int getTargetCecVersion(HdmiCecLocalDevice localDevice,
+            int targetLogicalAddress) {
+        HdmiDeviceInfo targetDevice = localDevice.mService.getHdmiCecNetwork().getCecDeviceInfo(
+                targetLogicalAddress);
+        if (targetDevice != null) {
+            return targetDevice.getCecVersion();
+        }
+        return HdmiControlManager.HDMI_CEC_VERSION_1_4_B;
+    }
+
+    private static int getTargetDevicePowerStatus(HdmiCecLocalDevice localDevice,
+            int targetLogicalAddress, int defaultPowerStatus) {
+        HdmiDeviceInfo targetDevice = localDevice.mService.getHdmiCecNetwork().getCecDeviceInfo(
+                targetLogicalAddress);
+        if (targetDevice != null) {
+            return targetDevice.getDevicePowerStatus();
+        }
+        return defaultPowerStatus;
+    }
 }
diff --git a/services/core/java/com/android/server/hdmi/cec_config.xml b/services/core/java/com/android/server/hdmi/cec_config.xml
deleted file mode 100644
index 191e725..0000000
--- a/services/core/java/com/android/server/hdmi/cec_config.xml
+++ /dev/null
@@ -1,133 +0,0 @@
-<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
-<cec-settings>
-  <setting name="hdmi_cec_enabled"
-           value-type="int"
-           user-configurable="true">
-    <allowed-values>
-      <value int-value="0" />
-      <value int-value="1" />
-    </allowed-values>
-    <default-value int-value="1" />
-  </setting>
-  <setting name="hdmi_cec_version"
-           value-type="int"
-           user-configurable="true">
-    <allowed-values>
-      <value int-value="0x05" />
-      <value int-value="0x06" />
-    </allowed-values>
-    <default-value int-value="0x05" />
-  </setting>
-  <setting name="send_standby_on_sleep"
-           value-type="string"
-           user-configurable="true">
-    <allowed-values>
-      <value string-value="to_tv" />
-      <value string-value="broadcast" />
-      <value string-value="none" />
-    </allowed-values>
-    <default-value string-value="to_tv" />
-  </setting>
-  <setting name="power_state_change_on_active_source_lost"
-           value-type="string"
-           user-configurable="true">
-    <allowed-values>
-      <value string-value="none" />
-      <value string-value="standby_now" />
-    </allowed-values>
-    <default-value string-value="none" />
-  </setting>
-  <setting name="system_audio_mode_muting"
-           value-type="int"
-           user-configurable="true">
-    <allowed-values>
-      <value int-value="0" />
-      <value int-value="1" />
-    </allowed-values>
-    <default-value int-value="1" />
-  </setting>
-  <setting name="volume_control_enabled"
-      value-type="int"
-      user-configurable="true">
-    <allowed-values>
-      <value int-value="0" />
-      <value int-value="1" />
-    </allowed-values>
-    <default-value int-value="1" />
-  </setting>
-  <setting name="tv_wake_on_one_touch_play"
-      value-type="int"
-      user-configurable="true">
-    <allowed-values>
-      <value int-value="0" />
-      <value int-value="1" />
-    </allowed-values>
-    <default-value int-value="1" />
-  </setting>
-  <setting name="tv_send_standby_on_sleep"
-      value-type="int"
-      user-configurable="true">
-    <allowed-values>
-      <value int-value="0" />
-      <value int-value="1" />
-    </allowed-values>
-    <default-value int-value="1" />
-  </setting>
-  <setting name="rc_profile_tv"
-      value-type="int"
-      user-configurable="false">
-    <allowed-values>
-      <value int-value="0x0" />
-      <value int-value="0x2" />
-      <value int-value="0x6" />
-      <value int-value="0xA" />
-      <value int-value="0xE" />
-    </allowed-values>
-    <default-value int-value="0x0" />
-  </setting>
-  <setting name="rc_profile_source_handles_root_menu"
-      value-type="int"
-      user-configurable="false">
-    <allowed-values>
-      <value int-value="0" />
-      <value int-value="1" />
-    </allowed-values>
-    <default-value int-value="1" />
-  </setting>
-  <setting name="rc_profile_source_handles_setup_menu"
-      value-type="int"
-      user-configurable="false">
-    <allowed-values>
-      <value int-value="0" />
-      <value int-value="1" />
-    </allowed-values>
-    <default-value int-value="1" />
-  </setting>
-  <setting name="rc_profile_source_handles_contents_menu"
-      value-type="int"
-      user-configurable="false">
-    <allowed-values>
-      <value int-value="0" />
-      <value int-value="1" />
-    </allowed-values>
-    <default-value int-value="0" />
-  </setting>
-  <setting name="rc_profile_source_handles_top_menu"
-      value-type="int"
-      user-configurable="false">
-    <allowed-values>
-      <value int-value="0" />
-      <value int-value="1" />
-    </allowed-values>
-    <default-value int-value="0" />
-  </setting>
-  <setting name="rc_profile_source_handles_media_context_sensitive_menu"
-      value-type="int"
-      user-configurable="false">
-    <allowed-values>
-      <value int-value="0" />
-      <value int-value="1" />
-    </allowed-values>
-    <default-value int-value="0" />
-  </setting>
-</cec-settings>
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 7dc9a0b..cbe6e69 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -304,7 +304,7 @@
             int displayId, InputApplicationHandle application);
     private static native void nativeSetFocusedDisplay(long ptr, int displayId);
     private static native boolean nativeTransferTouchFocus(long ptr,
-            IBinder fromChannelToken, IBinder toChannelToken);
+            IBinder fromChannelToken, IBinder toChannelToken, boolean isDragDrop);
     private static native void nativeSetPointerSpeed(long ptr, int speed);
     private static native void nativeSetShowTouches(long ptr, boolean enabled);
     private static native void nativeSetInteractive(long ptr, boolean interactive);
@@ -1727,12 +1727,14 @@
      * @param fromChannel The channel of a window that currently has touch focus.
      * @param toChannel The channel of the window that should receive touch focus in
      * place of the first.
+     * @param isDragDrop True if transfer touch focus for drag and drop.
      * @return True if the transfer was successful.  False if the window with the
      * specified channel did not actually have touch focus at the time of the request.
      */
     public boolean transferTouchFocus(@NonNull InputChannel fromChannel,
-            @NonNull InputChannel toChannel) {
-        return nativeTransferTouchFocus(mPtr, fromChannel.getToken(), toChannel.getToken());
+            @NonNull InputChannel toChannel, boolean isDragDrop) {
+        return nativeTransferTouchFocus(mPtr, fromChannel.getToken(), toChannel.getToken(),
+                isDragDrop);
     }
 
     /**
@@ -1752,7 +1754,8 @@
             @NonNull IBinder toChannelToken) {
         Objects.nonNull(fromChannelToken);
         Objects.nonNull(toChannelToken);
-        return nativeTransferTouchFocus(mPtr, fromChannelToken, toChannelToken);
+        return nativeTransferTouchFocus(mPtr, fromChannelToken, toChannelToken,
+                false /* isDragDrop */);
     }
 
     @Override // Binder call
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index a89cb55..e9c3ec3 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -2381,9 +2381,12 @@
             showCurrentInputLocked(mCurFocusedWindow, getAppShowFlags(), null,
                     SoftInputShowHideReason.ATTACH_NEW_INPUT);
         }
+        final InputMethodInfo curInputMethodInfo = mMethodMap.get(mCurId);
+        final boolean suppressesSpellChecker =
+                curInputMethodInfo != null && curInputMethodInfo.suppressesSpellChecker();
         return new InputBindResult(InputBindResult.ResultCode.SUCCESS_WITH_IME_SESSION,
                 session.session, (session.channel != null ? session.channel.dup() : null),
-                mCurId, mCurSeq, mCurActivityViewToScreenMatrix);
+                mCurId, mCurSeq, mCurActivityViewToScreenMatrix, suppressesSpellChecker);
     }
 
     @Nullable
@@ -2425,7 +2428,7 @@
             // party code.
             return new InputBindResult(
                     InputBindResult.ResultCode.ERROR_SYSTEM_NOT_READY,
-                    null, null, mCurMethodId, mCurSeq, null);
+                    null, null, mCurMethodId, mCurSeq, null, false);
         }
 
         if (!InputMethodUtils.checkIfPackageBelongsToUid(mAppOpsManager, cs.uid,
@@ -2501,7 +2504,7 @@
                     requestClientSessionLocked(cs);
                     return new InputBindResult(
                             InputBindResult.ResultCode.SUCCESS_WAITING_IME_SESSION,
-                            null, null, mCurId, mCurSeq, null);
+                            null, null, mCurId, mCurSeq, null, false);
                 } else if (SystemClock.uptimeMillis()
                         < (mLastBindTime+TIME_TO_RECONNECT)) {
                     // In this case we have connected to the service, but
@@ -2513,7 +2516,7 @@
                     // to see if we can get back in touch with the service.
                     return new InputBindResult(
                             InputBindResult.ResultCode.SUCCESS_WAITING_IME_BINDING,
-                            null, null, mCurId, mCurSeq, null);
+                            null, null, mCurId, mCurSeq, null, false);
                 } else {
                     EventLog.writeEvent(EventLogTags.IMF_FORCE_RECONNECT_IME,
                             mCurMethodId, SystemClock.uptimeMillis()-mLastBindTime, 0);
@@ -2553,7 +2556,7 @@
             }
             return new InputBindResult(
                     InputBindResult.ResultCode.SUCCESS_WAITING_IME_BINDING,
-                    null, null, mCurId, mCurSeq, null);
+                    null, null, mCurId, mCurSeq, null, false);
         }
         mCurIntent = null;
         Slog.w(TAG, "Failure connecting to input method service: " + mCurIntent);
@@ -2621,9 +2624,8 @@
                 }
                 if (DEBUG) Slog.v(TAG, "Initiating attach with token: " + mCurToken);
                 // Dispatch display id for InputMethodService to update context display.
-                executeOrSendMessage(mCurMethod, mCaller.obtainMessageIOOO(
-                        MSG_INITIALIZE_IME, mCurTokenDisplayId, mCurMethod, mCurToken,
-                        mMethodMap.get(mCurMethodId).getConfigChanges()));
+                executeOrSendMessage(mCurMethod, mCaller.obtainMessageIOO(
+                        MSG_INITIALIZE_IME, mCurTokenDisplayId, mCurMethod, mCurToken));
                 scheduleNotifyImeUidToAudioService(mCurMethodUid);
                 if (mCurClient != null) {
                     clearClientSessionLocked(mCurClient);
@@ -3510,7 +3512,7 @@
             }
             return new InputBindResult(
                     InputBindResult.ResultCode.SUCCESS_REPORT_WINDOW_FOCUS_ONLY,
-                    null, null, null, -1, null);
+                    null, null, null, -1, null, false);
         }
 
         mCurFocusedWindow = windowToken;
@@ -4479,8 +4481,7 @@
                     }
                     final IBinder token = (IBinder) args.arg2;
                     ((IInputMethod) args.arg1).initializeInternal(token, msg.arg1,
-                            new InputMethodPrivilegedOperationsImpl(this, token),
-                            (int) args.arg3);
+                            new InputMethodPrivilegedOperationsImpl(this, token));
                 } catch (RemoteException e) {
                 }
                 args.recycle();
@@ -5838,7 +5839,22 @@
     @BinderThread
     @ShellCommandResult
     private int handleShellCommandTraceInputMethod(@NonNull ShellCommand shellCommand) {
-        int result = ImeTracing.getInstance().onShellCommand(shellCommand);
+        final String cmd = shellCommand.getNextArgRequired();
+        final PrintWriter pw = shellCommand.getOutPrintWriter();
+        switch (cmd) {
+            case "start":
+                ImeTracing.getInstance().getInstance().startTrace(pw);
+                break;
+            case "stop":
+                ImeTracing.getInstance().stopTrace(pw);
+                break;
+            default:
+                pw.println("Unknown command: " + cmd);
+                pw.println("Input method trace options:");
+                pw.println("  start: Start tracing");
+                pw.println("  stop: Stop tracing");
+                return ShellCommandResult.FAILURE;
+        }
         boolean isImeTraceEnabled = ImeTracing.getInstance().isEnabled();
         ArrayMap<IBinder, ClientState> clients;
         synchronized (mMethodMap) {
@@ -5854,7 +5870,7 @@
                 }
             }
         }
-        return result;
+        return ShellCommandResult.SUCCESS;
     }
 
     /**
diff --git a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
index 1dd3d41..ef1489b 100644
--- a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
@@ -1748,7 +1748,7 @@
                         return new InputBindResult(
                                 InputBindResult.ResultCode.SUCCESS_WAITING_IME_SESSION,
                                 null, null, data.mCurrentInputMethodInfo.getId(),
-                                clientInfo.mBindingSequence, null);
+                                clientInfo.mBindingSequence, null, false);
                     case InputMethodClientState.READY_TO_SEND_FIRST_BIND_RESULT:
                     case InputMethodClientState.ALREADY_SENT_BIND_RESULT:
                         clientInfo.mBindingSequence++;
@@ -1770,7 +1770,7 @@
                                 clientInfo.mInputMethodSession,
                                 clientInfo.mWriteChannel.dup(),
                                 data.mCurrentInputMethodInfo.getId(),
-                                clientInfo.mBindingSequence, null);
+                                clientInfo.mBindingSequence, null, false);
                     case InputMethodClientState.UNREGISTERED:
                         Slog.e(TAG, "The client is already unregistered.");
                         return InputBindResult.INVALID_CLIENT;
diff --git a/services/core/java/com/android/server/location/gnss/hal/GnssNative.java b/services/core/java/com/android/server/location/gnss/hal/GnssNative.java
index f275663..1eef0de 100644
--- a/services/core/java/com/android/server/location/gnss/hal/GnssNative.java
+++ b/services/core/java/com/android/server/location/gnss/hal/GnssNative.java
@@ -27,6 +27,7 @@
 import android.location.GnssNavigationMessage;
 import android.location.GnssStatus;
 import android.location.Location;
+import android.os.Binder;
 import android.os.SystemClock;
 import android.util.Log;
 
@@ -921,6 +922,7 @@
 
     @NativeEntryPoint
     void reportGnssServiceDied() {
+        // Not necessary to clear (and restore) binder identity since it runs on another thread.
         Log.e(TAG, "gnss hal died - restarting shortly...");
 
         // move to another thread just in case there is some awkward gnss thread dependency with
@@ -940,96 +942,111 @@
 
     @NativeEntryPoint
     void reportLocation(boolean hasLatLong, Location location) {
-        if (hasLatLong && !mHasFirstFix) {
-            mHasFirstFix = true;
+        Binder.withCleanCallingIdentity(() -> {
+            if (hasLatLong && !mHasFirstFix) {
+                mHasFirstFix = true;
 
-            // notify status listeners
-            int ttff = (int) (SystemClock.elapsedRealtime() - mStartRealtimeMs);
-            for (int i = 0; i < mStatusCallbacks.length; i++) {
-                mStatusCallbacks[i].onReportFirstFix(ttff);
+                // notify status listeners
+                int ttff = (int) (SystemClock.elapsedRealtime() - mStartRealtimeMs);
+                for (int i = 0; i < mStatusCallbacks.length; i++) {
+                    mStatusCallbacks[i].onReportFirstFix(ttff);
+                }
             }
-        }
 
-        if (location.hasSpeed()) {
-            boolean exceeded = location.getSpeed() > ITAR_SPEED_LIMIT_METERS_PER_SECOND;
-            if (!mItarSpeedLimitExceeded && exceeded) {
-                Log.w(TAG, "speed nearing ITAR threshold - blocking further GNSS output");
-            } else if (mItarSpeedLimitExceeded && !exceeded) {
-                Log.w(TAG, "speed leaving ITAR threshold - allowing further GNSS output");
+            if (location.hasSpeed()) {
+                boolean exceeded = location.getSpeed() > ITAR_SPEED_LIMIT_METERS_PER_SECOND;
+                if (!mItarSpeedLimitExceeded && exceeded) {
+                    Log.w(TAG, "speed nearing ITAR threshold - blocking further GNSS output");
+                } else if (mItarSpeedLimitExceeded && !exceeded) {
+                    Log.w(TAG, "speed leaving ITAR threshold - allowing further GNSS output");
+                }
+                mItarSpeedLimitExceeded = exceeded;
             }
-            mItarSpeedLimitExceeded = exceeded;
-        }
 
-        if (mItarSpeedLimitExceeded) {
-            return;
-        }
+            if (mItarSpeedLimitExceeded) {
+                return;
+            }
 
-        for (int i = 0; i < mLocationCallbacks.length; i++) {
-            mLocationCallbacks[i].onReportLocation(hasLatLong, location);
-        }
+            for (int i = 0; i < mLocationCallbacks.length; i++) {
+                mLocationCallbacks[i].onReportLocation(hasLatLong, location);
+            }
+        });
     }
 
     @NativeEntryPoint
     void reportStatus(@StatusCallbacks.GnssStatusValue int gnssStatus) {
-        for (int i = 0; i < mStatusCallbacks.length; i++) {
-            mStatusCallbacks[i].onReportStatus(gnssStatus);
-        }
+        Binder.withCleanCallingIdentity(() -> {
+            for (int i = 0; i < mStatusCallbacks.length; i++) {
+                mStatusCallbacks[i].onReportStatus(gnssStatus);
+            }
+        });
     }
 
     @NativeEntryPoint
     void reportSvStatus(int svCount, int[] svidWithFlags, float[] cn0DbHzs,
             float[] elevations, float[] azimuths, float[] carrierFrequencies,
             float[] basebandCn0DbHzs) {
-        GnssStatus gnssStatus = GnssStatus.wrap(svCount, svidWithFlags, cn0DbHzs, elevations,
-                azimuths, carrierFrequencies, basebandCn0DbHzs);
-        for (int i = 0; i < mSvStatusCallbacks.length; i++) {
-            mSvStatusCallbacks[i].onReportSvStatus(gnssStatus);
-        }
+        Binder.withCleanCallingIdentity(() -> {
+            GnssStatus gnssStatus = GnssStatus.wrap(svCount, svidWithFlags, cn0DbHzs, elevations,
+                    azimuths, carrierFrequencies, basebandCn0DbHzs);
+            for (int i = 0; i < mSvStatusCallbacks.length; i++) {
+                mSvStatusCallbacks[i].onReportSvStatus(gnssStatus);
+            }
+        });
     }
 
     @NativeEntryPoint
     void reportAGpsStatus(int agpsType, int agpsStatus, byte[] suplIpAddr) {
-        mAGpsCallbacks.onReportAGpsStatus(agpsType, agpsStatus, suplIpAddr);
+        Binder.withCleanCallingIdentity(
+                () -> mAGpsCallbacks.onReportAGpsStatus(agpsType, agpsStatus, suplIpAddr));
     }
 
     @NativeEntryPoint
     void reportNmea(long timestamp) {
-        if (mItarSpeedLimitExceeded) {
-            return;
-        }
+        Binder.withCleanCallingIdentity(() -> {
+            if (mItarSpeedLimitExceeded) {
+                return;
+            }
 
-        for (int i = 0; i < mNmeaCallbacks.length; i++) {
-            mNmeaCallbacks[i].onReportNmea(timestamp);
-        }
+            for (int i = 0; i < mNmeaCallbacks.length; i++) {
+                mNmeaCallbacks[i].onReportNmea(timestamp);
+            }
+        });
     }
 
     @NativeEntryPoint
     void reportMeasurementData(GnssMeasurementsEvent event) {
-        if (mItarSpeedLimitExceeded) {
-            return;
-        }
+        Binder.withCleanCallingIdentity(() -> {
+            if (mItarSpeedLimitExceeded) {
+                return;
+            }
 
-        for (int i = 0; i < mMeasurementCallbacks.length; i++) {
-            mMeasurementCallbacks[i].onReportMeasurements(event);
-        }
+            for (int i = 0; i < mMeasurementCallbacks.length; i++) {
+                mMeasurementCallbacks[i].onReportMeasurements(event);
+            }
+        });
     }
 
     @NativeEntryPoint
     void reportAntennaInfo(List<GnssAntennaInfo> antennaInfos) {
-        for (int i = 0; i < mAntennaInfoCallbacks.length; i++) {
-            mAntennaInfoCallbacks[i].onReportAntennaInfo(antennaInfos);
-        }
+        Binder.withCleanCallingIdentity(() -> {
+            for (int i = 0; i < mAntennaInfoCallbacks.length; i++) {
+                mAntennaInfoCallbacks[i].onReportAntennaInfo(antennaInfos);
+            }
+        });
     }
 
     @NativeEntryPoint
     void reportNavigationMessage(GnssNavigationMessage event) {
-        if (mItarSpeedLimitExceeded) {
-            return;
-        }
+        Binder.withCleanCallingIdentity(() -> {
+            if (mItarSpeedLimitExceeded) {
+                return;
+            }
 
-        for (int i = 0; i < mNavigationMessageCallbacks.length; i++) {
-            mNavigationMessageCallbacks[i].onReportNavigationMessage(event);
-        }
+            for (int i = 0; i < mNavigationMessageCallbacks.length; i++) {
+                mNavigationMessageCallbacks[i].onReportNavigationMessage(event);
+            }
+        });
     }
 
     @NativeEntryPoint
@@ -1061,15 +1078,17 @@
 
     private void onCapabilitiesChanged(GnssCapabilities oldCapabilities,
             GnssCapabilities newCapabilities) {
-        if (newCapabilities.equals(oldCapabilities)) {
-            return;
-        }
+        Binder.withCleanCallingIdentity(() -> {
+            if (newCapabilities.equals(oldCapabilities)) {
+                return;
+            }
 
-        Log.i(TAG, "gnss capabilities changed to " + newCapabilities);
+            Log.i(TAG, "gnss capabilities changed to " + newCapabilities);
 
-        for (int i = 0; i < mBaseCallbacks.length; i++) {
-            mBaseCallbacks[i].onCapabilitiesChanged(oldCapabilities, newCapabilities);
-        }
+            for (int i = 0; i < mBaseCallbacks.length; i++) {
+                mBaseCallbacks[i].onCapabilitiesChanged(oldCapabilities, newCapabilities);
+            }
+        });
     }
 
     @NativeEntryPoint
@@ -1089,88 +1108,103 @@
 
     @NativeEntryPoint
     void reportLocationBatch(Location[] locations) {
-        for (int i = 0; i < mLocationCallbacks.length; i++) {
-            mLocationCallbacks[i].onReportLocations(locations);
-        }
+        Binder.withCleanCallingIdentity(() -> {
+            for (int i = 0; i < mLocationCallbacks.length; i++) {
+                mLocationCallbacks[i].onReportLocations(locations);
+            }
+        });
     }
 
     @NativeEntryPoint
     void psdsDownloadRequest(int psdsType) {
-        mPsdsCallbacks.onRequestPsdsDownload(psdsType);
+        Binder.withCleanCallingIdentity(() -> mPsdsCallbacks.onRequestPsdsDownload(psdsType));
     }
 
     @NativeEntryPoint
     void reportGeofenceTransition(int geofenceId, Location location, int transition,
             long transitionTimestamp) {
-        mGeofenceCallbacks.onReportGeofenceTransition(geofenceId, location, transition,
-                transitionTimestamp);
+        Binder.withCleanCallingIdentity(
+                () -> mGeofenceCallbacks.onReportGeofenceTransition(geofenceId, location,
+                        transition, transitionTimestamp));
     }
 
     @NativeEntryPoint
     void reportGeofenceStatus(int status, Location location) {
-        mGeofenceCallbacks.onReportGeofenceStatus(status, location);
+        Binder.withCleanCallingIdentity(
+                () -> mGeofenceCallbacks.onReportGeofenceStatus(status, location));
     }
 
     @NativeEntryPoint
     void reportGeofenceAddStatus(int geofenceId, @GeofenceCallbacks.GeofenceStatus int status) {
-        mGeofenceCallbacks.onReportGeofenceAddStatus(geofenceId, status);
+        Binder.withCleanCallingIdentity(
+                () -> mGeofenceCallbacks.onReportGeofenceAddStatus(geofenceId, status));
     }
 
     @NativeEntryPoint
     void reportGeofenceRemoveStatus(int geofenceId, @GeofenceCallbacks.GeofenceStatus int status) {
-        mGeofenceCallbacks.onReportGeofenceRemoveStatus(geofenceId, status);
+        Binder.withCleanCallingIdentity(
+                () -> mGeofenceCallbacks.onReportGeofenceRemoveStatus(geofenceId, status));
     }
 
     @NativeEntryPoint
     void reportGeofencePauseStatus(int geofenceId, @GeofenceCallbacks.GeofenceStatus int status) {
-        mGeofenceCallbacks.onReportGeofencePauseStatus(geofenceId, status);
+        Binder.withCleanCallingIdentity(
+                () -> mGeofenceCallbacks.onReportGeofencePauseStatus(geofenceId, status));
     }
 
     @NativeEntryPoint
     void reportGeofenceResumeStatus(int geofenceId, @GeofenceCallbacks.GeofenceStatus int status) {
-        mGeofenceCallbacks.onReportGeofenceResumeStatus(geofenceId, status);
+        Binder.withCleanCallingIdentity(
+                () -> mGeofenceCallbacks.onReportGeofenceResumeStatus(geofenceId, status));
     }
 
     @NativeEntryPoint
     void reportNiNotification(int notificationId, int niType, int notifyFlags,
             int timeout, int defaultResponse, String requestorId, String text,
             int requestorIdEncoding, int textEncoding) {
-        mNotificationCallbacks.onReportNiNotification(notificationId, niType, notifyFlags, timeout,
-                    defaultResponse, requestorId, text, requestorIdEncoding, textEncoding);
+        Binder.withCleanCallingIdentity(
+                () -> mNotificationCallbacks.onReportNiNotification(notificationId, niType,
+                        notifyFlags, timeout, defaultResponse, requestorId, text,
+                        requestorIdEncoding, textEncoding));
     }
 
     @NativeEntryPoint
     void requestSetID(int flags) {
-        mAGpsCallbacks.onRequestSetID(flags);
+        Binder.withCleanCallingIdentity(() -> mAGpsCallbacks.onRequestSetID(flags));
     }
 
     @NativeEntryPoint
     void requestLocation(boolean independentFromGnss, boolean isUserEmergency) {
-        mLocationRequestCallbacks.onRequestLocation(independentFromGnss, isUserEmergency);
+        Binder.withCleanCallingIdentity(
+                () -> mLocationRequestCallbacks.onRequestLocation(independentFromGnss,
+                        isUserEmergency));
     }
 
     @NativeEntryPoint
     void requestUtcTime() {
-        mTimeCallbacks.onRequestUtcTime();
+        Binder.withCleanCallingIdentity(() -> mTimeCallbacks.onRequestUtcTime());
     }
 
     @NativeEntryPoint
     void requestRefLocation() {
-        mLocationRequestCallbacks.onRequestRefLocation();
+        Binder.withCleanCallingIdentity(
+                () -> mLocationRequestCallbacks.onRequestRefLocation());
     }
 
     @NativeEntryPoint
     void reportNfwNotification(String proxyAppPackageName, byte protocolStack,
             String otherProtocolStackName, byte requestor, String requestorId,
             byte responseType, boolean inEmergencyMode, boolean isCachedLocation) {
-        mNotificationCallbacks.onReportNfwNotification(proxyAppPackageName, protocolStack,
-                    otherProtocolStackName, requestor, requestorId, responseType, inEmergencyMode,
-                    isCachedLocation);
+        Binder.withCleanCallingIdentity(
+                () -> mNotificationCallbacks.onReportNfwNotification(proxyAppPackageName,
+                        protocolStack, otherProtocolStackName, requestor, requestorId, responseType,
+                        inEmergencyMode, isCachedLocation));
     }
 
     @NativeEntryPoint
     boolean isInEmergencySession() {
-        return mEmergencyHelper.isInEmergency(mConfiguration.getEsExtensionSec());
+        return Binder.withCleanCallingIdentity(
+                () -> mEmergencyHelper.isInEmergency(mConfiguration.getEsExtensionSec()));
     }
 
     /**
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 0cc9f9e..d5a9e3c 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -7376,15 +7376,7 @@
                     // so need to check the notification still valide for vibrate.
                     synchronized (mNotificationLock) {
                         if (mNotificationsByKey.get(record.getKey()) != null) {
-                            // Vibrator checks the appops for the op package, not the caller,
-                            // so we need to add the bypass dnd flag to be heard. it's ok to
-                            // always add this flag here because we've already checked that we can
-                            // bypass dnd
-                            AudioAttributes.Builder aab =
-                                    new AudioAttributes.Builder(record.getAudioAttributes())
-                                    .setFlags(FLAG_BYPASS_INTERRUPTION_POLICY);
-                            mVibrator.vibrate(record.getSbn().getUid(), record.getSbn().getOpPkg(),
-                                    effect, "Notification (delayed)", aab.build());
+                            vibrate(record, effect, true);
                         } else {
                             Slog.e(TAG, "No vibration for canceled notification : "
                                     + record.getKey());
@@ -7392,8 +7384,7 @@
                     }
                 }).start();
             } else {
-                mVibrator.vibrate(record.getSbn().getUid(), record.getSbn().getPackageName(),
-                        effect, "Notification", record.getAudioAttributes());
+                vibrate(record, effect, false);
             }
             return true;
         } finally{
@@ -7401,6 +7392,16 @@
         }
     }
 
+    private void vibrate(NotificationRecord record, VibrationEffect effect, boolean delayed) {
+        // We need to vibrate as "android" so we can breakthrough DND. VibratorManagerService
+        // doesn't have a concept of vibrating on an app's behalf, so add the app information
+        // to the reason so we can still debug from bugreports
+        String reason = "Notification (" + record.getSbn().getOpPkg() + " "
+                + record.getSbn().getUid() + ") " + (delayed ? "(Delayed)" : "");
+        mVibrator.vibrate(Process.SYSTEM_UID, PackageManagerService.PLATFORM_PACKAGE_NAME,
+                effect, reason, record.getAudioAttributes());
+    }
+
     private boolean isNotificationForCurrentUser(NotificationRecord record) {
         final int currentUser;
         final long token = Binder.clearCallingIdentity();
diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java
index 1acbabd..ca8202f 100644
--- a/services/core/java/com/android/server/pm/AppsFilter.java
+++ b/services/core/java/com/android/server/pm/AppsFilter.java
@@ -105,6 +105,12 @@
     private final SparseSetArray<Integer> mQueriesViaComponent = new SparseSetArray<>();
 
     /**
+     * A mapping from the set of App IDs that query other App IDs via library name to the
+     * list of packages that they can see.
+     */
+    private final SparseSetArray<Integer> mQueryableViaUsesLibrary = new SparseSetArray<>();
+
+    /**
      * Executor for running reasonably short background tasks such as building the initial
      * visibility cache.
      */
@@ -239,6 +245,7 @@
         Snapshots.copy(mImplicitlyQueryable, orig.mImplicitlyQueryable);
         Snapshots.copy(mQueriesViaPackage, orig.mQueriesViaPackage);
         Snapshots.copy(mQueriesViaComponent, orig.mQueriesViaComponent);
+        Snapshots.copy(mQueryableViaUsesLibrary, orig.mQueryableViaUsesLibrary);
         mQueriesViaComponentRequireRecompute = orig.mQueriesViaComponentRequireRecompute;
         mForceQueryable.addAll(orig.mForceQueryable);
         mForceQueryableByDevicePackageNames = orig.mForceQueryableByDevicePackageNames;
@@ -508,6 +515,22 @@
         return false;
     }
 
+    private static boolean canQueryViaUsesLibrary(AndroidPackage querying,
+            AndroidPackage potentialTarget) {
+        if (potentialTarget.getLibraryNames().isEmpty()) {
+            return false;
+        }
+        final List<String> libNames = potentialTarget.getLibraryNames();
+        for (int i = 0, size = libNames.size(); i < size; i++) {
+            final String libName = libNames.get(i);
+            if (querying.getUsesLibraries().contains(libName)
+                    || querying.getUsesOptionalLibraries().contains(libName)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     private static boolean matchesProviders(
             Set<String> queriesAuthorities, AndroidPackage potentialTarget) {
         for (int p = ArrayUtils.size(potentialTarget.getProviders()) - 1; p >= 0; p--) {
@@ -707,6 +730,9 @@
                         || canQueryAsInstaller(existingSetting, newPkg)) {
                     mQueriesViaPackage.add(existingSetting.appId, newPkgSetting.appId);
                 }
+                if (canQueryViaUsesLibrary(existingPkg, newPkg)) {
+                    mQueryableViaUsesLibrary.add(existingSetting.appId, newPkgSetting.appId);
+                }
             }
             // now we'll evaluate our new package's ability to see existing packages
             if (!mForceQueryable.contains(existingSetting.appId)) {
@@ -718,6 +744,9 @@
                         || canQueryAsInstaller(newPkgSetting, existingPkg)) {
                     mQueriesViaPackage.add(newPkgSetting.appId, existingSetting.appId);
                 }
+                if (canQueryViaUsesLibrary(newPkg, existingPkg)) {
+                    mQueryableViaUsesLibrary.add(newPkgSetting.appId, existingSetting.appId);
+                }
             }
             // if either package instruments the other, mark both as visible to one another
             if (newPkgSetting.pkg != null && existingSetting.pkg != null
@@ -1035,6 +1064,10 @@
             for (int i = mQueriesViaPackage.size() - 1; i >= 0; i--) {
                 mQueriesViaPackage.remove(mQueriesViaPackage.keyAt(i), setting.appId);
             }
+            mQueryableViaUsesLibrary.remove(setting.appId);
+            for (int i = mQueryableViaUsesLibrary.size() - 1; i >= 0; i--) {
+                mQueryableViaUsesLibrary.remove(mQueryableViaUsesLibrary.keyAt(i), setting.appId);
+            }
 
             mForceQueryable.remove(setting.appId);
 
@@ -1315,6 +1348,18 @@
                 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
             }
 
+            try {
+                Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "mQueryableViaUsesLibrary");
+                if (mQueryableViaUsesLibrary.contains(callingAppId, targetAppId)) {
+                    if (DEBUG_LOGGING) {
+                        log(callingSetting, targetPkgSetting, "queryable for library users");
+                    }
+                    return false;
+                }
+            } finally {
+                Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+            }
+
             return true;
         } finally {
             Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
@@ -1394,6 +1439,8 @@
                     filteringAppId == null ? null : UserHandle.getUid(user, filteringAppId),
                     mImplicitlyQueryable, "      ", expandPackages);
         }
+        pw.println("  queryable via uses-library:");
+        dumpQueriesMap(pw, filteringAppId, mQueryableViaUsesLibrary, "    ", expandPackages);
     }
 
     private static void dumpQueriesMap(PrintWriter pw, @Nullable Integer filteringId,
diff --git a/services/core/java/com/android/server/pm/DataLoaderManagerService.java b/services/core/java/com/android/server/pm/DataLoaderManagerService.java
index b34611b..29322e2 100644
--- a/services/core/java/com/android/server/pm/DataLoaderManagerService.java
+++ b/services/core/java/com/android/server/pm/DataLoaderManagerService.java
@@ -180,6 +180,8 @@
             mId = id;
             mListener = listener;
             mDataLoader = null;
+
+            callListener(IDataLoaderStatusListener.DATA_LOADER_BINDING);
         }
 
         @Override
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 82b12aa..bafe987 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -1011,8 +1011,9 @@
                         "DataLoader installation of APEX modules is not allowed.");
             }
 
-            if (this.params.dataLoaderParams.getComponentName().getPackageName()
-                    == SYSTEM_DATA_LOADER_PACKAGE && mContext.checkCallingOrSelfPermission(
+            boolean systemDataLoader = SYSTEM_DATA_LOADER_PACKAGE.equals(
+                    this.params.dataLoaderParams.getComponentName().getPackageName());
+            if (systemDataLoader && mContext.checkCallingOrSelfPermission(
                     Manifest.permission.USE_SYSTEM_DATA_LOADERS)
                     != PackageManager.PERMISSION_GRANTED) {
                 throw new SecurityException("You need the "
@@ -3653,6 +3654,7 @@
             @Override
             public void onStatusChanged(int dataLoaderId, int status) {
                 switch (status) {
+                    case IDataLoaderStatusListener.DATA_LOADER_BINDING:
                     case IDataLoaderStatusListener.DATA_LOADER_STOPPED:
                     case IDataLoaderStatusListener.DATA_LOADER_DESTROYED:
                         return;
@@ -3763,8 +3765,8 @@
             healthCheckParams.unhealthyTimeoutMs = INCREMENTAL_STORAGE_UNHEALTHY_TIMEOUT_MS;
             healthCheckParams.unhealthyMonitoringMs = INCREMENTAL_STORAGE_UNHEALTHY_MONITORING_MS;
 
-            final boolean systemDataLoader =
-                    params.getComponentName().getPackageName() == SYSTEM_DATA_LOADER_PACKAGE;
+            final boolean systemDataLoader = SYSTEM_DATA_LOADER_PACKAGE.equals(
+                    params.getComponentName().getPackageName());
 
             final IStorageHealthListener healthListener = new IStorageHealthListener.Stub() {
                 @Override
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index f828a11..dfe72b2 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -410,6 +410,7 @@
 import com.android.server.utils.WatchedArrayMap;
 import com.android.server.utils.WatchedLongSparseArray;
 import com.android.server.utils.WatchedSparseBooleanArray;
+import com.android.server.utils.WatchedSparseIntArray;
 import com.android.server.utils.Watcher;
 import com.android.server.wm.ActivityTaskManagerInternal;
 
@@ -892,7 +893,7 @@
     // that created the isolated process.
     @Watched
     @GuardedBy("mLock")
-    final SparseIntArray mIsolatedOwners = new SparseIntArray();
+    final WatchedSparseIntArray mIsolatedOwners = new WatchedSparseIntArray();
 
     /**
      * Tracks new system packages [received in an OTA] that we expect to
@@ -1795,7 +1796,7 @@
         public static final int SNAPPED = 2;
 
         public final Settings settings;
-        public final SparseIntArray isolatedOwners;
+        public final WatchedSparseIntArray isolatedOwners;
         public final WatchedArrayMap<String, AndroidPackage> packages;
         public final WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>> sharedLibs;
         public final WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>> staticLibs;
@@ -1814,7 +1815,7 @@
         Snapshot(int type) {
             if (type == Snapshot.SNAPPED) {
                 settings = mSettings.snapshot();
-                isolatedOwners = mIsolatedOwners.clone();
+                isolatedOwners = mIsolatedOwners.snapshot();
                 packages = mPackages.snapshot();
                 sharedLibs = mSharedLibraries.snapshot();
                 staticLibs = mStaticLibsByDeclaringPackage.snapshot();
@@ -2016,7 +2017,7 @@
         // Cached attributes.  The names in this class are the same as the
         // names in PackageManagerService; see that class for documentation.
         private final Settings mSettings;
-        private final SparseIntArray mIsolatedOwners;
+        private final WatchedSparseIntArray mIsolatedOwners;
         private final WatchedArrayMap<String, AndroidPackage> mPackages;
         private final WatchedArrayMap<ComponentName, ParsedInstrumentation>
                 mInstrumentation;
@@ -3551,7 +3552,7 @@
         public String getInstantAppPackageName(int callingUid) {
             // If the caller is an isolated app use the owner's uid for the lookup.
             if (Process.isIsolated(callingUid)) {
-                callingUid = mIsolatedOwners.get(callingUid);
+                callingUid = getIsolatedOwner(callingUid);
             }
             final int appId = UserHandle.getAppId(callingUid);
             final Object obj = mSettings.getSettingLPr(appId);
@@ -3563,6 +3564,19 @@
             return null;
         }
 
+        /**
+         * Finds the owner for the provided isolated UID. Throws IllegalStateException if no such
+         * isolated UID is found.
+         */
+        private int getIsolatedOwner(int isolatedUid) {
+            final int ownerUid = mIsolatedOwners.get(isolatedUid, -1);
+            if (ownerUid == -1) {
+                throw new IllegalStateException(
+                        "No owner UID found for isolated UID " + isolatedUid);
+            }
+            return ownerUid;
+        }
+
         public String resolveExternalPackageNameLPr(AndroidPackage pkg) {
             if (pkg.getStaticSharedLibName() != null) {
                 return pkg.getManifestPackageName();
@@ -3929,7 +3943,7 @@
         public boolean isInstantAppInternalBody(String packageName, @UserIdInt int userId,
                 int callingUid) {
             if (Process.isIsolated(callingUid)) {
-                callingUid = mIsolatedOwners.get(callingUid);
+                callingUid = getIsolatedOwner(callingUid);
             }
             final PackageSetting ps = mSettings.getPackageLPr(packageName);
             final boolean returnAllowed =
@@ -4083,7 +4097,7 @@
                 @Nullable ComponentName component, @ComponentType int componentType, int userId) {
             // if we're in an isolated process, get the real calling UID
             if (Process.isIsolated(callingUid)) {
-                callingUid = mIsolatedOwners.get(callingUid);
+                callingUid = getIsolatedOwner(callingUid);
             }
             final String instantAppPkgName = getInstantAppPackageName(callingUid);
             final boolean callerIsInstantApp = instantAppPkgName != null;
@@ -6164,6 +6178,7 @@
         mAppsFilter.registerObserver(mWatcher);
         mInstantAppRegistry.registerObserver(mWatcher);
         mSettings.registerObserver(mWatcher);
+        mIsolatedOwners.registerObserver(mWatcher);
         // If neither "build" attribute is true then this may be a mockito test, and verification
         // can fail as a false positive.
         Watchable.verifyWatchedAttributes(this, mWatcher, !(mIsEngBuild || mIsUserDebugBuild));
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerInternal.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerInternal.java
index 0c2b4c5..b4bcde7 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerInternal.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerInternal.java
@@ -80,14 +80,14 @@
      * been preserved for migration purposes, but is otherwise ignored. Corresponds to
      * {@link PackageManager#INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS}.
      */
-    int APPROVAL_LEVEL_LEGACY_ALWAYS = 1;
+    int APPROVAL_LEVEL_LEGACY_ALWAYS = 2;
 
     /**
      * The app has been chosen by the user through
      * {@link DomainVerificationManager#setDomainVerificationUserSelection(UUID, Set, boolean)},
      * indicating an explicit choice to use this app to open an unverified domain.
      */
-    int APPROVAL_LEVEL_SELECTION = 2;
+    int APPROVAL_LEVEL_SELECTION = 3;
 
     /**
      * The app is approved through the digital asset link statement being hosted at the domain
@@ -95,7 +95,7 @@
      * {@link DomainVerificationManager#setDomainVerificationStatus(UUID, Set, int)} by
      * the domain verification agent on device.
      */
-    int APPROVAL_LEVEL_VERIFIED = 3;
+    int APPROVAL_LEVEL_VERIFIED = 4;
 
     /**
      * The app has been installed as an instant app, which grants it total authority on the domains
@@ -105,7 +105,7 @@
      * The user is still able to disable instant app link handling through
      * {@link DomainVerificationManager#setDomainVerificationLinkHandlingAllowed(String, boolean)}.
      */
-    int APPROVAL_LEVEL_INSTANT_APP = 4;
+    int APPROVAL_LEVEL_INSTANT_APP = 5;
 
     /**
      * Defines the possible values for {@link #approvalLevelForDomain(PackageSetting, Intent, int)}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 047e3b3..ffea6a7 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -345,6 +345,9 @@
      */
     private final Object mLock = new Object();
 
+    /** List of {@link ScreenOnListener}s which do not belong to the default display. */
+    private final SparseArray<ScreenOnListener> mScreenOnListeners = new SparseArray<>();
+
     Context mContext;
     IWindowManager mWindowManager;
     WindowManagerFuncs mWindowManagerFuncs;
@@ -434,8 +437,25 @@
     volatile boolean mBeganFromNonInteractive;
     volatile boolean mEndCallKeyHandled;
     volatile boolean mCameraGestureTriggeredDuringGoingToSleep;
-    volatile boolean mGoingToSleep;
-    volatile boolean mRequestedOrGoingToSleep;
+
+    /**
+     * {@code true} if the device is entering a low-power state; {@code false otherwise}.
+     *
+     * <p>This differs from {@link #mRequestedOrSleepingDefaultDisplay} which tracks the power state
+     * of the {@link #mDefaultDisplay default display} versus the power state of the entire device.
+     */
+    volatile boolean mDeviceGoingToSleep;
+
+    /**
+     * {@code true} if the {@link #mDefaultDisplay default display} is entering or was requested to
+     * enter a low-power state; {@code false otherwise}.
+     *
+     * <p>This differs from {@link #mDeviceGoingToSleep} which tracks the power state of the entire
+     * device versus the power state of the {@link #mDefaultDisplay default display}.
+     */
+    // TODO(b/178103325): Track sleep/requested sleep for every display.
+    volatile boolean mRequestedOrSleepingDefaultDisplay;
+
     volatile boolean mRecentsVisible;
     volatile boolean mNavBarVirtualKeyHapticFeedbackEnabled = true;
     volatile boolean mPictureInPictureVisible;
@@ -917,13 +937,14 @@
                 case SHORT_PRESS_POWER_NOTHING:
                     break;
                 case SHORT_PRESS_POWER_GO_TO_SLEEP:
-                    goToSleepFromPowerButton(eventTime, 0);
+                    sleepDefaultDisplayFromPowerButton(eventTime, 0);
                     break;
                 case SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP:
-                    goToSleepFromPowerButton(eventTime, PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE);
+                    sleepDefaultDisplayFromPowerButton(eventTime,
+                            PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE);
                     break;
                 case SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP_AND_GO_HOME:
-                    if (goToSleepFromPowerButton(eventTime,
+                    if (sleepDefaultDisplayFromPowerButton(eventTime,
                             PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE)) {
                         launchHomeFromHotKey(DEFAULT_DISPLAY);
                     }
@@ -951,11 +972,12 @@
     }
 
     /**
-     * Sends the device to sleep as a result of a power button press.
+     * Sends the default display to sleep as a result of a power button press.
      *
-     * @return True if the was device was sent to sleep, false if sleep was suppressed.
+     * @return {@code true} if the device was sent to sleep, {@code false} if the device did not
+     * sleep.
      */
-    private boolean goToSleepFromPowerButton(long eventTime, int flags) {
+    private boolean sleepDefaultDisplayFromPowerButton(long eventTime, int flags) {
         // Before we actually go to sleep, we check the last wakeup reason.
         // If the device very recently woke up from a gesture (like user lifting their device)
         // then ignore the sleep instruction. This is because users have developed
@@ -975,12 +997,12 @@
             }
         }
 
-        goToSleep(eventTime, PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, flags);
+        sleepDefaultDisplay(eventTime, PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, flags);
         return true;
     }
 
-    private void goToSleep(long eventTime, int reason, int flags) {
-        mRequestedOrGoingToSleep = true;
+    private void sleepDefaultDisplay(long eventTime, int reason, int flags) {
+        mRequestedOrSleepingDefaultDisplay = true;
         mPowerManager.goToSleep(eventTime, reason, flags);
     }
 
@@ -1017,7 +1039,8 @@
                             Settings.Global.THEATER_MODE_ON, 1);
 
                     if (mGoToSleepOnButtonPressTheaterMode && interactive) {
-                        goToSleep(eventTime, PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, 0);
+                        sleepDefaultDisplay(eventTime, PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON,
+                                0);
                     }
                 }
                 break;
@@ -1126,7 +1149,7 @@
             case SHORT_PRESS_SLEEP_GO_TO_SLEEP:
             case SHORT_PRESS_SLEEP_GO_TO_SLEEP_AND_GO_HOME:
                 Slog.i(TAG, "sleepRelease() calling goToSleep(GO_TO_SLEEP_REASON_SLEEP_BUTTON)");
-                goToSleep(eventTime, PowerManager.GO_TO_SLEEP_REASON_SLEEP_BUTTON, 0);
+                sleepDefaultDisplay(eventTime, PowerManager.GO_TO_SLEEP_REASON_SLEEP_BUTTON, 0);
                 break;
         }
     }
@@ -3511,7 +3534,7 @@
                             }
                             if ((mEndcallBehavior
                                     & Settings.System.END_BUTTON_BEHAVIOR_SLEEP) != 0) {
-                                goToSleep(event.getEventTime(),
+                                sleepDefaultDisplay(event.getEventTime(),
                                         PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, 0);
                                 isWakeKey = false;
                             }
@@ -3538,10 +3561,12 @@
                 // Any activity on the power button stops the accessibility shortcut
                 result &= ~ACTION_PASS_TO_USER;
                 isWakeKey = false; // wake-up will be handled separately
+                final boolean isDefaultDisplayOn = Display.isOnState(mDefaultDisplay.getState());
+                final boolean interactiveAndOn = interactive && isDefaultDisplayOn;
                 if (down) {
-                    interceptPowerKeyDown(event, interactive);
+                    interceptPowerKeyDown(event, interactiveAndOn);
                 } else {
-                    interceptPowerKeyUp(event, interactive, canceled);
+                    interceptPowerKeyUp(event, interactiveAndOn, canceled);
                 }
                 break;
             }
@@ -3746,7 +3771,7 @@
         final MutableBoolean outLaunched = new MutableBoolean(false);
         final boolean gesturedServiceIntercepted = gestureService.interceptPowerKeyDown(event,
                 interactive, outLaunched);
-        if (outLaunched.value && mRequestedOrGoingToSleep) {
+        if (outLaunched.value && mRequestedOrSleepingDefaultDisplay) {
             mCameraGestureTriggeredDuringGoingToSleep = true;
         }
         return gesturedServiceIntercepted;
@@ -4088,8 +4113,8 @@
                                     pmSleepReason)) + ")");
         }
 
-        mGoingToSleep = true;
-        mRequestedOrGoingToSleep = true;
+        mDeviceGoingToSleep = true;
+        mRequestedOrSleepingDefaultDisplay = true;
 
         if (mKeyguardDelegate != null) {
             mKeyguardDelegate.onStartedGoingToSleep(pmSleepReason);
@@ -4108,8 +4133,8 @@
         }
         MetricsLogger.histogram(mContext, "screen_timeout", mLockScreenTimeout / 1000);
 
-        mGoingToSleep = false;
-        mRequestedOrGoingToSleep = false;
+        mDeviceGoingToSleep = false;
+        mRequestedOrSleepingDefaultDisplay = false;
         mDefaultDisplayPolicy.setAwake(false);
 
         // We must get this work done here because the power manager will drop
@@ -4253,21 +4278,25 @@
     // Called on the DisplayManager's DisplayPowerController thread.
     @Override
     public void screenTurnedOff(int displayId) {
-        if (displayId != DEFAULT_DISPLAY) {
-            return;
-        }
+        if (DEBUG_WAKEUP) Slog.i(TAG, "Display" + displayId + " turned off...");
 
-        if (DEBUG_WAKEUP) Slog.i(TAG, "Screen turned off...");
-
-        updateScreenOffSleepToken(true);
-        mDefaultDisplayPolicy.screenTurnedOff();
-        synchronized (mLock) {
-            if (mKeyguardDelegate != null) {
-                mKeyguardDelegate.onScreenTurnedOff();
+        if (displayId == DEFAULT_DISPLAY) {
+            updateScreenOffSleepToken(true);
+            mRequestedOrSleepingDefaultDisplay = false;
+            mDefaultDisplayPolicy.screenTurnedOff();
+            synchronized (mLock) {
+                if (mKeyguardDelegate != null) {
+                    mKeyguardDelegate.onScreenTurnedOff();
+                }
+            }
+            mDefaultDisplayRotation.updateOrientationListener();
+            reportScreenStateToVrManager(false);
+            if (mCameraGestureTriggeredDuringGoingToSleep) {
+                wakeUp(SystemClock.uptimeMillis(), mAllowTheaterModeWakeFromPowerKey,
+                        PowerManager.WAKE_REASON_CAMERA_LAUNCH,
+                        "com.android.systemui:CAMERA_GESTURE_PREVENT_LOCK");
             }
         }
-        mDefaultDisplayRotation.updateOrientationListener();
-        reportScreenStateToVrManager(false);
     }
 
     private long getKeyguardDrawnTimeout() {
@@ -4280,27 +4309,28 @@
     // Called on the DisplayManager's DisplayPowerController thread.
     @Override
     public void screenTurningOn(int displayId, final ScreenOnListener screenOnListener) {
-        if (displayId != DEFAULT_DISPLAY) {
-            return;
-        }
+        if (DEBUG_WAKEUP) Slog.i(TAG, "Display " + displayId + " turning on...");
 
-        if (DEBUG_WAKEUP) Slog.i(TAG, "Screen turning on...");
+        if (displayId == DEFAULT_DISPLAY) {
+            Trace.asyncTraceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "screenTurningOn",
+                    0 /* cookie */);
+            updateScreenOffSleepToken(false);
+            mDefaultDisplayPolicy.screenTurnedOn(screenOnListener);
 
-        Trace.asyncTraceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "screenTurningOn", 0 /* cookie */);
-        updateScreenOffSleepToken(false);
-        mDefaultDisplayPolicy.screenTurnedOn(screenOnListener);
-
-        synchronized (mLock) {
-            if (mKeyguardDelegate != null && mKeyguardDelegate.hasKeyguard()) {
-                mHandler.removeMessages(MSG_KEYGUARD_DRAWN_TIMEOUT);
-                mHandler.sendEmptyMessageDelayed(MSG_KEYGUARD_DRAWN_TIMEOUT,
-                        getKeyguardDrawnTimeout());
-                mKeyguardDelegate.onScreenTurningOn(mKeyguardDrawnCallback);
-            } else {
-                if (DEBUG_WAKEUP) Slog.d(TAG,
-                        "null mKeyguardDelegate: setting mKeyguardDrawComplete.");
-                mHandler.sendEmptyMessage(MSG_KEYGUARD_DRAWN_COMPLETE);
+            synchronized (mLock) {
+                if (mKeyguardDelegate != null && mKeyguardDelegate.hasKeyguard()) {
+                    mHandler.removeMessages(MSG_KEYGUARD_DRAWN_TIMEOUT);
+                    mHandler.sendEmptyMessageDelayed(MSG_KEYGUARD_DRAWN_TIMEOUT,
+                            getKeyguardDrawnTimeout());
+                    mKeyguardDelegate.onScreenTurningOn(mKeyguardDrawnCallback);
+                } else {
+                    if (DEBUG_WAKEUP) Slog.d(TAG,
+                            "null mKeyguardDelegate: setting mKeyguardDrawComplete.");
+                    mHandler.sendEmptyMessage(MSG_KEYGUARD_DRAWN_COMPLETE);
+                }
             }
+        } else {
+            mScreenOnListeners.put(displayId, screenOnListener);
         }
     }
 
@@ -4321,11 +4351,12 @@
 
     @Override
     public void screenTurningOff(int displayId, ScreenOffListener screenOffListener) {
+        mWindowManagerFuncs.screenTurningOff(displayId, screenOffListener);
         if (displayId != DEFAULT_DISPLAY) {
             return;
         }
 
-        mWindowManagerFuncs.screenTurningOff(screenOffListener);
+        mRequestedOrSleepingDefaultDisplay = true;
         synchronized (mLock) {
             if (mKeyguardDelegate != null) {
                 mKeyguardDelegate.onScreenTurningOff();
@@ -4380,6 +4411,14 @@
             listener.onScreenOn();
         }
 
+        for (int i = mScreenOnListeners.size() - 1; i >= 0; i--) {
+            final ScreenOnListener screenOnListener = mScreenOnListeners.valueAt(i);
+            if (screenOnListener != null) {
+                screenOnListener.onScreenOn();
+            }
+        }
+        mScreenOnListeners.clear();
+
         if (enableScreen) {
             try {
                 mWindowManager.enableScreenIfNeeded();
@@ -4410,7 +4449,7 @@
 
     @Override
     public boolean okToAnimate() {
-        return mDefaultDisplayPolicy.isAwake() && !mGoingToSleep;
+        return mDefaultDisplayPolicy.isAwake() && !mDeviceGoingToSleep;
     }
 
     /** {@inheritDoc} */
@@ -4777,7 +4816,7 @@
                     mWindowManagerFuncs.lockDeviceNow();
                     break;
                 case LID_BEHAVIOR_SLEEP:
-                    goToSleep(SystemClock.uptimeMillis(),
+                    sleepDefaultDisplay(SystemClock.uptimeMillis(),
                             PowerManager.GO_TO_SLEEP_REASON_LID_SWITCH,
                             PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE);
                     break;
diff --git a/services/core/java/com/android/server/policy/SplashScreenSurface.java b/services/core/java/com/android/server/policy/SplashScreenSurface.java
index b9202c3..72933a0 100644
--- a/services/core/java/com/android/server/policy/SplashScreenSurface.java
+++ b/services/core/java/com/android/server/policy/SplashScreenSurface.java
@@ -45,7 +45,7 @@
     }
 
     @Override
-    public void remove() {
+    public void remove(boolean animate) {
         if (DEBUG_SPLASH_SCREEN) Slog.v(TAG, "Removing splash screen window for " + mAppToken + ": "
                         + this + " Callers=" + Debug.getCallers(4));
 
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index b5a9aca..0735977b 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -238,8 +238,9 @@
         /**
          * Removes the starting window surface. Do not hold the window manager lock when calling
          * this method!
+         * @param animate Whether need to play the default exit animation for starting window.
          */
-        void remove();
+        void remove(boolean animate);
     }
 
     /**
@@ -303,9 +304,10 @@
         /**
          * Notifies the window manager that screen is being turned off.
          *
+         * @param displayId the ID of the display which is turning off
          * @param listener callback to call when display can be turned off
          */
-        void screenTurningOff(ScreenOffListener listener);
+        void screenTurningOff(int displayId, ScreenOffListener listener);
 
         /**
          * Convert the lid state to a human readable format.
diff --git a/services/core/java/com/android/server/rollback/RollbackStore.java b/services/core/java/com/android/server/rollback/RollbackStore.java
index 3a08ddc..fc62f5b 100644
--- a/services/core/java/com/android/server/rollback/RollbackStore.java
+++ b/services/core/java/com/android/server/rollback/RollbackStore.java
@@ -24,6 +24,7 @@
 import android.content.rollback.PackageRollbackInfo;
 import android.content.rollback.PackageRollbackInfo.RestoreInfo;
 import android.content.rollback.RollbackInfo;
+import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.system.ErrnoException;
 import android.system.Os;
@@ -227,6 +228,15 @@
                 packageSessionIds, extensionVersions);
     }
 
+    private static boolean isLinkPossible(File oldFile, File newFile) {
+        try {
+            return Os.stat(oldFile.getAbsolutePath()).st_dev
+                    == Os.stat(newFile.getAbsolutePath()).st_dev;
+        } catch (ErrnoException ignore) {
+            return false;
+        }
+    }
+
     /**
      * Creates a backup copy of an apk or apex for a package.
      * For packages containing splits, this method should be called for each
@@ -239,16 +249,29 @@
         targetDir.mkdirs();
         File targetFile = new File(targetDir, sourceFile.getName());
 
-        try {
-            // Create a hard link to avoid copy
-            // TODO(b/168562373)
-            // Linking between non-encrypted and encrypted is not supported and we have
-            // encrypted /data/rollback and non-encrypted /data/apex/active. For now this works
-            // because we happen to store encrypted files under /data/apex/active which is no
-            // longer the case when compressed apex rolls out. We have to handle this case in
-            // order not to fall back to copy.
-            Os.link(sourceFile.getAbsolutePath(), targetFile.getAbsolutePath());
-        } catch (ErrnoException ignore) {
+        boolean fallbackToCopy = !isLinkPossible(sourceFile, targetFile);
+        if (!fallbackToCopy) {
+            try {
+                // Create a hard link to avoid copy
+                // TODO(b/168562373)
+                // Linking between non-encrypted and encrypted is not supported and we have
+                // encrypted /data/rollback and non-encrypted /data/apex/active. For now this works
+                // because we happen to store encrypted files under /data/apex/active which is no
+                // longer the case when compressed apex rolls out. We have to handle this case in
+                // order not to fall back to copy.
+                Os.link(sourceFile.getAbsolutePath(), targetFile.getAbsolutePath());
+            } catch (ErrnoException e) {
+                boolean isRollbackTest =
+                        SystemProperties.getBoolean("persist.rollback.is_test", false);
+                if (isRollbackTest) {
+                    throw new IOException(e);
+                } else {
+                    fallbackToCopy = true;
+                }
+            }
+        }
+
+        if (fallbackToCopy) {
             // Fall back to copy if hardlink can't be created
             Files.copy(sourceFile.toPath(), targetFile.toPath());
         }
diff --git a/services/core/java/com/android/server/stats/pull/SystemMemoryUtil.java b/services/core/java/com/android/server/stats/pull/SystemMemoryUtil.java
index 628c1d6..9f8b27f 100644
--- a/services/core/java/com/android/server/stats/pull/SystemMemoryUtil.java
+++ b/services/core/java/com/android/server/stats/pull/SystemMemoryUtil.java
@@ -26,7 +26,7 @@
     private SystemMemoryUtil() {}
 
     static Metrics getMetrics() {
-        int totalIonKb = (int) Debug.getIonHeapsSizeKb();
+        int totalIonKb = (int) Debug.getDmabufHeapTotalExportedKb();
         int gpuTotalUsageKb = (int) Debug.getGpuTotalUsageKb();
         int gpuDmaBufUsageKb = (int) Debug.getGpuDmaBufUsageKb();
         int dmaBufTotalExportedKb = (int) Debug.getDmabufTotalExportedKb();
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
index 7523671..970420a 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
@@ -160,4 +160,10 @@
      * Handles a logging command from the WM shell command.
      */
     void handleWindowManagerLoggingCommand(String[] args, ParcelFileDescriptor outFd);
+
+    /**
+     * @see com.android.internal.statusbar.IStatusBar#setNavigationBarLumaSamplingEnabled(int,
+     * boolean)
+     */
+    void setNavigationBarLumaSamplingEnabled(int displayId, boolean enable);
 }
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 546e420..302a23f 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -588,6 +588,15 @@
                 } catch (RemoteException ex) { }
             }
         }
+
+        @Override
+        public void setNavigationBarLumaSamplingEnabled(int displayId, boolean enable) {
+            if (mBar != null) {
+                try {
+                    mBar.setNavigationBarLumaSamplingEnabled(displayId, enable);
+                } catch (RemoteException ex) { }
+            }
+        }
     };
 
     private final GlobalActionsProvider mGlobalActionsProvider = new GlobalActionsProvider() {
diff --git a/services/core/java/com/android/server/timezonedetector/MetricsTimeZoneDetectorState.java b/services/core/java/com/android/server/timezonedetector/MetricsTimeZoneDetectorState.java
new file mode 100644
index 0000000..c8c828f
--- /dev/null
+++ b/services/core/java/com/android/server/timezonedetector/MetricsTimeZoneDetectorState.java
@@ -0,0 +1,344 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.timezonedetector;
+
+import static libcore.io.IoUtils.closeQuietly;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.timezonedetector.ManualTimeZoneSuggestion;
+import android.app.timezonedetector.TelephonyTimeZoneSuggestion;
+import android.util.proto.ProtoOutputStream;
+
+import java.io.ByteArrayOutputStream;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * A class that provides time zone detector state information for metrics.
+ *
+ * <p>
+ * Regarding time zone ID ordinals:
+ * <p>
+ * We don't want to leak user location information by reporting time zone IDs. Instead, time zone
+ * IDs are consistently identified within a given instance of this class by a numeric ID. This
+ * allows comparison of IDs without revealing what those IDs are.
+ */
+public final class MetricsTimeZoneDetectorState {
+
+    @IntDef(prefix = "DETECTION_MODE_",
+            value = { DETECTION_MODE_MANUAL, DETECTION_MODE_GEO, DETECTION_MODE_TELEPHONY})
+    @interface DetectionMode {};
+
+    @DetectionMode
+    public static final int DETECTION_MODE_MANUAL = 0;
+    @DetectionMode
+    public static final int DETECTION_MODE_GEO = 1;
+    @DetectionMode
+    public static final int DETECTION_MODE_TELEPHONY = 2;
+
+    @NonNull
+    private final ConfigurationInternal mConfigurationInternal;
+    @NonNull
+    private final int mDeviceTimeZoneIdOrdinal;
+    @Nullable
+    private final MetricsTimeZoneSuggestion mLatestManualSuggestion;
+    @Nullable
+    private final MetricsTimeZoneSuggestion mLatestTelephonySuggestion;
+    @Nullable
+    private final MetricsTimeZoneSuggestion mLatestGeolocationSuggestion;
+
+    private MetricsTimeZoneDetectorState(
+            @NonNull ConfigurationInternal configurationInternal,
+            int deviceTimeZoneIdOrdinal,
+            @Nullable MetricsTimeZoneSuggestion latestManualSuggestion,
+            @Nullable MetricsTimeZoneSuggestion latestTelephonySuggestion,
+            @Nullable MetricsTimeZoneSuggestion latestGeolocationSuggestion) {
+        mConfigurationInternal = Objects.requireNonNull(configurationInternal);
+        mDeviceTimeZoneIdOrdinal = deviceTimeZoneIdOrdinal;
+        mLatestManualSuggestion = latestManualSuggestion;
+        mLatestTelephonySuggestion = latestTelephonySuggestion;
+        mLatestGeolocationSuggestion = latestGeolocationSuggestion;
+    }
+
+    /**
+     * Creates {@link MetricsTimeZoneDetectorState} from the supplied parameters, using the {@link
+     * OrdinalGenerator} to generate time zone ID ordinals.
+     */
+    public static MetricsTimeZoneDetectorState create(
+            @NonNull OrdinalGenerator<String> tzIdOrdinalGenerator,
+            @NonNull ConfigurationInternal configurationInternal,
+            @NonNull String deviceTimeZoneId,
+            @Nullable ManualTimeZoneSuggestion latestManualSuggestion,
+            @Nullable TelephonyTimeZoneSuggestion latestTelephonySuggestion,
+            @Nullable GeolocationTimeZoneSuggestion latestGeolocationSuggestion) {
+
+        // TODO(b/172934905) Add logic to canonicalize the time zone IDs to Android's preferred IDs
+        //  so that the ordinals will match even when the ID is not identical, just equivalent.
+        int deviceTimeZoneIdOrdinal =
+                tzIdOrdinalGenerator.ordinal(Objects.requireNonNull(deviceTimeZoneId));
+        MetricsTimeZoneSuggestion latestObfuscatedManualSuggestion =
+                createMetricsTimeZoneSuggestion(tzIdOrdinalGenerator, latestManualSuggestion);
+        MetricsTimeZoneSuggestion latestObfuscatedTelephonySuggestion =
+                createMetricsTimeZoneSuggestion(tzIdOrdinalGenerator, latestTelephonySuggestion);
+        MetricsTimeZoneSuggestion latestObfuscatedGeolocationSuggestion =
+                createMetricsTimeZoneSuggestion(tzIdOrdinalGenerator, latestGeolocationSuggestion);
+
+        return new MetricsTimeZoneDetectorState(
+                configurationInternal, deviceTimeZoneIdOrdinal, latestObfuscatedManualSuggestion,
+                latestObfuscatedTelephonySuggestion, latestObfuscatedGeolocationSuggestion);
+    }
+
+    /** Returns true if the device supports telephony time zone detection. */
+    public boolean isTelephonyDetectionSupported() {
+        return mConfigurationInternal.isTelephonyDetectionSupported();
+    }
+
+    /** Returns true if the device supports geolocation time zone detection. */
+    public boolean isGeoDetectionSupported() {
+        return mConfigurationInternal.isGeoDetectionSupported();
+    }
+
+    /** Returns true if user's location can be used generally. */
+    public boolean isUserLocationEnabled() {
+        return mConfigurationInternal.isLocationEnabled();
+    }
+
+    /** Returns the value of the geolocation time zone detection enabled setting. */
+    public boolean getGeoDetectionEnabledSetting() {
+        return mConfigurationInternal.getGeoDetectionEnabledSetting();
+    }
+
+    /** Returns the value of the auto time zone detection enabled setting. */
+    public boolean getAutoDetectionEnabledSetting() {
+        return mConfigurationInternal.getAutoDetectionEnabledSetting();
+    }
+
+    /**
+     * Returns the detection mode the device is currently using, which can be influenced by various
+     * things besides the user's setting.
+     */
+    @DetectionMode
+    public int getDetectionMode() {
+        if (!mConfigurationInternal.getAutoDetectionEnabledBehavior()) {
+            return DETECTION_MODE_MANUAL;
+        } else if (mConfigurationInternal.getGeoDetectionEnabledBehavior()) {
+            return DETECTION_MODE_GEO;
+        } else {
+            return DETECTION_MODE_TELEPHONY;
+        }
+    }
+
+    /**
+     * Returns the ordinal for the device's currently set time zone ID.
+     * See {@link MetricsTimeZoneDetectorState} for information about ordinals.
+     */
+    @NonNull
+    public int getDeviceTimeZoneIdOrdinal() {
+        return mDeviceTimeZoneIdOrdinal;
+    }
+
+    /**
+     * Returns bytes[] for a {@link MetricsTimeZoneSuggestion} for the last manual
+     * suggestion received.
+     */
+    @Nullable
+    public byte[] getLatestManualSuggestionProtoBytes() {
+        return suggestionProtoBytes(mLatestManualSuggestion);
+    }
+
+    /**
+     * Returns bytes[] for a {@link MetricsTimeZoneSuggestion} for the last, best
+     * telephony suggestion received.
+     */
+    @Nullable
+    public byte[] getLatestTelephonySuggestionProtoBytes() {
+        return suggestionProtoBytes(mLatestTelephonySuggestion);
+    }
+
+    /**
+     * Returns bytes[] for a {@link MetricsTimeZoneSuggestion} for the last geolocation
+     * suggestion received.
+     */
+    @Nullable
+    public byte[] getLatestGeolocationSuggestionProtoBytes() {
+        return suggestionProtoBytes(mLatestGeolocationSuggestion);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        MetricsTimeZoneDetectorState that = (MetricsTimeZoneDetectorState) o;
+        return mDeviceTimeZoneIdOrdinal == that.mDeviceTimeZoneIdOrdinal
+                && mConfigurationInternal.equals(that.mConfigurationInternal)
+                && Objects.equals(mLatestManualSuggestion, that.mLatestManualSuggestion)
+                && Objects.equals(mLatestTelephonySuggestion, that.mLatestTelephonySuggestion)
+                && Objects.equals(mLatestGeolocationSuggestion, that.mLatestGeolocationSuggestion);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mConfigurationInternal, mDeviceTimeZoneIdOrdinal,
+                mLatestManualSuggestion, mLatestTelephonySuggestion, mLatestGeolocationSuggestion);
+    }
+
+    @Override
+    public String toString() {
+        return "MetricsTimeZoneDetectorState{"
+                + "mConfigurationInternal=" + mConfigurationInternal
+                + ", mDeviceTimeZoneIdOrdinal=" + mDeviceTimeZoneIdOrdinal
+                + ", mLatestManualSuggestion=" + mLatestManualSuggestion
+                + ", mLatestTelephonySuggestion=" + mLatestTelephonySuggestion
+                + ", mLatestGeolocationSuggestion=" + mLatestGeolocationSuggestion
+                + '}';
+    }
+
+    private static byte[] suggestionProtoBytes(
+            @Nullable MetricsTimeZoneSuggestion suggestion) {
+        if (suggestion == null) {
+            return null;
+        }
+        return suggestion.toBytes();
+    }
+
+    @Nullable
+    private static MetricsTimeZoneSuggestion createMetricsTimeZoneSuggestion(
+            @NonNull OrdinalGenerator<String> zoneIdOrdinalGenerator,
+            @NonNull ManualTimeZoneSuggestion manualSuggestion) {
+        if (manualSuggestion == null) {
+            return null;
+        }
+
+        int zoneIdOrdinal = zoneIdOrdinalGenerator.ordinal(manualSuggestion.getZoneId());
+        return MetricsTimeZoneSuggestion.createCertain(
+                new int[] { zoneIdOrdinal });
+    }
+
+    @Nullable
+    private static MetricsTimeZoneSuggestion createMetricsTimeZoneSuggestion(
+            @NonNull OrdinalGenerator<String> zoneIdOrdinalGenerator,
+            @NonNull TelephonyTimeZoneSuggestion telephonySuggestion) {
+        if (telephonySuggestion == null) {
+            return null;
+        }
+        if (telephonySuggestion.getZoneId() == null) {
+            return MetricsTimeZoneSuggestion.createUncertain();
+        }
+        int zoneIdOrdinal = zoneIdOrdinalGenerator.ordinal(telephonySuggestion.getZoneId());
+        return MetricsTimeZoneSuggestion.createCertain(new int[] { zoneIdOrdinal });
+    }
+
+    @Nullable
+    private static MetricsTimeZoneSuggestion createMetricsTimeZoneSuggestion(
+            @NonNull OrdinalGenerator<String> zoneIdOrdinalGenerator,
+            @Nullable GeolocationTimeZoneSuggestion geolocationSuggestion) {
+        if (geolocationSuggestion == null) {
+            return null;
+        }
+
+        List<String> zoneIds = geolocationSuggestion.getZoneIds();
+        if (zoneIds == null) {
+            return MetricsTimeZoneSuggestion.createUncertain();
+        }
+        return MetricsTimeZoneSuggestion.createCertain(zoneIdOrdinalGenerator.ordinals(zoneIds));
+    }
+
+    /**
+     * A Java class that closely matches the android.app.time.MetricsTimeZoneSuggestion
+     * proto definition.
+     */
+    private static final class MetricsTimeZoneSuggestion {
+        @Nullable
+        private final int[] mZoneIdOrdinals;
+
+        MetricsTimeZoneSuggestion(@Nullable int[] zoneIdOrdinals) {
+            mZoneIdOrdinals = zoneIdOrdinals;
+        }
+
+        @NonNull
+        static MetricsTimeZoneSuggestion createUncertain() {
+            return new MetricsTimeZoneSuggestion(null);
+        }
+
+        public static MetricsTimeZoneSuggestion createCertain(
+                @NonNull int[] zoneIdOrdinals) {
+            return new MetricsTimeZoneSuggestion(zoneIdOrdinals);
+        }
+
+        boolean isCertain() {
+            return mZoneIdOrdinals != null;
+        }
+
+        @Nullable
+        int[] getZoneIdOrdinals() {
+            return mZoneIdOrdinals;
+        }
+
+        byte[] toBytes() {
+            // We don't get access to the atoms.proto definition for nested proto fields, so we use
+            // an identically specified proto.
+            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+            ProtoOutputStream protoOutputStream = new ProtoOutputStream(byteArrayOutputStream);
+            int typeProtoValue = isCertain()
+                    ? android.app.time.MetricsTimeZoneSuggestion.CERTAIN
+                    : android.app.time.MetricsTimeZoneSuggestion.UNCERTAIN;
+            protoOutputStream.write(android.app.time.MetricsTimeZoneSuggestion.TYPE,
+                    typeProtoValue);
+            if (isCertain()) {
+                for (int zoneIdOrdinal : getZoneIdOrdinals()) {
+                    protoOutputStream.write(
+                            android.app.time.MetricsTimeZoneSuggestion.TIME_ZONE_ORDINALS,
+                            zoneIdOrdinal);
+                }
+            }
+            protoOutputStream.flush();
+            closeQuietly(byteArrayOutputStream);
+            return byteArrayOutputStream.toByteArray();
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (o == null || getClass() != o.getClass()) {
+                return false;
+            }
+            MetricsTimeZoneSuggestion that = (MetricsTimeZoneSuggestion) o;
+            return Arrays.equals(mZoneIdOrdinals, that.mZoneIdOrdinals);
+        }
+
+        @Override
+        public int hashCode() {
+            return Arrays.hashCode(mZoneIdOrdinals);
+        }
+
+        @Override
+        public String toString() {
+            return "MetricsTimeZoneSuggestion{"
+                    + "mZoneIdOrdinals=" + Arrays.toString(mZoneIdOrdinals)
+                    + '}';
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/timezonedetector/OrdinalGenerator.java b/services/core/java/com/android/server/timezonedetector/OrdinalGenerator.java
new file mode 100644
index 0000000..a448773
--- /dev/null
+++ b/services/core/java/com/android/server/timezonedetector/OrdinalGenerator.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.timezonedetector;
+
+import android.util.ArraySet;
+
+import java.util.List;
+
+/**
+ * A helper class that turns a set of objects into ordinal values, i.e. each object is offered
+ * up via {@link #ordinal(Object)} or similar method, and a number will be returned. If the
+ * object has been seen before by the instance then the same number will be returned. Intended
+ * for situations where it is useful to know if values from some finite set are the same or
+ * different, but the value is either large or may reveal PII. This class relies on {@link
+ * Object#equals(Object)} and {@link Object#hashCode()}.
+ */
+class OrdinalGenerator<T> {
+    private final ArraySet<T> mKnownIds = new ArraySet<>();
+
+    int ordinal(T object) {
+        int ordinal = mKnownIds.indexOf(object);
+        if (ordinal < 0) {
+            ordinal = mKnownIds.size();
+            mKnownIds.add(object);
+        }
+        return ordinal;
+    }
+
+    int[] ordinals(List<T> objects) {
+        int[] ordinals = new int[objects.size()];
+        for (int i = 0; i < ordinals.length; i++) {
+            ordinals[i] = ordinal(objects.get(i));
+        }
+        return ordinals;
+    }
+}
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternal.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternal.java
index cd220b1..d429b87 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternal.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternal.java
@@ -50,4 +50,8 @@
      * available, and so on. This method may be implemented asynchronously.
      */
     void suggestGeolocationTimeZone(@NonNull GeolocationTimeZoneSuggestion timeZoneSuggestion);
+
+    /** Generates a state snapshot for metrics. */
+    @NonNull
+    MetricsTimeZoneDetectorState generateMetricsState();
 }
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternalImpl.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternalImpl.java
index 7ba20ee..4e78f5a 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternalImpl.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternalImpl.java
@@ -90,4 +90,10 @@
         mHandler.post(
                 () -> mTimeZoneDetectorStrategy.suggestGeolocationTimeZone(timeZoneSuggestion));
     }
+
+    @Override
+    @NonNull
+    public MetricsTimeZoneDetectorState generateMetricsState() {
+        return mTimeZoneDetectorStrategy.generateMetricsState();
+    }
 }
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java
index 8266f12..e3f31b6 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java
@@ -66,9 +66,10 @@
  * <p>Threading:
  *
  * <p>Suggestion calls with a void return type may be handed off to a separate thread and handled
- * asynchronously. Synchronous calls like {@link #getCurrentUserConfigurationInternal()}, and debug
- * calls like {@link #dump(IndentingPrintWriter, String[])}, may be called on a different thread
- * concurrently with other operations.
+ * asynchronously. Synchronous calls like {@link #getCurrentUserConfigurationInternal()},
+ * {@link #generateMetricsState()} and debug calls like {@link
+ * #dump(IndentingPrintWriter, String[])}, may be called on a different thread concurrently with
+ * other operations.
  *
  * @hide
  */
@@ -123,4 +124,8 @@
      * suggestion.
      */
     void suggestTelephonyTimeZone(@NonNull TelephonyTimeZoneSuggestion suggestion);
+
+    /** Generates a state snapshot for metrics. */
+    @NonNull
+    MetricsTimeZoneDetectorState generateMetricsState();
 }
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java
index 2e96a10..5d34dd7 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java
@@ -371,6 +371,28 @@
         }
     }
 
+    @Override
+    @NonNull
+    public synchronized MetricsTimeZoneDetectorState generateMetricsState() {
+        int currentUserId = mEnvironment.getCurrentUserId();
+        // Just capture one telephony suggestion: the one that would be used right now if telephony
+        // detection is in use.
+        QualifiedTelephonyTimeZoneSuggestion bestQualifiedTelephonySuggestion =
+                findBestTelephonySuggestion();
+        TelephonyTimeZoneSuggestion telephonySuggestion =
+                bestQualifiedTelephonySuggestion == null
+                        ? null : bestQualifiedTelephonySuggestion.suggestion;
+        // A new generator is created each time: we don't want / require consistency.
+        OrdinalGenerator<String> tzIdOrdinalGenerator = new OrdinalGenerator<>();
+        return MetricsTimeZoneDetectorState.create(
+                tzIdOrdinalGenerator,
+                getConfigurationInternal(currentUserId),
+                mEnvironment.getDeviceTimeZone(),
+                getLatestManualSuggestion(),
+                telephonySuggestion,
+                getLatestGeolocationSuggestion());
+    }
+
     private static int scoreTelephonySuggestion(@NonNull TelephonyTimeZoneSuggestion suggestion) {
         int score;
         if (suggestion.getZoneId() == null) {
diff --git a/services/core/java/com/android/server/timezonedetector/location/BinderLocationTimeZoneProvider.java b/services/core/java/com/android/server/timezonedetector/location/BinderLocationTimeZoneProvider.java
index 417a636..4fa920e 100644
--- a/services/core/java/com/android/server/timezonedetector/location/BinderLocationTimeZoneProvider.java
+++ b/services/core/java/com/android/server/timezonedetector/location/BinderLocationTimeZoneProvider.java
@@ -42,10 +42,12 @@
     @NonNull private final LocationTimeZoneProviderProxy mProxy;
 
     BinderLocationTimeZoneProvider(
+            @NonNull ProviderMetricsLogger providerMetricsLogger,
             @NonNull ThreadingDomain threadingDomain,
             @NonNull String providerName,
             @NonNull LocationTimeZoneProviderProxy proxy) {
-        super(threadingDomain, providerName, new ZoneInfoDbTimeZoneIdValidator());
+        super(providerMetricsLogger, threadingDomain, providerName,
+                new ZoneInfoDbTimeZoneIdValidator());
         mProxy = Objects.requireNonNull(proxy);
     }
 
diff --git a/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerService.java b/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerService.java
index 5883821..ca4a640 100644
--- a/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerService.java
+++ b/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerService.java
@@ -45,6 +45,7 @@
 import com.android.server.SystemService;
 import com.android.server.timezonedetector.ServiceConfigAccessor;
 import com.android.server.timezonedetector.TimeZoneDetectorInternal;
+import com.android.server.timezonedetector.location.LocationTimeZoneProvider.ProviderMetricsLogger;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -297,7 +298,9 @@
                     R.string.config_primaryLocationTimeZoneProviderPackageName
             );
         }
-        return new BinderLocationTimeZoneProvider(mThreadingDomain, PRIMARY_PROVIDER_NAME, proxy);
+        ProviderMetricsLogger providerMetricsLogger = new RealProviderMetricsLogger(0);
+        return new BinderLocationTimeZoneProvider(
+                providerMetricsLogger, mThreadingDomain, PRIMARY_PROVIDER_NAME, proxy);
     }
 
     @NonNull
@@ -317,7 +320,9 @@
                     R.string.config_secondaryLocationTimeZoneProviderPackageName
             );
         }
-        return new BinderLocationTimeZoneProvider(mThreadingDomain, SECONDARY_PROVIDER_NAME, proxy);
+        ProviderMetricsLogger providerMetricsLogger = new RealProviderMetricsLogger(1);
+        return new BinderLocationTimeZoneProvider(
+                providerMetricsLogger, mThreadingDomain, SECONDARY_PROVIDER_NAME, proxy);
     }
 
     /** Used for bug triage and in tests to simulate provider events. */
diff --git a/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneProvider.java b/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneProvider.java
index b97c838..cc815dc6 100644
--- a/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneProvider.java
+++ b/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneProvider.java
@@ -98,6 +98,14 @@
     }
 
     /**
+     * Listener interface used to log provider events for metrics.
+     */
+    interface ProviderMetricsLogger {
+        /** Logs that a provider changed state. */
+        void onProviderStateChanged(@ProviderStateEnum int stateEnum);
+    }
+
+    /**
      * Information about the provider's current state.
      */
     static class ProviderState {
@@ -349,6 +357,7 @@
         }
     }
 
+    @NonNull private final ProviderMetricsLogger mProviderMetricsLogger;
     @NonNull final ThreadingDomain mThreadingDomain;
     @NonNull final Object mSharedLock;
     @NonNull final String mProviderName;
@@ -380,10 +389,12 @@
     @NonNull private TimeZoneIdValidator mTimeZoneIdValidator;
 
     /** Creates the instance. */
-    LocationTimeZoneProvider(@NonNull ThreadingDomain threadingDomain,
+    LocationTimeZoneProvider(@NonNull ProviderMetricsLogger providerMetricsLogger,
+            @NonNull ThreadingDomain threadingDomain,
             @NonNull String providerName,
             @NonNull TimeZoneIdValidator timeZoneIdValidator) {
         mThreadingDomain = Objects.requireNonNull(threadingDomain);
+        mProviderMetricsLogger = Objects.requireNonNull(providerMetricsLogger);
         mInitializationTimeoutQueue = threadingDomain.createSingleRunnableQueue();
         mSharedLock = threadingDomain.getLockObject();
         mProviderName = Objects.requireNonNull(providerName);
@@ -485,6 +496,7 @@
             mCurrentState.set(newState);
             onSetCurrentState(newState);
             if (!Objects.equals(newState, oldState)) {
+                mProviderMetricsLogger.onProviderStateChanged(newState.stateEnum);
                 if (mStateChangeRecording) {
                     mRecordedStates.add(newState);
                 }
diff --git a/services/core/java/com/android/server/timezonedetector/location/RealProviderMetricsLogger.java b/services/core/java/com/android/server/timezonedetector/location/RealProviderMetricsLogger.java
new file mode 100644
index 0000000..dfff6f2
--- /dev/null
+++ b/services/core/java/com/android/server/timezonedetector/location/RealProviderMetricsLogger.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 com.android.server.timezonedetector.location;
+
+import android.annotation.IntRange;
+
+import com.android.internal.util.FrameworkStatsLog;
+import com.android.server.timezonedetector.location.LocationTimeZoneProvider.ProviderMetricsLogger;
+import com.android.server.timezonedetector.location.LocationTimeZoneProvider.ProviderState.ProviderStateEnum;
+
+/**
+ * The real implementation of {@link ProviderMetricsLogger} which logs using
+ * {@link FrameworkStatsLog}.
+ */
+public class RealProviderMetricsLogger implements ProviderMetricsLogger {
+
+    @IntRange(from = 0, to = 1)
+    private final int mProviderIndex;
+
+    public RealProviderMetricsLogger(@IntRange(from = 0, to = 1) int providerIndex) {
+        mProviderIndex = providerIndex;
+    }
+
+    @Override
+    public void onProviderStateChanged(@ProviderStateEnum int stateEnum) {
+        // TODO(b/172934905): Implement once the atom has landed.
+    }
+}
diff --git a/services/core/java/com/android/server/vibrator/VibratorController.java b/services/core/java/com/android/server/vibrator/VibratorController.java
index eaba083..e3dc70b 100644
--- a/services/core/java/com/android/server/vibrator/VibratorController.java
+++ b/services/core/java/com/android/server/vibrator/VibratorController.java
@@ -54,50 +54,6 @@
         void onComplete(int vibratorId, long vibrationId);
     }
 
-    /**
-     * Initializes the native part of this controller, creating a global reference to given
-     * {@link OnVibrationCompleteListener} and returns a newly allocated native pointer. This
-     * wrapper is responsible for deleting this pointer by calling the method pointed
-     * by {@link #vibratorGetFinalizer()}.
-     *
-     * <p><b>Note:</b> Make sure the given implementation of {@link OnVibrationCompleteListener}
-     * do not hold any strong reference to the instance responsible for deleting the returned
-     * pointer, to avoid creating a cyclic GC root reference.
-     */
-    static native long vibratorInit(int vibratorId, OnVibrationCompleteListener listener);
-
-    /**
-     * Returns pointer to native function responsible for cleaning up the native pointer allocated
-     * and returned by {@link #vibratorInit(int, OnVibrationCompleteListener)}.
-     */
-    static native long vibratorGetFinalizer();
-
-    static native boolean vibratorIsAvailable(long nativePtr);
-
-    static native void vibratorOn(long nativePtr, long milliseconds, long vibrationId);
-
-    static native void vibratorOff(long nativePtr);
-
-    static native void vibratorSetAmplitude(long nativePtr, int amplitude);
-
-    static native int[] vibratorGetSupportedEffects(long nativePtr);
-
-    static native int[] vibratorGetSupportedPrimitives(long nativePtr);
-
-    static native long vibratorPerformEffect(
-            long nativePtr, long effect, long strength, long vibrationId);
-
-    static native long vibratorPerformComposedEffect(
-            long nativePtr, VibrationEffect.Composition.PrimitiveEffect[] effect, long vibrationId);
-
-    static native void vibratorSetExternalControl(long nativePtr, boolean enabled);
-
-    static native long vibratorGetCapabilities(long nativePtr);
-
-    static native void vibratorAlwaysOnEnable(long nativePtr, long id, long effect, long strength);
-
-    static native void vibratorAlwaysOnDisable(long nativePtr, long id);
-
     VibratorController(int vibratorId, OnVibrationCompleteListener listener) {
         this(vibratorId, listener, new NativeWrapper());
     }
@@ -109,7 +65,8 @@
         mNativeWrapper.init(vibratorId, listener);
 
         mVibratorInfo = new VibratorInfo(vibratorId, nativeWrapper.getCapabilities(),
-                nativeWrapper.getSupportedEffects(), nativeWrapper.getSupportedPrimitives());
+                nativeWrapper.getSupportedEffects(), nativeWrapper.getSupportedPrimitives(),
+                nativeWrapper.getResonantFrequency(), nativeWrapper.getQFactor());
     }
 
     /** Register state listener for this vibrator. */
@@ -336,13 +293,47 @@
     /** Wrapper around the static-native methods of {@link VibratorController} for tests. */
     @VisibleForTesting
     public static class NativeWrapper {
+        /**
+         * Initializes the native part of this controller, creating a global reference to given
+         * {@link OnVibrationCompleteListener} and returns a newly allocated native pointer. This
+         * wrapper is responsible for deleting this pointer by calling the method pointed
+         * by {@link #getNativeFinalizer()}.
+         *
+         * <p><b>Note:</b> Make sure the given implementation of {@link OnVibrationCompleteListener}
+         * do not hold any strong reference to the instance responsible for deleting the returned
+         * pointer, to avoid creating a cyclic GC root reference.
+         */
+        private static native long nativeInit(int vibratorId, OnVibrationCompleteListener listener);
+
+        /**
+         * Returns pointer to native function responsible for cleaning up the native pointer
+         * allocated and returned by {@link #nativeInit(int, OnVibrationCompleteListener)}.
+         */
+        private static native long getNativeFinalizer();
+        private static native boolean isAvailable(long nativePtr);
+        private static native void on(long nativePtr, long milliseconds, long vibrationId);
+        private static native void off(long nativePtr);
+        private static native void setAmplitude(long nativePtr, int amplitude);
+        private static native int[] getSupportedEffects(long nativePtr);
+        private static native int[] getSupportedPrimitives(long nativePtr);
+        private static native long performEffect(
+                long nativePtr, long effect, long strength, long vibrationId);
+        private static native long performComposedEffect(long nativePtr,
+                VibrationEffect.Composition.PrimitiveEffect[] effect, long vibrationId);
+        private static native void setExternalControl(long nativePtr, boolean enabled);
+        private static native long getCapabilities(long nativePtr);
+        private static native void alwaysOnEnable(long nativePtr, long id, long effect,
+                long strength);
+        private static native void alwaysOnDisable(long nativePtr, long id);
+        private static native float getResonantFrequency(long nativePtr);
+        private static native float getQFactor(long nativePtr);
 
         private long mNativePtr = 0;
 
         /** Initializes native controller and allocation registry to destroy native instances. */
         public void init(int vibratorId, OnVibrationCompleteListener listener) {
-            mNativePtr = VibratorController.vibratorInit(vibratorId, listener);
-            long finalizerPtr = VibratorController.vibratorGetFinalizer();
+            mNativePtr = nativeInit(vibratorId, listener);
+            long finalizerPtr = getNativeFinalizer();
 
             if (finalizerPtr != 0) {
                 NativeAllocationRegistry registry =
@@ -354,65 +345,73 @@
 
         /** Check if the vibrator is currently available. */
         public boolean isAvailable() {
-            return VibratorController.vibratorIsAvailable(mNativePtr);
+            return isAvailable(mNativePtr);
         }
 
         /** Turns vibrator on for given time. */
         public void on(long milliseconds, long vibrationId) {
-            VibratorController.vibratorOn(mNativePtr, milliseconds, vibrationId);
+            on(mNativePtr, milliseconds, vibrationId);
         }
 
         /** Turns vibrator off. */
         public void off() {
-            VibratorController.vibratorOff(mNativePtr);
+            off(mNativePtr);
         }
 
         /** Sets the amplitude for the vibrator to run. */
         public void setAmplitude(int amplitude) {
-            VibratorController.vibratorSetAmplitude(mNativePtr, amplitude);
+            setAmplitude(mNativePtr, amplitude);
         }
 
         /** Returns all predefined effects supported by the device vibrator. */
         public int[] getSupportedEffects() {
-            return VibratorController.vibratorGetSupportedEffects(mNativePtr);
+            return getSupportedEffects(mNativePtr);
         }
 
         /** Returns all compose primitives supported by the device vibrator. */
         public int[] getSupportedPrimitives() {
-            return VibratorController.vibratorGetSupportedPrimitives(mNativePtr);
+            return getSupportedPrimitives(mNativePtr);
         }
 
         /** Turns vibrator on to perform one of the supported effects. */
         public long perform(long effect, long strength, long vibrationId) {
-            return VibratorController.vibratorPerformEffect(
-                    mNativePtr, effect, strength, vibrationId);
+            return performEffect(mNativePtr, effect, strength, vibrationId);
         }
 
         /** Turns vibrator on to perform one of the supported composed effects. */
         public long compose(
                 VibrationEffect.Composition.PrimitiveEffect[] effect, long vibrationId) {
-            return VibratorController.vibratorPerformComposedEffect(mNativePtr, effect,
-                    vibrationId);
+            return performComposedEffect(mNativePtr, effect, vibrationId);
         }
 
         /** Enabled the device vibrator to be controlled by another service. */
         public void setExternalControl(boolean enabled) {
-            VibratorController.vibratorSetExternalControl(mNativePtr, enabled);
+            setExternalControl(mNativePtr, enabled);
         }
 
         /** Returns all capabilities of the device vibrator. */
         public long getCapabilities() {
-            return VibratorController.vibratorGetCapabilities(mNativePtr);
+            return getCapabilities(mNativePtr);
         }
 
         /** Enable always-on vibration with given id and effect. */
         public void alwaysOnEnable(long id, long effect, long strength) {
-            VibratorController.vibratorAlwaysOnEnable(mNativePtr, id, effect, strength);
+            alwaysOnEnable(mNativePtr, id, effect, strength);
         }
 
         /** Disable always-on vibration for given id. */
         public void alwaysOnDisable(long id) {
-            VibratorController.vibratorAlwaysOnDisable(mNativePtr, id);
+            alwaysOnDisable(mNativePtr, id);
+        }
+
+        /** Gets the vibrator's resonant frequency (F0) */
+        public float getResonantFrequency() {
+            return getResonantFrequency(mNativePtr);
+        }
+
+        /** Gets the vibrator's Q factor */
+        public float getQFactor() {
+            return getQFactor(mNativePtr);
         }
     }
 }
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index aeeabe2..db3d7ad 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -137,6 +137,7 @@
 import static com.android.server.wm.ActivityRecordProto.DEFER_HIDING_CLIENT;
 import static com.android.server.wm.ActivityRecordProto.FILLS_PARENT;
 import static com.android.server.wm.ActivityRecordProto.FRONT_OF_TASK;
+import static com.android.server.wm.ActivityRecordProto.IN_SIZE_COMPAT_MODE;
 import static com.android.server.wm.ActivityRecordProto.IS_ANIMATING;
 import static com.android.server.wm.ActivityRecordProto.IS_WAITING_FOR_TRANSITION_START;
 import static com.android.server.wm.ActivityRecordProto.LAST_ALL_DRAWN;
@@ -2114,7 +2115,7 @@
                     }
                 }
                 if (abort) {
-                    surface.remove();
+                    surface.remove(false /* prepareAnimation */);
                 }
             } else {
                 ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Surface returned was null: %s",
@@ -2128,7 +2129,8 @@
     private int getStartingWindowType(boolean newTask, boolean taskSwitch, boolean processRunning,
             boolean allowTaskSnapshot, boolean activityCreated,
             TaskSnapshot snapshot) {
-        if (newTask || !processRunning || (taskSwitch && !activityCreated)) {
+        if ((newTask || !processRunning || (taskSwitch && !activityCreated))
+                && !isActivityTypeHome()) {
             return STARTING_WINDOW_TYPE_SPLASH_SCREEN;
         } else if (taskSwitch && allowTaskSnapshot) {
             if (isSnapshotCompatible(snapshot)) {
@@ -2179,7 +2181,6 @@
                         + ActivityRecord.this + " state " + mTransferringSplashScreenState);
                 if (isTransferringSplashScreen()) {
                     mTransferringSplashScreenState = TRANSFER_SPLASH_SCREEN_FINISH;
-                    // TODO show default exit splash screen animation
                     removeStartingWindow();
                 }
             }
@@ -2196,6 +2197,9 @@
     }
 
     private boolean transferSplashScreenIfNeeded() {
+        if (!mWmService.mStartingSurfaceController.DEBUG_ENABLE_SHELL_DRAWER) {
+            return false;
+        }
         if (!mHandleExitSplashScreen || mStartingSurface == null || mStartingWindow == null
                 || mTransferringSplashScreenState == TRANSFER_SPLASH_SCREEN_FINISH) {
             return false;
@@ -2265,10 +2269,14 @@
         }
         // no matter what, remove the starting window.
         mTransferringSplashScreenState = TRANSFER_SPLASH_SCREEN_FINISH;
-        removeStartingWindow();
+        removeStartingWindowAnimation(false /* prepareAnimation */);
     }
 
     void removeStartingWindow() {
+        removeStartingWindowAnimation(true /* prepareAnimation */);
+    }
+
+    void removeStartingWindowAnimation(boolean prepareAnimation) {
         if (transferSplashScreenIfNeeded()) {
             return;
         }
@@ -2313,7 +2321,7 @@
         mWmService.mAnimationHandler.post(() -> {
             ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Removing startingView=%s", surface);
             try {
-                surface.remove();
+                surface.remove(prepareAnimation);
             } catch (Exception e) {
                 Slog.w(TAG_WM, "Exception when removing starting window", e);
             }
@@ -6190,7 +6198,7 @@
             // Remove orphaned starting window.
             if (DEBUG_VISIBILITY) Slog.w(TAG_VISIBILITY, "Found orphaned starting window " + this);
             mStartingWindowState = STARTING_WINDOW_REMOVED;
-            removeStartingWindow();
+            removeStartingWindowAnimation(false /* prepareAnimation */);
         }
         if (isState(INITIALIZING) && !shouldBeVisible(
                 true /* behindFullscreenActivity */, true /* ignoringKeyguard */)) {
@@ -8255,6 +8263,7 @@
             proto.write(PROC_ID, app.getPid());
         }
         proto.write(PIP_AUTO_ENTER_ENABLED, pictureInPictureArgs.isAutoEnterEnabled());
+        proto.write(IN_SIZE_COMPAT_MODE, inSizeCompatMode());
     }
 
     @Override
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index d4eedf1..52d110c 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -557,7 +557,7 @@
     boolean mSupportsPictureInPicture;
     boolean mSupportsMultiDisplay;
     boolean mForceResizableActivities;
-    boolean mSupportsNonResizableMultiWindow;
+    volatile boolean mSupportsNonResizableMultiWindow;
 
     final List<ActivityTaskManagerInternal.ScreenObserver> mScreenObservers = new ArrayList<>();
 
@@ -3432,6 +3432,11 @@
     }
 
     @Override
+    public boolean supportsNonResizableMultiWindow() {
+        return mSupportsNonResizableMultiWindow;
+    }
+
+    @Override
     public boolean updateConfiguration(Configuration values) {
         mAmInternal.enforceCallingPermission(CHANGE_CONFIGURATION, "updateConfiguration()");
 
diff --git a/services/core/java/com/android/server/wm/BlurController.java b/services/core/java/com/android/server/wm/BlurController.java
index 13295e8..128d452 100644
--- a/services/core/java/com/android/server/wm/BlurController.java
+++ b/services/core/java/com/android/server/wm/BlurController.java
@@ -22,12 +22,17 @@
 import android.os.RemoteException;
 import android.view.ICrossWindowBlurEnabledListener;
 
+import com.android.internal.annotations.GuardedBy;
+
 final class BlurController {
 
     private final RemoteCallbackList<ICrossWindowBlurEnabledListener>
             mBlurEnabledListeners = new RemoteCallbackList<>();
     private final Object mLock = new Object();
+    @GuardedBy("mLock")
     boolean mBlurEnabled;
+    @GuardedBy("mLock")
+    boolean mBlurForceDisabled;
 
     BlurController() {
         mBlurEnabled = CROSS_WINDOW_BLUR_SUPPORTED;
@@ -46,19 +51,24 @@
         mBlurEnabledListeners.unregister(listener);
     }
 
-    private void updateBlurEnabled() {
-        // TODO: add other factors disabling blurs
-        final boolean newEnabled = CROSS_WINDOW_BLUR_SUPPORTED;
+    void setForceCrossWindowBlurDisabled(boolean disable) {
         synchronized (mLock) {
-            if (mBlurEnabled == newEnabled) {
-                return;
-            }
-            mBlurEnabled = newEnabled;
-            notifyBlurEnabledChanged(newEnabled);
+            mBlurForceDisabled = disable;
+            updateBlurEnabledLocked();
         }
+
     }
 
-    private void notifyBlurEnabledChanged(boolean enabled) {
+    private void updateBlurEnabledLocked() {
+        final boolean newEnabled = CROSS_WINDOW_BLUR_SUPPORTED && !mBlurForceDisabled;
+        if (mBlurEnabled == newEnabled) {
+            return;
+        }
+        mBlurEnabled = newEnabled;
+        notifyBlurEnabledChangedLocked(newEnabled);
+    }
+
+    private void notifyBlurEnabledChangedLocked(boolean enabled) {
         int i = mBlurEnabledListeners.beginBroadcast();
         while (i > 0) {
             i--;
@@ -71,6 +81,4 @@
         }
         mBlurEnabledListeners.finishBroadcast();
     }
-
-
 }
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 32152ec..01f0359 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -1410,9 +1410,9 @@
             boolean localClient) {
         final InsetsState state =
                 mDisplayContent.getInsetsPolicy().getInsetsForWindowMetrics(attrs);
-        final boolean inSizeCompatMode = WindowState.inSizeCompatMode(attrs, windowToken);
-        outInsetsState.set(state, inSizeCompatMode || localClient);
-        if (inSizeCompatMode) {
+        final boolean hasCompatScale = WindowState.hasCompatScale(attrs, windowToken);
+        outInsetsState.set(state, hasCompatScale || localClient);
+        if (hasCompatScale) {
             final float compatScale = windowToken != null
                     ? windowToken.getSizeCompatScale()
                     : mDisplayContent.mCompatibleScreenScale;
diff --git a/services/core/java/com/android/server/wm/DragDropController.java b/services/core/java/com/android/server/wm/DragDropController.java
index 627af91..1120a07 100644
--- a/services/core/java/com/android/server/wm/DragDropController.java
+++ b/services/core/java/com/android/server/wm/DragDropController.java
@@ -182,8 +182,6 @@
                     if (SHOW_LIGHT_TRANSACTIONS) {
                         Slog.i(TAG_WM, "<<< CLOSE TRANSACTION performDrag");
                     }
-
-                    mDragState.notifyLocationLocked(touchX, touchY);
                 } finally {
                     if (surface != null) {
                         surface.release();
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index 0b3c065..08d5e80 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -515,50 +515,6 @@
         mTransaction.setPosition(mSurfaceControl, x - mThumbOffsetX, y - mThumbOffsetY).apply();
         ProtoLog.i(WM_SHOW_TRANSACTIONS, "DRAG %s: pos=(%d,%d)", mSurfaceControl,
                 (int) (x - mThumbOffsetX), (int) (y - mThumbOffsetY));
-
-        notifyLocationLocked(x, y);
-    }
-
-    void notifyLocationLocked(float x, float y) {
-        // Tell the affected window
-        WindowState touchedWin = mDisplayContent.getTouchableWinAtPointLocked(x, y);
-        if (touchedWin != null && !isWindowNotified(touchedWin)) {
-            // The drag point is over a window which was not notified about a drag start.
-            // Pretend it's over empty space.
-            touchedWin = null;
-        }
-
-        try {
-            final int myPid = Process.myPid();
-
-            // have we dragged over a new window?
-            if ((touchedWin != mTargetWindow) && (mTargetWindow != null)) {
-                if (DEBUG_DRAG) {
-                    Slog.d(TAG_WM, "sending DRAG_EXITED to " + mTargetWindow);
-                }
-                // force DRAG_EXITED_EVENT if appropriate
-                DragEvent evt = obtainDragEvent(mTargetWindow, DragEvent.ACTION_DRAG_EXITED,
-                        0, 0, 0, 0, null, null, null, null, null, false);
-                mTargetWindow.mClient.dispatchDragEvent(evt);
-                if (myPid != mTargetWindow.mSession.mPid) {
-                    evt.recycle();
-                }
-            }
-            if (touchedWin != null) {
-                if (false && DEBUG_DRAG) {
-                    Slog.d(TAG_WM, "sending DRAG_LOCATION to " + touchedWin);
-                }
-                DragEvent evt = obtainDragEvent(touchedWin, DragEvent.ACTION_DRAG_LOCATION,
-                        x, y, mThumbOffsetX, mThumbOffsetY, null, null, null, null, null, false);
-                touchedWin.mClient.dispatchDragEvent(evt);
-                if (myPid != touchedWin.mSession.mPid) {
-                    evt.recycle();
-                }
-            }
-        } catch (RemoteException e) {
-            Slog.w(TAG_WM, "can't send drag notification to windows");
-        }
-        mTargetWindow = touchedWin;
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/FixedRotationAnimationController.java b/services/core/java/com/android/server/wm/FixedRotationAnimationController.java
index a1e3ac7..aa73170 100644
--- a/services/core/java/com/android/server/wm/FixedRotationAnimationController.java
+++ b/services/core/java/com/android/server/wm/FixedRotationAnimationController.java
@@ -37,10 +37,15 @@
         super(displayContent);
         final DisplayPolicy displayPolicy = displayContent.getDisplayPolicy();
         mStatusBar = displayPolicy.getStatusBar();
-        // Do not animate movable navigation bar (e.g. non-gesture mode).
+
+        final RecentsAnimationController controller =
+                displayContent.mWmService.getRecentsAnimationController();
+        final boolean navBarControlledByRecents =
+                controller != null && controller.isNavigationBarAttachedToApp();
+        // Do not animate movable navigation bar (e.g. non-gesture mode) or when the navigation bar
+        // is currently controlled by recents animation.
         mNavigationBar = !displayPolicy.navigationBarCanMove()
-                ? displayPolicy.getNavigationBar()
-                : null;
+                && !navBarControlledByRecents ? displayPolicy.getNavigationBar() : null;
     }
 
     /** Applies show animation on the previously hidden window tokens. */
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index 45c4233..35e5491 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -30,7 +30,6 @@
 import static com.android.server.wm.InsetsSourceProviderProto.CONTROL_TARGET;
 import static com.android.server.wm.InsetsSourceProviderProto.FAKE_CONTROL;
 import static com.android.server.wm.InsetsSourceProviderProto.FAKE_CONTROL_TARGET;
-import static com.android.server.wm.InsetsSourceProviderProto.FINISH_SEAMLESS_ROTATE_FRAME_NUMBER;
 import static com.android.server.wm.InsetsSourceProviderProto.FRAME;
 import static com.android.server.wm.InsetsSourceProviderProto.IME_OVERRIDDEN_FRAME;
 import static com.android.server.wm.InsetsSourceProviderProto.IS_LEASH_READY_FOR_DISPATCHING;
@@ -59,6 +58,7 @@
 import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
 
 import java.io.PrintWriter;
+import java.util.function.Consumer;
 
 /**
  * Controller for a specific inset source on the server. It's called provider as it provides the
@@ -84,6 +84,16 @@
     private final Rect mImeOverrideFrame = new Rect();
     private boolean mIsLeashReadyForDispatching;
 
+    private final Consumer<Transaction> mSetLeashPositionConsumer = t -> {
+        if (mControl != null) {
+            final SurfaceControl leash = mControl.getLeash();
+            if (leash != null) {
+                final Point position = mControl.getSurfacePosition();
+                t.setPosition(leash, position.x, position.y);
+            }
+        }
+    };
+
     /** The visibility override from the current controlling window. */
     private boolean mClientVisible;
 
@@ -149,7 +159,6 @@
             // TODO: Ideally, we should wait for the animation to finish so previous window can
             // animate-out as new one animates-in.
             mWin.cancelAnimation();
-            mWin.mPendingPositionChanged = null;
             mWin.mProvidedInsetsSources.remove(mSource.getType());
         }
         ProtoLog.d(WM_DEBUG_IME, "InsetsSource setWin %s", win);
@@ -248,31 +257,16 @@
         if (mControl != null) {
             final Point position = getWindowFrameSurfacePosition();
             if (mControl.setSurfacePosition(position.x, position.y) && mControlTarget != null) {
-                if (!mWin.getWindowFrames().didFrameSizeChange()) {
-                    updateLeashPosition(-1 /* frameNumber */);
-                } else if (mWin.mInRelayout) {
-                    updateLeashPosition(mWin.getFrameNumber());
+                if (mWin.getWindowFrames().didFrameSizeChange()) {
+                    mWin.applyWithNextDraw(mSetLeashPositionConsumer);
                 } else {
-                    mWin.mPendingPositionChanged = this;
+                    mSetLeashPositionConsumer.accept(mWin.getPendingTransaction());
                 }
                 mStateController.notifyControlChanged(mControlTarget);
             }
         }
     }
 
-    void updateLeashPosition(long frameNumber) {
-        if (mControl == null) {
-            return;
-        }
-        final SurfaceControl leash = mControl.getLeash();
-        if (leash != null) {
-            final Transaction t = mDisplayContent.getPendingTransaction();
-            final Point position = mControl.getSurfacePosition();
-            t.setPosition(leash, position.x, position.y);
-            deferTransactionUntil(t, leash, frameNumber);
-        }
-    }
-
     private Point getWindowFrameSurfacePosition() {
         final Rect frame = mWin.getFrame();
         final Point position = new Point();
@@ -280,14 +274,6 @@
         return position;
     }
 
-    private void deferTransactionUntil(Transaction t, SurfaceControl leash, long frameNumber) {
-        if (frameNumber >= 0) {
-            final SurfaceControl barrier = mWin.getClientViewRootSurface();
-            t.deferTransactionUntil(mWin.getSurfaceControl(), barrier, frameNumber);
-            t.deferTransactionUntil(leash, barrier, frameNumber);
-        }
-    }
-
     /**
      * @see InsetsStateController#onControlFakeTargetChanged(int, InsetsControlTarget)
      */
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index e02cce4..914e456 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -17,7 +17,9 @@
 package com.android.server.wm;
 
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
 import static android.view.RemoteAnimationTarget.MODE_CLOSING;
 import static android.view.RemoteAnimationTarget.MODE_OPENING;
 import static android.view.WindowManager.INPUT_CONSUMER_RECENTS_ANIMATION;
@@ -104,7 +106,8 @@
     public @interface ReorderMode {}
 
     private final WindowManagerService mService;
-    private final StatusBarManagerInternal mStatusBar;
+    @VisibleForTesting
+    final StatusBarManagerInternal mStatusBar;
     private IRecentsAnimationRunner mRunner;
     private final RecentsAnimationCallbacks mCallbacks;
     private final ArrayList<TaskAnimationAdapter> mPendingAnimations = new ArrayList<>();
@@ -149,6 +152,7 @@
 
     @VisibleForTesting
     boolean mShouldAttachNavBarToAppDuringTransition;
+    private boolean mNavigationBarAttachedToApp;
 
     /**
      * Animates the screenshot of task that used to be controlled by RecentsAnimation.
@@ -369,7 +373,17 @@
         }
 
         @Override
-        public void detachNavigationBarFromApp() {}
+        public void detachNavigationBarFromApp(boolean moveHomeToTop) {
+            final long token = Binder.clearCallingIdentity();
+            try {
+                synchronized (mService.getWindowManagerLock()) {
+                    restoreNavigationBarFromApp(moveHomeToTop);
+                    mService.mWindowPlacerLocked.requestTraversal();
+                }
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
     };
 
     /**
@@ -440,9 +454,7 @@
             return;
         }
 
-        if (mShouldAttachNavBarToAppDuringTransition) {
-            attachNavBarToApp();
-        }
+        attachNavigationBarToApp();
 
         // Adjust the wallpaper visibility for the showing target activity
         ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS,
@@ -577,32 +589,52 @@
         }
     }
 
-    @VisibleForTesting
-    WindowToken getNavigationBarWindowToken() {
-        WindowState navBar = mDisplayContent.getDisplayPolicy().getNavigationBar();
-        if (navBar != null) {
-            return navBar.mToken;
-        }
-        return null;
+    boolean isNavigationBarAttachedToApp() {
+        return mNavigationBarAttachedToApp;
     }
 
-    private void attachNavBarToApp() {
+    @VisibleForTesting
+    WindowState getNavigationBarWindow() {
+        return mDisplayContent.getDisplayPolicy().getNavigationBar();
+    }
+
+    private void attachNavigationBarToApp() {
+        if (!mShouldAttachNavBarToAppDuringTransition
+                // Skip the case where the nav bar is controlled by fixed rotation.
+                || mDisplayContent.getFixedRotationAnimationController() != null) {
+            return;
+        }
         ActivityRecord topActivity = null;
+        boolean shouldTranslateNavBar = false;
+        final boolean isDisplayLandscape =
+                mDisplayContent.getConfiguration().orientation == ORIENTATION_LANDSCAPE;
         for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
             final TaskAnimationAdapter adapter = mPendingAnimations.get(i);
             final Task task = adapter.mTask;
-            if (!task.isHomeOrRecentsRootTask()) {
-                topActivity = task.getTopVisibleActivity();
-                break;
+            final boolean isSplitScreenSecondary =
+                    task.getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
+            if (task.isHomeOrRecentsRootTask()
+                    // TODO(b/178449492): Will need to update for the new split screen mode once
+                    // it's ready.
+                    // Skip if the task is the secondary split screen and in landscape.
+                    || (isSplitScreenSecondary && isDisplayLandscape)) {
+                continue;
             }
-        }
-        final WindowToken navToken = getNavigationBarWindowToken();
-        if (topActivity == null || navToken == null) {
-            return;
+            shouldTranslateNavBar = isSplitScreenSecondary;
+            topActivity = task.getTopVisibleActivity();
+            break;
         }
 
-        final SurfaceControl.Transaction t = navToken.getPendingTransaction();
-        final SurfaceControl navSurfaceControl = navToken.getSurfaceControl();
+        final WindowState navWindow = getNavigationBarWindow();
+        if (topActivity == null || navWindow == null || navWindow.mToken == null) {
+            return;
+        }
+        mNavigationBarAttachedToApp = true;
+        final SurfaceControl.Transaction t = navWindow.mToken.getPendingTransaction();
+        final SurfaceControl navSurfaceControl = navWindow.mToken.getSurfaceControl();
+        if (shouldTranslateNavBar) {
+            navWindow.setSurfaceTranslationY(-topActivity.getBounds().top);
+        }
         t.reparent(navSurfaceControl, topActivity.getSurfaceControl());
         t.show(navSurfaceControl);
 
@@ -613,16 +645,32 @@
             // Place the nav bar on top of anything else in the top activity.
             t.setLayer(navSurfaceControl, Integer.MAX_VALUE);
         }
+        if (mStatusBar != null) {
+            mStatusBar.setNavigationBarLumaSamplingEnabled(mDisplayId, false);
+        }
     }
 
-    private void restoreNavBarFromApp(boolean animate) {
-        // Reparent the SurfaceControl of nav bar token back.
-        final WindowToken navToken = getNavigationBarWindowToken();
-        final SurfaceControl.Transaction t = mDisplayContent.getPendingTransaction();
-        if (navToken != null) {
-            final WindowContainer parent = navToken.getParent();
-            t.reparent(navToken.getSurfaceControl(), parent.getSurfaceControl());
+    private void restoreNavigationBarFromApp(boolean animate) {
+        if (!mNavigationBarAttachedToApp) {
+            return;
         }
+        if (mStatusBar != null) {
+            mStatusBar.setNavigationBarLumaSamplingEnabled(mDisplayId, true);
+        }
+
+        final WindowState navWindow = getNavigationBarWindow();
+        if (navWindow == null) {
+            return;
+        }
+        navWindow.setSurfaceTranslationY(0);
+
+        if (navWindow.mToken == null) {
+            return;
+        }
+        final SurfaceControl.Transaction t = mDisplayContent.getPendingTransaction();
+        final WindowContainer parent = navWindow.mToken.getParent();
+        // Reparent the SurfaceControl of nav bar token back.
+        t.reparent(navWindow.mToken.getSurfaceControl(), parent.getSurfaceControl());
 
         if (animate) {
             // Run fade-in animation to show navigation bar back to bottom of the display.
@@ -852,9 +900,7 @@
             removeWallpaperAnimation(wallpaperAdapter);
         }
 
-        if (mShouldAttachNavBarToAppDuringTransition) {
-            restoreNavBarFromApp(reorderMode == REORDER_MOVE_TO_TOP);
-        }
+        restoreNavigationBarFromApp(reorderMode == REORDER_MOVE_TO_TOP);
 
         // Clear any pending failsafe runnables
         mService.mH.removeCallbacks(mFailsafeRunnable);
diff --git a/services/core/java/com/android/server/wm/StartingSurfaceController.java b/services/core/java/com/android/server/wm/StartingSurfaceController.java
index ef4a40f..6c46135 100644
--- a/services/core/java/com/android/server/wm/StartingSurfaceController.java
+++ b/services/core/java/com/android/server/wm/StartingSurfaceController.java
@@ -40,9 +40,8 @@
     private static final String TAG = TAG_WITH_CLASS_NAME
             ? StartingSurfaceController.class.getSimpleName() : TAG_WM;
     /** Set to {@code true} to enable shell starting surface drawer. */
-    private static final boolean DEBUG_ENABLE_SHELL_DRAWER =
-            SystemProperties.getBoolean("persist.debug.shell_starting_surface", false);
-
+    static final boolean DEBUG_ENABLE_SHELL_DRAWER =
+            SystemProperties.getBoolean("persist.debug.shell_starting_surface", true);
     private final WindowManagerService mService;
 
     public StartingSurfaceController(WindowManagerService wm) {
@@ -139,8 +138,9 @@
         }
 
         @Override
-        public void remove() {
-            mService.mAtmService.mTaskOrganizerController.removeStartingWindow(mTask);
+        public void remove(boolean animate) {
+            mService.mAtmService.mTaskOrganizerController.removeStartingWindow(mTask,
+                    animate);
         }
     }
 }
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 04a254c..a4b4726 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -4135,6 +4135,8 @@
         final StartingWindowInfo info = new StartingWindowInfo();
         info.taskInfo = getTaskInfo();
 
+        info.isKeyguardOccluded =
+            mAtmService.mKeyguardController.isDisplayOccluded(DEFAULT_DISPLAY);
         final ActivityRecord topActivity = getTopMostActivity();
         if (topActivity != null) {
             info.startingWindowTypeParameter =
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index fc6db61..5d22f8f 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -32,6 +32,7 @@
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ParceledListSlice;
+import android.graphics.Rect;
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.Parcel;
@@ -131,10 +132,28 @@
             });
         }
 
-        void removeStartingWindow(Task task) {
+        void removeStartingWindow(Task task, boolean prepareAnimation) {
             mDeferTaskOrgCallbacksConsumer.accept(() -> {
+                SurfaceControl firstWindowLeash = null;
+                Rect mainFrame = null;
+                // TODO enable shift up animation once we fix flicker test
+//                final boolean playShiftUpAnimation = !task.inMultiWindowMode();
+//                if (prepareAnimation && playShiftUpAnimation) {
+//                    final ActivityRecord topActivity = task.topActivityWithStartingWindow();
+//                    if (topActivity != null) {
+//                        final WindowState mainWindow =
+//                                topActivity.findMainWindow(false/* includeStartingApp */);
+//                        if (mainWindow != null) {
+                // TODO create proper leash instead of the copied SC
+//                            firstWindowLeash = new SurfaceControl(mainWindow.getSurfaceControl(),
+//                                    "TaskOrganizerController.removeStartingWindow");
+//                            mainFrame = mainWindow.getRelativeFrame();
+//                        }
+//                    }
+//                }
                 try {
-                    mTaskOrganizer.removeStartingWindow(task.mTaskId);
+                    mTaskOrganizer.removeStartingWindow(task.mTaskId, firstWindowLeash, mainFrame,
+                            prepareAnimation);
                 } catch (RemoteException e) {
                     Slog.e(TAG, "Exception sending onStartTaskFinished callback", e);
                 }
@@ -249,8 +268,8 @@
             mOrganizer.addStartingWindow(t, appToken, launchTheme);
         }
 
-        void removeStartingWindow(Task t) {
-            mOrganizer.removeStartingWindow(t);
+        void removeStartingWindow(Task t, boolean prepareAnimation) {
+            mOrganizer.removeStartingWindow(t, prepareAnimation);
         }
 
         void copySplashScreenView(Task t) {
@@ -495,14 +514,14 @@
         return true;
     }
 
-    void removeStartingWindow(Task task) {
+    void removeStartingWindow(Task task, boolean prepareAnimation) {
         final Task rootTask = task.getRootTask();
         if (rootTask == null || rootTask.mTaskOrganizer == null) {
             return;
         }
         final TaskOrganizerState state =
                 mTaskOrganizerStates.get(rootTask.mTaskOrganizer.asBinder());
-        state.removeStartingWindow(task);
+        state.removeStartingWindow(task, prepareAnimation);
     }
 
     boolean copySplashScreenView(Task task) {
@@ -865,6 +884,7 @@
             mPendingTaskEvents.remove(pending);
         }
         mPendingTaskEvents.add(pending);
+        mService.mWindowManager.mWindowPlacerLocked.requestTraversal();
         return true;
     }
 
diff --git a/services/core/java/com/android/server/wm/TaskPositioningController.java b/services/core/java/com/android/server/wm/TaskPositioningController.java
index 9d35c25..525420e 100644
--- a/services/core/java/com/android/server/wm/TaskPositioningController.java
+++ b/services/core/java/com/android/server/wm/TaskPositioningController.java
@@ -188,7 +188,8 @@
             transferFocusFromWin = displayContent.mCurrentFocus;
         }
         if (!mInputManager.transferTouchFocus(
-                transferFocusFromWin.mInputChannel, mTaskPositioner.mClientChannel)) {
+                transferFocusFromWin.mInputChannel, mTaskPositioner.mClientChannel,
+                false /* isDragDrop */)) {
             Slog.e(TAG_WM, "startPositioningLocked: Unable to transfer touch focus");
             cleanUpTaskPositioner();
             return false;
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index b810de9..8915eba 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -37,6 +37,7 @@
 import android.util.ArraySet;
 import android.util.Pair;
 import android.util.Slog;
+import android.view.Display;
 import android.view.InsetsState;
 import android.view.SurfaceControl;
 import android.view.ThreadedRenderer;
@@ -624,7 +625,7 @@
     /**
      * Called when screen is being turned off.
      */
-    void screenTurningOff(ScreenOffListener listener) {
+    void screenTurningOff(int displayId, ScreenOffListener listener) {
         if (shouldDisableSnapshots()) {
             listener.onScreenOff();
             return;
@@ -635,7 +636,7 @@
             try {
                 synchronized (mService.mGlobalLock) {
                     mTmpTasks.clear();
-                    mService.mRoot.forAllTasks(task -> {
+                    mService.mRoot.getDisplayContent(displayId).forAllTasks(task -> {
                         // Since RecentsAnimation will handle task snapshot while switching apps
                         // with the best capture timing (e.g. IME window capture), No need
                         // additional task capture while task is controlled by RecentsAnimation.
@@ -645,7 +646,7 @@
                     });
                     // Allow taking snapshot of home when turning screen off to reduce the delay of
                     // waking from secure lock to home.
-                    final boolean allowSnapshotHome =
+                    final boolean allowSnapshotHome = displayId == Display.DEFAULT_DISPLAY &&
                             mService.mPolicy.isKeyguardSecure(mService.mCurrentUserId);
                     snapshotTasks(mTmpTasks, allowSnapshotHome);
                 }
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
index 07610ab..79a6bd7 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
@@ -281,13 +281,14 @@
     }
 
     @Override
-    public void remove() {
+    public void remove(boolean animate) {
         synchronized (mService.mGlobalLock) {
             final long now = SystemClock.uptimeMillis();
             if (mSizeMismatch && now - mShownTime < SIZE_MISMATCH_MINIMUM_TIME_MS
                     // Show the latest content as soon as possible for unlocking to home.
                     && mActivityType != ACTIVITY_TYPE_HOME) {
-                mHandler.postAtTime(this::remove, mShownTime + SIZE_MISMATCH_MINIMUM_TIME_MS);
+                mHandler.postAtTime(() -> remove(false /* prepareAnimation */),
+                        mShownTime + SIZE_MISMATCH_MINIMUM_TIME_MS);
                 ProtoLog.v(WM_DEBUG_STARTING_WINDOW,
                         "Defer removing snapshot surface in %dms", (now - mShownTime));
 
@@ -517,7 +518,7 @@
                 // The orientation of the screen is changing. We better remove the snapshot ASAP as
                 // we are going to wait on the new window in any case to unfreeze the screen, and
                 // the starting window is not needed anymore.
-                sHandler.post(mOuter::remove);
+                sHandler.post(() -> mOuter.remove(false /* prepareAnimation */));
             }
             if (reportDraw) {
                 sHandler.obtainMessage(MSG_REPORT_DRAW, mOuter).sendToTarget();
diff --git a/services/core/java/com/android/server/wm/WindowFrames.java b/services/core/java/com/android/server/wm/WindowFrames.java
index 9245f8c..ffd6d21 100644
--- a/services/core/java/com/android/server/wm/WindowFrames.java
+++ b/services/core/java/com/android/server/wm/WindowFrames.java
@@ -113,7 +113,7 @@
     }
 
     /**
-     * @return true if the width or height has changed since last reported to the client.
+     * @return true if the width or height has changed since last updating resizing window.
      */
     boolean didFrameSizeChange() {
         return (mLastFrame.width() != mFrame.width()) || (mLastFrame.height() != mFrame.height());
@@ -135,6 +135,13 @@
     }
 
     /**
+     * @return true if the width or height has changed since last reported to the client.
+     */
+    boolean isFrameSizeChangeReported() {
+        return mFrameSizeChanged || didFrameSizeChange();
+    }
+
+    /**
      * Resets the size changed flags so they're all set to false again. This should be called
      * after the frames are reported to client.
      */
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index 7450782..53ebfb2 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -221,7 +221,8 @@
                 DragState state, Display display, InputManagerService service,
                 InputChannel source) {
             state.register(display);
-            return service.transferTouchFocus(source, state.getInputChannel());
+            return service.transferTouchFocus(source, state.getInputChannel(),
+                    true /* isDragDrop */);
         }
 
         /**
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 0a75924..b95674e 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2234,11 +2234,6 @@
 
             final DisplayContent dc = win.getDisplayContent();
 
-            if (win.mPendingPositionChanged != null) {
-                win.mPendingPositionChanged.updateLeashPosition(frameNumber);
-                win.mPendingPositionChanged = null;
-            }
-
             if (mUseBLASTSync && win.useBLASTSync() && viewVisibility != View.GONE) {
                 win.prepareDrawHandlers();
                 result |= RELAYOUT_RES_BLAST_SYNC;
@@ -2985,8 +2980,8 @@
     }
 
     @Override
-    public void screenTurningOff(ScreenOffListener listener) {
-        mTaskSnapshotController.screenTurningOff(listener);
+    public void screenTurningOff(int displayId, ScreenOffListener listener) {
+        mTaskSnapshotController.screenTurningOff(displayId, listener);
     }
 
     @Override
@@ -5680,6 +5675,11 @@
         mBlurController.unregisterCrossWindowBlurEnabledListener(listener);
     }
 
+    @Override
+    public void setForceCrossWindowBlurDisabled(boolean disable) {
+        mBlurController.setForceCrossWindowBlurDisabled(disable);
+    }
+
     // -------------------------------------------------------------
     // Internals
     // -------------------------------------------------------------
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index eaa3b23..7ebc1cc 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -168,8 +168,8 @@
 import static com.android.server.wm.WindowStateProto.FORCE_SEAMLESS_ROTATION;
 import static com.android.server.wm.WindowStateProto.GIVEN_CONTENT_INSETS;
 import static com.android.server.wm.WindowStateProto.GLOBAL_SCALE;
+import static com.android.server.wm.WindowStateProto.HAS_COMPAT_SCALE;
 import static com.android.server.wm.WindowStateProto.HAS_SURFACE;
-import static com.android.server.wm.WindowStateProto.IN_SIZE_COMPAT_MODE;
 import static com.android.server.wm.WindowStateProto.IS_ON_SCREEN;
 import static com.android.server.wm.WindowStateProto.IS_READY_FOR_DISPLAY;
 import static com.android.server.wm.WindowStateProto.IS_VISIBLE;
@@ -726,8 +726,6 @@
      */
     private InsetsState mFrozenInsetsState;
 
-    @Nullable InsetsSourceProvider mPendingPositionChanged;
-
     private static final float DEFAULT_DIM_AMOUNT_DEAD_WINDOW = 0.5f;
     private KeyInterceptionInfo mKeyInterceptionInfo;
 
@@ -774,6 +772,17 @@
         updateSurfacePosition(t);
     };
 
+    private final Consumer<SurfaceControl.Transaction> mSetSurfacePositionConsumer = t -> {
+        if (mSurfaceControl != null && mSurfaceControl.isValid()) {
+            t.setPosition(mSurfaceControl, mSurfacePosition.x, mSurfacePosition.y);
+        }
+    };
+
+    /**
+     * @see #setSurfaceTranslationY(int)
+     */
+    private int mSurfaceTranslationY;
+
     /**
      * Returns the visibility of the given {@link InternalInsetsType type} requested by the client.
      *
@@ -1084,18 +1093,18 @@
      * scaling override set.
      * @see CompatModePackages#getCompatScale
      * @see android.content.res.CompatibilityInfo#supportsScreen
-     * @see ActivityRecord#inSizeCompatMode()
+     * @see ActivityRecord#hasSizeCompatBounds()
      */
-    boolean inSizeCompatMode() {
-        return mOverrideScale != 1f || inSizeCompatMode(mAttrs, mActivityRecord);
+    boolean hasCompatScale() {
+        return mOverrideScale != 1f || hasCompatScale(mAttrs, mActivityRecord);
     }
 
     /**
      * @return {@code true} if the application runs in size compatibility mode.
      * @see android.content.res.CompatibilityInfo#supportsScreen
-     * @see ActivityRecord#inSizeCompatMode()
+     * @see ActivityRecord#hasSizeCompatBounds()
      */
-    static boolean inSizeCompatMode(WindowManager.LayoutParams attrs, WindowToken windowToken) {
+    static boolean hasCompatScale(WindowManager.LayoutParams attrs, WindowToken windowToken) {
         return (attrs.privateFlags & PRIVATE_FLAG_COMPATIBLE_WINDOW) != 0
                 || (windowToken != null && windowToken.hasSizeCompatBounds()
                 // Exclude starting window because it is not displayed by the application.
@@ -1300,7 +1309,7 @@
         windowFrames.offsetFrames(-layoutXDiff, -layoutYDiff);
 
         windowFrames.mCompatFrame.set(windowFrames.mFrame);
-        if (inSizeCompatMode()) {
+        if (hasCompatScale()) {
             // Also the scaled frame that we report to the app needs to be
             // adjusted to be in its coordinate space.
             windowFrames.mCompatFrame.scale(mInvGlobalScale);
@@ -1572,7 +1581,7 @@
      */
     InsetsState getCompatInsetsState() {
         InsetsState state = getInsetsState();
-        if (inSizeCompatMode()) {
+        if (hasCompatScale()) {
             state = new InsetsState(state, true);
             state.scale(mInvGlobalScale);
         }
@@ -1710,7 +1719,7 @@
     }
 
     void prelayout() {
-        if (inSizeCompatMode()) {
+        if (hasCompatScale()) {
             if (mOverrideScale != 1f) {
                 mGlobalScale = mToken.hasSizeCompatBounds()
                         ? mToken.getSizeCompatScale() * mOverrideScale
@@ -2124,6 +2133,8 @@
                 : getTask().getWindowConfiguration().hasMovementAnimations();
         if (mToken.okToAnimate()
                 && (mAttrs.privateFlags & PRIVATE_FLAG_NO_MOVE_ANIMATION) == 0
+                && !mWindowFrames.didFrameSizeChange()
+                && !surfaceInsetsChanging()
                 && !isDragResizing()
                 && hasMovementAnimation
                 && !mWinAnimator.mLastHidden
@@ -3624,7 +3635,7 @@
     void fillClientWindowFrames(ClientWindowFrames outFrames) {
         outFrames.frame.set(mWindowFrames.mCompatFrame);
         outFrames.displayFrame.set(mWindowFrames.mDisplayFrame);
-        if (mInvGlobalScale != 1.0f && inSizeCompatMode()) {
+        if (mInvGlobalScale != 1.0f && hasCompatScale()) {
             outFrames.displayFrame.scale(mInvGlobalScale);
         }
 
@@ -4024,7 +4035,7 @@
         proto.write(PENDING_SEAMLESS_ROTATION, mPendingSeamlessRotate != null);
         proto.write(FINISHED_SEAMLESS_ROTATION_FRAME, mFinishSeamlessRotateFrameNumber);
         proto.write(FORCE_SEAMLESS_ROTATION, mForceSeamlesslyRotate);
-        proto.write(IN_SIZE_COMPAT_MODE, inSizeCompatMode());
+        proto.write(HAS_COMPAT_SCALE, hasCompatScale());
         proto.write(GLOBAL_SCALE, mGlobalScale);
         proto.end(token);
     }
@@ -4126,7 +4137,7 @@
         pw.println(prefix + "mHasSurface=" + mHasSurface
                 + " isReadyForDisplay()=" + isReadyForDisplay()
                 + " mWindowRemovalAllowed=" + mWindowRemovalAllowed);
-        if (inSizeCompatMode()) {
+        if (hasCompatScale()) {
             pw.println(prefix + "mCompatFrame=" + mWindowFrames.mCompatFrame.toShortString(sTmpSB));
         }
         if (dumpAll) {
@@ -4249,18 +4260,18 @@
         float x, y;
         int w,h;
 
-        final boolean inSizeCompatMode = inSizeCompatMode();
+        final boolean hasCompatScale = hasCompatScale();
         if ((mAttrs.flags & FLAG_SCALED) != 0) {
             if (mAttrs.width < 0) {
                 w = pw;
-            } else if (inSizeCompatMode) {
+            } else if (hasCompatScale) {
                 w = (int)(mAttrs.width * mGlobalScale + .5f);
             } else {
                 w = mAttrs.width;
             }
             if (mAttrs.height < 0) {
                 h = ph;
-            } else if (inSizeCompatMode) {
+            } else if (hasCompatScale) {
                 h = (int)(mAttrs.height * mGlobalScale + .5f);
             } else {
                 h = mAttrs.height;
@@ -4268,21 +4279,21 @@
         } else {
             if (mAttrs.width == MATCH_PARENT) {
                 w = pw;
-            } else if (inSizeCompatMode) {
+            } else if (hasCompatScale) {
                 w = (int)(mRequestedWidth * mGlobalScale + .5f);
             } else {
                 w = mRequestedWidth;
             }
             if (mAttrs.height == MATCH_PARENT) {
                 h = ph;
-            } else if (inSizeCompatMode) {
+            } else if (hasCompatScale) {
                 h = (int)(mRequestedHeight * mGlobalScale + .5f);
             } else {
                 h = mRequestedHeight;
             }
         }
 
-        if (inSizeCompatMode) {
+        if (hasCompatScale) {
             x = mAttrs.x * mGlobalScale;
             y = mAttrs.y * mGlobalScale;
         } else {
@@ -4310,7 +4321,7 @@
         // We need to make sure we update the CompatFrame as it is used for
         // cropping decisions, etc, on systems where we lack a decor layer.
         windowFrames.mCompatFrame.set(windowFrames.mFrame);
-        if (inSizeCompatMode) {
+        if (hasCompatScale) {
             // See comparable block in computeFrameLw.
             windowFrames.mCompatFrame.scale(mInvGlobalScale);
         }
@@ -4428,7 +4439,7 @@
 
     float translateToWindowX(float x) {
         float winX = x - mWindowFrames.mFrame.left;
-        if (inSizeCompatMode()) {
+        if (hasCompatScale()) {
             winX *= mGlobalScale;
         }
         return winX;
@@ -4436,7 +4447,7 @@
 
     float translateToWindowY(float y) {
         float winY = y - mWindowFrames.mFrame.top;
-        if (inSizeCompatMode()) {
+        if (hasCompatScale()) {
             winY *= mGlobalScale;
         }
         return winY;
@@ -5313,13 +5324,17 @@
         // prior to the rotation.
         if (!mSurfaceAnimator.hasLeash() && mPendingSeamlessRotate == null
                 && !mLastSurfacePosition.equals(mSurfacePosition)) {
-            t.setPosition(mSurfaceControl, mSurfacePosition.x, mSurfacePosition.y);
+            final boolean frameSizeChanged = mWindowFrames.isFrameSizeChangeReported();
+            final boolean surfaceInsetsChanged = surfaceInsetsChanging();
+            final boolean surfaceSizeChanged = frameSizeChanged || surfaceInsetsChanged;
             mLastSurfacePosition.set(mSurfacePosition.x, mSurfacePosition.y);
-            if (surfaceInsetsChanging() && mWinAnimator.hasSurface()) {
+            if (surfaceInsetsChanged) {
                 mLastSurfaceInsets.set(mAttrs.surfaceInsets);
-                t.deferTransactionUntil(mSurfaceControl,
-                        mWinAnimator.mSurfaceController.mSurfaceControl,
-                        getFrameNumber());
+            }
+            if (surfaceSizeChanged) {
+                applyWithNextDraw(mSetSurfacePositionConsumer);
+            } else {
+                mSetSurfacePositionConsumer.accept(t);
             }
         }
     }
@@ -5358,6 +5373,8 @@
         // Expand for surface insets. See WindowState.expandForSurfaceInsets.
         transformSurfaceInsetsPosition(mTmpPoint, mAttrs.surfaceInsets);
         outPoint.offset(-mTmpPoint.x, -mTmpPoint.y);
+
+        outPoint.y += mSurfaceTranslationY;
     }
 
     /**
@@ -5365,7 +5382,7 @@
      * scaled, the insets also need to be scaled for surface position in global coordinate.
      */
     private void transformSurfaceInsetsPosition(Point outPos, Rect surfaceInsets) {
-        if (!inSizeCompatMode()) {
+        if (!hasCompatScale()) {
             outPos.x = surfaceInsets.left;
             outPos.y = surfaceInsets.top;
             return;
@@ -5876,4 +5893,13 @@
 
         return hadHandlers;
     }
+
+    /**
+     * Adds an additional translation offset to be applied when positioning the surface. Used to
+     * correct offsets in specific reparenting situations, e.g. the navigation bar window attached
+     * on the lower split-screen app.
+     */
+    void setSurfaceTranslationY(int translationY) {
+        mSurfaceTranslationY = translationY;
+    }
 }
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 10705af..be06d03 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -1783,8 +1783,9 @@
     im->setSystemUiLightsOut(lightsOut);
 }
 
-static jboolean nativeTransferTouchFocus(JNIEnv* env,
-        jclass /* clazz */, jlong ptr, jobject fromChannelTokenObj, jobject toChannelTokenObj) {
+static jboolean nativeTransferTouchFocus(JNIEnv* env, jclass /* clazz */, jlong ptr,
+                                         jobject fromChannelTokenObj, jobject toChannelTokenObj,
+                                         jboolean isDragDrop) {
     if (fromChannelTokenObj == nullptr || toChannelTokenObj == nullptr) {
         return JNI_FALSE;
     }
@@ -1793,8 +1794,8 @@
     sp<IBinder> toChannelToken = ibinderForJavaObject(env, toChannelTokenObj);
 
     NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
-    if (im->getInputManager()->getDispatcher()->transferTouchFocus(
-            fromChannelToken, toChannelToken)) {
+    if (im->getInputManager()->getDispatcher()->transferTouchFocus(fromChannelToken, toChannelToken,
+                                                                   isDragDrop)) {
         return JNI_TRUE;
     } else {
         return JNI_FALSE;
@@ -2267,7 +2268,7 @@
          (void*)nativeRequestPointerCapture},
         {"nativeSetInputDispatchMode", "(JZZ)V", (void*)nativeSetInputDispatchMode},
         {"nativeSetSystemUiLightsOut", "(JZ)V", (void*)nativeSetSystemUiLightsOut},
-        {"nativeTransferTouchFocus", "(JLandroid/os/IBinder;Landroid/os/IBinder;)Z",
+        {"nativeTransferTouchFocus", "(JLandroid/os/IBinder;Landroid/os/IBinder;Z)Z",
          (void*)nativeTransferTouchFocus},
         {"nativeSetPointerSpeed", "(JI)V", (void*)nativeSetPointerSpeed},
         {"nativeSetShowTouches", "(JZ)V", (void*)nativeSetShowTouches},
diff --git a/services/core/jni/com_android_server_vibrator_VibratorController.cpp b/services/core/jni/com_android_server_vibrator_VibratorController.cpp
index ef2d0ba..f60b354 100644
--- a/services/core/jni/com_android_server_vibrator_VibratorController.cpp
+++ b/services/core/jni/com_android_server_vibrator_VibratorController.cpp
@@ -32,8 +32,6 @@
 #include "com_android_server_vibrator_VibratorManagerService.h"
 
 namespace V1_0 = android::hardware::vibrator::V1_0;
-namespace V1_1 = android::hardware::vibrator::V1_1;
-namespace V1_2 = android::hardware::vibrator::V1_2;
 namespace V1_3 = android::hardware::vibrator::V1_3;
 namespace aidl = android::hardware::vibrator;
 
@@ -85,10 +83,11 @@
 class VibratorControllerWrapper {
 public:
     VibratorControllerWrapper(JNIEnv* env, int32_t vibratorId, jobject callbackListener)
-          : mHal(std::move(findVibrator(vibratorId))),
+          : mHal(findVibrator(vibratorId)),
             mVibratorId(vibratorId),
             mCallbackListener(env->NewGlobalRef(callbackListener)) {
-        LOG_ALWAYS_FATAL_IF(mHal == nullptr, "Unable to find reference to vibrator hal");
+        LOG_ALWAYS_FATAL_IF(mHal == nullptr,
+                            "Failed to connect to vibrator HAL, or vibratorId is invalid");
         LOG_ALWAYS_FATAL_IF(mCallbackListener == nullptr,
                             "Unable to create global reference to vibration callback handler");
     }
@@ -130,15 +129,15 @@
     }
 }
 
-static jlong vibratorInit(JNIEnv* env, jclass /* clazz */, jint vibratorId,
-                          jobject callbackListener) {
+static jlong vibratorNativeInit(JNIEnv* env, jclass /* clazz */, jint vibratorId,
+                                jobject callbackListener) {
     std::unique_ptr<VibratorControllerWrapper> wrapper =
             std::make_unique<VibratorControllerWrapper>(env, vibratorId, callbackListener);
     wrapper->hal()->init();
     return reinterpret_cast<jlong>(wrapper.release());
 }
 
-static jlong vibratorGetFinalizer(JNIEnv* /* env */, jclass /* clazz */) {
+static jlong vibratorGetNativeFinalizer(JNIEnv* /* env */, jclass /* clazz */) {
     return static_cast<jlong>(reinterpret_cast<uintptr_t>(&destroyNativeWrapper));
 }
 
@@ -286,25 +285,46 @@
     wrapper->hal()->alwaysOnDisable(static_cast<int32_t>(id));
 }
 
+static float vibratorGetResonantFrequency(JNIEnv* env, jclass /* clazz */, jlong ptr) {
+    VibratorControllerWrapper* wrapper = reinterpret_cast<VibratorControllerWrapper*>(ptr);
+    if (wrapper == nullptr) {
+        ALOGE("vibratorGetResonantFrequency failed because native wrapper was not initialized");
+        return NAN;
+    }
+    auto result = wrapper->hal()->getResonantFrequency();
+    return result.isOk() ? static_cast<jfloat>(result.value()) : NAN;
+}
+
+static float vibratorGetQFactor(JNIEnv* env, jclass /* clazz */, jlong ptr) {
+    VibratorControllerWrapper* wrapper = reinterpret_cast<VibratorControllerWrapper*>(ptr);
+    if (wrapper == nullptr) {
+        ALOGE("vibratorGetQFactor failed because native wrapper was not initialized");
+        return NAN;
+    }
+    auto result = wrapper->hal()->getQFactor();
+    return result.isOk() ? static_cast<jfloat>(result.value()) : NAN;
+}
+
 static const JNINativeMethod method_table[] = {
-        {"vibratorInit",
+        {"nativeInit",
          "(ILcom/android/server/vibrator/VibratorController$OnVibrationCompleteListener;)J",
-         (void*)vibratorInit},
-        {"vibratorGetFinalizer", "()J", (void*)vibratorGetFinalizer},
-        {"vibratorIsAvailable", "(J)Z", (void*)vibratorIsAvailable},
-        {"vibratorOn", "(JJJ)V", (void*)vibratorOn},
-        {"vibratorOff", "(J)V", (void*)vibratorOff},
-        {"vibratorSetAmplitude", "(JI)V", (void*)vibratorSetAmplitude},
-        {"vibratorPerformEffect", "(JJJJ)J", (void*)vibratorPerformEffect},
-        {"vibratorPerformComposedEffect",
-         "(J[Landroid/os/VibrationEffect$Composition$PrimitiveEffect;J)J",
+         (void*)vibratorNativeInit},
+        {"getNativeFinalizer", "()J", (void*)vibratorGetNativeFinalizer},
+        {"isAvailable", "(J)Z", (void*)vibratorIsAvailable},
+        {"on", "(JJJ)V", (void*)vibratorOn},
+        {"off", "(J)V", (void*)vibratorOff},
+        {"setAmplitude", "(JI)V", (void*)vibratorSetAmplitude},
+        {"performEffect", "(JJJJ)J", (void*)vibratorPerformEffect},
+        {"performComposedEffect", "(J[Landroid/os/VibrationEffect$Composition$PrimitiveEffect;J)J",
          (void*)vibratorPerformComposedEffect},
-        {"vibratorGetSupportedEffects", "(J)[I", (void*)vibratorGetSupportedEffects},
-        {"vibratorGetSupportedPrimitives", "(J)[I", (void*)vibratorGetSupportedPrimitives},
-        {"vibratorSetExternalControl", "(JZ)V", (void*)vibratorSetExternalControl},
-        {"vibratorGetCapabilities", "(J)J", (void*)vibratorGetCapabilities},
-        {"vibratorAlwaysOnEnable", "(JJJJ)V", (void*)vibratorAlwaysOnEnable},
-        {"vibratorAlwaysOnDisable", "(JJ)V", (void*)vibratorAlwaysOnDisable},
+        {"getSupportedEffects", "(J)[I", (void*)vibratorGetSupportedEffects},
+        {"getSupportedPrimitives", "(J)[I", (void*)vibratorGetSupportedPrimitives},
+        {"setExternalControl", "(JZ)V", (void*)vibratorSetExternalControl},
+        {"getCapabilities", "(J)J", (void*)vibratorGetCapabilities},
+        {"alwaysOnEnable", "(JJJJ)V", (void*)vibratorAlwaysOnEnable},
+        {"alwaysOnDisable", "(JJ)V", (void*)vibratorAlwaysOnDisable},
+        {"getResonantFrequency", "(J)F", (void*)vibratorGetResonantFrequency},
+        {"getQFactor", "(J)F", (void*)vibratorGetQFactor},
 };
 
 int register_android_server_vibrator_VibratorController(JavaVM* jvm, JNIEnv* env) {
@@ -320,7 +340,8 @@
     sPrimitiveClassInfo.scale = GetFieldIDOrDie(env, primitiveClass, "scale", "F");
     sPrimitiveClassInfo.delay = GetFieldIDOrDie(env, primitiveClass, "delay", "I");
 
-    return jniRegisterNativeMethods(env, "com/android/server/vibrator/VibratorController",
+    return jniRegisterNativeMethods(env,
+                                    "com/android/server/vibrator/VibratorController$NativeWrapper",
                                     method_table, NELEM(method_table));
 }
 
diff --git a/services/core/xsd/Android.bp b/services/core/xsd/Android.bp
index 6a8f6d4..d43cf3f 100644
--- a/services/core/xsd/Android.bp
+++ b/services/core/xsd/Android.bp
@@ -45,13 +45,6 @@
 }
 
 xsd_config {
-    name: "cec-config",
-    srcs: ["cec-config/cec-config.xsd"],
-    api_dir: "cec-config/schema",
-    package_name: "com.android.server.hdmi.cec.config",
-}
-
-xsd_config {
     name: "device-state-config",
     srcs: ["device-state-config/device-state-config.xsd"],
     api_dir: "device-state-config/schema",
diff --git a/services/core/xsd/cec-config/cec-config.xsd b/services/core/xsd/cec-config/cec-config.xsd
deleted file mode 100644
index b59c93c..0000000
--- a/services/core/xsd/cec-config/cec-config.xsd
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<xs:schema version="2.0"
-           elementFormDefault="qualified"
-           attributeFormDefault="unqualified"
-  xmlns:xs="http://www.w3.org/2001/XMLSchema">
-  <xs:element name="cec-settings">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:element name="setting" type="setting" minOccurs="0" maxOccurs="unbounded"/>
-      </xs:sequence>
-    </xs:complexType>
-  </xs:element>
-  <xs:complexType name="setting">
-    <xs:attribute name="name" type="xs:string"/>
-    <xs:attribute name="value-type" type="xs:string"/>
-    <xs:attribute name="user-configurable" type="xs:boolean"/>
-    <xs:element name="allowed-values" type="value-list" minOccurs="1" maxOccurs="1"/>
-    <xs:element name="default-value" type="value" minOccurs="1" maxOccurs="1"/>
-  </xs:complexType>
-  <xs:complexType name="value-list">
-      <xs:sequence>
-        <xs:element name="value" type="value" minOccurs="1" maxOccurs="unbounded"/>
-      </xs:sequence>
-  </xs:complexType>
-  <xs:complexType name="value">
-    <xs:attribute name="string-value" type="xs:string"/>
-    <xs:attribute name="int-value" type="xs:string"/>
-  </xs:complexType>
-</xs:schema>
diff --git a/services/core/xsd/cec-config/schema/current.txt b/services/core/xsd/cec-config/schema/current.txt
deleted file mode 100644
index 75872d4..0000000
--- a/services/core/xsd/cec-config/schema/current.txt
+++ /dev/null
@@ -1,44 +0,0 @@
-// Signature format: 2.0
-package com.android.server.hdmi.cec.config {
-
-  public class CecSettings {
-    ctor public CecSettings();
-    method public java.util.List<com.android.server.hdmi.cec.config.Setting> getSetting();
-  }
-
-  public class Setting {
-    ctor public Setting();
-    method public com.android.server.hdmi.cec.config.ValueList getAllowedValues();
-    method public com.android.server.hdmi.cec.config.Value getDefaultValue();
-    method public String getName();
-    method public boolean getUserConfigurable();
-    method public String getValueType();
-    method public void setAllowedValues(com.android.server.hdmi.cec.config.ValueList);
-    method public void setDefaultValue(com.android.server.hdmi.cec.config.Value);
-    method public void setName(String);
-    method public void setUserConfigurable(boolean);
-    method public void setValueType(String);
-  }
-
-  public class Value {
-    ctor public Value();
-    method public String getIntValue();
-    method public String getStringValue();
-    method public void setIntValue(String);
-    method public void setStringValue(String);
-  }
-
-  public class ValueList {
-    ctor public ValueList();
-    method public java.util.List<com.android.server.hdmi.cec.config.Value> getValue();
-  }
-
-  public class XmlParser {
-    ctor public XmlParser();
-    method public static com.android.server.hdmi.cec.config.CecSettings read(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
-    method public static String readText(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
-    method public static void skip(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
-  }
-
-}
-
diff --git a/services/core/xsd/cec-config/schema/last_current.txt b/services/core/xsd/cec-config/schema/last_current.txt
deleted file mode 100644
index e69de29..0000000
--- a/services/core/xsd/cec-config/schema/last_current.txt
+++ /dev/null
diff --git a/services/core/xsd/cec-config/schema/last_removed.txt b/services/core/xsd/cec-config/schema/last_removed.txt
deleted file mode 100644
index e69de29..0000000
--- a/services/core/xsd/cec-config/schema/last_removed.txt
+++ /dev/null
diff --git a/services/core/xsd/cec-config/schema/removed.txt b/services/core/xsd/cec-config/schema/removed.txt
deleted file mode 100644
index d802177..0000000
--- a/services/core/xsd/cec-config/schema/removed.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
index 48ae8d6..aed13b2 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
@@ -19,6 +19,8 @@
 import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_NONE;
 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
 
+import static com.android.server.devicepolicy.DevicePolicyManagerService.LOG_TAG;
+
 import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
 import static org.xmlpull.v1.XmlPullParser.END_TAG;
 import static org.xmlpull.v1.XmlPullParser.TEXT;
@@ -38,7 +40,6 @@
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.IndentingPrintWriter;
-import android.util.Log;
 import android.util.Slog;
 import android.util.TypedXmlPullParser;
 import android.util.TypedXmlSerializer;
@@ -455,8 +456,7 @@
                     try {
                         trustAgentInfo.options.saveToXml(out);
                     } catch (XmlPullParserException e) {
-                        Log.e(DevicePolicyManagerService.LOG_TAG,
-                                "Failed to save TrustAgent options", e);
+                        Slog.e(LOG_TAG, e, "Failed to save TrustAgent options");
                     }
                     out.endTag(null, TAG_TRUST_AGENT_COMPONENT_OPTIONS);
                 }
@@ -629,8 +629,7 @@
             String tag = parser.getName();
             if (TAG_POLICIES.equals(tag)) {
                 if (shouldOverridePolicies) {
-                    Log.d(DevicePolicyManagerService.LOG_TAG,
-                            "Overriding device admin policies from XML.");
+                    Slog.d(LOG_TAG, "Overriding device admin policies from XML.");
                     info.readPoliciesFromXml(parser);
                 }
             } else if (TAG_PASSWORD_QUALITY.equals(tag)) {
@@ -726,16 +725,14 @@
                 if (type == TypedXmlPullParser.TEXT) {
                     shortSupportMessage = parser.getText();
                 } else {
-                    Log.w(DevicePolicyManagerService.LOG_TAG,
-                            "Missing text when loading short support message");
+                    Slog.w(LOG_TAG, "Missing text when loading short support message");
                 }
             } else if (TAG_LONG_SUPPORT_MESSAGE.equals(tag)) {
                 type = parser.next();
                 if (type == TypedXmlPullParser.TEXT) {
                     longSupportMessage = parser.getText();
                 } else {
-                    Log.w(DevicePolicyManagerService.LOG_TAG,
-                            "Missing text when loading long support message");
+                    Slog.w(LOG_TAG, "Missing text when loading long support message");
                 }
             } else if (TAG_PARENT_ADMIN.equals(tag)) {
                 Preconditions.checkState(!isParent);
@@ -748,8 +745,7 @@
                 if (type == TypedXmlPullParser.TEXT) {
                     organizationName = parser.getText();
                 } else {
-                    Log.w(DevicePolicyManagerService.LOG_TAG,
-                            "Missing text when loading organization name");
+                    Slog.w(LOG_TAG, "Missing text when loading organization name");
                 }
             } else if (TAG_IS_LOGOUT_ENABLED.equals(tag)) {
                 isLogoutEnabled = parser.getAttributeBoolean(null, ATTR_VALUE, false);
@@ -758,16 +754,14 @@
                 if (type == TypedXmlPullParser.TEXT) {
                     startUserSessionMessage = parser.getText();
                 } else {
-                    Log.w(DevicePolicyManagerService.LOG_TAG,
-                            "Missing text when loading start session message");
+                    Slog.w(LOG_TAG, "Missing text when loading start session message");
                 }
             } else if (TAG_END_USER_SESSION_MESSAGE.equals(tag)) {
                 type = parser.next();
                 if (type == TypedXmlPullParser.TEXT) {
                     endUserSessionMessage = parser.getText();
                 } else {
-                    Log.w(DevicePolicyManagerService.LOG_TAG,
-                            "Missing text when loading end session message");
+                    Slog.w(LOG_TAG, "Missing text when loading end session message");
                 }
             } else if (TAG_CROSS_PROFILE_CALENDAR_PACKAGES.equals(tag)) {
                 mCrossProfileCalendarPackages = readPackageList(parser, tag);
@@ -802,16 +796,14 @@
                 if (type == TypedXmlPullParser.TEXT) {
                     mOrganizationId = parser.getText();
                 } else {
-                    Log.w(DevicePolicyManagerService.LOG_TAG,
-                            "Missing Organization ID.");
+                    Slog.w(LOG_TAG, "Missing Organization ID.");
                 }
             } else if (TAG_ENROLLMENT_SPECIFIC_ID.equals(tag)) {
                 type = parser.next();
                 if (type == TypedXmlPullParser.TEXT) {
                     mEnrollmentSpecificId = parser.getText();
                 } else {
-                    Log.w(DevicePolicyManagerService.LOG_TAG,
-                            "Missing Enrollment-specific ID.");
+                    Slog.w(LOG_TAG, "Missing Enrollment-specific ID.");
                 }
             } else if (TAG_ADMIN_CAN_GRANT_SENSORS_PERMISSIONS.equals(tag)) {
                 mAdminCanGrantSensorsPermissions = parser.getAttributeBoolean(null, ATTR_VALUE,
@@ -820,7 +812,7 @@
                 mUsbDataSignalingEnabled = parser.getAttributeBoolean(null, ATTR_VALUE,
                         USB_DATA_SIGNALING_ENABLED_DEFAULT);
             } else {
-                Slog.w(DevicePolicyManagerService.LOG_TAG, "Unknown admin tag: " + tag);
+                Slog.w(LOG_TAG, "Unknown admin tag: %s", tag);
                 XmlUtils.skipCurrentTag(parser);
             }
         }
@@ -842,12 +834,10 @@
                 if (packageName != null) {
                     result.add(packageName);
                 } else {
-                    Slog.w(DevicePolicyManagerService.LOG_TAG,
-                            "Package name missing under " + outerTag);
+                    Slog.w(LOG_TAG, "Package name missing under %s", outerTag);
                 }
             } else {
-                Slog.w(DevicePolicyManagerService.LOG_TAG,
-                        "Unknown tag under " + tag +  ": " + outerTag);
+                Slog.w(LOG_TAG, "Unknown tag under %s: ", tag, outerTag);
             }
         }
         return result;
@@ -868,8 +858,7 @@
             if (tag.equals(tagDAM)) {
                 result.add(parser.getAttributeValue(null, ATTR_VALUE));
             } else {
-                Slog.e(DevicePolicyManagerService.LOG_TAG,
-                        "Expected tag " + tag +  " but found " + tagDAM);
+                Slog.e(LOG_TAG, "Expected tag %s but found %s", tag, tagDAM);
             }
         }
     }
@@ -891,8 +880,7 @@
                 final TrustAgentInfo trustAgentInfo = getTrustAgentInfo(parser, tag);
                 result.put(component, trustAgentInfo);
             } else {
-                Slog.w(DevicePolicyManagerService.LOG_TAG,
-                        "Unknown tag under " + tag +  ": " + tagDAM);
+                Slog.w(LOG_TAG, "Unknown tag under %s: %s", tag, tagDAM);
             }
         }
         return result;
@@ -912,8 +900,7 @@
             if (TAG_TRUST_AGENT_COMPONENT_OPTIONS.equals(tagDAM)) {
                 result.options = PersistableBundle.restoreFromXml(parser);
             } else {
-                Slog.w(DevicePolicyManagerService.LOG_TAG,
-                        "Unknown tag under " + tag +  ": " + tagDAM);
+                Slog.w(LOG_TAG, "Unknown tag under %s: %s", tag, tagDAM);
             }
         }
         return result;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/CertificateMonitor.java b/services/devicepolicy/java/com/android/server/devicepolicy/CertificateMonitor.java
index d812b8f..e0c5e32 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/CertificateMonitor.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/CertificateMonitor.java
@@ -16,6 +16,8 @@
 
 package com.android.server.devicepolicy;
 
+import static com.android.server.devicepolicy.DevicePolicyManagerService.LOG_TAG;
+
 import android.app.Notification;
 import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
@@ -33,7 +35,7 @@
 import android.security.Credentials;
 import android.security.KeyChain;
 import android.security.KeyChain.KeyChainConnection;
-import android.util.Log;
+import android.util.Slog;
 
 import com.android.internal.R;
 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
@@ -47,7 +49,6 @@
 import java.util.List;
 
 public class CertificateMonitor {
-    protected static final String LOG_TAG = DevicePolicyManagerService.LOG_TAG;
     protected static final int MONITORING_CERT_NOTIFICATION_ID = SystemMessage.NOTE_SSL_CERT_INFO;
 
     private final DevicePolicyManagerService mService;
@@ -78,16 +79,16 @@
             X509Certificate cert = parseCert(certBuffer);
             pemCert = Credentials.convertToPem(cert);
         } catch (CertificateException | IOException ce) {
-            Log.e(LOG_TAG, "Problem converting cert", ce);
+            Slog.e(LOG_TAG, ce, "Problem converting cert");
             return null;
         }
 
         try (KeyChainConnection keyChainConnection = mInjector.keyChainBindAsUser(userHandle)) {
             return keyChainConnection.getService().installCaCertificate(pemCert);
         } catch (RemoteException e) {
-            Log.e(LOG_TAG, "installCaCertsToKeyChain(): ", e);
+            Slog.e(LOG_TAG, e, "installCaCertsToKeyChain(): ");
         } catch (InterruptedException e1) {
-            Log.w(LOG_TAG, "installCaCertsToKeyChain(): ", e1);
+            Slog.w(LOG_TAG, e1, "installCaCertsToKeyChain(): ");
             Thread.currentThread().interrupt();
         }
         return null;
@@ -99,9 +100,9 @@
                 keyChainConnection.getService().deleteCaCertificate(aliases[i]);
             }
         } catch (RemoteException e) {
-            Log.e(LOG_TAG, "from CaCertUninstaller: ", e);
+            Slog.e(LOG_TAG, e, "from CaCertUninstaller: ");
         } catch (InterruptedException ie) {
-            Log.w(LOG_TAG, "CaCertUninstaller: ", ie);
+            Slog.w(LOG_TAG, ie, "CaCertUninstaller: ");
             Thread.currentThread().interrupt();
         }
     }
@@ -137,7 +138,8 @@
     };
 
     private void updateInstalledCertificates(final UserHandle userHandle) {
-        if (!mInjector.getUserManager().isUserUnlocked(userHandle.getIdentifier())) {
+        final int userId = userHandle.getIdentifier();
+        if (!mInjector.getUserManager().isUserUnlocked(userId)) {
             return;
         }
 
@@ -145,7 +147,8 @@
         try {
             installedCerts = getInstalledCaCertificates(userHandle);
         } catch (RemoteException | RuntimeException e) {
-            Log.e(LOG_TAG, "Could not retrieve certificates from KeyChain service", e);
+            Slog.e(LOG_TAG, e, "Could not retrieve certificates from KeyChain service for user %d",
+                    userId);
             return;
         }
         mService.onInstalledCertificatesChanged(userHandle, installedCerts);
@@ -167,7 +170,7 @@
         try {
             userContext = mInjector.createContextAsUser(userHandle);
         } catch (PackageManager.NameNotFoundException e) {
-            Log.e(LOG_TAG, "Create context as " + userHandle + " failed", e);
+            Slog.e(LOG_TAG, e, "Create context as %s failed", userHandle);
             return null;
         }
 
@@ -183,7 +186,6 @@
             smallIconId = R.drawable.stat_sys_certificate_info;
             parentUserId = mService.getProfileParentId(userHandle.getIdentifier());
         } else if (mService.getDeviceOwnerUserId() == userHandle.getIdentifier()) {
-            final String ownerName = mService.getDeviceOwnerName();
             contentText = resources.getString(R.string.ssl_ca_cert_noti_managed,
                     mService.getDeviceOwnerName());
             smallIconId = R.drawable.stat_sys_certificate_info;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceAdminServiceController.java b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceAdminServiceController.java
index 3067d45..00e0292 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceAdminServiceController.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceAdminServiceController.java
@@ -46,19 +46,11 @@
     final Object mLock = new Object();
     final Context mContext;
 
-    private final DevicePolicyManagerService mService;
     private final DevicePolicyManagerService.Injector mInjector;
     private final DevicePolicyConstants mConstants;
 
     private final Handler mHandler; // needed?
 
-    static void debug(String format, Object... args) {
-        if (!DEBUG) {
-            return;
-        }
-        Slog.d(TAG, String.format(format, args));
-    }
-
     private class DevicePolicyServiceConnection
             extends PersistentConnection<IDeviceAdminService> {
         public DevicePolicyServiceConnection(int userId, @NonNull ComponentName componentName) {
@@ -88,7 +80,6 @@
 
     public DeviceAdminServiceController(DevicePolicyManagerService service,
             DevicePolicyConstants constants) {
-        mService = service;
         mInjector = service.mInjector;
         mContext = mInjector.mContext;
         mHandler = new Handler(BackgroundThread.get().getLooper());
@@ -122,8 +113,9 @@
             synchronized (mLock) {
                 final ServiceInfo service = findService(packageName, userId);
                 if (service == null) {
-                    debug("Owner package %s on u%d has no service.",
-                            packageName, userId);
+                    if (DEBUG) {
+                        Slog.d(TAG, "Owner package %s on u%d has no service.", packageName, userId);
+                    }
                     disconnectServiceOnUserLocked(userId, actionForLog);
                     return;
                 }
@@ -134,14 +126,17 @@
                     // Note even when we're already connected to the same service, the binding
                     // would have died at this point due to a package update.  So we disconnect
                     // anyway and re-connect.
-                    debug("Disconnecting from existing service connection.",
-                            packageName, userId);
+                    if (DEBUG) {
+                        Slog.d("Disconnecting from existing service connection.", packageName,
+                                userId);
+                    }
                     disconnectServiceOnUserLocked(userId, actionForLog);
                 }
 
-                debug("Owner package %s on u%d has service %s for %s",
-                        packageName, userId,
+                if (DEBUG) {
+                    Slog.d("Owner package %s on u%d has service %s for %s", packageName, userId,
                         service.getComponentName().flattenToShortString(), actionForLog);
+                }
 
                 final DevicePolicyServiceConnection conn =
                         new DevicePolicyServiceConnection(
@@ -172,8 +167,10 @@
     private void disconnectServiceOnUserLocked(int userId, @NonNull String actionForLog) {
         final DevicePolicyServiceConnection conn = mConnections.get(userId);
         if (conn != null) {
-            debug("Stopping service for u%d if already running for %s.",
-                    userId, actionForLog);
+            if (DEBUG) {
+                Slog.d(TAG, "Stopping service for u%d if already running for %s.", userId,
+                        actionForLog);
+            }
             conn.unbind();
             mConnections.remove(userId);
         }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyConstants.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyConstants.java
index 464d6f5..84e6da0 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyConstants.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyConstants.java
@@ -88,7 +88,7 @@
         } catch (IllegalArgumentException e) {
             // Failed to parse the settings string, log this and move on
             // with defaults.
-            Slog.e(TAG, "Bad device policy settings: " + settings);
+            Slog.e(TAG, "Bad device policy settings: %s", settings);
         }
 
         long dasDiedServiceReconnectBackoffSec = parser.getLong(
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java
index c0b2ed4..52cdce6 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java
@@ -179,11 +179,11 @@
      */
     static boolean store(DevicePolicyData policyData, JournaledFile file, boolean isFdeDevice) {
         FileOutputStream stream = null;
+        File chooseForWrite = null;
         try {
-            File chooseForWrite = file.chooseForWrite();
+            chooseForWrite = file.chooseForWrite();
             if (VERBOSE_LOG) {
-                Slog.v(TAG, "Storing data for user " + policyData.mUserId + " on "
-                        + chooseForWrite);
+                Slog.v(TAG, "Storing data for user %d on %s ", policyData.mUserId, chooseForWrite);
             }
             stream = new FileOutputStream(chooseForWrite, false);
             TypedXmlSerializer out = Xml.resolveSerializer(stream);
@@ -195,7 +195,7 @@
                         policyData.mRestrictionsProvider.flattenToString());
             }
             if (policyData.mUserSetupComplete) {
-                if (VERBOSE_LOG) Slog.v(TAG, "setting " + ATTR_SETUP_COMPLETE + " to true");
+                if (VERBOSE_LOG) Slog.v(TAG, "setting %s to true", ATTR_SETUP_COMPLETE);
                 out.attributeBoolean(null, ATTR_SETUP_COMPLETE, true);
             }
             if (policyData.mPaired) {
@@ -216,8 +216,8 @@
 
             if (policyData.mFactoryResetFlags != 0) {
                 if (VERBOSE_LOG) {
-                    Slog.v(TAG, "Storing factory reset flags for user " + policyData.mUserId + ": "
-                            + factoryResetFlagsToString(policyData.mFactoryResetFlags));
+                    Slog.v(TAG, "Storing factory reset flags for user %d: %s", policyData.mUserId,
+                            factoryResetFlagsToString(policyData.mFactoryResetFlags));
                 }
                 out.attributeInt(null, ATTR_FACTORY_RESET_FLAGS, policyData.mFactoryResetFlags);
             }
@@ -382,7 +382,7 @@
             file.commit();
             return true;
         } catch (XmlPullParserException | IOException e) {
-            Slog.w(TAG, "failed writing file", e);
+            Slog.w(TAG, e, "failed writing file %s", chooseForWrite);
             try {
                 if (stream != null) {
                     stream.close();
@@ -404,10 +404,8 @@
             ComponentName ownerComponent) {
         FileInputStream stream = null;
         File file = journaledFile.chooseForRead();
-        if (VERBOSE_LOG) {
-            Slog.v(TAG, "Loading data for user " + policy.mUserId + " from " + file);
-        }
-
+        if (VERBOSE_LOG) Slog.v(TAG, "Loading data for user %d from %s", policy.mUserId, file);
+        boolean needsRewrite = false;
         try {
             stream = new FileInputStream(file);
             TypedXmlPullParser parser = Xml.resolvePullParser(stream);
@@ -454,8 +452,8 @@
 
             policy.mFactoryResetFlags = parser.getAttributeInt(null, ATTR_FACTORY_RESET_FLAGS, 0);
             if (VERBOSE_LOG) {
-                Slog.v(TAG, "Restored factory reset flags for user " + policy.mUserId + ": "
-                        + factoryResetFlagsToString(policy.mFactoryResetFlags));
+                Slog.v(TAG, "Restored factory reset flags for user %d: %s", policy.mUserId,
+                        factoryResetFlagsToString(policy.mFactoryResetFlags));
             }
             policy.mFactoryResetReason = parser.getAttributeValue(null, ATTR_FACTORY_RESET_REASON);
 
@@ -488,7 +486,7 @@
                             policy.mAdminMap.put(ap.info.getComponent(), ap);
                         }
                     } catch (RuntimeException e) {
-                        Slog.w(TAG, "Failed loading admin " + name, e);
+                        Slog.w(TAG, e, "Failed loading admin %s", name);
                     }
                 } else if ("delegation".equals(tag)) {
                     // Parse delegation info.
@@ -560,7 +558,7 @@
                     policy.mAppsSuspended =
                             parser.getAttributeBoolean(null, ATTR_VALUE, false);
                 } else {
-                    Slog.w(TAG, "Unknown tag: " + tag);
+                    Slog.w(TAG, "Unknown tag: %s", tag);
                     XmlUtils.skipCurrentTag(parser);
                 }
             }
@@ -568,7 +566,7 @@
             // Don't be noisy, this is normal if we haven't defined any policies.
         } catch (NullPointerException | NumberFormatException | XmlPullParserException | IOException
                 | IndexOutOfBoundsException e) {
-            Slog.w(TAG, "failed parsing " + file, e);
+            Slog.w(TAG, e, "failed parsing %s", file);
         }
         try {
             if (stream != null) {
@@ -592,8 +590,8 @@
                 }
             }
             if (!haveOwner) {
-                Slog.w(TAG, "Previous password owner " + mPasswordOwner
-                        + " no longer active; disabling");
+                Slog.w(TAG, "Previous password owner %s no longer active; disabling",
+                        mPasswordOwner);
                 mPasswordOwner = -1;
             }
         }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 1590ef1..577f3f5 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -1106,7 +1106,7 @@
      * Used by {@code setDevicePolicySafetyChecker()} above and {@link OneTimeSafetyChecker}.
      */
     void setDevicePolicySafetyCheckerUnchecked(DevicePolicySafetyChecker safetyChecker) {
-        Slog.i(LOG_TAG, String.format("Setting DevicePolicySafetyChecker as %s", safetyChecker));
+        Slog.i(LOG_TAG, "Setting DevicePolicySafetyChecker as %s", safetyChecker);
         mSafetyChecker = safetyChecker;
         mInjector.setDevicePolicySafetyChecker(safetyChecker);
     }
@@ -1588,7 +1588,7 @@
             CryptoTestHelper.runAndLogSelfTest();
         }
 
-        public String[] getPersonalAppsForSuspension(int userId) {
+        public String[] getPersonalAppsForSuspension(@UserIdInt int userId) {
             return PersonalAppsSuspensionHelper.forUser(mContext, userId)
                     .getPersonalAppsForSuspension();
         }
@@ -2969,7 +2969,7 @@
 
     private class DpmsUpgradeDataProvider implements PolicyUpgraderDataProvider {
         @Override
-        public boolean isUserDeviceOwner(int userId, ComponentName who) {
+        public boolean isDeviceOwner(int userId, ComponentName who) {
             return mOwners.isDeviceOwnerUserId(userId)
                     && mOwners.getDeviceOwnerComponent().equals(who);
         }
@@ -2999,14 +2999,19 @@
             return component -> findAdmin(component, userId, /* throwForMissingPermission= */
                     false);
         }
+
+        @Override
+        public int[] getUsersForUpgrade() {
+            List<UserInfo> allUsers = mUserManager.getUsers();
+            return allUsers.stream().mapToInt(u -> u.id).toArray();
+        }
     }
 
     private void performPolicyVersionUpgrade() {
-        List<UserInfo> allUsers = mUserManager.getUsers();
         PolicyVersionUpgrader upgrader = new PolicyVersionUpgrader(
                 new DpmsUpgradeDataProvider());
 
-        upgrader.upgradePolicy(allUsers.stream().mapToInt(u -> u.id).toArray(), DPMS_VERSION);
+        upgrader.upgradePolicy(DPMS_VERSION);
     }
 
     private void revertTransferOwnershipIfNecessaryLocked() {
@@ -10615,6 +10620,30 @@
     }
 
     @Override
+    public List<String> listPolicyExemptApps() {
+        Preconditions.checkCallAuthorization(
+                hasCallingOrSelfPermission(permission.MANAGE_DEVICE_ADMINS));
+
+        // TODO(b/181238156): decide whether it should only list the apps set by the resources,
+        // or also the "critical" apps defined by PersonalAppsSuspensionHelper (like SMS app).
+        // If it's the latter, refactor PersonalAppsSuspensionHelper so it (or a superclass) takes
+        // the resources on constructor.
+        String[] core = mContext.getResources().getStringArray(R.array.policy_exempt_apps);
+        String[] vendor = mContext.getResources().getStringArray(R.array.vendor_policy_exempt_apps);
+
+        int size = core.length + vendor.length;
+        Set<String> apps = new ArraySet<>(size);
+        for (String app : core) {
+            apps.add(app);
+        }
+        for (String app : vendor) {
+            apps.add(app);
+        }
+
+        return new ArrayList<>(apps);
+    }
+
+    @Override
     public void setUserRestriction(ComponentName who, String key, boolean enabledFromThisOwner,
             boolean parent) {
         Objects.requireNonNull(who, "ComponentName is null");
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java
index 5484a14..8e31029 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java
@@ -21,6 +21,7 @@
 import com.android.server.devicepolicy.Owners.OwnerDto;
 
 import java.io.PrintWriter;
+import java.util.Collection;
 import java.util.List;
 import java.util.Objects;
 
@@ -30,6 +31,7 @@
     private static final String CMD_IS_SAFE_OPERATION_BY_REASON = "is-operation-safe-by-reason";
     private static final String CMD_SET_SAFE_OPERATION = "set-operation-safe";
     private static final String CMD_LIST_OWNERS = "list-owners";
+    private static final String CMD_LIST_POLICY_EXEMPT_APPS = "list-policy-exempt-apps";
 
     private final DevicePolicyManagerService mService;
 
@@ -60,6 +62,8 @@
                     return runSetSafeOperation(pw);
                 case CMD_LIST_OWNERS:
                     return runListOwners(pw);
+                case CMD_LIST_POLICY_EXEMPT_APPS:
+                    return runListPolicyExemptApps(pw);
                 default:
                     return onInvalidCommand(pw, cmd);
             }
@@ -88,6 +92,8 @@
                 + " \n\n");
         pw.printf("  %s\n", CMD_LIST_OWNERS);
         pw.printf("    Lists the device / profile owners per user \n\n");
+        pw.printf("  %s\n", CMD_LIST_POLICY_EXEMPT_APPS);
+        pw.printf("    Lists the apps that are exempt from policies\n\n");
     }
 
     private int runIsSafeOperation(PrintWriter pw) {
@@ -119,18 +125,20 @@
         return 0;
     }
 
-    private int runListOwners(PrintWriter pw) {
-        List<OwnerDto> owners = mService.listAllOwners();
-        if (owners.isEmpty()) {
-            pw.println("none");
+    private int printAndGetSize(PrintWriter pw, Collection<?> collection, String nameOnSingular) {
+        if (collection.isEmpty()) {
+            pw.printf("no %ss\n", nameOnSingular);
             return 0;
         }
-        int size = owners.size();
-        if (size == 1) {
-            pw.println("1 owner:");
-        } else {
-            pw.printf("%d owners:\n", size);
-        }
+        int size = collection.size();
+        pw.printf("%d %s%s:\n", size, nameOnSingular, (size == 1 ? "" : "s"));
+        return size;
+    }
+
+    private int runListOwners(PrintWriter pw) {
+        List<OwnerDto> owners = mService.listAllOwners();
+        int size = printAndGetSize(pw, owners, "owner");
+        if (size == 0) return 0;
 
         for (int i = 0; i < size; i++) {
             OwnerDto owner = owners.get(i);
@@ -150,4 +158,17 @@
         return 0;
     }
 
+
+    private int runListPolicyExemptApps(PrintWriter pw) {
+        List<String> apps = mService.listPolicyExemptApps();
+        int size = printAndGetSize(pw, apps, "policy exempt app");
+
+        if (size == 0) return 0;
+
+        for (int i = 0; i < size; i++) {
+            String app = apps.get(i);
+            pw.printf("  %d: %s\n", i, app);
+        }
+        return 0;
+    }
 }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/FactoryResetter.java b/services/devicepolicy/java/com/android/server/devicepolicy/FactoryResetter.java
index 457255b..28a6987 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/FactoryResetter.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/FactoryResetter.java
@@ -68,17 +68,16 @@
         IResultReceiver receiver = new IResultReceiver.Stub() {
             @Override
             public void send(int resultCode, Bundle resultData) throws RemoteException {
-                Slog.i(TAG, String.format("Factory reset confirmed by %s, proceeding",
-                        mSafetyChecker));
+                Slog.i(TAG, "Factory reset confirmed by %s, proceeding", mSafetyChecker);
                 try {
                     factoryResetInternalUnchecked();
                 } catch (IOException e) {
                     // Shouldn't happen
-                    Slog.wtf(TAG, "IOException calling underlying systems", e);
+                    Slog.wtf(TAG, e, "IOException calling underlying systems");
                 }
             }
         };
-        Slog.i(TAG, String.format("Delaying factory reset until %s confirms", mSafetyChecker));
+        Slog.i(TAG, "Delaying factory reset until %s confirms", mSafetyChecker);
         mSafetyChecker.onFactoryReset(receiver);
         return false;
     }
@@ -113,9 +112,9 @@
     }
 
     private void factoryResetInternalUnchecked() throws IOException {
-        Slog.i(TAG, String.format("factoryReset(): reason=%s, shutdown=%b, force=%b, wipeEuicc=%b, "
+        Slog.i(TAG, "factoryReset(): reason=%s, shutdown=%b, force=%b, wipeEuicc=%b, "
                 + "wipeAdoptableStorage=%b, wipeFRP=%b", mReason, mShutdown, mForce, mWipeEuicc,
-                mWipeAdoptableStorage, mWipeFactoryResetProtection));
+                mWipeAdoptableStorage, mWipeFactoryResetProtection);
 
         UserManager um = mContext.getSystemService(UserManager.class);
         if (!mForce && um.hasUserRestriction(UserManager.DISALLOW_FACTORY_RESET)) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PersonalAppsSuspensionHelper.java b/services/devicepolicy/java/com/android/server/devicepolicy/PersonalAppsSuspensionHelper.java
index 37dbfc1..0b9ece4 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PersonalAppsSuspensionHelper.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PersonalAppsSuspensionHelper.java
@@ -18,6 +18,8 @@
 
 import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_ALL_MASK;
 
+import static com.android.server.devicepolicy.DevicePolicyManagerService.LOG_TAG;
+
 import android.accessibilityservice.AccessibilityServiceInfo;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
@@ -36,6 +38,7 @@
 import android.text.TextUtils;
 import android.util.ArraySet;
 import android.util.IndentingPrintWriter;
+import android.util.Log;
 import android.util.Slog;
 import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.IAccessibilityManager;
@@ -105,7 +108,9 @@
             result.remove(pkg);
         }
 
-        Slog.i(LOG_TAG, "Packages subject to suspension: " + String.join(",", result));
+        if (Log.isLoggable(LOG_TAG, Log.INFO)) {
+            Slog.i(LOG_TAG, "Packages subject to suspension: %s", String.join(",", result));
+        }
         return result.toArray(new String[0]);
     }
 
@@ -118,7 +123,7 @@
         for (final ResolveInfo resolveInfo : matchingActivities) {
             if (resolveInfo.activityInfo == null
                     || TextUtils.isEmpty(resolveInfo.activityInfo.packageName)) {
-                Slog.wtf(LOG_TAG, "Could not find package name for launcher app" + resolveInfo);
+                Slog.wtf(LOG_TAG, "Could not find package name for launcher app %s", resolveInfo);
                 continue;
             }
             final String packageName = resolveInfo.activityInfo.packageName;
@@ -129,7 +134,8 @@
                     result.add(packageName);
                 }
             } catch (PackageManager.NameNotFoundException e) {
-                Slog.e(LOG_TAG, "Could not find application info for launcher app: " + packageName);
+                Slog.e(LOG_TAG, "Could not find application info for launcher app: %s",
+                        packageName);
             }
         }
         return result;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyUpgraderDataProvider.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyUpgraderDataProvider.java
index c20d0f5..19a7659 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyUpgraderDataProvider.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyUpgraderDataProvider.java
@@ -33,7 +33,7 @@
      * Returns true if the provided {@code userId} is a device owner. May affect some policy
      * defaults.
      */
-    boolean isUserDeviceOwner(int userId, ComponentName who);
+    boolean isDeviceOwner(int userId, ComponentName who);
 
     /**
      * Returns true if the storage manager indicates file-based encryption is enabled.
@@ -60,4 +60,9 @@
      * user.
      */
     Function<ComponentName, DeviceAdminInfo> getAdminInfoSupplier(int userId);
+
+    /**
+     * Returns the users to upgrade.
+     */
+    int[] getUsersForUpgrade();
 }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyVersionUpgrader.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyVersionUpgrader.java
index 2ab4b66..6bc7ba6 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyVersionUpgrader.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyVersionUpgrader.java
@@ -62,7 +62,7 @@
      *                 managed profile user IDs.
      * @param dpmsVersion The version to upgrade to.
      */
-    public void upgradePolicy(int[] allUsers, int dpmsVersion) {
+    public void upgradePolicy(int dpmsVersion) {
         int oldVersion = readVersion();
         if (oldVersion >= dpmsVersion) {
             Slog.i(LOG_TAG, String.format("Current version %d, latest version %d, not upgrading.",
@@ -70,6 +70,8 @@
             return;
         }
 
+        final int[] allUsers = mProvider.getUsersForUpgrade();
+
         //NOTE: The current version is provided in case the XML file format changes in a
         // non-backwards-compatible way, so that DeviceAdminData could load it with
         // old tags, for example.
@@ -94,7 +96,7 @@
                     continue;
                 }
                 for (ActiveAdmin admin : userData.mAdminList) {
-                    if (mProvider.isUserDeviceOwner(userId, admin.info.getComponent())) {
+                    if (mProvider.isDeviceOwner(userId, admin.info.getComponent())) {
                         Slog.i(LOG_TAG, String.format(
                                 "Marking Device Owner in user %d for permission grant ", userId));
                         admin.mAdminCanGrantSensorsPermissions = true;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportManager.java
index 543f381..2959c10 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportManager.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportManager.java
@@ -25,6 +25,8 @@
 import static android.app.admin.DevicePolicyManager.NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED;
 import static android.app.admin.DevicePolicyManager.NOTIFICATION_BUGREPORT_STARTED;
 
+import static com.android.server.devicepolicy.DevicePolicyManagerService.LOG_TAG;
+
 import android.annotation.IntDef;
 import android.app.Notification;
 import android.app.PendingIntent;
@@ -58,7 +60,6 @@
  * Class managing bugreport collection upon device owner's request.
  */
 public class RemoteBugreportManager {
-    private static final String LOG_TAG = DevicePolicyManagerService.LOG_TAG;
 
     static final String BUGREPORT_MIMETYPE = "application/vnd.android.bugreport";
 
@@ -206,7 +207,7 @@
             return true;
         } catch (RemoteException re) {
             // should never happen
-            Slog.e(LOG_TAG, "Failed to make remote calls to start bugreportremote service", re);
+            Slog.e(LOG_TAG, re, "Failed to make remote calls to start bugreportremote service");
             return false;
         } finally {
             mInjector.binderRestoreCallingIdentity(callingIdentity);
@@ -220,7 +221,7 @@
             mContext.registerReceiver(mRemoteBugreportFinishedReceiver, filterFinished);
         } catch (IntentFilter.MalformedMimeTypeException e) {
             // should never happen, as setting a constant
-            Slog.w(LOG_TAG, "Failed to set type " + BUGREPORT_MIMETYPE, e);
+            Slog.w(LOG_TAG, e, "Failed to set type %s", BUGREPORT_MIMETYPE);
         }
         final IntentFilter filterConsent = new IntentFilter();
         filterConsent.addAction(ACTION_BUGREPORT_SHARING_DECLINED);
diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp
index 1fcc284..c38d0b3 100644
--- a/services/incremental/IncrementalService.cpp
+++ b/services/incremental/IncrementalService.cpp
@@ -74,6 +74,13 @@
 
     // If DL was up and not crashing for 10mins, we consider it healthy and reset all delays.
     static constexpr auto healthyDataLoaderUptime = 10min;
+
+    // For healthy DLs, we'll retry every ~5secs for ~10min
+    static constexpr auto bindRetryInterval = 5s;
+    static constexpr auto bindGracePeriod = 10min;
+
+    static constexpr auto bindingTimeout = 1min;
+
     // 10s, 100s (~2min), 1000s (~15min), 10000s (~3hrs)
     static constexpr auto minBindDelay = 10s;
     static constexpr auto maxBindDelay = 10000s;
@@ -293,6 +300,7 @@
         mTimedQueue(sm.getTimedQueue()),
         mProgressUpdateJobQueue(sm.getProgressUpdateJobQueue()),
         mFs(sm.getFs()),
+        mClock(sm.getClock()),
         mIncrementalDir(rootDir) {
     CHECK(mVold) << "Vold service is unavailable";
     CHECK(mDataLoaderManager) << "DataLoaderManagerService is unavailable";
@@ -302,6 +310,7 @@
     CHECK(mTimedQueue) << "TimedQueue is unavailable";
     CHECK(mProgressUpdateJobQueue) << "mProgressUpdateJobQueue is unavailable";
     CHECK(mFs) << "Fs is unavailable";
+    CHECK(mClock) << "Clock is unavailable";
 
     mJobQueue.reserve(16);
     mJobProcessor = std::thread([this]() {
@@ -2241,17 +2250,44 @@
                << status << " (current " << mCurrentStatus << ")";
 }
 
-Milliseconds IncrementalService::DataLoaderStub::updateBindDelay() {
+std::optional<Milliseconds> IncrementalService::DataLoaderStub::needToBind() {
     std::unique_lock lock(mMutex);
+
+    const auto now = mService.mClock->now();
+    const bool healthy = (mPreviousBindDelay == 0ms);
+
+    if (mCurrentStatus == IDataLoaderStatusListener::DATA_LOADER_BINDING &&
+        now - mCurrentStatusTs <= Constants::bindingTimeout) {
+        LOG(INFO) << "Binding still in progress. "
+                  << (healthy ? "The DL is healthy/freshly bound, ok to retry for a few times."
+                              : "Already unhealthy, don't do anything.");
+        // Binding still in progress.
+        if (!healthy) {
+            // Already unhealthy, don't do anything.
+            return {};
+        }
+        // The DL is healthy/freshly bound, ok to retry for a few times.
+        if (now - mPreviousBindTs <= Constants::bindGracePeriod) {
+            // Still within grace period.
+            if (now - mCurrentStatusTs >= Constants::bindRetryInterval) {
+                // Retry interval passed, retrying.
+                mCurrentStatusTs = now;
+                mPreviousBindDelay = 0ms;
+                return 0ms;
+            }
+            return {};
+        }
+        // fallthrough, mark as unhealthy, and retry with delay
+    }
+
     const auto previousBindTs = mPreviousBindTs;
-    const auto now = Clock::now();
     mPreviousBindTs = now;
 
     const auto nonCrashingInterval = std::max(castToMs(now - previousBindTs), 100ms);
     if (previousBindTs.time_since_epoch() == Clock::duration::zero() ||
         nonCrashingInterval > Constants::healthyDataLoaderUptime) {
         mPreviousBindDelay = 0ms;
-        return mPreviousBindDelay;
+        return 0ms;
     }
 
     constexpr auto minBindDelayMs = castToMs(Constants::minBindDelay);
@@ -2264,12 +2300,16 @@
     const auto bindDelayJitterRangeMs = bindDelayMs / Constants::bindDelayJitterDivider;
     const auto bindDelayJitterMs = rand() % (bindDelayJitterRangeMs * 2) - bindDelayJitterRangeMs;
     mPreviousBindDelay = std::chrono::milliseconds(bindDelayMs + bindDelayJitterMs);
-
     return mPreviousBindDelay;
 }
 
 bool IncrementalService::DataLoaderStub::bind() {
-    const auto bindDelay = updateBindDelay();
+    const auto maybeBindDelay = needToBind();
+    if (!maybeBindDelay) {
+        LOG(DEBUG) << "Skipping bind to " << mParams.packageName << " because of pending bind.";
+        return true;
+    }
+    const auto bindDelay = *maybeBindDelay;
     if (bindDelay > 1s) {
         LOG(INFO) << "Delaying bind to " << mParams.packageName << " by "
                   << bindDelay.count() / 1000 << "s";
@@ -2279,7 +2319,21 @@
     auto status = mService.mDataLoaderManager->bindToDataLoader(id(), mParams, bindDelay.count(),
                                                                 this, &result);
     if (!status.isOk() || !result) {
-        LOG(ERROR) << "Failed to bind a data loader for mount " << id();
+        const bool healthy = (bindDelay == 0ms);
+        LOG(ERROR) << "Failed to bind a data loader for mount " << id()
+                   << (healthy ? ", retrying." : "");
+
+        // Internal error, retry for healthy/new DLs.
+        // Let needToBind migrate it to unhealthy after too many retries.
+        if (healthy) {
+            if (mService.addTimedJob(*mService.mTimedQueue, id(), Constants::bindRetryInterval,
+                                     [this]() { fsmStep(); })) {
+                // Mark as binding so that we know it's not the DL's fault.
+                setCurrentStatus(IDataLoaderStatusListener::DATA_LOADER_BINDING);
+                return true;
+            }
+        }
+
         return false;
     }
     return true;
@@ -2339,7 +2393,14 @@
             // Do nothing, this is a reset state.
             break;
         case IDataLoaderStatusListener::DATA_LOADER_DESTROYED: {
-            return destroy();
+            switch (currentStatus) {
+                case IDataLoaderStatusListener::DATA_LOADER_BINDING:
+                    setCurrentStatus(IDataLoaderStatusListener::DATA_LOADER_DESTROYED);
+                    return true;
+                default:
+                    return destroy();
+            }
+            break;
         }
         case IDataLoaderStatusListener::DATA_LOADER_STARTED: {
             switch (currentStatus) {
@@ -2353,6 +2414,7 @@
             switch (currentStatus) {
                 case IDataLoaderStatusListener::DATA_LOADER_DESTROYED:
                 case IDataLoaderStatusListener::DATA_LOADER_UNAVAILABLE:
+                case IDataLoaderStatusListener::DATA_LOADER_BINDING:
                     return bind();
                 case IDataLoaderStatusListener::DATA_LOADER_BOUND:
                     return create();
@@ -2372,7 +2434,8 @@
                 fromServiceSpecificError(-EINVAL, "onStatusChange came to invalid DataLoaderStub");
     }
     if (id() != mountId) {
-        LOG(ERROR) << "Mount ID mismatch: expected " << id() << ", but got: " << mountId;
+        LOG(ERROR) << "onStatusChanged: mount ID mismatch: expected " << id()
+                   << ", but got: " << mountId;
         return binder::Status::fromServiceSpecificError(-EPERM, "Mount ID mismatch.");
     }
     if (newStatus == IDataLoaderStatusListener::DATA_LOADER_UNRECOVERABLE) {
@@ -2396,11 +2459,13 @@
         }
 
         oldStatus = mCurrentStatus;
-        mCurrentStatus = newStatus;
         targetStatus = mTargetStatus;
-
         listener = mStatusListener;
 
+        // Change the status.
+        mCurrentStatus = newStatus;
+        mCurrentStatusTs = mService.mClock->now();
+
         if (mCurrentStatus == IDataLoaderStatusListener::DATA_LOADER_UNAVAILABLE ||
             mCurrentStatus == IDataLoaderStatusListener::DATA_LOADER_UNRECOVERABLE) {
             // For unavailable, unbind from DataLoader to ensure proper re-commit.
@@ -2428,7 +2493,8 @@
                                          "reportStreamHealth came to invalid DataLoaderStub");
     }
     if (id() != mountId) {
-        LOG(ERROR) << "Mount ID mismatch: expected " << id() << ", but got: " << mountId;
+        LOG(ERROR) << "reportStreamHealth: mount ID mismatch: expected " << id()
+                   << ", but got: " << mountId;
         return binder::Status::fromServiceSpecificError(-EPERM, "Mount ID mismatch.");
     }
     {
@@ -2694,6 +2760,8 @@
 void IncrementalService::DataLoaderStub::onDump(int fd) {
     dprintf(fd, "    dataLoader: {\n");
     dprintf(fd, "      currentStatus: %d\n", mCurrentStatus);
+    dprintf(fd, "      currentStatusTs: %lldmcs\n",
+            (long long)(elapsedMcs(mCurrentStatusTs, Clock::now())));
     dprintf(fd, "      targetStatus: %d\n", mTargetStatus);
     dprintf(fd, "      targetStatusTs: %lldmcs\n",
             (long long)(elapsedMcs(mTargetStatusTs, Clock::now())));
diff --git a/services/incremental/IncrementalService.h b/services/incremental/IncrementalService.h
index 14e5a77..4eb5138 100644
--- a/services/incremental/IncrementalService.h
+++ b/services/incremental/IncrementalService.h
@@ -267,7 +267,10 @@
         BootClockTsUs getOldestTsFromLastPendingReads();
         Milliseconds elapsedMsSinceKernelTs(TimePoint now, BootClockTsUs kernelTsUs);
 
-        Milliseconds updateBindDelay();
+        // If the stub has to bind to the DL.
+        // Returns {} if bind operation is already in progress.
+        // Or bind delay in ms.
+        std::optional<Milliseconds> needToBind();
 
         void registerForPendingReads();
         void unregisterFromPendingReads();
@@ -283,6 +286,7 @@
 
         std::condition_variable mStatusCondition;
         int mCurrentStatus = content::pm::IDataLoaderStatusListener::DATA_LOADER_DESTROYED;
+        TimePoint mCurrentStatusTs = {};
         int mTargetStatus = content::pm::IDataLoaderStatusListener::DATA_LOADER_DESTROYED;
         TimePoint mTargetStatusTs = {};
 
@@ -443,6 +447,7 @@
     const std::unique_ptr<TimedQueueWrapper> mTimedQueue;
     const std::unique_ptr<TimedQueueWrapper> mProgressUpdateJobQueue;
     const std::unique_ptr<FsWrapper> mFs;
+    const std::unique_ptr<ClockWrapper> mClock;
     const std::string mIncrementalDir;
 
     mutable std::mutex mLock;
diff --git a/services/incremental/ServiceWrappers.cpp b/services/incremental/ServiceWrappers.cpp
index d613289..80f409f 100644
--- a/services/incremental/ServiceWrappers.cpp
+++ b/services/incremental/ServiceWrappers.cpp
@@ -329,6 +329,14 @@
     }
 };
 
+class RealClockWrapper final : public ClockWrapper {
+public:
+    RealClockWrapper() = default;
+    ~RealClockWrapper() = default;
+
+    TimePoint now() const final { return Clock::now(); }
+};
+
 RealServiceManager::RealServiceManager(sp<IServiceManager> serviceManager, JNIEnv* env)
       : mServiceManager(std::move(serviceManager)), mJvm(RealJniWrapper::getJvm(env)) {}
 
@@ -388,6 +396,10 @@
     return std::make_unique<RealFsWrapper>();
 }
 
+std::unique_ptr<ClockWrapper> RealServiceManager::getClock() {
+    return std::make_unique<RealClockWrapper>();
+}
+
 static JavaVM* getJavaVm(JNIEnv* env) {
     CHECK(env);
     JavaVM* jvm = nullptr;
diff --git a/services/incremental/ServiceWrappers.h b/services/incremental/ServiceWrappers.h
index 245bb31..d113f99 100644
--- a/services/incremental/ServiceWrappers.h
+++ b/services/incremental/ServiceWrappers.h
@@ -158,6 +158,12 @@
     virtual void listFilesRecursive(std::string_view directoryPath, FileCallback onFile) const = 0;
 };
 
+class ClockWrapper {
+public:
+    virtual ~ClockWrapper() = default;
+    virtual TimePoint now() const = 0;
+};
+
 class ServiceManagerWrapper {
 public:
     virtual ~ServiceManagerWrapper() = default;
@@ -170,6 +176,7 @@
     virtual std::unique_ptr<TimedQueueWrapper> getTimedQueue() = 0;
     virtual std::unique_ptr<TimedQueueWrapper> getProgressUpdateJobQueue() = 0;
     virtual std::unique_ptr<FsWrapper> getFs() = 0;
+    virtual std::unique_ptr<ClockWrapper> getClock() = 0;
 };
 
 // --- Real stuff ---
@@ -187,6 +194,7 @@
     std::unique_ptr<TimedQueueWrapper> getTimedQueue() final;
     std::unique_ptr<TimedQueueWrapper> getProgressUpdateJobQueue() final;
     std::unique_ptr<FsWrapper> getFs() final;
+    std::unique_ptr<ClockWrapper> getClock() final;
 
 private:
     template <class INTERFACE>
diff --git a/services/incremental/test/IncrementalServiceTest.cpp b/services/incremental/test/IncrementalServiceTest.cpp
index 5236983..25b34b56 100644
--- a/services/incremental/test/IncrementalServiceTest.cpp
+++ b/services/incremental/test/IncrementalServiceTest.cpp
@@ -248,6 +248,27 @@
         }
         return binder::Status::ok();
     }
+    binder::Status bindToDataLoaderNotOkWithNoDelay(int32_t mountId,
+                                                    const DataLoaderParamsParcel& params,
+                                                    int bindDelayMs,
+                                                    const sp<IDataLoaderStatusListener>& listener,
+                                                    bool* _aidl_return) {
+        CHECK(bindDelayMs == 0) << bindDelayMs;
+        *_aidl_return = false;
+        return binder::Status::ok();
+    }
+    binder::Status bindToDataLoaderBindingWithNoDelay(int32_t mountId,
+                                                      const DataLoaderParamsParcel& params,
+                                                      int bindDelayMs,
+                                                      const sp<IDataLoaderStatusListener>& listener,
+                                                      bool* _aidl_return) {
+        CHECK(bindDelayMs == 0) << bindDelayMs;
+        *_aidl_return = true;
+        if (listener) {
+            listener->onStatusChanged(mId, IDataLoaderStatusListener::DATA_LOADER_BINDING);
+        }
+        return binder::Status::ok();
+    }
     binder::Status bindToDataLoaderOkWith10sDelay(int32_t mountId,
                                                   const DataLoaderParamsParcel& params,
                                                   int bindDelayMs,
@@ -557,6 +578,21 @@
     }
 };
 
+class MockClockWrapper : public ClockWrapper {
+public:
+    MOCK_CONST_METHOD0(now, TimePoint());
+
+    void start() { ON_CALL(*this, now()).WillByDefault(Invoke(this, &MockClockWrapper::getClock)); }
+    template <class Delta>
+    void advance(Delta delta) {
+        mClock += delta;
+    }
+
+    TimePoint getClock() const { return mClock; }
+
+    TimePoint mClock = Clock::now();
+};
+
 class MockStorageHealthListener : public os::incremental::BnStorageHealthListener {
 public:
     MOCK_METHOD2(onHealthStatus, binder::Status(int32_t storageId, int32_t status));
@@ -594,7 +630,7 @@
                        std::unique_ptr<MockLooperWrapper> looper,
                        std::unique_ptr<MockTimedQueueWrapper> timedQueue,
                        std::unique_ptr<MockTimedQueueWrapper> progressUpdateJobQueue,
-                       std::unique_ptr<MockFsWrapper> fs)
+                       std::unique_ptr<MockFsWrapper> fs, std::unique_ptr<MockClockWrapper> clock)
           : mVold(std::move(vold)),
             mDataLoaderManager(std::move(dataLoaderManager)),
             mIncFs(std::move(incfs)),
@@ -603,7 +639,8 @@
             mLooper(std::move(looper)),
             mTimedQueue(std::move(timedQueue)),
             mProgressUpdateJobQueue(std::move(progressUpdateJobQueue)),
-            mFs(std::move(fs)) {}
+            mFs(std::move(fs)),
+            mClock(std::move(clock)) {}
     std::unique_ptr<VoldServiceWrapper> getVoldService() final { return std::move(mVold); }
     std::unique_ptr<DataLoaderManagerWrapper> getDataLoaderManager() final {
         return std::move(mDataLoaderManager);
@@ -619,6 +656,7 @@
         return std::move(mProgressUpdateJobQueue);
     }
     std::unique_ptr<FsWrapper> getFs() final { return std::move(mFs); }
+    std::unique_ptr<ClockWrapper> getClock() final { return std::move(mClock); }
 
 private:
     std::unique_ptr<MockVoldService> mVold;
@@ -630,6 +668,7 @@
     std::unique_ptr<MockTimedQueueWrapper> mTimedQueue;
     std::unique_ptr<MockTimedQueueWrapper> mProgressUpdateJobQueue;
     std::unique_ptr<MockFsWrapper> mFs;
+    std::unique_ptr<MockClockWrapper> mClock;
 };
 
 // --- IncrementalServiceTest ---
@@ -657,6 +696,8 @@
         mProgressUpdateJobQueue = progressUpdateJobQueue.get();
         auto fs = std::make_unique<NiceMock<MockFsWrapper>>();
         mFs = fs.get();
+        auto clock = std::make_unique<NiceMock<MockClockWrapper>>();
+        mClock = clock.get();
         mIncrementalService = std::make_unique<
                 IncrementalService>(MockServiceManager(std::move(vold),
                                                        std::move(dataloaderManager),
@@ -664,12 +705,13 @@
                                                        std::move(jni), std::move(looper),
                                                        std::move(timedQueue),
                                                        std::move(progressUpdateJobQueue),
-                                                       std::move(fs)),
+                                                       std::move(fs), std::move(clock)),
                                     mRootDir.path);
         mDataLoaderParcel.packageName = "com.test";
         mDataLoaderParcel.arguments = "uri";
         mDataLoaderManager->unbindFromDataLoaderSuccess();
         mIncrementalService->onSystemReady();
+        mClock->start();
         setupSuccess();
     }
 
@@ -724,6 +766,7 @@
     NiceMock<MockTimedQueueWrapper>* mTimedQueue = nullptr;
     NiceMock<MockTimedQueueWrapper>* mProgressUpdateJobQueue = nullptr;
     NiceMock<MockFsWrapper>* mFs = nullptr;
+    NiceMock<MockClockWrapper>* mClock = nullptr;
     NiceMock<MockDataLoader>* mDataLoader = nullptr;
     std::unique_ptr<IncrementalService> mIncrementalService;
     TemporaryDir mRootDir;
@@ -853,6 +896,119 @@
     mDataLoaderManager->setDataLoaderStatusDestroyed();
 }
 
+TEST_F(IncrementalServiceTest, testDataLoaderOnRestart) {
+    mIncFs->waitForPendingReadsSuccess();
+    mIncFs->openMountSuccess();
+
+    constexpr auto bindRetryInterval = 5s;
+
+    EXPECT_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _, _)).Times(10);
+    EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_)).Times(1);
+    EXPECT_CALL(*mDataLoader, create(_, _, _, _)).Times(6);
+    EXPECT_CALL(*mDataLoader, start(_)).Times(6);
+    EXPECT_CALL(*mDataLoader, destroy(_)).Times(1);
+    EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
+    EXPECT_CALL(*mTimedQueue, addJob(_, _, _)).Times(2);
+    TemporaryDir tempDir;
+    int storageId =
+            mIncrementalService->createStorage(tempDir.path, mDataLoaderParcel,
+                                               IncrementalService::CreateOptions::CreateNew);
+    ASSERT_GE(storageId, 0);
+
+    // First binds to DataLoader fails... because it's restart.
+    ON_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _, _))
+            .WillByDefault(Invoke(mDataLoaderManager,
+                                  &MockDataLoaderManager::bindToDataLoaderNotOkWithNoDelay));
+
+    // Request DL start.
+    mIncrementalService->startLoading(storageId, std::move(mDataLoaderParcel), {}, {}, {}, {});
+
+    // Retry callback present.
+    ASSERT_EQ(storageId, mTimedQueue->mId);
+    ASSERT_EQ(mTimedQueue->mAfter, bindRetryInterval);
+    auto retryCallback = mTimedQueue->mWhat;
+    mTimedQueue->clearJob(storageId);
+
+    // Expecting the same bindToDataLoaderNotOkWithNoDelay call.
+    mClock->advance(5s);
+
+    retryCallback();
+    // Retry callback present.
+    ASSERT_EQ(storageId, mTimedQueue->mId);
+    ASSERT_EQ(mTimedQueue->mAfter, bindRetryInterval);
+    retryCallback = mTimedQueue->mWhat;
+    mTimedQueue->clearJob(storageId);
+
+    // Returning "binding" so that we can retry.
+    ON_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _, _))
+            .WillByDefault(Invoke(mDataLoaderManager,
+                                  &MockDataLoaderManager::bindToDataLoaderBindingWithNoDelay));
+
+    // Expecting bindToDataLoaderBindingWithNoDelay call.
+    mClock->advance(5s);
+
+    retryCallback();
+    // No retry callback.
+    ASSERT_EQ(mTimedQueue->mAfter, 0ms);
+    ASSERT_EQ(mTimedQueue->mWhat, nullptr);
+
+    // Should not change the bindToDataLoader call count
+    ASSERT_NE(nullptr, mLooper->mCallback);
+    ASSERT_NE(nullptr, mLooper->mCallbackData);
+    auto looperCb = mLooper->mCallback;
+    auto looperCbData = mLooper->mCallbackData;
+    looperCb(-1, -1, looperCbData);
+
+    // Expecting the same bindToDataLoaderBindingWithNoDelay call.
+    mClock->advance(5s);
+
+    // Use pending reads callback to trigger binding.
+    looperCb(-1, -1, looperCbData);
+
+    // No retry callback.
+    ASSERT_EQ(mTimedQueue->mAfter, 0ms);
+    ASSERT_EQ(mTimedQueue->mWhat, nullptr);
+
+    // Now we are out of 10m "retry" budget, let's finally bind.
+    ON_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _, _))
+            .WillByDefault(Invoke(mDataLoaderManager, &MockDataLoaderManager::bindToDataLoaderOk));
+    mClock->advance(11min);
+
+    // Use pending reads callback to trigger binding.
+    looperCb(-1, -1, looperCbData);
+
+    // No retry callback.
+    ASSERT_EQ(mTimedQueue->mAfter, 0ms);
+    ASSERT_EQ(mTimedQueue->mWhat, nullptr);
+
+    // And test the rest of the backoff.
+    // Simulated crash/other connection breakage.
+    ON_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _, _))
+            .WillByDefault(Invoke(mDataLoaderManager,
+                                  &MockDataLoaderManager::bindToDataLoaderOkWith10sDelay));
+    mDataLoaderManager->setDataLoaderStatusDestroyed();
+
+    ON_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _, _))
+            .WillByDefault(Invoke(mDataLoaderManager,
+                                  &MockDataLoaderManager::bindToDataLoaderOkWith100sDelay));
+    mDataLoaderManager->setDataLoaderStatusDestroyed();
+
+    ON_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _, _))
+            .WillByDefault(Invoke(mDataLoaderManager,
+                                  &MockDataLoaderManager::bindToDataLoaderOkWith1000sDelay));
+    mDataLoaderManager->setDataLoaderStatusDestroyed();
+
+    ON_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _, _))
+            .WillByDefault(Invoke(mDataLoaderManager,
+                                  &MockDataLoaderManager::bindToDataLoaderOkWith10000sDelay));
+    mDataLoaderManager->setDataLoaderStatusDestroyed();
+
+    ON_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _, _))
+            .WillByDefault(Invoke(mDataLoaderManager,
+                                  &MockDataLoaderManager::bindToDataLoaderOkWith10000sDelay));
+    mDataLoaderManager->setDataLoaderStatusDestroyed();
+}
+
 TEST_F(IncrementalServiceTest, testStartDataLoaderCreate) {
     mDataLoader->initializeCreateOkNoStatus();
     EXPECT_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _, _)).Times(1);
diff --git a/services/smartspace/java/com/android/server/smartspace/SmartspaceManagerService.java b/services/smartspace/java/com/android/server/smartspace/SmartspaceManagerService.java
index 169b85e..b07fe19 100644
--- a/services/smartspace/java/com/android/server/smartspace/SmartspaceManagerService.java
+++ b/services/smartspace/java/com/android/server/smartspace/SmartspaceManagerService.java
@@ -19,6 +19,7 @@
 import static android.Manifest.permission.MANAGE_SMARTSPACE;
 import static android.app.ActivityManagerInternal.ALLOW_NON_FULL;
 import static android.content.Context.SMARTSPACE_SERVICE;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -161,11 +162,13 @@
                 Slog.d(TAG, "runForUserLocked:" + func + " from pid=" + Binder.getCallingPid()
                         + ", uid=" + Binder.getCallingUid());
             }
-            if (!(mServiceNameResolver.isTemporary(userId)
+            Context ctx = getContext();
+            if (!(ctx.checkCallingPermission(MANAGE_SMARTSPACE) == PERMISSION_GRANTED
+                    || mServiceNameResolver.isTemporary(userId)
                     || mActivityTaskManagerInternal.isCallerRecents(Binder.getCallingUid()))) {
 
-                String msg = "Permission Denial: " + func + " from pid=" + Binder.getCallingPid()
-                        + ", uid=" + Binder.getCallingUid();
+                String msg = "Permission Denial: Cannot call " + func + " from pid="
+                        + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid();
                 Slog.w(TAG, msg);
                 throw new SecurityException(msg);
             }
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityManagerTest.java b/services/tests/servicestests/src/com/android/server/am/ActivityManagerTest.java
index 129d263..e13597d 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityManagerTest.java
@@ -19,23 +19,37 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
 import android.app.ActivityManager;
+import android.app.ActivityManager.OnUidImportanceListener;
 import android.app.ActivityManager.RecentTaskInfo;
+import android.app.ActivityManager.RunningAppProcessInfo;
 import android.app.IActivityManager;
+import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.ServiceConnection;
 import android.content.pm.PackageManager;
+import android.os.Bundle;
+import android.os.DropBoxManager;
+import android.os.Handler;
 import android.os.IBinder;
 import android.os.IRemoteCallback;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Messenger;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.platform.test.annotations.Presubmit;
 import android.support.test.uiautomator.UiDevice;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.text.TextUtils;
+import android.util.Log;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.FlakyTest;
@@ -65,6 +79,12 @@
     private static final long AWAIT_TIMEOUT = 2000;
     private static final long CHECK_INTERVAL = 100;
 
+    private static final String TEST_FGS_CLASS =
+            "com.android.servicestests.apps.simpleservicetestapp.SimpleFgService";
+    private static final String ACTION_FGS_STATS_TEST =
+            "com.android.servicestests.apps.simpleservicetestapp.ACTION_FGS_STATS_TEST";
+    private static final String EXTRA_MESSENGER = "extra_messenger";
+
     private IActivityManager mService;
     private IRemoteCallback mCallback;
     private Context mContext;
@@ -204,4 +224,184 @@
         public void onServiceDisconnected(ComponentName name) {
         }
     }
+
+    /**
+     * Note: This test actually only works in eng build. It'll always pass
+     * in user and userdebug build, because the expected exception won't be
+     * thrown in those builds.
+     */
+    @LargeTest
+    @Test
+    public void testFgsProcStatsTracker() throws Exception {
+        final PackageManager pm = mContext.getPackageManager();
+        final long timeout = 5000;
+        int uid = pm.getPackageUid(TEST_APP, 0);
+        final MyUidImportanceListener uidListener1 = new MyUidImportanceListener(uid);
+        final MyUidImportanceListener uidListener2 = new MyUidImportanceListener(uid);
+        final ActivityManager am = mContext.getSystemService(ActivityManager.class);
+        final CountDownLatch[] latchHolder = new CountDownLatch[1];
+        final H handler = new H(Looper.getMainLooper(), latchHolder);
+        final Messenger messenger = new Messenger(handler);
+        final DropBoxManager dbox = mContext.getSystemService(DropBoxManager.class);
+        final CountDownLatch dboxLatch = new CountDownLatch(1);
+        final BroadcastReceiver receiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                final String tag_wtf = "system_server_wtf";
+                if (tag_wtf.equals(intent.getStringExtra(DropBoxManager.EXTRA_TAG))) {
+                    final DropBoxManager.Entry e = dbox.getNextEntry(tag_wtf, intent.getLongExtra(
+                            DropBoxManager.EXTRA_TIME, 0) - 1);
+                    final String text = e.getText(8192);
+                    if (TextUtils.isEmpty(text)) {
+                        return;
+                    }
+                    if (text.indexOf("can't store negative values") == -1) {
+                        return;
+                    }
+                    dboxLatch.countDown();
+                }
+            }
+        };
+        try {
+            mContext.registerReceiver(receiver,
+                    new IntentFilter(DropBoxManager.ACTION_DROPBOX_ENTRY_ADDED));
+            am.addOnUidImportanceListener(uidListener1,
+                    RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE);
+            am.addOnUidImportanceListener(uidListener2, RunningAppProcessInfo.IMPORTANCE_GONE);
+            runShellCommand("cmd deviceidle whitelist +" + TEST_APP);
+            toggleScreenOn(true);
+
+            final Intent intent = new Intent(ACTION_FGS_STATS_TEST);
+            final ComponentName cn = ComponentName.unflattenFromString(
+                    TEST_APP + "/" + TEST_FGS_CLASS);
+            final Bundle bundle = new Bundle();
+            intent.setComponent(cn);
+            bundle.putBinder(EXTRA_MESSENGER, messenger.getBinder());
+            intent.putExtras(bundle);
+
+            latchHolder[0] = new CountDownLatch(1);
+            mContext.startForegroundService(intent);
+            assertTrue("Timed out to start fg service", uidListener1.waitFor(
+                    RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE, timeout));
+            assertTrue("Timed out to get the remote messenger", latchHolder[0].await(
+                    timeout, TimeUnit.MILLISECONDS));
+
+            Thread.sleep(timeout);
+            latchHolder[0] = new CountDownLatch(1);
+            handler.sendRemoteMessage(H.MSG_STOP_FOREGROUND, 0, 0, null);
+            assertTrue("Timed out to wait for stop fg", latchHolder[0].await(
+                    timeout, TimeUnit.MILLISECONDS));
+
+            Thread.sleep(timeout);
+            latchHolder[0] = new CountDownLatch(1);
+            handler.sendRemoteMessage(H.MSG_START_FOREGROUND, 0, 0, null);
+            assertTrue("Timed out to wait for start fg", latchHolder[0].await(
+                    timeout, TimeUnit.MILLISECONDS));
+
+            toggleScreenOn(false);
+            latchHolder[0] = new CountDownLatch(1);
+            handler.sendRemoteMessage(H.MSG_STOP_FOREGROUND, 0, 0, null);
+            assertTrue("Timed out to wait for stop fg", latchHolder[0].await(
+                    timeout, TimeUnit.MILLISECONDS));
+            assertFalse("There shouldn't be negative values", dboxLatch.await(
+                    timeout * 2, TimeUnit.MILLISECONDS));
+        } finally {
+            toggleScreenOn(true);
+            runShellCommand("cmd deviceidle whitelist -" + TEST_APP);
+            am.removeOnUidImportanceListener(uidListener1);
+            am.removeOnUidImportanceListener(uidListener2);
+            am.forceStopPackage(TEST_APP);
+            mContext.unregisterReceiver(receiver);
+        }
+    }
+
+    /**
+     * Make sure the screen state.
+     */
+    private void toggleScreenOn(final boolean screenon) throws Exception {
+        if (screenon) {
+            runShellCommand("input keyevent KEYCODE_WAKEUP");
+            runShellCommand("wm dismiss-keyguard");
+        } else {
+            runShellCommand("input keyevent KEYCODE_SLEEP");
+        }
+        // Since the screen on/off intent is ordered, they will not be sent right now.
+        Thread.sleep(2_000);
+    }
+
+    private class H extends Handler {
+        static final int MSG_INIT = 0;
+        static final int MSG_DONE = 1;
+        static final int MSG_START_FOREGROUND = 2;
+        static final int MSG_STOP_FOREGROUND = 3;
+
+        private Messenger mRemoteMessenger;
+        private CountDownLatch[] mLatchHolder;
+
+        H(Looper looper, CountDownLatch[] latchHolder) {
+            super(looper);
+            mLatchHolder = latchHolder;
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_INIT:
+                    mRemoteMessenger = (Messenger) msg.obj;
+                    mLatchHolder[0].countDown();
+                    break;
+                case MSG_DONE:
+                    mLatchHolder[0].countDown();
+                    break;
+            }
+        }
+
+        void sendRemoteMessage(int what, int arg1, int arg2, Object obj) {
+            Message msg = Message.obtain();
+            msg.what = what;
+            msg.arg1 = arg1;
+            msg.arg2 = arg2;
+            msg.obj = obj;
+            try {
+                mRemoteMessenger.send(msg);
+            } catch (RemoteException e) {
+            }
+            msg.recycle();
+        }
+    }
+
+    private static class MyUidImportanceListener implements OnUidImportanceListener {
+        final CountDownLatch[] mLatchHolder = new CountDownLatch[1];
+        private final int mExpectedUid;
+        private int mExpectedImportance;
+        private int mCurrentImportance = RunningAppProcessInfo.IMPORTANCE_GONE;
+
+        MyUidImportanceListener(int uid) {
+            mExpectedUid = uid;
+        }
+
+        @Override
+        public void onUidImportance(int uid, int importance) {
+            if (uid == mExpectedUid) {
+                synchronized (this) {
+                    if (importance == mExpectedImportance && mLatchHolder[0] != null) {
+                        mLatchHolder[0].countDown();
+                    }
+                    mCurrentImportance = importance;
+                }
+                Log.i(TAG, "uid " + uid + " importance: " + importance);
+            }
+        }
+
+        boolean waitFor(int expectedImportance, long timeout) throws Exception {
+            synchronized (this) {
+                mExpectedImportance = expectedImportance;
+                if (mCurrentImportance == expectedImportance) {
+                    return true;
+                }
+                mLatchHolder[0] = new CountDownLatch(1);
+            }
+            return mLatchHolder[0].await(timeout, TimeUnit.MILLISECONDS);
+        }
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java b/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java
index f00edcc..fcd6b84 100644
--- a/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java
+++ b/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java
@@ -120,6 +120,11 @@
         return this;
     }
 
+    CompatConfigBuilder addEnabledSinceApexChangeWithId(int sdk, long id) {
+        mChanges.add(new CompatChange(id, "", -1, sdk, false, false, "", false));
+        return this;
+    }
+
     CompatConfig build() {
         CompatConfig config = new CompatConfig(mBuildClassifier, mContext);
         config.forceNonDebuggableFinalForTest(false);
diff --git a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
index b6b6932..bd77405 100644
--- a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
@@ -86,6 +86,7 @@
         // Assume userdebug/eng non-final build
         when(mBuildClassifier.isDebuggableBuild()).thenReturn(true);
         when(mBuildClassifier.isFinalBuild()).thenReturn(false);
+        when(mBuildClassifier.platformTargetSdk()).thenReturn(30);
         ChangeIdStateCache.disable();
         when(mPackageManager.getApplicationInfo(anyString(), anyInt()))
                 .thenThrow(new NameNotFoundException());
@@ -567,6 +568,34 @@
     }
 
     @Test
+    public void testReadApexConfig() throws IOException {
+        String configXml = "<config>"
+                + "<compat-change id=\"1234\" name=\"MY_CHANGE1\" enableAfterTargetSdk=\"2\" />"
+                + "<compat-change id=\"1235\" name=\"MY_CHANGE2\" disabled=\"true\" />"
+                + "<compat-change id=\"1236\" name=\"MY_CHANGE3\" />"
+                + "<compat-change id=\"1237\" name=\"MY_CHANGE4\" enableSinceTargetSdk=\"31\" />"
+                + "</config>";
+
+        File dir = createTempDir();
+        writeToFile(dir, "platform_compat_config.xml", configXml);
+        CompatConfig compatConfig = new CompatConfig(mBuildClassifier, mContext);
+        compatConfig.forceNonDebuggableFinalForTest(false);
+
+        compatConfig.initConfigFromLib(dir);
+
+        assertThat(compatConfig.isChangeEnabled(1234L,
+            ApplicationInfoBuilder.create().withTargetSdk(1).build())).isFalse();
+        assertThat(compatConfig.isChangeEnabled(1234L,
+            ApplicationInfoBuilder.create().withTargetSdk(3).build())).isTrue();
+        assertThat(compatConfig.isChangeEnabled(1235L,
+            ApplicationInfoBuilder.create().withTargetSdk(5).build())).isFalse();
+        assertThat(compatConfig.isChangeEnabled(1236L,
+            ApplicationInfoBuilder.create().withTargetSdk(1).build())).isTrue();
+        assertThat(compatConfig.isChangeEnabled(1237L,
+            ApplicationInfoBuilder.create().withTargetSdk(31).build())).isTrue();
+    }
+
+    @Test
     public void testReadConfigMultipleFiles() throws IOException {
         String configXml1 = "<config>"
                 + "<compat-change id=\"1234\" name=\"MY_CHANGE1\" enableAfterTargetSdk=\"2\" />"
diff --git a/services/tests/servicestests/src/com/android/server/compat/OverrideValidatorImplTest.java b/services/tests/servicestests/src/com/android/server/compat/OverrideValidatorImplTest.java
index 0fd6445..57fdcd3 100644
--- a/services/tests/servicestests/src/com/android/server/compat/OverrideValidatorImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/compat/OverrideValidatorImplTest.java
@@ -22,6 +22,7 @@
 import static com.android.internal.compat.OverrideAllowedState.DISABLED_NOT_DEBUGGABLE;
 import static com.android.internal.compat.OverrideAllowedState.DISABLED_TARGET_SDK_TOO_HIGH;
 import static com.android.internal.compat.OverrideAllowedState.LOGGING_ONLY_CHANGE;
+import static com.android.internal.compat.OverrideAllowedState.PLATFORM_TOO_OLD;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -52,6 +53,7 @@
     private static final int TARGET_SDK = 10;
     private static final int TARGET_SDK_BEFORE = 9;
     private static final int TARGET_SDK_AFTER = 11;
+    private static final int PLATFORM_SDK_VERSION = 30;
 
     @Mock
     private PackageManager mPackageManager;
@@ -61,6 +63,7 @@
     private AndroidBuildClassifier debuggableBuild() {
         AndroidBuildClassifier buildClassifier = mock(AndroidBuildClassifier.class);
         when(buildClassifier.isDebuggableBuild()).thenReturn(true);
+        when(buildClassifier.platformTargetSdk()).thenReturn(PLATFORM_SDK_VERSION);
         return buildClassifier;
     }
 
@@ -68,6 +71,7 @@
         AndroidBuildClassifier buildClassifier = mock(AndroidBuildClassifier.class);
         when(buildClassifier.isDebuggableBuild()).thenReturn(false);
         when(buildClassifier.isFinalBuild()).thenReturn(false);
+        when(buildClassifier.platformTargetSdk()).thenReturn(PLATFORM_SDK_VERSION);
         return buildClassifier;
     }
 
@@ -75,6 +79,7 @@
         AndroidBuildClassifier buildClassifier = mock(AndroidBuildClassifier.class);
         when(buildClassifier.isDebuggableBuild()).thenReturn(false);
         when(buildClassifier.isFinalBuild()).thenReturn(true);
+        when(buildClassifier.platformTargetSdk()).thenReturn(PLATFORM_SDK_VERSION);
         return buildClassifier;
     }
 
@@ -333,6 +338,26 @@
     }
 
     @Test
+    public void getOverrideAllowedState_targetSdkChangeGreaterThanOsVersion_rejectOverride()
+            throws Exception {
+        final AndroidBuildClassifier buildClassifier = finalBuild();
+        CompatConfig config = CompatConfigBuilder.create(finalBuild(), mContext)
+                        .addEnabledSinceApexChangeWithId(PLATFORM_SDK_VERSION + 1, 1).build();
+        IOverrideValidator overrideValidator = config.getOverrideValidator();
+        when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
+                .thenReturn(ApplicationInfoBuilder.create()
+                        .withPackageName(PACKAGE_NAME)
+                        .debuggable()
+                        .build());
+
+        OverrideAllowedState stateTargetSdkLessChange =
+                overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME);
+        assertThat(stateTargetSdkLessChange).isEqualTo(
+                new OverrideAllowedState(PLATFORM_TOO_OLD, -1,
+                                         PLATFORM_SDK_VERSION));
+    }
+
+    @Test
     public void getOverrideAllowedState_finalBuildEnabledChangeDebugApp_rejectOverride()
             throws Exception {
         CompatConfig config = CompatConfigBuilder.create(finalBuild(), mContext)
diff --git a/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java b/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java
index 799b067..3fc6e99 100644
--- a/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java
+++ b/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java
@@ -78,11 +78,12 @@
         when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
             .thenThrow(new PackageManager.NameNotFoundException());
         mCompatConfig = new CompatConfig(mBuildClassifier, mContext);
-        mPlatformCompat = new PlatformCompat(mContext, mCompatConfig);
+        mPlatformCompat = new PlatformCompat(mContext, mCompatConfig, mBuildClassifier);
         // Assume userdebug/eng non-final build
         mCompatConfig.forceNonDebuggableFinalForTest(false);
         when(mBuildClassifier.isDebuggableBuild()).thenReturn(true);
         when(mBuildClassifier.isFinalBuild()).thenReturn(false);
+        when(mBuildClassifier.platformTargetSdk()).thenReturn(30);
         LocalServices.removeServiceForTest(PackageManagerInternal.class);
         LocalServices.addService(PackageManagerInternal.class, mPackageManagerInternal);
     }
@@ -99,7 +100,7 @@
                 .addLoggingOnlyChangeWithId(7L)
                 .addOverridableChangeWithId(8L)
                 .build();
-        mPlatformCompat = new PlatformCompat(mContext, mCompatConfig);
+        mPlatformCompat = new PlatformCompat(mContext, mCompatConfig, mBuildClassifier);
         assertThat(mPlatformCompat.listAllChanges()).asList().containsExactly(
                 new CompatibilityChangeInfo(1L, "", -1, -1, false, false, "", false),
                 new CompatibilityChangeInfo(2L, "change2", -1, -1, true, false, "", false),
@@ -125,8 +126,9 @@
                 .addEnableSinceSdkChangeWithId(Build.VERSION_CODES.Q, 5L)
                 .addEnableSinceSdkChangeWithId(Build.VERSION_CODES.R, 6L)
                 .addLoggingOnlyChangeWithId(7L)
+                .addEnableSinceSdkChangeWithId(31, 8L)
                 .build();
-        mPlatformCompat = new PlatformCompat(mContext, mCompatConfig);
+        mPlatformCompat = new PlatformCompat(mContext, mCompatConfig, mBuildClassifier);
         assertThat(mPlatformCompat.listUIChanges()).asList().containsExactly(
                 new CompatibilityChangeInfo(1L, "", -1, -1, false, false, "", false),
                 new CompatibilityChangeInfo(2L, "change2", -1, -1, true, false, "", false),
@@ -144,7 +146,7 @@
                 .addEnableAfterSdkChangeWithId(Build.VERSION_CODES.O, 3L)
                 .build();
         mCompatConfig.forceNonDebuggableFinalForTest(true);
-        mPlatformCompat = new PlatformCompat(mContext, mCompatConfig);
+        mPlatformCompat = new PlatformCompat(mContext, mCompatConfig, mBuildClassifier);
 
         // Before adding overrides.
         assertThat(mPlatformCompat.isChangeEnabledByPackageName(1, PACKAGE_NAME, 0)).isTrue();
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 89435e9..77a39d8 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -107,6 +107,7 @@
 import android.telephony.data.ApnSetting;
 import android.test.MoreAsserts; // TODO(b/171932723): replace by Truth
 import android.util.ArraySet;
+import android.util.Log;
 import android.util.Pair;
 
 import androidx.test.filters.SmallTest;
@@ -154,6 +155,9 @@
 @SmallTest
 @Presubmit
 public class DevicePolicyManagerTest extends DpmTestBase {
+
+    private static final String TAG = DevicePolicyManagerTest.class.getSimpleName();
+
     private static final List<String> OWNER_SETUP_PERMISSIONS = Arrays.asList(
             permission.MANAGE_DEVICE_ADMINS, permission.MANAGE_PROFILE_AND_DEVICE_OWNERS,
             permission.MANAGE_USERS, permission.INTERACT_ACROSS_USERS_FULL);
@@ -7187,6 +7191,47 @@
         assertThat(dpm.isUsbDataSignalingEnabled()).isEqualTo(enabled);
     }
 
+    @Test
+    public void testGetPolicyExemptApps_noPermission() {
+        assertThrows(SecurityException.class, () -> dpm.getPolicyExemptApps());
+    }
+
+    @Test
+    public void testGetPolicyExemptApps_empty() {
+        grantManageDeviceAdmins();
+        mockPolicyExemptApps();
+        mockVendorPolicyExemptApps();
+
+        assertThat(dpm.getPolicyExemptApps()).isEmpty();
+    }
+
+    @Test
+    public void testGetPolicyExemptApps_baseOnly() {
+        grantManageDeviceAdmins();
+        mockPolicyExemptApps("foo");
+        mockVendorPolicyExemptApps();
+
+        assertThat(dpm.getPolicyExemptApps()).containsExactly("foo");
+    }
+
+    @Test
+    public void testGetPolicyExemptApps_vendorOnly() {
+        grantManageDeviceAdmins();
+        mockPolicyExemptApps();
+        mockVendorPolicyExemptApps("bar");
+
+        assertThat(dpm.getPolicyExemptApps()).containsExactly("bar");
+    }
+
+    @Test
+    public void testGetPolicyExemptApps_baseAndVendor() {
+        grantManageDeviceAdmins();
+        mockPolicyExemptApps("4", "23", "15", "42", "8");
+        mockVendorPolicyExemptApps("16", "15", "4");
+
+        assertThat(dpm.getPolicyExemptApps()).containsExactly("4", "8", "15", "16", "23", "42");
+    }
+
     private void setUserUnlocked(int userHandle, boolean unlocked) {
         when(getServices().userManager.isUserUnlocked(eq(userHandle))).thenReturn(unlocked);
     }
@@ -7408,4 +7453,18 @@
         return new StringParceledListSlice(Arrays.asList(s));
     }
 
+    private void grantManageDeviceAdmins() {
+        Log.d(TAG, "Granting " + permission.MANAGE_DEVICE_ADMINS);
+        mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
+    }
+
+    private void mockPolicyExemptApps(String... apps) {
+        Log.d(TAG, "Mocking R.array.policy_exempt_apps to return " + Arrays.toString(apps));
+        when(mContext.resources.getStringArray(R.array.policy_exempt_apps)).thenReturn(apps);
+    }
+
+    private void mockVendorPolicyExemptApps(String... apps) {
+        Log.d(TAG, "Mocking R.array.vendor_policy_exempt_apps to return " + Arrays.toString(apps));
+        when(mContext.resources.getStringArray(R.array.vendor_policy_exempt_apps)).thenReturn(apps);
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/PolicyVersionUpgraderTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/PolicyVersionUpgraderTest.java
index 2fe47d3..2fe2f40 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/PolicyVersionUpgraderTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/PolicyVersionUpgraderTest.java
@@ -65,9 +65,10 @@
         Map<Integer, ComponentName> mUserToComponent = new HashMap<>();
         Map<ComponentName, DeviceAdminInfo> mComponentToDeviceAdminInfo = new HashMap<>();
         File mDataDir;
+        int[] mUsers;
 
         @Override
-        public boolean isUserDeviceOwner(int userId, ComponentName who) {
+        public boolean isDeviceOwner(int userId, ComponentName who) {
             return userId == mDeviceOwnerUserId && mDeviceOwnerComponent.equals(who);
         }
 
@@ -105,6 +106,11 @@
         public Function<ComponentName, DeviceAdminInfo> getAdminInfoSupplier(int userId) {
             return componentName -> mComponentToDeviceAdminInfo.get(componentName);
         }
+
+        @Override
+        public int[] getUsersForUpgrade() {
+            return mUsers;
+        }
     }
 
     private final Context mRealTestContext = InstrumentationRegistry.getTargetContext();
@@ -126,16 +132,17 @@
         ActivityInfo activityInfo = createActivityInfo(mFakeAdmin);
         DeviceAdminInfo dai = createDeviceAdminInfo(activityInfo);
         mProvider.mComponentToDeviceAdminInfo.put(mFakeAdmin, dai);
+        mProvider.mUsers = new int[] {0};
     }
 
     @Test
     public void testSameVersionDoesNothing() throws IOException {
-        int[] users = new int[] {0};
         writeVersionToXml(DevicePolicyManagerService.DPMS_VERSION);
-        preparePoliciesFile(users[0]);
-        String oldContents = readPoliciesFile(0);
+        final int userId = mProvider.mUsers[0];
+        preparePoliciesFile(userId);
+        String oldContents = readPoliciesFile(userId);
 
-        mUpgrader.upgradePolicy(users, DevicePolicyManagerService.DPMS_VERSION);
+        mUpgrader.upgradePolicy(DevicePolicyManagerService.DPMS_VERSION);
 
         String newContents = readPoliciesFile(0);
         assertThat(newContents).isEqualTo(oldContents);
@@ -144,18 +151,18 @@
     @Test
     public void testUpgrade0To1RemovesPasswordMetrics() throws IOException, XmlPullParserException {
         final String activePasswordTag = "active-password";
-        int[] users = new int[] {0, 10};
+        mProvider.mUsers = new int[] {0, 10};
         writeVersionToXml(0);
-        for (int userId : users) {
+        for (int userId : mProvider.mUsers) {
             preparePoliciesFile(userId);
         }
         // Validate test set-up.
         assertThat(isTagPresent(readPoliciesFileToStream(0), activePasswordTag)).isTrue();
 
-        mUpgrader.upgradePolicy(users, 1);
+        mUpgrader.upgradePolicy(1);
 
         assertThat(readVersionFromXml()).isGreaterThan(1);
-        for (int user: users) {
+        for (int user: mProvider.mUsers) {
             assertThat(isTagPresent(readPoliciesFileToStream(user), activePasswordTag)).isFalse();
         }
     }
@@ -163,21 +170,22 @@
     @Test
     public void testUpgrade1To2MarksDoForPermissionControl()
             throws IOException, XmlPullParserException {
-        int[] users = new int[] {0, 10};
+        final int ownerUser = 10;
+        mProvider.mUsers = new int[] {0, ownerUser};
         writeVersionToXml(1);
-        for (int userId : users) {
+        for (int userId : mProvider.mUsers) {
             preparePoliciesFile(userId);
         }
-        mProvider.mDeviceOwnerUserId = 10;
+        mProvider.mDeviceOwnerUserId = ownerUser;
         mProvider.mDeviceOwnerComponent = mFakeAdmin;
-        mProvider.mUserToComponent.put(10, mFakeAdmin);
+        mProvider.mUserToComponent.put(ownerUser, mFakeAdmin);
 
-        mUpgrader.upgradePolicy(users, 2);
+        mUpgrader.upgradePolicy(2);
 
         assertThat(readVersionFromXml()).isEqualTo(2);
-        assertThat(getBooleanValueTag(readPoliciesFileToStream(users[0]),
+        assertThat(getBooleanValueTag(readPoliciesFileToStream(mProvider.mUsers[0]),
                 PERMISSIONS_TAG)).isFalse();
-        assertThat(getBooleanValueTag(readPoliciesFileToStream(users[1]),
+        assertThat(getBooleanValueTag(readPoliciesFileToStream(ownerUser),
                 PERMISSIONS_TAG)).isTrue();
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/graphics/fonts/UpdatableFontDirTest.java b/services/tests/servicestests/src/com/android/server/graphics/fonts/UpdatableFontDirTest.java
index 843296e..dbb415c 100644
--- a/services/tests/servicestests/src/com/android/server/graphics/fonts/UpdatableFontDirTest.java
+++ b/services/tests/servicestests/src/com/android/server/graphics/fonts/UpdatableFontDirTest.java
@@ -68,7 +68,7 @@
      */
     private static class FakeFontFileParser implements UpdatableFontDir.FontFileParser {
         @Override
-        public String getPostScriptName(File file) throws IOException {
+        public String getCanonicalFileName(File file) throws IOException {
             String content = FileUtils.readTextFile(file, 100, "");
             return content.split(",")[0];
         }
@@ -160,10 +160,10 @@
         assertThat(dirForPreparation.getSystemFontConfig().getLastModifiedTimeMillis())
                 .isEqualTo(expectedModifiedDate);
         dirForPreparation.update(Arrays.asList(
-                newFontUpdateRequest("foo,1", GOOD_SIGNATURE),
-                newFontUpdateRequest("bar,2", GOOD_SIGNATURE),
-                newFontUpdateRequest("foo,3", GOOD_SIGNATURE),
-                newFontUpdateRequest("bar,4", GOOD_SIGNATURE),
+                newFontUpdateRequest("foo.ttf,1", GOOD_SIGNATURE),
+                newFontUpdateRequest("bar.ttf,2", GOOD_SIGNATURE),
+                newFontUpdateRequest("foo.ttf,3", GOOD_SIGNATURE),
+                newFontUpdateRequest("bar.ttf,4", GOOD_SIGNATURE),
                 newAddFontFamilyRequest("<family name='foobar'>"
                         + "  <font>foo.ttf</font>"
                         + "  <font>bar.ttf</font>"
@@ -214,10 +214,10 @@
                 mConfigFile);
         dirForPreparation.loadFontFileMap();
         dirForPreparation.update(Arrays.asList(
-                newFontUpdateRequest("foo,1", GOOD_SIGNATURE),
-                newFontUpdateRequest("bar,2", GOOD_SIGNATURE),
-                newFontUpdateRequest("foo,3", GOOD_SIGNATURE),
-                newFontUpdateRequest("bar,4", GOOD_SIGNATURE),
+                newFontUpdateRequest("foo.ttf,1", GOOD_SIGNATURE),
+                newFontUpdateRequest("bar.ttf,2", GOOD_SIGNATURE),
+                newFontUpdateRequest("foo.ttf,3", GOOD_SIGNATURE),
+                newFontUpdateRequest("bar.ttf,4", GOOD_SIGNATURE),
                 newAddFontFamilyRequest("<family name='foobar'>"
                         + "  <font>foo.ttf</font>"
                         + "  <font>bar.ttf</font>"
@@ -246,10 +246,10 @@
                 mConfigFile);
         dirForPreparation.loadFontFileMap();
         dirForPreparation.update(Arrays.asList(
-                newFontUpdateRequest("foo,1", GOOD_SIGNATURE),
-                newFontUpdateRequest("bar,2", GOOD_SIGNATURE),
-                newFontUpdateRequest("foo,3", GOOD_SIGNATURE),
-                newFontUpdateRequest("bar,4", GOOD_SIGNATURE),
+                newFontUpdateRequest("foo.ttf,1", GOOD_SIGNATURE),
+                newFontUpdateRequest("bar.ttf,2", GOOD_SIGNATURE),
+                newFontUpdateRequest("foo.ttf,3", GOOD_SIGNATURE),
+                newFontUpdateRequest("bar.ttf,4", GOOD_SIGNATURE),
                 newAddFontFamilyRequest("<family name='foobar'>"
                         + "  <font>foo.ttf</font>"
                         + "  <font>bar.ttf</font>"
@@ -279,10 +279,10 @@
                 mConfigFile);
         dirForPreparation.loadFontFileMap();
         dirForPreparation.update(Arrays.asList(
-                newFontUpdateRequest("foo,1", GOOD_SIGNATURE),
-                newFontUpdateRequest("bar,2", GOOD_SIGNATURE),
-                newFontUpdateRequest("foo,3", GOOD_SIGNATURE),
-                newFontUpdateRequest("bar,4", GOOD_SIGNATURE),
+                newFontUpdateRequest("foo.ttf,1", GOOD_SIGNATURE),
+                newFontUpdateRequest("bar.ttf,2", GOOD_SIGNATURE),
+                newFontUpdateRequest("foo.ttf,3", GOOD_SIGNATURE),
+                newFontUpdateRequest("bar.ttf,4", GOOD_SIGNATURE),
                 newAddFontFamilyRequest("<family name='foobar'>"
                         + "  <font>foo.ttf</font>"
                         + "  <font>bar.ttf</font>"
@@ -332,14 +332,14 @@
                 mConfigFile);
         dirForPreparation.loadFontFileMap();
         dirForPreparation.update(Arrays.asList(
-                newFontUpdateRequest("foo,1", GOOD_SIGNATURE),
+                newFontUpdateRequest("foo.ttf,1", GOOD_SIGNATURE),
                 newAddFontFamilyRequest("<family name='foobar'>"
                         + "  <font>foo.ttf</font>"
                         + "</family>")));
         try {
             dirForPreparation.update(Arrays.asList(
-                    newFontUpdateRequest("foo,2", GOOD_SIGNATURE),
-                    newFontUpdateRequest("bar,2", "Invalid signature"),
+                    newFontUpdateRequest("foo.ttf,2", GOOD_SIGNATURE),
+                    newFontUpdateRequest("bar.ttf,2", "Invalid signature"),
                     newAddFontFamilyRequest("<family name='foobar'>"
                             + "  <font>foo.ttf</font>"
                             + "  <font>bar.ttf</font>"
@@ -372,7 +372,7 @@
                 mConfigFile);
         dir.loadFontFileMap();
 
-        dir.update(Collections.singletonList(newFontUpdateRequest("test,1", GOOD_SIGNATURE)));
+        dir.update(Collections.singletonList(newFontUpdateRequest("test.ttf,1", GOOD_SIGNATURE)));
         assertThat(dir.getFontFileMap()).containsKey("test.ttf");
         assertThat(parser.getRevision(dir.getFontFileMap().get("test.ttf"))).isEqualTo(1);
         File fontFile = dir.getFontFileMap().get("test.ttf");
@@ -390,9 +390,9 @@
                 mConfigFile);
         dir.loadFontFileMap();
 
-        dir.update(Collections.singletonList(newFontUpdateRequest("test,1", GOOD_SIGNATURE)));
+        dir.update(Collections.singletonList(newFontUpdateRequest("test.ttf,1", GOOD_SIGNATURE)));
         Map<String, File> mapBeforeUpgrade = dir.getFontFileMap();
-        dir.update(Collections.singletonList(newFontUpdateRequest("test,2", GOOD_SIGNATURE)));
+        dir.update(Collections.singletonList(newFontUpdateRequest("test.ttf,2", GOOD_SIGNATURE)));
         assertThat(dir.getFontFileMap()).containsKey("test.ttf");
         assertThat(parser.getRevision(dir.getFontFileMap().get("test.ttf"))).isEqualTo(2);
         assertThat(mapBeforeUpgrade).containsKey("test.ttf");
@@ -409,9 +409,10 @@
                 mConfigFile);
         dir.loadFontFileMap();
 
-        dir.update(Collections.singletonList(newFontUpdateRequest("test,2", GOOD_SIGNATURE)));
+        dir.update(Collections.singletonList(newFontUpdateRequest("test.ttf,2", GOOD_SIGNATURE)));
         try {
-            dir.update(Collections.singletonList(newFontUpdateRequest("test,1", GOOD_SIGNATURE)));
+            dir.update(Collections.singletonList(newFontUpdateRequest("test.ttf,1",
+                    GOOD_SIGNATURE)));
             fail("Expect SystemFontException");
         } catch (FontManagerService.SystemFontException e) {
             assertThat(e.getErrorCode()).isEqualTo(FontManager.RESULT_ERROR_DOWNGRADING);
@@ -430,8 +431,8 @@
                 mConfigFile);
         dir.loadFontFileMap();
 
-        dir.update(Collections.singletonList(newFontUpdateRequest("foo,1", GOOD_SIGNATURE)));
-        dir.update(Collections.singletonList(newFontUpdateRequest("bar,2", GOOD_SIGNATURE)));
+        dir.update(Collections.singletonList(newFontUpdateRequest("foo.ttf,1", GOOD_SIGNATURE)));
+        dir.update(Collections.singletonList(newFontUpdateRequest("bar.ttf,2", GOOD_SIGNATURE)));
         assertThat(dir.getFontFileMap()).containsKey("foo.ttf");
         assertThat(parser.getRevision(dir.getFontFileMap().get("foo.ttf"))).isEqualTo(1);
         assertThat(dir.getFontFileMap()).containsKey("bar.ttf");
@@ -448,8 +449,8 @@
         dir.loadFontFileMap();
 
         dir.update(Arrays.asList(
-                newFontUpdateRequest("foo,1", GOOD_SIGNATURE),
-                newFontUpdateRequest("bar,2", GOOD_SIGNATURE)));
+                newFontUpdateRequest("foo.ttf,1", GOOD_SIGNATURE),
+                newFontUpdateRequest("bar.ttf,2", GOOD_SIGNATURE)));
         assertThat(dir.getFontFileMap()).containsKey("foo.ttf");
         assertThat(parser.getRevision(dir.getFontFileMap().get("foo.ttf"))).isEqualTo(1);
         assertThat(dir.getFontFileMap()).containsKey("bar.ttf");
@@ -467,7 +468,8 @@
 
         try {
             dir.update(
-                    Collections.singletonList(newFontUpdateRequest("test,1", "Invalid signature")));
+                    Collections.singletonList(newFontUpdateRequest("test.ttf,1",
+                            "Invalid signature")));
             fail("Expect SystemFontException");
         } catch (FontManagerService.SystemFontException e) {
             assertThat(e.getErrorCode())
@@ -480,14 +482,15 @@
     public void installFontFile_olderThanPreinstalledFont() throws Exception {
         FakeFontFileParser parser = new FakeFontFileParser();
         FakeFsverityUtil fakeFsverityUtil = new FakeFsverityUtil();
-        FileUtils.stringToFile(new File(mPreinstalledFontDirs.get(0), "test.ttf"), "test,1");
+        FileUtils.stringToFile(new File(mPreinstalledFontDirs.get(0), "test.ttf"), "test.ttf,1");
         UpdatableFontDir dir = new UpdatableFontDir(
                 mUpdatableFontFilesDir, mPreinstalledFontDirs, parser, fakeFsverityUtil,
                 mConfigFile);
         dir.loadFontFileMap();
 
         try {
-            dir.update(Collections.singletonList(newFontUpdateRequest("test,1", GOOD_SIGNATURE)));
+            dir.update(Collections.singletonList(newFontUpdateRequest("test.ttf,1",
+                    GOOD_SIGNATURE)));
             fail("Expect SystemFontException");
         } catch (FontManagerService.SystemFontException e) {
             assertThat(e.getErrorCode()).isEqualTo(FontManager.RESULT_ERROR_DOWNGRADING);
@@ -500,7 +503,7 @@
         long expectedModifiedDate = 1234567890;
         FakeFontFileParser parser = new FakeFontFileParser();
         FakeFsverityUtil fakeFsverityUtil = new FakeFsverityUtil();
-        FileUtils.stringToFile(new File(mPreinstalledFontDirs.get(0), "test.ttf"), "test,1");
+        FileUtils.stringToFile(new File(mPreinstalledFontDirs.get(0), "test.ttf"), "test.ttf,1");
 
         File readonlyDir = new File(mCacheDir, "readonly");
         assertThat(readonlyDir.mkdir()).isTrue();
@@ -519,7 +522,8 @@
 
             try {
                 dir.update(
-                        Collections.singletonList(newFontUpdateRequest("test,2", GOOD_SIGNATURE)));
+                        Collections.singletonList(newFontUpdateRequest("test.ttf,2",
+                                GOOD_SIGNATURE)));
             } catch (FontManagerService.SystemFontException e) {
                 assertThat(e.getErrorCode())
                         .isEqualTo(FontManager.RESULT_ERROR_FAILED_UPDATE_CONFIG);
@@ -539,7 +543,7 @@
                 mUpdatableFontFilesDir, mPreinstalledFontDirs,
                 new UpdatableFontDir.FontFileParser() {
                     @Override
-                    public String getPostScriptName(File file) throws IOException {
+                    public String getCanonicalFileName(File file) throws IOException {
                         return null;
                     }
 
@@ -551,7 +555,8 @@
         dir.loadFontFileMap();
 
         try {
-            dir.update(Collections.singletonList(newFontUpdateRequest("foo,1", GOOD_SIGNATURE)));
+            dir.update(Collections.singletonList(newFontUpdateRequest("foo.ttf,1",
+                    GOOD_SIGNATURE)));
             fail("Expect SystemFontException");
         } catch (FontManagerService.SystemFontException e) {
             assertThat(e.getErrorCode())
@@ -567,7 +572,7 @@
                 mUpdatableFontFilesDir, mPreinstalledFontDirs,
                 new UpdatableFontDir.FontFileParser() {
                     @Override
-                    public String getPostScriptName(File file) throws IOException {
+                    public String getCanonicalFileName(File file) throws IOException {
                         throw new IOException();
                     }
 
@@ -579,7 +584,8 @@
         dir.loadFontFileMap();
 
         try {
-            dir.update(Collections.singletonList(newFontUpdateRequest("foo,1", GOOD_SIGNATURE)));
+            dir.update(Collections.singletonList(newFontUpdateRequest("foo.ttf,1",
+                    GOOD_SIGNATURE)));
             fail("Expect SystemFontException");
         } catch (FontManagerService.SystemFontException e) {
             assertThat(e.getErrorCode())
@@ -615,7 +621,8 @@
         dir.loadFontFileMap();
 
         try {
-            dir.update(Collections.singletonList(newFontUpdateRequest("foo,1", GOOD_SIGNATURE)));
+            dir.update(Collections.singletonList(newFontUpdateRequest("foo.ttf,1",
+                    GOOD_SIGNATURE)));
             fail("Expect SystemFontException");
         } catch (FontManagerService.SystemFontException e) {
             assertThat(e.getErrorCode())
@@ -633,11 +640,11 @@
                 mConfigFile);
         dir.loadFontFileMap();
 
-        dir.update(Collections.singletonList(newFontUpdateRequest("foo,1", GOOD_SIGNATURE)));
+        dir.update(Collections.singletonList(newFontUpdateRequest("foo.ttf,1", GOOD_SIGNATURE)));
         try {
             dir.update(Arrays.asList(
-                    newFontUpdateRequest("foo,2", GOOD_SIGNATURE),
-                    newFontUpdateRequest("bar,2", "Invalid signature")));
+                    newFontUpdateRequest("foo.ttf,2", GOOD_SIGNATURE),
+                    newFontUpdateRequest("bar.ttf,2", "Invalid signature")));
             fail("Batch update with invalid signature should fail");
         } catch (FontManagerService.SystemFontException e) {
             // Expected
@@ -657,7 +664,7 @@
         dir.loadFontFileMap();
 
         dir.update(Arrays.asList(
-                newFontUpdateRequest("test,1", GOOD_SIGNATURE),
+                newFontUpdateRequest("test.ttf,1", GOOD_SIGNATURE),
                 newAddFontFamilyRequest("<family name='test'>"
                         + "  <font>test.ttf</font>"
                         + "</family>")));
@@ -680,7 +687,7 @@
 
         try {
             dir.update(Arrays.asList(
-                    newFontUpdateRequest("test,1", GOOD_SIGNATURE),
+                    newFontUpdateRequest("test.ttf,1", GOOD_SIGNATURE),
                     newAddFontFamilyRequest("<family lang='en'>"
                             + "  <font>test.ttf</font>"
                             + "</family>")));
@@ -722,7 +729,7 @@
         assertNamedFamilyExists(dir.getSystemFontConfig(), "monospace");
 
         dir.update(Arrays.asList(
-                newFontUpdateRequest("test,1", GOOD_SIGNATURE),
+                newFontUpdateRequest("test.ttf,1", GOOD_SIGNATURE),
                 // Updating an existing font family.
                 newAddFontFamilyRequest("<family name='monospace'>"
                         + "  <font>test.ttf</font>"
@@ -755,7 +762,7 @@
         assertThat(firstFontFamily.getName()).isNotEmpty();
 
         dir.update(Arrays.asList(
-                newFontUpdateRequest("test,1", GOOD_SIGNATURE),
+                newFontUpdateRequest("test.ttf,1", GOOD_SIGNATURE),
                 newAddFontFamilyRequest("<family name='" + firstFontFamily.getName() + "'>"
                         + "  <font>test.ttf</font>"
                         + "</family>")));
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/FakeHdmiCecConfig.java b/services/tests/servicestests/src/com/android/server/hdmi/FakeHdmiCecConfig.java
index 137bd88..375704e 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/FakeHdmiCecConfig.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/FakeHdmiCecConfig.java
@@ -16,183 +16,206 @@
 
 package com.android.server.hdmi;
 
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+
 import android.annotation.NonNull;
 import android.content.Context;
-import android.util.Slog;
+import android.content.ContextWrapper;
+import android.content.res.Resources;
 
-import com.android.server.hdmi.cec.config.CecSettings;
-import com.android.server.hdmi.cec.config.XmlParser;
-
-import org.xmlpull.v1.XmlPullParserException;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-
-import javax.xml.datatype.DatatypeConfigurationException;
+import com.android.internal.R;
 
 /**
- * Fake class which loads default system configuration with user-configurable
+ * Fake class which stubs default system configuration with user-configurable
  * settings (useful for testing).
  */
 final class FakeHdmiCecConfig extends HdmiCecConfig {
     private static final String TAG = "FakeHdmiCecConfig";
 
-    private static final String SYSTEM_CONFIG_XML =
-            "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
-                    + "<cec-settings>"
-                    + "  <setting name=\"send_standby_on_sleep\""
-                    + "           value-type=\"string\""
-                    + "           user-configurable=\"true\">"
-                    + "    <allowed-values>"
-                    + "      <value string-value=\"to_tv\" />"
-                    + "      <value string-value=\"broadcast\" />"
-                    + "      <value string-value=\"none\" />"
-                    + "    </allowed-values>"
-                    + "    <default-value string-value=\"to_tv\" />"
-                    + "  </setting>"
-                    + "  <setting name=\"power_state_change_on_active_source_lost\""
-                    + "           value-type=\"string\""
-                    + "           user-configurable=\"true\">"
-                    + "    <allowed-values>"
-                    + "      <value string-value=\"none\" />"
-                    + "      <value string-value=\"standby_now\" />"
-                    + "    </allowed-values>"
-                    + "    <default-value string-value=\"none\" />"
-                    + "  </setting>"
-                    + "  <setting name=\"hdmi_cec_enabled\""
-                    + "           value-type=\"int\""
-                    + "           user-configurable=\"true\">"
-                    + "    <allowed-values>"
-                    + "      <value int-value=\"0\" />"
-                    + "      <value int-value=\"1\" />"
-                    + "    </allowed-values>"
-                    + "    <default-value int-value=\"1\" />"
-                    + "  </setting>"
-                    + "  <setting name=\"hdmi_cec_version\""
-                    + "           value-type=\"int\""
-                    + "           user-configurable=\"true\">"
-                    + "    <allowed-values>"
-                    + "      <value int-value=\"0x05\" />"
-                    + "      <value int-value=\"0x06\" />"
-                    + "    </allowed-values>"
-                    + "    <default-value int-value=\"0x05\" />"
-                    + "  </setting>"
-                    + "  <setting name=\"system_audio_mode_muting\""
-                    + "           value-type=\"int\""
-                    + "           user-configurable=\"true\">"
-                    + "    <allowed-values>"
-                    + "      <value int-value=\"0\" />"
-                    + "      <value int-value=\"1\" />"
-                    + "    </allowed-values>"
-                    + "    <default-value int-value=\"1\" />"
-                    + "  </setting>"
-                    + "  <setting name=\"hdmi_cec_enabled\""
-                    + "           value-type=\"int\""
-                    + "           user-configurable=\"true\">"
-                    + "    <allowed-values>"
-                    + "      <value int-value=\"0\" />"
-                    + "      <value int-value=\"1\" />"
-                    + "    </allowed-values>"
-                    + "    <default-value int-value=\"1\" />"
-                    + "  </setting>"
-                    + "  <setting name=\"volume_control_enabled\""
-                    + "           value-type=\"int\""
-                    + "           user-configurable=\"true\">"
-                    + "    <allowed-values>"
-                    + "      <value int-value=\"0\" />"
-                    + "      <value int-value=\"1\" />"
-                    + "    </allowed-values>"
-                    + "    <default-value int-value=\"1\" />"
-                    + "  </setting>"
-                    + "  <setting name=\"tv_wake_on_one_touch_play\""
-                    + "           value-type=\"int\""
-                    + "           user-configurable=\"true\">"
-                    + "    <allowed-values>"
-                    + "      <value int-value=\"0\" />"
-                    + "      <value int-value=\"1\" />"
-                    + "    </allowed-values>"
-                    + "    <default-value int-value=\"1\" />"
-                    + "  </setting>"
-                    + "  <setting name=\"tv_send_standby_on_sleep\""
-                    + "           value-type=\"int\""
-                    + "           user-configurable=\"true\">"
-                    + "    <allowed-values>"
-                    + "      <value int-value=\"0\" />"
-                    + "      <value int-value=\"1\" />"
-                    + "    </allowed-values>"
-                    + "    <default-value int-value=\"1\" />"
-                    + "  </setting>"
-                    + "  <setting name=\"rc_profile_tv\""
-                    + "           value-type=\"int\""
-                    + "           user-configurable=\"false\">"
-                    + "    <allowed-values>"
-                    + "      <value int-value=\"0x0\" />"
-                    + "      <value int-value=\"0x2\" />"
-                    + "      <value int-value=\"0x6\" />"
-                    + "      <value int-value=\"0xA\" />"
-                    + "      <value int-value=\"0xE\" />"
-                    + "    </allowed-values>"
-                    + "    <default-value int-value=\"0x0\" />"
-                    + "  </setting>"
-                    + "  <setting name=\"rc_profile_source_handles_root_menu\""
-                    + "           value-type=\"int\""
-                    + "           user-configurable=\"false\">"
-                    + "    <allowed-values>"
-                    + "      <value int-value=\"0\" />"
-                    + "      <value int-value=\"1\" />"
-                    + "    </allowed-values>"
-                    + "    <default-value int-value=\"1\" />"
-                    + "  </setting>"
-                    + "  <setting name=\"rc_profile_source_handles_setup_menu\""
-                    + "           value-type=\"int\""
-                    + "           user-configurable=\"false\">"
-                    + "    <allowed-values>"
-                    + "      <value int-value=\"0\" />"
-                    + "      <value int-value=\"1\" />"
-                    + "    </allowed-values>"
-                    + "    <default-value int-value=\"1\" />"
-                    + "  </setting>"
-                    + "  <setting name=\"rc_profile_source_handles_contents_menu\""
-                    + "           value-type=\"int\""
-                    + "           user-configurable=\"false\">"
-                    + "    <allowed-values>"
-                    + "      <value int-value=\"0\" />"
-                    + "      <value int-value=\"1\" />"
-                    + "    </allowed-values>"
-                    + "    <default-value int-value=\"0\" />"
-                    + "  </setting>"
-                    + "  <setting name=\"rc_profile_source_handles_top_menu\""
-                    + "           value-type=\"int\""
-                    + "           user-configurable=\"false\">"
-                    + "    <allowed-values>"
-                    + "      <value int-value=\"0\" />"
-                    + "      <value int-value=\"1\" />"
-                    + "    </allowed-values>"
-                    + "    <default-value int-value=\"0\" />"
-                    + "  </setting>"
-                    + "  <setting name=\"rc_profile_source_handles_media_context_sensitive_menu\""
-                    + "           value-type=\"int\""
-                    + "           user-configurable=\"false\">"
-                    + "    <allowed-values>"
-                    + "      <value int-value=\"0\" />"
-                    + "      <value int-value=\"1\" />"
-                    + "    </allowed-values>"
-                    + "    <default-value int-value=\"0\" />"
-                    + "  </setting>"
-                    + "</cec-settings>";
-
-    FakeHdmiCecConfig(@NonNull Context context) {
-        super(context, new StorageAdapter(context), parseFromString(SYSTEM_CONFIG_XML), null);
+    public static Context buildContext(Context context) {
+        Context contextSpy = spy(new ContextWrapper(context));
+        doReturn(buildResources(context)).when(contextSpy).getResources();
+        return contextSpy;
     }
 
-    private static CecSettings parseFromString(@NonNull String configXml) {
-        CecSettings config = null;
-        try {
-            config = XmlParser.read(
-                    new ByteArrayInputStream(configXml.getBytes()));
-        } catch (IOException | DatatypeConfigurationException | XmlPullParserException e) {
-            Slog.e(TAG, "Encountered an error while reading/parsing CEC config strings", e);
-        }
-        return config;
+    private static Resources buildResources(Context context) {
+        Resources resources = spy(context.getResources());
+
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecHdmiCecEnabled_userConfigurable);
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecHdmiCecControlEnabled_allowed);
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecHdmiCecControlEnabled_default);
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecHdmiCecControlDisabled_allowed);
+        doReturn(false).when(resources).getBoolean(
+                R.bool.config_cecHdmiCecControlDisabled_default);
+
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecHdmiCecVersion_userConfigurable);
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecHdmiCecVersion14b_allowed);
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecHdmiCecVersion14b_default);
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecHdmiCecVersion20_allowed);
+        doReturn(false).when(resources).getBoolean(
+                R.bool.config_cecHdmiCecVersion20_default);
+
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecSendStandbyOnSleep_userConfigurable);
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecPowerControlModeTv_allowed);
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecPowerControlModeTv_default);
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecPowerControlModeBroadcast_allowed);
+        doReturn(false).when(resources).getBoolean(
+                R.bool.config_cecPowerControlModeBroadcast_default);
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecPowerControlModeNone_allowed);
+        doReturn(false).when(resources).getBoolean(
+                R.bool.config_cecPowerControlModeNone_default);
+
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecPowerStateChangeOnActiveSourceLost_userConfigurable);
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecPowerStateChangeOnActiveSourceLostNone_allowed);
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecPowerStateChangeOnActiveSourceLostNone_default);
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecPowerStateChangeOnActiveSourceLostStandbyNow_allowed);
+        doReturn(false).when(resources).getBoolean(
+                R.bool.config_cecPowerStateChangeOnActiveSourceLostStandbyNow_default);
+
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecSystemAudioModeMuting_userConfigurable);
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecSystemAudioModeMutingEnabled_allowed);
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecSystemAudioModeMutingEnabled_default);
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecSystemAudioModeMutingDisabled_allowed);
+        doReturn(false).when(resources).getBoolean(
+                R.bool.config_cecSystemAudioModeMutingDisabled_default);
+
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecVolumeControlMode_userConfigurable);
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecVolumeControlModeEnabled_allowed);
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecVolumeControlModeEnabled_default);
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecVolumeControlModeDisabled_allowed);
+        doReturn(false).when(resources).getBoolean(
+                R.bool.config_cecVolumeControlModeDisabled_default);
+
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecTvWakeOnOneTouchPlay_userConfigurable);
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecTvWakeOnOneTouchPlayEnabled_allowed);
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecTvWakeOnOneTouchPlayEnabled_default);
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecTvWakeOnOneTouchPlayDisabled_allowed);
+        doReturn(false).when(resources).getBoolean(
+                R.bool.config_cecTvWakeOnOneTouchPlayDisabled_default);
+
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecTvSendStandbyOnSleep_userConfigurable);
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecTvSendStandbyOnSleepEnabled_allowed);
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecTvSendStandbyOnSleepEnabled_default);
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecTvSendStandbyOnSleepDisabled_allowed);
+        doReturn(false).when(resources).getBoolean(
+                R.bool.config_cecTvSendStandbyOnSleepDisabled_default);
+
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecRcProfileTv_userConfigurable);
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecRcProfileTvNone_allowed);
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecRcProfileTvNone_default);
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecRcProfileTvOne_allowed);
+        doReturn(false).when(resources).getBoolean(
+                R.bool.config_cecRcProfileTvOne_default);
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecRcProfileTvTwo_allowed);
+        doReturn(false).when(resources).getBoolean(
+                R.bool.config_cecRcProfileTvTwo_default);
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecRcProfileTvThree_allowed);
+        doReturn(false).when(resources).getBoolean(
+                R.bool.config_cecRcProfileTvThree_default);
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecRcProfileTvFour_allowed);
+        doReturn(false).when(resources).getBoolean(
+                R.bool.config_cecRcProfileTvFour_default);
+
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecRcProfileSourceRootMenu_userConfigurable);
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecRcProfileSourceRootMenuHandled_allowed);
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecRcProfileSourceRootMenuHandled_default);
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecRcProfileSourceRootMenuNotHandled_allowed);
+        doReturn(false).when(resources).getBoolean(
+                R.bool.config_cecRcProfileSourceRootMenuNotHandled_default);
+
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecRcProfileSourceSetupMenu_userConfigurable);
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecRcProfileSourceSetupMenuHandled_allowed);
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecRcProfileSourceSetupMenuHandled_default);
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecRcProfileSourceSetupMenuNotHandled_allowed);
+        doReturn(false).when(resources).getBoolean(
+                R.bool.config_cecRcProfileSourceSetupMenuNotHandled_default);
+
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecRcProfileSourceContentsMenu_userConfigurable);
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecRcProfileSourceContentsMenuHandled_allowed);
+        doReturn(false).when(resources).getBoolean(
+                R.bool.config_cecRcProfileSourceContentsMenuHandled_default);
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecRcProfileSourceContentsMenuNotHandled_allowed);
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecRcProfileSourceContentsMenuNotHandled_default);
+
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecRcProfileSourceTopMenu_userConfigurable);
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecRcProfileSourceTopMenuHandled_allowed);
+        doReturn(false).when(resources).getBoolean(
+                R.bool.config_cecRcProfileSourceTopMenuHandled_default);
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecRcProfileSourceTopMenuNotHandled_allowed);
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecRcProfileSourceTopMenuNotHandled_default);
+
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecRcProfileSourceMediaContextSensitiveMenu_userConfigurable);
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecRcProfileSourceMediaContextSensitiveMenuHandled_allowed);
+        doReturn(false).when(resources).getBoolean(
+                R.bool.config_cecRcProfileSourceMediaContextSensitiveMenuHandled_default);
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecRcProfileSourceMediaContextSensitiveMenuNotHandled_allowed);
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecRcProfileSourceMediaContextSensitiveMenuNotHandled_default);
+
+        return resources;
+    }
+
+    FakeHdmiCecConfig(@NonNull Context context) {
+        super(buildContext(context), new StorageAdapter(context));
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecConfigTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecConfigTest.java
index 798cf85..c834510 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecConfigTest.java
@@ -20,6 +20,7 @@
 import static junit.framework.Assert.assertTrue;
 import static junit.framework.Assert.fail;
 
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -27,6 +28,7 @@
 
 import android.annotation.NonNull;
 import android.content.Context;
+import android.content.res.Resources;
 import android.hardware.hdmi.HdmiControlManager;
 import android.os.test.TestLooper;
 import android.platform.test.annotations.Presubmit;
@@ -35,6 +37,8 @@
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
 
+import com.android.internal.R;
+
 import org.junit.Before;
 import org.junit.Ignore;
 import org.junit.Test;
@@ -61,265 +65,118 @@
     @Mock private HdmiCecConfig.StorageAdapter mStorageAdapter;
     @Mock private HdmiCecConfig.SettingChangeListener mSettingChangeListener;
 
+    private void setBooleanResource(int resId, boolean value) {
+        Resources resources = mContext.getResources();
+        doReturn(value).when(resources).getBoolean(resId);
+    }
+
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
-        mContext = InstrumentationRegistry.getTargetContext();
-    }
-
-    @Test
-    public void getAllCecSettings_NoMasterXml() {
-        HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
-                mContext, mStorageAdapter, null, null);
-        assertThat(hdmiCecConfig.getAllSettings()).isEmpty();
-    }
-
-    @Test
-    public void getAllCecSettings_Empty() {
-        HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
-                mContext, mStorageAdapter,
-                "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
-                + "<cec-settings>"
-                + "</cec-settings>", null);
-        assertThat(hdmiCecConfig.getAllSettings()).isEmpty();
+        mContext = FakeHdmiCecConfig.buildContext(InstrumentationRegistry.getTargetContext());
     }
 
     @Test
     public void getAllCecSettings_BasicSanity() {
-        HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
-                mContext, mStorageAdapter,
-                "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
-                + "<cec-settings>"
-                + "  <setting name=\"hdmi_cec_enabled\""
-                + "           value-type=\"int\""
-                + "           user-configurable=\"true\">"
-                + "    <allowed-values>"
-                + "      <value int-value=\"0\" />"
-                + "      <value int-value=\"1\" />"
-                + "    </allowed-values>"
-                + "    <default-value int-value=\"1\" />"
-                + "  </setting>"
-                + "  <setting name=\"send_standby_on_sleep\""
-                + "           value-type=\"string\""
-                + "           user-configurable=\"false\">"
-                + "    <allowed-values>"
-                + "      <value string-value=\"to_tv\" />"
-                + "      <value string-value=\"broadcast\" />"
-                + "      <value string-value=\"none\" />"
-                + "    </allowed-values>"
-                + "    <default-value string-value=\"to_tv\" />"
-                + "  </setting>"
-                + "</cec-settings>", null);
+        HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
         assertThat(hdmiCecConfig.getAllSettings())
                 .containsExactly(HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
-                                 HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE);
+                    HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
+                    HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE,
+                    HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST,
+                    HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING,
+                    HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE,
+                    HdmiControlManager.CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY,
+                    HdmiControlManager.CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP,
+                    HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_TV,
+                    HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_ROOT_MENU,
+                    HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_SETUP_MENU,
+                    HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_CONTENTS_MENU,
+                    HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_TOP_MENU,
+                    HdmiControlManager
+                        .CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_MEDIA_CONTEXT_SENSITIVE_MENU);
     }
 
     @Test
-    public void getUserCecSettings_NoMasterXml() {
-        HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
-                mContext, mStorageAdapter, null, null);
-        assertThat(hdmiCecConfig.getUserSettings()).isEmpty();
-    }
-
-    @Test
-    public void getUserCecSettings_Empty() {
-        HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
-                mContext, mStorageAdapter,
-                "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
-                + "<cec-settings>"
-                + "</cec-settings>", null);
-        assertThat(hdmiCecConfig.getUserSettings()).isEmpty();
-    }
-
-    @Test
-    public void getUserCecSettings_OnlyMasterXml() {
-        HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
-                mContext, mStorageAdapter,
-                "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
-                + "<cec-settings>"
-                + "  <setting name=\"hdmi_cec_enabled\""
-                + "           value-type=\"int\""
-                + "           user-configurable=\"true\">"
-                + "    <allowed-values>"
-                + "      <value int-value=\"0\" />"
-                + "      <value int-value=\"1\" />"
-                + "    </allowed-values>"
-                + "    <default-value int-value=\"1\" />"
-                + "  </setting>"
-                + "  <setting name=\"send_standby_on_sleep\""
-                + "           value-type=\"string\""
-                + "           user-configurable=\"true\">"
-                + "    <allowed-values>"
-                + "      <value string-value=\"to_tv\" />"
-                + "      <value string-value=\"broadcast\" />"
-                + "      <value string-value=\"none\" />"
-                + "    </allowed-values>"
-                + "    <default-value string-value=\"to_tv\" />"
-                + "  </setting>"
-                + "</cec-settings>", null);
+    public void getUserCecSettings_BasicSanity() {
+        HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
         assertThat(hdmiCecConfig.getUserSettings())
                 .containsExactly(HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
-                                 HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE);
+                    HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
+                    HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE,
+                    HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST,
+                    HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING,
+                    HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE,
+                    HdmiControlManager.CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY,
+                    HdmiControlManager.CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP,
+                    HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_TV,
+                    HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_ROOT_MENU,
+                    HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_SETUP_MENU,
+                    HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_CONTENTS_MENU,
+                    HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_TOP_MENU,
+                    HdmiControlManager
+                        .CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_MEDIA_CONTEXT_SENSITIVE_MENU);
     }
 
     @Test
     public void getUserCecSettings_WithOverride() {
-        HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
-                mContext, mStorageAdapter,
-                "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
-                + "<cec-settings>"
-                + "  <setting name=\"hdmi_cec_enabled\""
-                + "           value-type=\"int\""
-                + "           user-configurable=\"true\">"
-                + "    <allowed-values>"
-                + "      <value int-value=\"0\" />"
-                + "      <value int-value=\"1\" />"
-                + "    </allowed-values>"
-                + "    <default-value int-value=\"1\" />"
-                + "  </setting>"
-                + "  <setting name=\"send_standby_on_sleep\""
-                + "           value-type=\"string\""
-                + "           user-configurable=\"true\">"
-                + "    <allowed-values>"
-                + "      <value string-value=\"to_tv\" />"
-                + "      <value string-value=\"broadcast\" />"
-                + "      <value string-value=\"none\" />"
-                + "    </allowed-values>"
-                + "    <default-value string-value=\"to_tv\" />"
-                + "  </setting>"
-                + "</cec-settings>",
-                "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
-                + "<cec-settings>"
-                + "  <setting name=\"send_standby_on_sleep\""
-                + "           value-type=\"string\""
-                + "           user-configurable=\"false\">"
-                + "    <allowed-values>"
-                + "      <value string-value=\"to_tv\" />"
-                + "      <value string-value=\"broadcast\" />"
-                + "      <value string-value=\"none\" />"
-                + "    </allowed-values>"
-                + "    <default-value string-value=\"to_tv\" />"
-                + "  </setting>"
-                + "</cec-settings>");
+        setBooleanResource(R.bool.config_cecHdmiCecEnabled_userConfigurable, false);
+        HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
         assertThat(hdmiCecConfig.getUserSettings())
-                .containsExactly(HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED);
-    }
-
-    @Test
-    public void isStringValueType_NoMasterXml() {
-        HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
-                mContext, mStorageAdapter, null, null);
-        assertThrows(IllegalArgumentException.class,
-                () -> hdmiCecConfig.isStringValueType("foo"));
+                .containsExactly(HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
+                    HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE,
+                    HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST,
+                    HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING,
+                    HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE,
+                    HdmiControlManager.CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY,
+                    HdmiControlManager.CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP,
+                    HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_TV,
+                    HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_ROOT_MENU,
+                    HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_SETUP_MENU,
+                    HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_CONTENTS_MENU,
+                    HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_TOP_MENU,
+                    HdmiControlManager
+                        .CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_MEDIA_CONTEXT_SENSITIVE_MENU);
     }
 
     @Test
     public void isStringValueType_InvalidSetting() {
-        HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
-                mContext, mStorageAdapter,
-                "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
-                + "<cec-settings>"
-                + "</cec-settings>", null);
+        HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
         assertThrows(IllegalArgumentException.class,
                 () -> hdmiCecConfig.isStringValueType("foo"));
     }
 
     @Test
     public void isStringValueType_BasicSanity() {
-        HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
-                mContext, mStorageAdapter,
-                "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
-                + "<cec-settings>"
-                + "  <setting name=\"send_standby_on_sleep\""
-                + "           value-type=\"string\""
-                + "           user-configurable=\"true\">"
-                + "    <allowed-values>"
-                + "      <value string-value=\"to_tv\" />"
-                + "      <value string-value=\"broadcast\" />"
-                + "      <value string-value=\"none\" />"
-                + "    </allowed-values>"
-                + "    <default-value string-value=\"to_tv\" />"
-                + "  </setting>"
-                + "</cec-settings>", null);
+        HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
         assertTrue(hdmiCecConfig.isStringValueType(
                     HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE));
     }
 
     @Test
-    public void isIntValueType_NoMasterXml() {
-        HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
-                mContext, mStorageAdapter, null, null);
-        assertThrows(IllegalArgumentException.class,
-                () -> hdmiCecConfig.isIntValueType("foo"));
-    }
-
-    @Test
     public void isIntValueType_InvalidSetting() {
-        HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
-                mContext, mStorageAdapter,
-                "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
-                + "<cec-settings>"
-                + "</cec-settings>", null);
+        HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
         assertThrows(IllegalArgumentException.class,
                 () -> hdmiCecConfig.isIntValueType("foo"));
     }
 
     @Test
     public void isIntValueType_BasicSanity() {
-        HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
-                mContext, mStorageAdapter,
-                "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
-                + "<cec-settings>"
-                + "  <setting name=\"hdmi_cec_enabled\""
-                + "           value-type=\"int\""
-                + "           user-configurable=\"true\">"
-                + "    <allowed-values>"
-                + "      <value int-value=\"0\" />"
-                + "      <value int-value=\"1\" />"
-                + "    </allowed-values>"
-                + "    <default-value int-value=\"1\" />"
-                + "  </setting>"
-                + "</cec-settings>", null);
+        HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
         assertTrue(hdmiCecConfig.isIntValueType(
                     HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED));
     }
 
     @Test
-    public void getAllowedStringValues_NoMasterXml() {
-        HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
-                mContext, mStorageAdapter, null, null);
-        assertThrows(IllegalArgumentException.class,
-                () -> hdmiCecConfig.getAllowedStringValues("foo"));
-    }
-
-    @Test
     public void getAllowedStringValues_InvalidSetting() {
-        HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
-                mContext, mStorageAdapter,
-                "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
-                + "<cec-settings>"
-                + "</cec-settings>", null);
+        HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
         assertThrows(IllegalArgumentException.class,
                 () -> hdmiCecConfig.getAllowedStringValues("foo"));
     }
 
     @Test
     public void getAllowedStringValues_InvalidValueType() {
-        HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
-                mContext, mStorageAdapter,
-                "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
-                + "<cec-settings>"
-                + "  <setting name=\"hdmi_cec_enabled\""
-                + "           value-type=\"int\""
-                + "           user-configurable=\"true\">"
-                + "    <allowed-values>"
-                + "      <value int-value=\"0\" />"
-                + "      <value int-value=\"1\" />"
-                + "    </allowed-values>"
-                + "    <default-value int-value=\"1\" />"
-                + "  </setting>"
-                + "</cec-settings>", null);
+        HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
         assertThrows(IllegalArgumentException.class,
                 () -> hdmiCecConfig.getAllowedStringValues(
                     HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED));
@@ -327,21 +184,7 @@
 
     @Test
     public void getAllowedStringValues_BasicSanity() {
-        HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
-                mContext, mStorageAdapter,
-                "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
-                + "<cec-settings>"
-                + "  <setting name=\"send_standby_on_sleep\""
-                + "           value-type=\"string\""
-                + "           user-configurable=\"true\">"
-                + "    <allowed-values>"
-                + "      <value string-value=\"to_tv\" />"
-                + "      <value string-value=\"broadcast\" />"
-                + "      <value string-value=\"none\" />"
-                + "    </allowed-values>"
-                + "    <default-value string-value=\"to_tv\" />"
-                + "  </setting>"
-                + "</cec-settings>", null);
+        HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
         assertThat(hdmiCecConfig.getAllowedStringValues(
                     HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE))
                 .containsExactly(HdmiControlManager.POWER_CONTROL_MODE_TV,
@@ -350,41 +193,25 @@
     }
 
     @Test
-    public void getAllowedIntValues_NoMasterXml() {
-        HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
-                mContext, mStorageAdapter, null, null);
-        assertThrows(IllegalArgumentException.class,
-                () -> hdmiCecConfig.getAllowedIntValues("foo"));
+    public void getAllowedStringValues_WithOverride() {
+        setBooleanResource(R.bool.config_cecPowerControlModeNone_allowed, false);
+        HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
+        assertThat(hdmiCecConfig.getAllowedStringValues(
+                    HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE))
+                .containsExactly(HdmiControlManager.POWER_CONTROL_MODE_TV,
+                                 HdmiControlManager.POWER_CONTROL_MODE_BROADCAST);
     }
 
     @Test
     public void getAllowedIntValues_InvalidSetting() {
-        HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
-                mContext, mStorageAdapter,
-                "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
-                + "<cec-settings>"
-                + "</cec-settings>", null);
+        HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
         assertThrows(IllegalArgumentException.class,
                 () -> hdmiCecConfig.getAllowedIntValues("foo"));
     }
 
     @Test
     public void getAllowedIntValues_InvalidValueType() {
-        HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
-                mContext, mStorageAdapter,
-                "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
-                + "<cec-settings>"
-                + "  <setting name=\"send_standby_on_sleep\""
-                + "           value-type=\"string\""
-                + "           user-configurable=\"true\">"
-                + "    <allowed-values>"
-                + "      <value string-value=\"to_tv\" />"
-                + "      <value string-value=\"broadcast\" />"
-                + "      <value string-value=\"none\" />"
-                + "    </allowed-values>"
-                + "    <default-value string-value=\"to_tv\" />"
-                + "  </setting>"
-                + "</cec-settings>", null);
+        HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
         assertThrows(IllegalArgumentException.class,
                 () -> hdmiCecConfig.getAllowedIntValues(
                     HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE));
@@ -392,20 +219,7 @@
 
     @Test
     public void getAllowedIntValues_BasicSanity() {
-        HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
-                mContext, mStorageAdapter,
-                "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
-                + "<cec-settings>"
-                + "  <setting name=\"hdmi_cec_enabled\""
-                + "           value-type=\"int\""
-                + "           user-configurable=\"true\">"
-                + "    <allowed-values>"
-                + "      <value int-value=\"0\" />"
-                + "      <value int-value=\"1\" />"
-                + "    </allowed-values>"
-                + "    <default-value int-value=\"1\" />"
-                + "  </setting>"
-                + "</cec-settings>", null);
+        HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
         assertThat(hdmiCecConfig.getAllowedIntValues(
                     HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED))
                 .containsExactly(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED,
@@ -413,62 +227,24 @@
     }
 
     @Test
-    public void getAllowedIntValues_HexValues() {
-        HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
-                mContext, mStorageAdapter,
-                "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
-                + "<cec-settings>"
-                + "  <setting name=\"hdmi_cec_enabled\""
-                + "           value-type=\"int\""
-                + "           user-configurable=\"true\">"
-                + "    <allowed-values>"
-                + "      <value int-value=\"0x00\" />"
-                + "      <value int-value=\"0x01\" />"
-                + "    </allowed-values>"
-                + "    <default-value int-value=\"0x01\" />"
-                + "  </setting>"
-                + "</cec-settings>", null);
+    public void getAllowedIntValues_WithOverride() {
+        setBooleanResource(R.bool.config_cecHdmiCecControlDisabled_allowed, false);
+        HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
         assertThat(hdmiCecConfig.getAllowedIntValues(
                     HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED))
-                .containsExactly(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED,
-                                 HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
-    }
-
-    @Test
-    public void getDefaultStringValue_NoMasterXml() {
-        HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
-                mContext, mStorageAdapter, null, null);
-        assertThrows(IllegalArgumentException.class,
-                () -> hdmiCecConfig.getDefaultStringValue("foo"));
+                .containsExactly(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
     }
 
     @Test
     public void getDefaultStringValue_InvalidSetting() {
-        HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
-                mContext, mStorageAdapter,
-                "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
-                + "<cec-settings>"
-                + "</cec-settings>", null);
+        HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
         assertThrows(IllegalArgumentException.class,
                 () -> hdmiCecConfig.getDefaultStringValue("foo"));
     }
 
     @Test
     public void getDefaultStringValue_InvalidValueType() {
-        HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
-                mContext, mStorageAdapter,
-                "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
-                + "<cec-settings>"
-                + "  <setting name=\"hdmi_cec_enabled\""
-                + "           value-type=\"int\""
-                + "           user-configurable=\"true\">"
-                + "    <allowed-values>"
-                + "      <value int-value=\"0\" />"
-                + "      <value int-value=\"1\" />"
-                + "    </allowed-values>"
-                + "    <default-value int-value=\"1\" />"
-                + "  </setting>"
-                + "</cec-settings>", null);
+        HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
         assertThrows(IllegalArgumentException.class,
                 () -> hdmiCecConfig.getDefaultStringValue(
                     HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED));
@@ -476,62 +252,46 @@
 
     @Test
     public void getDefaultStringValue_BasicSanity() {
-        HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
-                mContext, mStorageAdapter,
-                "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
-                + "<cec-settings>"
-                + "  <setting name=\"send_standby_on_sleep\""
-                + "           value-type=\"string\""
-                + "           user-configurable=\"true\">"
-                + "    <allowed-values>"
-                + "      <value string-value=\"to_tv\" />"
-                + "      <value string-value=\"broadcast\" />"
-                + "      <value string-value=\"none\" />"
-                + "    </allowed-values>"
-                + "    <default-value string-value=\"to_tv\" />"
-                + "  </setting>"
-                + "</cec-settings>", null);
+        HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
         assertThat(hdmiCecConfig.getDefaultStringValue(
                     HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE))
                 .isEqualTo(HdmiControlManager.POWER_CONTROL_MODE_TV);
     }
 
     @Test
-    public void getDefaultIntValue_NoMasterXml() {
-        HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
-                mContext, mStorageAdapter, null, null);
-        assertThrows(IllegalArgumentException.class,
-                () -> hdmiCecConfig.getDefaultIntValue("foo"));
+    public void getDefaultStringValue_WithOverride() {
+        setBooleanResource(R.bool.config_cecPowerControlModeTv_default, false);
+        setBooleanResource(R.bool.config_cecPowerControlModeBroadcast_default, true);
+        HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
+        assertThat(hdmiCecConfig.getDefaultStringValue(
+                    HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE))
+                .isEqualTo(HdmiControlManager.POWER_CONTROL_MODE_BROADCAST);
+    }
+
+    @Test
+    public void getDefaultStringValue_MultipleDefaults() {
+        setBooleanResource(R.bool.config_cecPowerControlModeBroadcast_default, true);
+        assertThrows(RuntimeException.class,
+                () -> new HdmiCecConfig(mContext, mStorageAdapter));
+    }
+
+    @Test
+    public void getDefaultStringValue_NoDefault() {
+        setBooleanResource(R.bool.config_cecPowerControlModeTv_default, false);
+        assertThrows(RuntimeException.class,
+                () -> new HdmiCecConfig(mContext, mStorageAdapter));
     }
 
     @Test
     public void getDefaultIntValue_InvalidSetting() {
-        HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
-                mContext, mStorageAdapter,
-                "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
-                + "<cec-settings>"
-                + "</cec-settings>", null);
+        HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
         assertThrows(IllegalArgumentException.class,
                 () -> hdmiCecConfig.getDefaultIntValue("foo"));
     }
 
     @Test
     public void getDefaultIntValue_InvalidValueType() {
-        HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
-                mContext, mStorageAdapter,
-                "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
-                + "<cec-settings>"
-                + "  <setting name=\"send_standby_on_sleep\""
-                + "           value-type=\"string\""
-                + "           user-configurable=\"true\">"
-                + "    <allowed-values>"
-                + "      <value string-value=\"to_tv\" />"
-                + "      <value string-value=\"broadcast\" />"
-                + "      <value string-value=\"none\" />"
-                + "    </allowed-values>"
-                + "    <default-value string-value=\"to_tv\" />"
-                + "  </setting>"
-                + "</cec-settings>", null);
+        HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
         assertThrows(IllegalArgumentException.class,
                 () -> hdmiCecConfig.getDefaultIntValue(
                     HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE));
@@ -539,81 +299,32 @@
 
     @Test
     public void getDefaultIntValue_BasicSanity() {
-        HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
-                mContext, mStorageAdapter,
-                "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
-                + "<cec-settings>"
-                + "  <setting name=\"hdmi_cec_enabled\""
-                + "           value-type=\"int\""
-                + "           user-configurable=\"true\">"
-                + "    <allowed-values>"
-                + "      <value int-value=\"0\" />"
-                + "      <value int-value=\"1\" />"
-                + "    </allowed-values>"
-                + "    <default-value int-value=\"1\" />"
-                + "  </setting>"
-                + "</cec-settings>", null);
+        HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
         assertThat(hdmiCecConfig.getDefaultIntValue(
                     HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED))
                 .isEqualTo(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
     }
 
     @Test
-    public void getDefaultIntValue_HexValue() {
-        HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
-                mContext, mStorageAdapter,
-                "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
-                + "<cec-settings>"
-                + "  <setting name=\"hdmi_cec_enabled\""
-                + "           value-type=\"int\""
-                + "           user-configurable=\"true\">"
-                + "    <allowed-values>"
-                + "      <value int-value=\"0x00\" />"
-                + "      <value int-value=\"0x01\" />"
-                + "    </allowed-values>"
-                + "    <default-value int-value=\"0x01\" />"
-                + "  </setting>"
-                + "</cec-settings>", null);
+    public void getDefaultIntValue_WithOverride() {
+        setBooleanResource(R.bool.config_cecHdmiCecControlEnabled_default, false);
+        setBooleanResource(R.bool.config_cecHdmiCecControlDisabled_default, true);
+        HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
         assertThat(hdmiCecConfig.getDefaultIntValue(
                     HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED))
-                .isEqualTo(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
-    }
-
-    @Test
-    public void getStringValue_NoMasterXml() {
-        HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
-                mContext, mStorageAdapter, null, null);
-        assertThrows(IllegalArgumentException.class,
-                () -> hdmiCecConfig.getStringValue("foo"));
+                .isEqualTo(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
     }
 
     @Test
     public void getStringValue_InvalidSetting() {
-        HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
-                mContext, mStorageAdapter,
-                "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
-                + "<cec-settings>"
-                + "</cec-settings>", null);
+        HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
         assertThrows(IllegalArgumentException.class,
                 () -> hdmiCecConfig.getStringValue("foo"));
     }
 
     @Test
     public void getStringValue_InvalidType() {
-        HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
-                mContext, mStorageAdapter,
-                "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
-                + "<cec-settings>"
-                + "  <setting name=\"hdmi_cec_enabled\""
-                + "           value-type=\"int\""
-                + "           user-configurable=\"true\">"
-                + "    <allowed-values>"
-                + "      <value int-value=\"0\" />"
-                + "      <value int-value=\"1\" />"
-                + "    </allowed-values>"
-                + "    <default-value int-value=\"1\" />"
-                + "  </setting>"
-                + "</cec-settings>", null);
+        HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
         assertThrows(IllegalArgumentException.class,
                 () -> hdmiCecConfig.getStringValue(
                     HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED));
@@ -625,21 +336,7 @@
                   Global.HDMI_CONTROL_SEND_STANDBY_ON_SLEEP,
                   HdmiControlManager.POWER_CONTROL_MODE_TV))
             .thenReturn(HdmiControlManager.POWER_CONTROL_MODE_BROADCAST);
-        HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
-                mContext, mStorageAdapter,
-                "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
-                + "<cec-settings>"
-                + "  <setting name=\"send_standby_on_sleep\""
-                + "           value-type=\"string\""
-                + "           user-configurable=\"true\">"
-                + "    <allowed-values>"
-                + "      <value string-value=\"to_tv\" />"
-                + "      <value string-value=\"broadcast\" />"
-                + "      <value string-value=\"none\" />"
-                + "    </allowed-values>"
-                + "    <default-value string-value=\"to_tv\" />"
-                + "  </setting>"
-                + "</cec-settings>", null);
+        HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
         assertThat(hdmiCecConfig.getStringValue(
                     HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE))
                 .isEqualTo(HdmiControlManager.POWER_CONTROL_MODE_BROADCAST);
@@ -652,61 +349,22 @@
                   HdmiControlManager.POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_NONE))
                 .thenReturn(
                         HdmiControlManager.POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_STANDBY_NOW);
-        HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
-                mContext, mStorageAdapter,
-                "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
-                + "<cec-settings>"
-                + "  <setting name=\"power_state_change_on_active_source_lost\""
-                + "           value-type=\"string\""
-                + "           user-configurable=\"true\">"
-                + "    <allowed-values>"
-                + "      <value string-value=\"none\" />"
-                + "      <value string-value=\"standby_now\" />"
-                + "    </allowed-values>"
-                + "    <default-value string-value=\"none\" />"
-                + "  </setting>"
-                + "</cec-settings>", null);
+        HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
         assertThat(hdmiCecConfig.getStringValue(
                     HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST))
                 .isEqualTo(HdmiControlManager.POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_STANDBY_NOW);
     }
 
     @Test
-    public void getIntValue_NoMasterXml() {
-        HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
-                mContext, mStorageAdapter, null, null);
-        assertThrows(IllegalArgumentException.class,
-                () -> hdmiCecConfig.getIntValue("foo"));
-    }
-
-    @Test
     public void getIntValue_InvalidSetting() {
-        HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
-                mContext, mStorageAdapter,
-                "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
-                + "<cec-settings>"
-                + "</cec-settings>", null);
+        HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
         assertThrows(IllegalArgumentException.class,
                 () -> hdmiCecConfig.getIntValue("foo"));
     }
 
     @Test
     public void getIntValue_InvalidType() {
-        HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
-                mContext, mStorageAdapter,
-                "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
-                + "<cec-settings>"
-                + "  <setting name=\"send_standby_on_sleep\""
-                + "           value-type=\"string\""
-                + "           user-configurable=\"true\">"
-                + "    <allowed-values>"
-                + "      <value string-value=\"to_tv\" />"
-                + "      <value string-value=\"broadcast\" />"
-                + "      <value string-value=\"none\" />"
-                + "    </allowed-values>"
-                + "    <default-value string-value=\"to_tv\" />"
-                + "  </setting>"
-                + "</cec-settings>", null);
+        HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
         assertThrows(IllegalArgumentException.class,
                 () -> hdmiCecConfig.getIntValue(
                     HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE));
@@ -718,45 +376,7 @@
                   Global.HDMI_CONTROL_ENABLED,
                   Integer.toString(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED)))
             .thenReturn(Integer.toString(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED));
-        HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
-                mContext, mStorageAdapter,
-                "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
-                + "<cec-settings>"
-                + "  <setting name=\"hdmi_cec_enabled\""
-                + "           value-type=\"int\""
-                + "           user-configurable=\"true\">"
-                + "    <allowed-values>"
-                + "      <value int-value=\"0\" />"
-                + "      <value int-value=\"1\" />"
-                + "    </allowed-values>"
-                + "    <default-value int-value=\"1\" />"
-                + "  </setting>"
-                + "</cec-settings>", null);
-        assertThat(hdmiCecConfig.getIntValue(
-                    HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED))
-                .isEqualTo(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
-    }
-
-    @Test
-    public void getIntValue_GlobalSetting_HexValue() {
-        when(mStorageAdapter.retrieveGlobalSetting(
-                  Global.HDMI_CONTROL_ENABLED,
-                  Integer.toHexString(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED)))
-            .thenReturn(Integer.toString(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED));
-        HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
-                mContext, mStorageAdapter,
-                "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
-                + "<cec-settings>"
-                + "  <setting name=\"hdmi_cec_enabled\""
-                + "           value-type=\"int\""
-                + "           user-configurable=\"true\">"
-                + "    <allowed-values>"
-                + "      <value int-value=\"0x0\" />"
-                + "      <value int-value=\"0x1\" />"
-                + "    </allowed-values>"
-                + "    <default-value int-value=\"0x1\" />"
-                + "  </setting>"
-                + "</cec-settings>", null);
+        HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
         assertThat(hdmiCecConfig.getIntValue(
                     HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED))
                 .isEqualTo(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
@@ -768,61 +388,23 @@
                   HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING,
                   Integer.toString(HdmiControlManager.SYSTEM_AUDIO_MODE_MUTING_ENABLED)))
                 .thenReturn(Integer.toString(HdmiControlManager.SYSTEM_AUDIO_MODE_MUTING_DISABLED));
-        HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
-                mContext, mStorageAdapter,
-                "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
-                + "<cec-settings>"
-                + "  <setting name=\"system_audio_mode_muting\""
-                + "           value-type=\"int\""
-                + "           user-configurable=\"true\">"
-                + "    <allowed-values>"
-                + "      <value int-value=\"0\" />"
-                + "      <value int-value=\"1\" />"
-                + "    </allowed-values>"
-                + "    <default-value int-value=\"1\" />"
-                + "  </setting>"
-                + "</cec-settings>", null);
+        HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
         assertThat(hdmiCecConfig.getIntValue(
                     HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING))
                 .isEqualTo(HdmiControlManager.SYSTEM_AUDIO_MODE_MUTING_DISABLED);
     }
 
     @Test
-    public void setStringValue_NoMasterXml() {
-        HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
-                mContext, mStorageAdapter, null, null);
-        assertThrows(IllegalArgumentException.class,
-                () -> hdmiCecConfig.setStringValue("foo", "bar"));
-    }
-
-    @Test
     public void setStringValue_InvalidSetting() {
-        HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
-                mContext, mStorageAdapter,
-                "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
-                + "<cec-settings>"
-                + "</cec-settings>", null);
+        HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
         assertThrows(IllegalArgumentException.class,
                 () -> hdmiCecConfig.setStringValue("foo", "bar"));
     }
 
     @Test
     public void setStringValue_NotConfigurable() {
-        HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
-                mContext, mStorageAdapter,
-                "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
-                + "<cec-settings>"
-                + "  <setting name=\"send_standby_on_sleep\""
-                + "           value-type=\"string\""
-                + "           user-configurable=\"false\">"
-                + "    <allowed-values>"
-                + "      <value string-value=\"to_tv\" />"
-                + "      <value string-value=\"broadcast\" />"
-                + "      <value string-value=\"none\" />"
-                + "    </allowed-values>"
-                + "    <default-value string-value=\"to_tv\" />"
-                + "  </setting>"
-                + "</cec-settings>", null);
+        setBooleanResource(R.bool.config_cecSendStandbyOnSleep_userConfigurable, false);
+        HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
         assertThrows(IllegalArgumentException.class,
                 () -> hdmiCecConfig.setStringValue(
                         HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE,
@@ -831,21 +413,7 @@
 
     @Test
     public void setStringValue_InvalidValue() {
-        HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
-                mContext, mStorageAdapter,
-                "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
-                + "<cec-settings>"
-                + "  <setting name=\"send_standby_on_sleep\""
-                + "           value-type=\"string\""
-                + "           user-configurable=\"true\">"
-                + "    <allowed-values>"
-                + "      <value string-value=\"to_tv\" />"
-                + "      <value string-value=\"broadcast\" />"
-                + "      <value string-value=\"none\" />"
-                + "    </allowed-values>"
-                + "    <default-value string-value=\"to_tv\" />"
-                + "  </setting>"
-                + "</cec-settings>", null);
+        HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
         assertThrows(IllegalArgumentException.class,
                 () -> hdmiCecConfig.setStringValue(
                         HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE,
@@ -854,21 +422,7 @@
 
     @Test
     public void setStringValue_GlobalSetting_BasicSanity() {
-        HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
-                mContext, mStorageAdapter,
-                "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
-                + "<cec-settings>"
-                + "  <setting name=\"send_standby_on_sleep\""
-                + "           value-type=\"string\""
-                + "           user-configurable=\"true\">"
-                + "    <allowed-values>"
-                + "      <value string-value=\"to_tv\" />"
-                + "      <value string-value=\"broadcast\" />"
-                + "      <value string-value=\"none\" />"
-                + "    </allowed-values>"
-                + "    <default-value string-value=\"to_tv\" />"
-                + "  </setting>"
-                + "</cec-settings>", null);
+        HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
         hdmiCecConfig.setStringValue(HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE,
                                HdmiControlManager.POWER_CONTROL_MODE_BROADCAST);
         verify(mStorageAdapter).storeGlobalSetting(
@@ -878,20 +432,7 @@
 
     @Test
     public void setStringValue_SharedPref_BasicSanity() {
-        HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
-                mContext, mStorageAdapter,
-                "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
-                + "<cec-settings>"
-                + "  <setting name=\"power_state_change_on_active_source_lost\""
-                + "           value-type=\"string\""
-                + "           user-configurable=\"true\">"
-                + "    <allowed-values>"
-                + "      <value string-value=\"none\" />"
-                + "      <value string-value=\"standby_now\" />"
-                + "    </allowed-values>"
-                + "    <default-value string-value=\"none\" />"
-                + "  </setting>"
-                + "</cec-settings>", null);
+        HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
         hdmiCecConfig.setStringValue(
                   HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST,
                   HdmiControlManager.POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_STANDBY_NOW);
@@ -901,40 +442,16 @@
     }
 
     @Test
-    public void setIntValue_NoMasterXml() {
-        HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
-                mContext, mStorageAdapter, null, null);
-        assertThrows(IllegalArgumentException.class,
-                () -> hdmiCecConfig.setIntValue("foo", 0));
-    }
-
-    @Test
     public void setIntValue_InvalidSetting() {
-        HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
-                mContext, mStorageAdapter,
-                "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
-                + "<cec-settings>"
-                + "</cec-settings>", null);
+        HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
         assertThrows(IllegalArgumentException.class,
                 () -> hdmiCecConfig.setIntValue("foo", 0));
     }
 
     @Test
     public void setIntValue_NotConfigurable() {
-        HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
-                mContext, mStorageAdapter,
-                "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
-                + "<cec-settings>"
-                + "  <setting name=\"hdmi_cec_enabled\""
-                + "           value-type=\"int\""
-                + "           user-configurable=\"false\">"
-                + "    <allowed-values>"
-                + "      <value int-value=\"0\" />"
-                + "      <value int-value=\"1\" />"
-                + "    </allowed-values>"
-                + "    <default-value int-value=\"1\" />"
-                + "  </setting>"
-                + "</cec-settings>", null);
+        setBooleanResource(R.bool.config_cecHdmiCecEnabled_userConfigurable, false);
+        HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
         assertThrows(IllegalArgumentException.class,
                 () -> hdmiCecConfig.setIntValue(
                         HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
@@ -943,20 +460,7 @@
 
     @Test
     public void setIntValue_InvalidValue() {
-        HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
-                mContext, mStorageAdapter,
-                "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
-                + "<cec-settings>"
-                + "  <setting name=\"hdmi_cec_enabled\""
-                + "           value-type=\"int\""
-                + "           user-configurable=\"true\">"
-                + "    <allowed-values>"
-                + "      <value int-value=\"0\" />"
-                + "      <value int-value=\"1\" />"
-                + "    </allowed-values>"
-                + "    <default-value int-value=\"1\" />"
-                + "  </setting>"
-                + "</cec-settings>", null);
+        HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
         assertThrows(IllegalArgumentException.class,
                 () -> hdmiCecConfig.setIntValue(
                         HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
@@ -965,43 +469,7 @@
 
     @Test
     public void setIntValue_GlobalSetting_BasicSanity() {
-        HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
-                mContext, mStorageAdapter,
-                "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
-                + "<cec-settings>"
-                + "  <setting name=\"hdmi_cec_enabled\""
-                + "           value-type=\"int\""
-                + "           user-configurable=\"true\">"
-                + "    <allowed-values>"
-                + "      <value int-value=\"0\" />"
-                + "      <value int-value=\"1\" />"
-                + "    </allowed-values>"
-                + "    <default-value int-value=\"1\" />"
-                + "  </setting>"
-                + "</cec-settings>", null);
-        hdmiCecConfig.setIntValue(HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
-                                  HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
-        verify(mStorageAdapter).storeGlobalSetting(
-                  Global.HDMI_CONTROL_ENABLED,
-                  Integer.toString(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED));
-    }
-
-    @Test
-    public void setIntValue_GlobalSetting_HexValue() {
-        HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
-                mContext, mStorageAdapter,
-                "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
-                + "<cec-settings>"
-                + "  <setting name=\"hdmi_cec_enabled\""
-                + "           value-type=\"int\""
-                + "           user-configurable=\"true\">"
-                + "    <allowed-values>"
-                + "      <value int-value=\"0x0\" />"
-                + "      <value int-value=\"0x1\" />"
-                + "    </allowed-values>"
-                + "    <default-value int-value=\"0x1\" />"
-                + "  </setting>"
-                + "</cec-settings>", null);
+        HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
         hdmiCecConfig.setIntValue(HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
                                   HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
         verify(mStorageAdapter).storeGlobalSetting(
@@ -1011,20 +479,7 @@
 
     @Test
     public void setIntValue_SharedPref_BasicSanity() {
-        HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
-                mContext, mStorageAdapter,
-                "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
-                        + "<cec-settings>"
-                        + "  <setting name=\"system_audio_mode_muting\""
-                        + "           value-type=\"int\""
-                        + "           user-configurable=\"true\">"
-                        + "    <allowed-values>"
-                        + "      <value int-value=\"0\" />"
-                        + "      <value int-value=\"1\" />"
-                        + "    </allowed-values>"
-                        + "    <default-value int-value=\"1\" />"
-                        + "  </setting>"
-                        + "</cec-settings>", null);
+        HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
         hdmiCecConfig.setIntValue(
                 HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING,
                 HdmiControlManager.SYSTEM_AUDIO_MODE_MUTING_DISABLED);
@@ -1035,20 +490,7 @@
 
     @Test
     public void registerChangeListener_SharedPref_BasicSanity() {
-        HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
-                mContext, mStorageAdapter,
-                "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
-                        + "<cec-settings>"
-                        + "  <setting name=\"system_audio_mode_muting\""
-                        + "           value-type=\"int\""
-                        + "           user-configurable=\"true\">"
-                        + "    <allowed-values>"
-                        + "      <value int-value=\"0\" />"
-                        + "      <value int-value=\"1\" />"
-                        + "    </allowed-values>"
-                        + "    <default-value int-value=\"1\" />"
-                        + "  </setting>"
-                        + "</cec-settings>", null);
+        HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
         hdmiCecConfig.registerChangeListener(
                 HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING,
                 mSettingChangeListener);
@@ -1061,20 +503,7 @@
 
     @Test
     public void removeChangeListener_SharedPref_BasicSanity() {
-        HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
-                mContext, mStorageAdapter,
-                "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
-                        + "<cec-settings>"
-                        + "  <setting name=\"system_audio_mode_muting\""
-                        + "           value-type=\"int\""
-                        + "           user-configurable=\"true\">"
-                        + "    <allowed-values>"
-                        + "      <value int-value=\"0\" />"
-                        + "      <value int-value=\"1\" />"
-                        + "    </allowed-values>"
-                        + "    <default-value int-value=\"1\" />"
-                        + "  </setting>"
-                        + "</cec-settings>", null);
+        HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
         hdmiCecConfig.registerChangeListener(
                 HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING,
                 mSettingChangeListener);
@@ -1100,20 +529,7 @@
         String originalValue = Global.getString(mContext.getContentResolver(),
                 Global.HDMI_CONTROL_ENABLED);
         try {
-            HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
-                    mContext, mStorageAdapter,
-                    "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
-                            + "<cec-settings>"
-                            + "  <setting name=\"hdmi_cec_enabled\""
-                            + "           value-type=\"int\""
-                            + "           user-configurable=\"true\">"
-                            + "    <allowed-values>"
-                            + "      <value int-value=\"0\" />"
-                            + "      <value int-value=\"1\" />"
-                            + "    </allowed-values>"
-                            + "    <default-value int-value=\"1\" />"
-                            + "  </setting>"
-                            + "</cec-settings>", null);
+            HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
             hdmiCecConfig.registerGlobalSettingsObserver(mTestLooper.getLooper());
             HdmiCecConfig.SettingChangeListener latchUpdateListener =
                     new HdmiCecConfig.SettingChangeListener() {
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/OneTouchPlayActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/OneTouchPlayActionTest.java
index 907cf3e..c61635c 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/OneTouchPlayActionTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/OneTouchPlayActionTest.java
@@ -136,7 +136,6 @@
         mPhysicalAddress = 0x2000;
         mNativeWrapper.setPhysicalAddress(mPhysicalAddress);
         mTestLooper.dispatchAll();
-        mHdmiControlService.getHdmiCecNetwork().addCecDevice(INFO_TV);
     }
 
     private OneTouchPlayAction createOneTouchPlayAction(HdmiCecLocalDevicePlayback device,
@@ -147,7 +146,47 @@
     }
 
     @Test
+    public void succeedWithUnknownTvDevice() {
+        HdmiCecLocalDevicePlayback playbackDevice = new HdmiCecLocalDevicePlayback(
+                mHdmiControlService);
+        playbackDevice.init();
+        mLocalDevices.add(playbackDevice);
+        mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
+        mTestLooper.dispatchAll();
+
+        TestActionTimer actionTimer = new TestActionTimer();
+        TestCallback callback = new TestCallback();
+        OneTouchPlayAction action = createOneTouchPlayAction(playbackDevice, actionTimer, callback,
+                false);
+        playbackDevice.addAndStartAction(action);
+        mTestLooper.dispatchAll();
+
+        HdmiCecMessage activeSource = HdmiCecMessageBuilder.buildActiveSource(
+                playbackDevice.mAddress, mPhysicalAddress);
+        HdmiCecMessage textViewOn = HdmiCecMessageBuilder.buildTextViewOn(playbackDevice.mAddress,
+                ADDR_TV);
+        HdmiCecMessage giveDevicePowerStatus = HdmiCecMessageBuilder
+                .buildGiveDevicePowerStatus(playbackDevice.mAddress, ADDR_TV);
+
+        assertThat(mNativeWrapper.getResultMessages()).contains(textViewOn);
+        assertThat(mNativeWrapper.getResultMessages()).contains(activeSource);
+        assertThat(mNativeWrapper.getResultMessages()).contains(giveDevicePowerStatus);
+        mNativeWrapper.clearResultMessages();
+        assertThat(actionTimer.getState()).isEqualTo(STATE_WAITING_FOR_REPORT_POWER_STATUS);
+        HdmiCecMessage reportPowerStatusOn = new HdmiCecMessage(
+                ADDR_TV, playbackDevice.mAddress, Constants.MESSAGE_REPORT_POWER_STATUS, POWER_ON);
+        action.processCommand(reportPowerStatusOn);
+        mTestLooper.dispatchAll();
+
+        assertThat(mNativeWrapper.getResultMessages()).doesNotContain(textViewOn);
+        assertThat(mNativeWrapper.getResultMessages()).contains(activeSource);
+        assertThat(mNativeWrapper.getResultMessages()).doesNotContain(giveDevicePowerStatus);
+        assertThat(callback.getResult()).isEqualTo(HdmiControlManager.RESULT_SUCCESS);
+    }
+
+    @Test
     public void succeedAfterGettingPowerStatusOn_Cec14b() {
+        mHdmiControlService.getHdmiCecNetwork().addCecDevice(INFO_TV);
         HdmiCecLocalDevicePlayback playbackDevice = new HdmiCecLocalDevicePlayback(
                 mHdmiControlService);
         playbackDevice.init();
@@ -187,6 +226,7 @@
 
     @Test
     public void succeedAfterGettingTransientPowerStatus_Cec14b() {
+        mHdmiControlService.getHdmiCecNetwork().addCecDevice(INFO_TV);
         HdmiCecLocalDevicePlayback playbackDevice = new HdmiCecLocalDevicePlayback(
                 mHdmiControlService);
         playbackDevice.init();
@@ -236,6 +276,7 @@
 
     @Test
     public void timeOut_Cec14b() {
+        mHdmiControlService.getHdmiCecNetwork().addCecDevice(INFO_TV);
         HdmiCecLocalDevicePlayback playbackDevice = new HdmiCecLocalDevicePlayback(
                 mHdmiControlService);
         playbackDevice.init();
@@ -276,6 +317,7 @@
 
     @Test
     public void succeedIfPowerStatusOn_Cec20() {
+        mHdmiControlService.getHdmiCecNetwork().addCecDevice(INFO_TV);
         HdmiCecLocalDevicePlayback playbackDevice = new HdmiCecLocalDevicePlayback(
                 mHdmiControlService);
         playbackDevice.init();
@@ -307,6 +349,7 @@
 
     @Test
     public void succeedIfPowerStatusUnknown_Cec20() {
+        mHdmiControlService.getHdmiCecNetwork().addCecDevice(INFO_TV);
         HdmiCecLocalDevicePlayback playbackDevice = new HdmiCecLocalDevicePlayback(
                 mHdmiControlService);
         playbackDevice.init();
@@ -348,6 +391,7 @@
 
     @Test
     public void succeedIfPowerStatusStandby_Cec20() {
+        mHdmiControlService.getHdmiCecNetwork().addCecDevice(INFO_TV);
         HdmiCecLocalDevicePlayback playbackDevice = new HdmiCecLocalDevicePlayback(
                 mHdmiControlService);
         playbackDevice.init();
diff --git a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
index 9a52643..9f428c7 100644
--- a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
@@ -31,6 +31,7 @@
 import android.content.IntentFilter;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageParser;
+import android.content.pm.PackageParser.SigningDetails;
 import android.content.pm.Signature;
 import android.content.pm.UserInfo;
 import android.content.pm.parsing.ParsingPackage;
@@ -141,6 +142,10 @@
         return pkg(packageName).addReceiver(receiver);
     }
 
+    private static ParsingPackage pkgWithSharedLibrary(String packageName, String libName) {
+        return pkg(packageName).addLibraryName(libName);
+    }
+
     private static ParsedActivity createActivity(String packageName, IntentFilter[] filters) {
         ParsedActivity activity = new ParsedActivity();
         activity.setPackageName(packageName);
@@ -413,6 +418,118 @@
     }
 
     @Test
+    public void testNoUsesLibrary_Filters() throws Exception {
+        final AppsFilter appsFilter = new AppsFilter(mStateProvider, mFeatureConfigMock,
+                new String[]{}, /* systemAppsQueryable */ false, /* overlayProvider */ null,
+                mMockExecutor);
+
+        simulateAddBasicAndroid(appsFilter);
+        appsFilter.onSystemReady();
+
+        final Signature mockSignature = Mockito.mock(Signature.class);
+        final SigningDetails mockSigningDetails = new SigningDetails(
+                new Signature[]{mockSignature},
+                SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V2);
+
+        final PackageSetting target = simulateAddPackage(appsFilter,
+                pkgWithSharedLibrary("com.some.package", "com.some.shared_library"),
+                DUMMY_TARGET_APPID,
+                setting -> setting.setSigningDetails(mockSigningDetails)
+                        .setPkgFlags(ApplicationInfo.FLAG_SYSTEM));
+        final PackageSetting calling = simulateAddPackage(appsFilter,
+                pkg("com.some.other.package"), DUMMY_CALLING_APPID);
+
+        assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target,
+                SYSTEM_USER));
+    }
+
+    @Test
+    public void testUsesLibrary_DoesntFilter() throws Exception {
+        final AppsFilter appsFilter = new AppsFilter(mStateProvider, mFeatureConfigMock,
+                new String[]{}, /* systemAppsQueryable */ false, /* overlayProvider */ null,
+                mMockExecutor);
+
+        simulateAddBasicAndroid(appsFilter);
+        appsFilter.onSystemReady();
+
+        final Signature mockSignature = Mockito.mock(Signature.class);
+        final SigningDetails mockSigningDetails = new SigningDetails(
+                new Signature[]{mockSignature},
+                SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V2);
+
+        final PackageSetting target = simulateAddPackage(appsFilter,
+                pkgWithSharedLibrary("com.some.package", "com.some.shared_library"),
+                DUMMY_TARGET_APPID,
+                setting -> setting.setSigningDetails(mockSigningDetails)
+                        .setPkgFlags(ApplicationInfo.FLAG_SYSTEM));
+        final PackageSetting calling = simulateAddPackage(appsFilter,
+                pkg("com.some.other.package").addUsesLibrary("com.some.shared_library"),
+                DUMMY_CALLING_APPID);
+
+        assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target,
+                SYSTEM_USER));
+    }
+
+    @Test
+    public void testUsesOptionalLibrary_DoesntFilter() throws Exception {
+        final AppsFilter appsFilter = new AppsFilter(mStateProvider, mFeatureConfigMock,
+                new String[]{}, /* systemAppsQueryable */ false, /* overlayProvider */ null,
+                mMockExecutor);
+
+        simulateAddBasicAndroid(appsFilter);
+        appsFilter.onSystemReady();
+
+        final Signature mockSignature = Mockito.mock(Signature.class);
+        final SigningDetails mockSigningDetails = new SigningDetails(
+                new Signature[]{mockSignature},
+                SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V2);
+
+        final PackageSetting target = simulateAddPackage(appsFilter,
+                pkgWithSharedLibrary("com.some.package", "com.some.shared_library"),
+                DUMMY_TARGET_APPID,
+                setting -> setting.setSigningDetails(mockSigningDetails)
+                        .setPkgFlags(ApplicationInfo.FLAG_SYSTEM));
+        final PackageSetting calling = simulateAddPackage(appsFilter,
+                pkg("com.some.other.package").addUsesOptionalLibrary("com.some.shared_library"),
+                DUMMY_CALLING_APPID);
+
+        assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target,
+                SYSTEM_USER));
+    }
+
+    @Test
+    public void testUsesLibrary_ShareUid_DoesntFilter() throws Exception {
+        final AppsFilter appsFilter = new AppsFilter(mStateProvider, mFeatureConfigMock,
+                new String[]{}, /* systemAppsQueryable */ false, /* overlayProvider */ null,
+                mMockExecutor);
+
+        simulateAddBasicAndroid(appsFilter);
+        appsFilter.onSystemReady();
+
+        final Signature mockSignature = Mockito.mock(Signature.class);
+        final SigningDetails mockSigningDetails = new SigningDetails(
+                new Signature[]{mockSignature},
+                SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V2);
+
+        final PackageSetting target = simulateAddPackage(appsFilter,
+                pkgWithSharedLibrary("com.some.package", "com.some.shared_library"),
+                DUMMY_TARGET_APPID,
+                setting -> setting.setSigningDetails(mockSigningDetails)
+                        .setPkgFlags(ApplicationInfo.FLAG_SYSTEM));
+        final PackageSetting calling = simulateAddPackage(appsFilter,
+                pkg("com.some.other.package_a").setSharedUserId("com.some.uid"),
+                DUMMY_CALLING_APPID);
+        simulateAddPackage(appsFilter, pkg("com.some.other.package_b")
+                .setSharedUserId("com.some.uid").addUsesLibrary("com.some.shared_library"),
+                DUMMY_CALLING_APPID);
+
+        // Although package_a doesn't use library, it should be granted visibility. It's because
+        // package_a shares userId with package_b, and package_b uses that shared library.
+        assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target,
+                SYSTEM_USER));
+    }
+
+    @Test
     public void testForceQueryable_SystemDoesntFilter() throws Exception {
         final AppsFilter appsFilter =
                 new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/FakeTimeZoneDetectorStrategy.java b/services/tests/servicestests/src/com/android/server/timezonedetector/FakeTimeZoneDetectorStrategy.java
index bad380a..51f627a 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/FakeTimeZoneDetectorStrategy.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/FakeTimeZoneDetectorStrategy.java
@@ -118,6 +118,11 @@
     }
 
     @Override
+    public MetricsTimeZoneDetectorState generateMetricsState() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
     public void addDumpable(Dumpable dumpable) {
         mDumpables.add(dumpable);
     }
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/OrdinalGeneratorTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/OrdinalGeneratorTest.java
new file mode 100644
index 0000000..af954d5
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/OrdinalGeneratorTest.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.timezonedetector;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+
+@RunWith(AndroidJUnit4.class)
+public class OrdinalGeneratorTest {
+
+    @Test
+    public void testOrdinal() {
+        OrdinalGenerator<String> ordinalGenerator = new OrdinalGenerator<>();
+        int oneOrd = ordinalGenerator.ordinal("One");
+        int twoOrd = ordinalGenerator.ordinal("Two");
+        assertNotEquals(oneOrd, twoOrd);
+
+        assertEquals(oneOrd, ordinalGenerator.ordinal("One"));
+        assertEquals(twoOrd, ordinalGenerator.ordinal("Two"));
+
+        int threeOrd = ordinalGenerator.ordinal("Three");
+        assertNotEquals(oneOrd, threeOrd);
+        assertNotEquals(twoOrd, threeOrd);
+    }
+
+    @Test
+    public void testOrdinals() {
+        OrdinalGenerator<String> ordinalGenerator = new OrdinalGenerator<>();
+        int[] oneTwoOrds = ordinalGenerator.ordinals(Arrays.asList("One", "Two"));
+        int[] twoThreeOrds = ordinalGenerator.ordinals(Arrays.asList("Two", "Three"));
+        assertEquals(oneTwoOrds[0], ordinalGenerator.ordinal("One"));
+        assertEquals(oneTwoOrds[1], ordinalGenerator.ordinal("Two"));
+        assertEquals(twoThreeOrds[0], ordinalGenerator.ordinal("Two"));
+        assertEquals(twoThreeOrds[1], ordinalGenerator.ordinal("Three"));
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java
index b0341d7..f91ce87 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java
@@ -925,6 +925,106 @@
         assertTrue(dumpCalled.get());
     }
 
+    @Test
+    public void testGenerateMetricsState() {
+        ConfigurationInternal expectedInternalConfig = CONFIG_INT_AUTO_DISABLED_GEO_DISABLED;
+        String expectedDeviceTimeZoneId = "InitialZoneId";
+
+        Script script = new Script()
+                .initializeConfig(expectedInternalConfig)
+                .initializeTimeZoneSetting(expectedDeviceTimeZoneId);
+
+        assertMetricsState(expectedInternalConfig, expectedDeviceTimeZoneId, null, null,
+                null, MetricsTimeZoneDetectorState.DETECTION_MODE_MANUAL);
+
+        // Make sure the manual suggestion is recorded.
+        ManualTimeZoneSuggestion manualSuggestion = createManualSuggestion("Zone1");
+        script.simulateManualTimeZoneSuggestion(USER_ID, manualSuggestion,
+                true /* expectedResult */)
+                .verifyTimeZoneChangedAndReset(manualSuggestion);
+        expectedDeviceTimeZoneId = manualSuggestion.getZoneId();
+        assertMetricsState(expectedInternalConfig, expectedDeviceTimeZoneId,
+                manualSuggestion, null, null,
+                MetricsTimeZoneDetectorState.DETECTION_MODE_MANUAL);
+
+        // With time zone auto detection off, telephony suggestions will be recorded, but geo
+        // suggestions won't out of an abundance of caution around respecting user privacy when
+        // geo detection is off.
+        TelephonyTimeZoneSuggestion telephonySuggestion =
+                createTelephonySuggestion(0 /* slotIndex */, MATCH_TYPE_NETWORK_COUNTRY_ONLY,
+                        QUALITY_SINGLE_ZONE, "Zone2");
+        GeolocationTimeZoneSuggestion geolocationTimeZoneSuggestion =
+                createGeoLocationSuggestion(Arrays.asList("Zone3", "Zone2"));
+        script.simulateTelephonyTimeZoneSuggestion(telephonySuggestion)
+                .verifyTimeZoneNotChanged()
+                .simulateGeolocationTimeZoneSuggestion(geolocationTimeZoneSuggestion)
+                .verifyTimeZoneNotChanged();
+
+        assertMetricsState(expectedInternalConfig, expectedDeviceTimeZoneId,
+                manualSuggestion, telephonySuggestion, null /* expectedGeoSuggestion */,
+                MetricsTimeZoneDetectorState.DETECTION_MODE_MANUAL);
+
+        // Update the config and confirm that the config metrics state updates also.
+        TimeZoneConfiguration configUpdate =
+                createConfig(true /* autoDetection */, true /* geoDetection */);
+        expectedInternalConfig = new ConfigurationInternal.Builder(expectedInternalConfig)
+                .setAutoDetectionEnabled(true)
+                .setGeoDetectionEnabled(true)
+                .build();
+        script.simulateUpdateConfiguration(USER_ID, configUpdate, true /* expectedResult */)
+                .verifyConfigurationChangedAndReset(expectedInternalConfig)
+                .verifyTimeZoneNotChanged();
+        assertMetricsState(expectedInternalConfig, expectedDeviceTimeZoneId,
+                manualSuggestion, telephonySuggestion, null  /* expectedGeoSuggestion */,
+                MetricsTimeZoneDetectorState.DETECTION_MODE_GEO);
+
+        // Now simulate a geo suggestion and confirm it is used and reported in the metrics too.
+        expectedDeviceTimeZoneId = geolocationTimeZoneSuggestion.getZoneIds().get(0);
+        script.simulateGeolocationTimeZoneSuggestion(geolocationTimeZoneSuggestion)
+                .verifyTimeZoneChangedAndReset(expectedDeviceTimeZoneId);
+        assertMetricsState(expectedInternalConfig, expectedDeviceTimeZoneId,
+                manualSuggestion, telephonySuggestion, geolocationTimeZoneSuggestion,
+                MetricsTimeZoneDetectorState.DETECTION_MODE_GEO);
+    }
+
+    /**
+     * Asserts that the information returned by {@link
+     * TimeZoneDetectorStrategy#generateMetricsState()} matches expectations.
+     */
+    private void assertMetricsState(
+            ConfigurationInternal expectedInternalConfig,
+            String expectedDeviceTimeZoneId, ManualTimeZoneSuggestion expectedManualSuggestion,
+            TelephonyTimeZoneSuggestion expectedTelephonySuggestion,
+            GeolocationTimeZoneSuggestion expectedGeolocationTimeZoneSuggestion,
+            int expectedDetectionMode) {
+
+        MetricsTimeZoneDetectorState actualState = mTimeZoneDetectorStrategy.generateMetricsState();
+
+        // Check the various feature state values are what we expect.
+        assertFeatureStateMatchesConfig(expectedInternalConfig, actualState, expectedDetectionMode);
+
+        OrdinalGenerator<String> tzIdOrdinalGenerator = new OrdinalGenerator<>();
+        MetricsTimeZoneDetectorState expectedState =
+                MetricsTimeZoneDetectorState.create(
+                        tzIdOrdinalGenerator, expectedInternalConfig, expectedDeviceTimeZoneId,
+                        expectedManualSuggestion, expectedTelephonySuggestion,
+                        expectedGeolocationTimeZoneSuggestion);
+        // Rely on MetricsTimeZoneDetectorState.equals() for time zone ID ordinal comparisons.
+        assertEquals(expectedState, actualState);
+    }
+
+    private static void assertFeatureStateMatchesConfig(ConfigurationInternal config,
+            MetricsTimeZoneDetectorState actualState, int expectedDetectionMode) {
+        assertEquals(config.isTelephonyDetectionSupported(),
+                actualState.isTelephonyDetectionSupported());
+        assertEquals(config.isGeoDetectionSupported(), actualState.isGeoDetectionSupported());
+        assertEquals(config.getAutoDetectionEnabledSetting(),
+                actualState.getAutoDetectionEnabledSetting());
+        assertEquals(config.getGeoDetectionEnabledSetting(),
+                actualState.getGeoDetectionEnabledSetting());
+        assertEquals(expectedDetectionMode, actualState.getDetectionMode());
+    }
+
     private static ManualTimeZoneSuggestion createManualSuggestion(String zoneId) {
         return new ManualTimeZoneSuggestion(zoneId);
     }
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/location/ControllerImplTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/location/ControllerImplTest.java
index 3daa7f0..5a100a2 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/location/ControllerImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/location/ControllerImplTest.java
@@ -79,15 +79,18 @@
         // For simplicity, the TestThreadingDomain uses the test's main thread. To execute posted
         // runnables, the test must call methods on mTestThreadingDomain otherwise those runnables
         // will never get a chance to execute.
+        LocationTimeZoneProvider.ProviderMetricsLogger stubbedProviderMetricsLogger = stateEnum -> {
+            // Stubbed.
+        };
         mTestThreadingDomain = new TestThreadingDomain();
         mTestCallback = new TestCallback(mTestThreadingDomain);
         mTimeZoneAvailabilityChecker = new FakeTimeZoneIdValidator();
-        mTestPrimaryLocationTimeZoneProvider =
-                new TestLocationTimeZoneProvider(
-                        mTestThreadingDomain, "primary", mTimeZoneAvailabilityChecker);
-        mTestSecondaryLocationTimeZoneProvider =
-                new TestLocationTimeZoneProvider(
-                        mTestThreadingDomain, "secondary", mTimeZoneAvailabilityChecker);
+        mTestPrimaryLocationTimeZoneProvider = new TestLocationTimeZoneProvider(
+                stubbedProviderMetricsLogger, mTestThreadingDomain, "primary",
+                mTimeZoneAvailabilityChecker);
+        mTestSecondaryLocationTimeZoneProvider = new TestLocationTimeZoneProvider(
+                stubbedProviderMetricsLogger, mTestThreadingDomain, "secondary",
+                mTimeZoneAvailabilityChecker);
     }
 
     @Test
@@ -1181,10 +1184,11 @@
         /**
          * Creates the instance.
          */
-        TestLocationTimeZoneProvider(ThreadingDomain threadingDomain,
-                String providerName,
+        TestLocationTimeZoneProvider(ProviderMetricsLogger providerMetricsLogger,
+                ThreadingDomain threadingDomain, String providerName,
                 TimeZoneIdValidator timeZoneIdValidator) {
-            super(threadingDomain, providerName, timeZoneIdValidator);
+            super(providerMetricsLogger, threadingDomain, providerName,
+                    timeZoneIdValidator);
         }
 
         public void setFailDuringInitialization(boolean failInitialization) {
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/location/LocationTimeZoneProviderTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/location/LocationTimeZoneProviderTest.java
index 278fdaf..d13a04e 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/location/LocationTimeZoneProviderTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/location/LocationTimeZoneProviderTest.java
@@ -53,6 +53,7 @@
 import java.time.Duration;
 import java.util.Arrays;
 import java.util.HashSet;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicReference;
@@ -79,19 +80,18 @@
     @Test
     public void lifecycle() {
         String providerName = "arbitrary";
-        TestLocationTimeZoneProvider provider =
-                new TestLocationTimeZoneProvider(
-                        mTestThreadingDomain,
-                        providerName,
-                        mTimeZoneAvailabilityChecker);
+        RecordingProviderMetricsLogger providerMetricsLogger = new RecordingProviderMetricsLogger();
+        TestLocationTimeZoneProvider provider = new TestLocationTimeZoneProvider(
+                providerMetricsLogger, mTestThreadingDomain, providerName,
+                mTimeZoneAvailabilityChecker);
         mTimeZoneAvailabilityChecker.validIds("Europe/London");
 
         // initialize()
         provider.initialize(mProviderListener);
         provider.assertOnInitializeCalled();
 
-        ProviderState currentState = provider.getCurrentState();
-        assertEquals(PROVIDER_STATE_STOPPED, currentState.stateEnum);
+        ProviderState currentState = assertAndReturnProviderState(
+                provider, providerMetricsLogger, PROVIDER_STATE_STOPPED);
         assertNull(currentState.currentUserConfiguration);
         assertSame(provider, currentState.provider);
         mTestThreadingDomain.assertQueueEmpty();
@@ -105,9 +105,9 @@
 
         provider.assertOnStartCalled(arbitraryInitializationTimeout);
 
-        currentState = provider.getCurrentState();
+        currentState = assertAndReturnProviderState(
+                provider, providerMetricsLogger, PROVIDER_STATE_STARTED_INITIALIZING);
         assertSame(provider, currentState.provider);
-        assertEquals(PROVIDER_STATE_STARTED_INITIALIZING, currentState.stateEnum);
         assertEquals(config, currentState.currentUserConfiguration);
         assertNull(currentState.event);
         // The initialization timeout should be queued.
@@ -129,9 +129,9 @@
         TimeZoneProviderEvent event = TimeZoneProviderEvent.createSuggestionEvent(suggestion);
         provider.simulateProviderEventReceived(event);
 
-        currentState = provider.getCurrentState();
+        currentState = assertAndReturnProviderState(
+                provider, providerMetricsLogger, PROVIDER_STATE_STARTED_CERTAIN);
         assertSame(provider, currentState.provider);
-        assertEquals(PROVIDER_STATE_STARTED_CERTAIN, currentState.stateEnum);
         assertEquals(event, currentState.event);
         assertEquals(config, currentState.currentUserConfiguration);
         mTestThreadingDomain.assertQueueEmpty();
@@ -141,9 +141,9 @@
         event = TimeZoneProviderEvent.createUncertainEvent();
         provider.simulateProviderEventReceived(event);
 
-        currentState = provider.getCurrentState();
+        currentState = assertAndReturnProviderState(
+                provider, providerMetricsLogger, PROVIDER_STATE_STARTED_UNCERTAIN);
         assertSame(provider, currentState.provider);
-        assertEquals(PROVIDER_STATE_STARTED_UNCERTAIN, currentState.stateEnum);
         assertEquals(event, currentState.event);
         assertEquals(config, currentState.currentUserConfiguration);
         mTestThreadingDomain.assertQueueEmpty();
@@ -153,7 +153,8 @@
         provider.stopUpdates();
         provider.assertOnStopUpdatesCalled();
 
-        currentState = provider.getCurrentState();
+        currentState = assertAndReturnProviderState(
+                provider, providerMetricsLogger, PROVIDER_STATE_STOPPED);
         assertSame(provider, currentState.provider);
         assertEquals(PROVIDER_STATE_STOPPED, currentState.stateEnum);
         assertNull(currentState.event);
@@ -171,11 +172,10 @@
     @Test
     public void defaultHandleTestCommandImpl() {
         String providerName = "primary";
-        TestLocationTimeZoneProvider provider =
-                new TestLocationTimeZoneProvider(
-                        mTestThreadingDomain,
-                        providerName,
-                        mTimeZoneAvailabilityChecker);
+        StubbedProviderMetricsLogger providerMetricsLogger = new StubbedProviderMetricsLogger();
+        TestLocationTimeZoneProvider provider = new TestLocationTimeZoneProvider(
+                providerMetricsLogger, mTestThreadingDomain, providerName,
+                mTimeZoneAvailabilityChecker);
 
         TestCommand testCommand = TestCommand.createForTests("test", new Bundle());
         AtomicReference<Bundle> resultReference = new AtomicReference<>();
@@ -191,11 +191,10 @@
     @Test
     public void stateRecording() {
         String providerName = "primary";
-        TestLocationTimeZoneProvider provider =
-                new TestLocationTimeZoneProvider(
-                        mTestThreadingDomain,
-                        providerName,
-                        mTimeZoneAvailabilityChecker);
+        StubbedProviderMetricsLogger providerMetricsLogger = new StubbedProviderMetricsLogger();
+        TestLocationTimeZoneProvider provider = new TestLocationTimeZoneProvider(
+                providerMetricsLogger, mTestThreadingDomain, providerName,
+                mTimeZoneAvailabilityChecker);
         provider.setStateChangeRecordingEnabled(true);
         mTimeZoneAvailabilityChecker.validIds("Europe/London");
 
@@ -237,11 +236,10 @@
     @Test
     public void considerSuggestionWithInvalidTimeZoneIdsAsUncertain() {
         String providerName = "primary";
-        TestLocationTimeZoneProvider provider =
-                new TestLocationTimeZoneProvider(
-                        mTestThreadingDomain,
-                        providerName,
-                        mTimeZoneAvailabilityChecker);
+        StubbedProviderMetricsLogger providerMetricsLogger = new StubbedProviderMetricsLogger();
+        TestLocationTimeZoneProvider provider = new TestLocationTimeZoneProvider(
+                providerMetricsLogger, mTestThreadingDomain, providerName,
+                mTimeZoneAvailabilityChecker);
         provider.setStateChangeRecordingEnabled(true);
         provider.initialize(mProviderListener);
 
@@ -285,6 +283,20 @@
         }
     }
 
+    /**
+     * Returns the provider's state after asserting that the current state matches what is expected.
+     * This also asserts that the metrics logger was informed of the state change.
+     */
+    private static ProviderState assertAndReturnProviderState(
+            TestLocationTimeZoneProvider provider,
+            RecordingProviderMetricsLogger providerMetricsLogger, int expectedStateEnum) {
+        ProviderState currentState = provider.getCurrentState();
+        assertEquals(expectedStateEnum, currentState.stateEnum);
+        providerMetricsLogger.assertChangeLoggedAndRemove(expectedStateEnum);
+        providerMetricsLogger.assertNoMoreLogEntries();
+        return currentState;
+    }
+
     private static class TestLocationTimeZoneProvider extends LocationTimeZoneProvider {
 
         private boolean mOnInitializeCalled;
@@ -294,10 +306,11 @@
         private boolean mOnStopUpdatesCalled;
 
         /** Creates the instance. */
-        TestLocationTimeZoneProvider(@NonNull ThreadingDomain threadingDomain,
+        TestLocationTimeZoneProvider(@NonNull ProviderMetricsLogger providerMetricsLogger,
+                @NonNull ThreadingDomain threadingDomain,
                 @NonNull String providerName,
                 @NonNull TimeZoneIdValidator timeZoneIdValidator) {
-            super(threadingDomain, providerName, timeZoneIdValidator);
+            super(providerMetricsLogger, threadingDomain, providerName, timeZoneIdValidator);
         }
 
         @Override
@@ -366,6 +379,36 @@
         public void validIds(String... timeZoneIdss) {
             mValidTimeZoneIds.addAll(asList(timeZoneIdss));
         }
+    }
 
+    private static class StubbedProviderMetricsLogger implements
+            LocationTimeZoneProvider.ProviderMetricsLogger {
+
+        @Override
+        public void onProviderStateChanged(int stateEnum) {
+            // Stubbed
+        }
+    }
+
+    private static class RecordingProviderMetricsLogger implements
+            LocationTimeZoneProvider.ProviderMetricsLogger {
+
+        private LinkedList<Integer> mStates = new LinkedList<>();
+
+        @Override
+        public void onProviderStateChanged(int stateEnum) {
+            mStates.add(stateEnum);
+        }
+
+        public void assertChangeLoggedAndRemove(int expectedLoggedState) {
+            assertEquals("expected loggedState=" + expectedLoggedState
+                    + " but states logged were=" + mStates,
+                    (Integer) expectedLoggedState, mStates.peekFirst());
+            mStates.removeFirst();
+        }
+
+        public void assertNoMoreLogEntries() {
+            assertTrue(mStates.isEmpty());
+        }
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/FakeVibratorControllerProvider.java b/services/tests/servicestests/src/com/android/server/vibrator/FakeVibratorControllerProvider.java
index 2a3c2c4..b54b696 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/FakeVibratorControllerProvider.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/FakeVibratorControllerProvider.java
@@ -49,6 +49,8 @@
     private int mCapabilities;
     private int[] mSupportedEffects;
     private int[] mSupportedPrimitives;
+    private float mResonantFrequency;
+    private float mQFactor;
 
     private final class FakeNativeWrapper extends VibratorController.NativeWrapper {
         public int vibratorId;
@@ -89,6 +91,14 @@
             return mSupportedPrimitives;
         }
 
+        public float getResonantFrequency() {
+            return mResonantFrequency;
+        }
+
+        public float getQFactor() {
+            return mQFactor;
+        }
+
         public long perform(long effect, long strength, long vibrationId) {
             if (mSupportedEffects == null
                     || Arrays.binarySearch(mSupportedEffects, (int) effect) < 0) {
@@ -198,6 +208,16 @@
         mSupportedPrimitives = primitives;
     }
 
+    /** Set the resonant frequency of the fake vibrator hardware. */
+    public void setResonantFrequency(float resonantFrequency) {
+        mResonantFrequency = resonantFrequency;
+    }
+
+    /** Set the Q factor of the fake vibrator hardware. */
+    public void setQFactor(float qFactor) {
+        mQFactor = qFactor;
+    }
+
     /**
      * Return the amplitudes set by this controller, including zeroes for each time the vibrator was
      * turned off.
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java
index a28d18f..ce6639c 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java
@@ -266,6 +266,8 @@
         vibrator.setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS, IVibrator.CAP_AMPLITUDE_CONTROL);
         vibrator.setSupportedEffects(VibrationEffect.EFFECT_CLICK);
         vibrator.setSupportedPrimitives(VibrationEffect.Composition.PRIMITIVE_CLICK);
+        vibrator.setResonantFrequency(123.f);
+        vibrator.setQFactor(Float.NaN);
         VibratorInfo info = createSystemReadyService().getVibratorInfo(1);
 
         assertNotNull(info);
@@ -279,6 +281,8 @@
                 info.isEffectSupported(VibrationEffect.EFFECT_TICK));
         assertTrue(info.isPrimitiveSupported(VibrationEffect.Composition.PRIMITIVE_CLICK));
         assertFalse(info.isPrimitiveSupported(VibrationEffect.Composition.PRIMITIVE_TICK));
+        assertEquals(123.f, info.getResonantFrequency(), 0.01 /*tolerance*/);
+        assertTrue(Float.isNaN(info.getQFactor()));
     }
 
     @Test
diff --git a/services/tests/servicestests/test-apps/SimpleServiceTestApp/AndroidManifest.xml b/services/tests/servicestests/test-apps/SimpleServiceTestApp/AndroidManifest.xml
index 8789992..799ec53 100644
--- a/services/tests/servicestests/test-apps/SimpleServiceTestApp/AndroidManifest.xml
+++ b/services/tests/servicestests/test-apps/SimpleServiceTestApp/AndroidManifest.xml
@@ -17,9 +17,13 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
         package="com.android.servicestests.apps.simpleservicetestapp">
 
+    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
+
     <application>
         <service android:name=".SimpleService"
                  android:exported="true" />
+        <service android:name=".SimpleFgService"
+                 android:exported="true" />
     </application>
 
 </manifest>
diff --git a/services/tests/servicestests/test-apps/SimpleServiceTestApp/src/com/android/servicestests/apps/simpleservicetestapp/SimpleFgService.java b/services/tests/servicestests/test-apps/SimpleServiceTestApp/src/com/android/servicestests/apps/simpleservicetestapp/SimpleFgService.java
new file mode 100644
index 0000000..ccfc0b7
--- /dev/null
+++ b/services/tests/servicestests/test-apps/SimpleServiceTestApp/src/com/android/servicestests/apps/simpleservicetestapp/SimpleFgService.java
@@ -0,0 +1,113 @@
+/*
+ * 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.servicestests.apps.simpleservicetestapp;
+
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.app.Service;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.android.internal.R;
+
+public class SimpleFgService extends Service {
+    private static final String TAG = SimpleFgService.class.getSimpleName();
+    private static final String NOTIFICATION_CHANNEL_ID = TAG;
+    private static final int NOTIFICATION_ID = 1;
+
+    private static final int MSG_INIT = 0;
+    private static final int MSG_DONE = 1;
+    private static final int MSG_START_FOREGROUND = 2;
+    private static final int MSG_STOP_FOREGROUND = 3;
+
+    private static final String ACTION_FGS_STATS_TEST =
+            "com.android.servicestests.apps.simpleservicetestapp.ACTION_FGS_STATS_TEST";
+    private static final String EXTRA_MESSENGER = "extra_messenger";
+
+    private final Handler mHandler = new Handler() {
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_START_FOREGROUND: {
+                    Log.i(TAG, "startForeground");
+                    startForeground(NOTIFICATION_ID, mNotification);
+                    sendRemoteMessage(MSG_DONE, 0, 0, null);
+                } break;
+                case MSG_STOP_FOREGROUND: {
+                    Log.i(TAG, "stopForeground");
+                    stopForeground(true);
+                    sendRemoteMessage(MSG_DONE, 0, 0, null);
+                } break;
+            }
+        }
+    };
+    private final Messenger mMessenger = new Messenger(mHandler);
+
+    private Notification mNotification;
+    private Messenger mRemoteMessenger;
+
+    @Override
+    public void onCreate() {
+        Log.i(TAG, "onCreate");
+        final NotificationManager nm = getSystemService(NotificationManager.class);
+        nm.createNotificationChannel(new NotificationChannel(NOTIFICATION_CHANNEL_ID,
+                NOTIFICATION_CHANNEL_ID, NotificationManager.IMPORTANCE_LOW));
+        mNotification = new Notification.Builder(this, NOTIFICATION_CHANNEL_ID)
+                .setContentTitle(TAG)
+                .setSmallIcon(R.drawable.ic_info)
+                .build();
+    }
+
+    @Override
+    public int onStartCommand(Intent intent, int flags, int startId) {
+        Log.i(TAG, "onStartCommand");
+        startForeground(NOTIFICATION_ID, mNotification);
+        if (ACTION_FGS_STATS_TEST.equals(intent.getAction())) {
+            mRemoteMessenger = new Messenger(intent.getExtras().getBinder(EXTRA_MESSENGER));
+            sendRemoteMessage(MSG_INIT, 0, 0, mMessenger);
+        }
+        return START_NOT_STICKY;
+    }
+
+    private void sendRemoteMessage(int what, int arg1, int arg2, Object obj) {
+        final Message msg = Message.obtain();
+        msg.what = what;
+        msg.arg1 = arg1;
+        msg.arg2 = arg2;
+        msg.obj = obj;
+        try {
+            mRemoteMessenger.send(msg);
+        } catch (RemoteException e) {
+        }
+    }
+
+    @Override
+    public void onDestroy() {
+        Log.i(TAG, "onDestroy");
+        mNotification = null;
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return null;
+    }
+}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
index e510b4f..5462f47 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
@@ -61,6 +61,7 @@
 import android.media.AudioManager;
 import android.net.Uri;
 import android.os.Handler;
+import android.os.Process;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.VibrationEffect;
@@ -81,10 +82,12 @@
 import com.android.internal.util.IntPair;
 import com.android.server.UiServiceTestCase;
 import com.android.server.lights.LogicalLight;
+import com.android.server.pm.PackageManagerService;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
 import org.mockito.ArgumentMatcher;
 import org.mockito.Mock;
 import org.mockito.Mockito;
@@ -412,12 +415,16 @@
     }
 
     private void verifyVibrate() {
+        ArgumentCaptor<AudioAttributes> captor = ArgumentCaptor.forClass(AudioAttributes.class);
         verify(mVibrator, times(1)).vibrate(anyInt(), anyString(), argThat(mVibrateOnceMatcher),
-                anyString(), any(AudioAttributes.class));
+                anyString(), captor.capture());
+        assertEquals(0, (captor.getValue().getAllFlags()
+                & AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY));
     }
 
     private void verifyVibrate(int times) {
-        verify(mVibrator, times(times)).vibrate(anyInt(), anyString(), any(), anyString(),
+        verify(mVibrator, times(times)).vibrate(eq(Process.SYSTEM_UID),
+                eq(PackageManagerService.PLATFORM_PACKAGE_NAME), any(), anyString(),
                 any(AudioAttributes.class));
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index d8e7582..c19f348 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -159,6 +159,11 @@
         setBooted(mAtm);
     }
 
+    private TestStartingWindowOrganizer registerTestStartingWindowOrganizer() {
+        return new TestStartingWindowOrganizer(mAtm,
+                mSystemServicesTestRule.getPowerManagerWrapper());
+    }
+
     @Test
     public void testStackCleanupOnClearingTask() {
         final ActivityRecord activity = createActivityWith2LevelTask();
@@ -2294,6 +2299,7 @@
 
     @Test
     public void testCreateRemoveStartingWindow() {
+        registerTestStartingWindowOrganizer();
         final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build();
         activity.addStartingWindow(mPackageName,
                 android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
@@ -2307,6 +2313,7 @@
 
     @Test
     public void testAddRemoveRace() {
+        registerTestStartingWindowOrganizer();
         // There was once a race condition between adding and removing starting windows
         final ActivityRecord appToken = new ActivityBuilder(mAtm).setCreateTask(true).build();
         for (int i = 0; i < 1000; i++) {
@@ -2321,6 +2328,7 @@
 
     @Test
     public void testTransferStartingWindow() {
+        registerTestStartingWindowOrganizer();
         final ActivityRecord activity1 = new ActivityBuilder(mAtm).setCreateTask(true).build();
         final ActivityRecord activity2 = new ActivityBuilder(mAtm).setCreateTask(true).build();
         activity1.addStartingWindow(mPackageName,
@@ -2337,9 +2345,10 @@
 
     @Test
     public void testTransferStartingWindowWhileCreating() {
+        final TestStartingWindowOrganizer organizer = registerTestStartingWindowOrganizer();
         final ActivityRecord activity1 = new ActivityBuilder(mAtm).setCreateTask(true).build();
         final ActivityRecord activity2 = new ActivityBuilder(mAtm).setCreateTask(true).build();
-        ((TestWindowManagerPolicy) activity1.mWmService.mPolicy).setRunnableWhenAddingSplashScreen(
+        organizer.setRunnableWhenAddingSplashScreen(
                 () -> {
                     // Surprise, ...! Transfer window in the middle of the creation flow.
                     activity2.addStartingWindow(mPackageName,
@@ -2357,6 +2366,7 @@
 
     @Test
     public void testTransferStartingWindowCanAnimate() {
+        registerTestStartingWindowOrganizer();
         final ActivityRecord activity1 = new ActivityBuilder(mAtm).setCreateTask(true).build();
         final ActivityRecord activity2 = new ActivityBuilder(mAtm).setCreateTask(true).build();
         activity1.addStartingWindow(mPackageName,
@@ -2380,6 +2390,7 @@
 
     @Test
     public void testTransferStartingWindowFromFinishingActivity() {
+        registerTestStartingWindowOrganizer();
         final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build();
         final Task task = activity.getTask();
         activity.addStartingWindow(mPackageName, android.R.style.Theme, null /* compatInfo */,
@@ -2423,6 +2434,7 @@
 
     @Test
     public void testTransferStartingWindowSetFixedRotation() {
+        registerTestStartingWindowOrganizer();
         final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build();
         final Task task = activity.getTask();
         final ActivityRecord topActivity = new ActivityBuilder(mAtm).setTask(task).build();
@@ -2454,6 +2466,7 @@
 
     @Test
     public void testTryTransferStartingWindowFromHiddenAboveToken() {
+        registerTestStartingWindowOrganizer();
         // Add two tasks on top of each other.
         final ActivityRecord activityTop = new ActivityBuilder(mAtm).setCreateTask(true).build();
         final ActivityRecord activityBottom = new ActivityBuilder(mAtm).build();
diff --git a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
index 8703c31..7f9e7da 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
@@ -154,7 +154,7 @@
         mWindow = createDropTargetWindow("Drag test window", 0);
         doReturn(mWindow).when(mDisplayContent).getTouchableWinAtPointLocked(0, 0);
         when(mWm.mInputManager.transferTouchFocus(any(InputChannel.class),
-                any(InputChannel.class))).thenReturn(true);
+                any(InputChannel.class), any(boolean.class))).thenReturn(true);
 
         mWm.mWindowMap.put(mWindow.mClient.asBinder(), mWindow);
     }
@@ -370,7 +370,7 @@
                     .build();
 
             assertTrue(mWm.mInputManager.transferTouchFocus(new InputChannel(),
-                    new InputChannel()));
+                    new InputChannel(), true /* isDragDrop */));
             mToken = mTarget.performDrag(0, 0, mWindow.mClient, flag, surface, 0, 0, 0, 0, 0, data);
             assertNotNull(mToken);
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
index c6be987..7a4ad74 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
@@ -16,6 +16,9 @@
 
 package com.android.server.wm;
 
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
@@ -49,6 +52,7 @@
 import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
 
 import android.content.pm.ActivityInfo;
 import android.content.res.Configuration;
@@ -511,6 +515,8 @@
         final WindowToken navToken = mDefaultDisplay.getDisplayPolicy().getNavigationBar().mToken;
         final SurfaceControl.Transaction transaction = navToken.getPendingTransaction();
 
+        verify(mController.mStatusBar).setNavigationBarLumaSamplingEnabled(
+                mDefaultDisplay.mDisplayId, false);
         verify(transaction).reparent(navToken.getSurfaceControl(), activity.getSurfaceControl());
 
         final WindowContainer parent = navToken.getParent();
@@ -518,6 +524,8 @@
                 mDefaultDisplay.getDisplayPolicy().getNavBarFadeAnimationController();
 
         mController.cleanupAnimation(REORDER_MOVE_TO_TOP);
+        verify(mController.mStatusBar).setNavigationBarLumaSamplingEnabled(
+                mDefaultDisplay.mDisplayId, true);
         verify(transaction).reparent(navToken.getSurfaceControl(), parent.getSurfaceControl());
         verify(navBarFadeAnimationController).fadeWindowToken(true);
     }
@@ -532,6 +540,8 @@
         final WindowToken navToken = mDefaultDisplay.getDisplayPolicy().getNavigationBar().mToken;
         final SurfaceControl.Transaction transaction = navToken.getPendingTransaction();
 
+        verify(mController.mStatusBar).setNavigationBarLumaSamplingEnabled(
+                mDefaultDisplay.mDisplayId, false);
         verify(transaction).reparent(navToken.getSurfaceControl(), activity.getSurfaceControl());
 
         final WindowContainer parent = navToken.getParent();
@@ -539,6 +549,51 @@
                 mDefaultDisplay.getDisplayPolicy().getNavBarFadeAnimationController();
 
         mController.cleanupAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION);
+        verify(mController.mStatusBar).setNavigationBarLumaSamplingEnabled(
+                mDefaultDisplay.mDisplayId, true);
+        verify(transaction).reparent(navToken.getSurfaceControl(), parent.getSurfaceControl());
+        verify(navBarFadeAnimationController, never()).fadeWindowToken(anyBoolean());
+    }
+
+    @Test
+    public void testNotAttachNavigationBar_controlledByFixedRotationAnimation() {
+        setupForShouldAttachNavBarDuringTransition();
+        FixedRotationAnimationController mockController =
+                mock(FixedRotationAnimationController.class);
+        doReturn(mockController).when(mDefaultDisplay).getFixedRotationAnimationController();
+        final ActivityRecord homeActivity = createHomeActivity();
+        initializeRecentsAnimationController(mController, homeActivity);
+        assertFalse(mController.isNavigationBarAttachedToApp());
+    }
+
+    @Test
+    public void testAttachNavBarInSplitScreenMode() {
+        setupForShouldAttachNavBarDuringTransition();
+        final ActivityRecord primary = createActivityRecordWithParentTask(mDefaultDisplay,
+                WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD);
+        final ActivityRecord secondary = createActivityRecordWithParentTask(mDefaultDisplay,
+                WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_STANDARD);
+        final ActivityRecord homeActivity = createHomeActivity();
+        homeActivity.setVisibility(true);
+        initializeRecentsAnimationController(mController, homeActivity);
+
+        WindowState navWindow = mController.getNavigationBarWindow();
+        final WindowToken navToken = navWindow.mToken;
+        final SurfaceControl.Transaction transaction = navToken.getPendingTransaction();
+
+        verify(mController.mStatusBar).setNavigationBarLumaSamplingEnabled(
+                mDefaultDisplay.mDisplayId, false);
+        verify(navWindow).setSurfaceTranslationY(-secondary.getBounds().top);
+        verify(transaction).reparent(navToken.getSurfaceControl(), secondary.getSurfaceControl());
+        reset(navWindow);
+
+        mController.cleanupAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION);
+        final WindowContainer parent = navToken.getParent();
+        final NavBarFadeAnimationController navBarFadeAnimationController =
+                mDefaultDisplay.getDisplayPolicy().getNavBarFadeAnimationController();
+        verify(mController.mStatusBar).setNavigationBarLumaSamplingEnabled(
+                mDefaultDisplay.mDisplayId, true);
+        verify(navWindow).setSurfaceTranslationY(0);
         verify(transaction).reparent(navToken.getSurfaceControl(), parent.getSurfaceControl());
         verify(navBarFadeAnimationController, never()).fadeWindowToken(anyBoolean());
     }
@@ -600,9 +655,10 @@
 
     private void setupForShouldAttachNavBarDuringTransition() {
         mController.mShouldAttachNavBarToAppDuringTransition = true;
-        final WindowState navBar = createWindow(null, TYPE_NAVIGATION_BAR, "NavigationBar");
+        final WindowState navBar = spy(createWindow(null, TYPE_NAVIGATION_BAR, "NavigationBar"));
         mDefaultDisplay.getDisplayPolicy().addWindowLw(navBar, navBar.mAttrs);
         mWm.setRecentsAnimationController(mController);
+        doReturn(navBar).when(mController).getNavigationBarWindow();
         final NavBarFadeAnimationController mockNavBarFadeAnimationController =
                 mock(NavBarFadeAnimationController.class);
         final DisplayPolicy displayPolicy = spy(mDefaultDisplay.getDisplayPolicy());
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java
index 75226b7..8bc4ced 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java
@@ -34,7 +34,6 @@
 import android.platform.test.annotations.Presubmit;
 import android.view.InputChannel;
 
-import androidx.test.filters.FlakyTest;
 import androidx.test.filters.SmallTest;
 
 import org.junit.Before;
@@ -63,7 +62,8 @@
 
         when(mWm.mInputManager.transferTouchFocus(
                 any(InputChannel.class),
-                any(InputChannel.class))).thenReturn(true);
+                any(InputChannel.class),
+                any(boolean.class))).thenReturn(true);
 
         mWindow = createWindow(null, TYPE_BASE_APPLICATION, "window");
         mWindow.getTask().setResizeMode(RESIZE_MODE_RESIZEABLE);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
index 86d8eee..7822a85 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -119,7 +119,7 @@
             mRunnableWhenAddingSplashScreen.run();
             mRunnableWhenAddingSplashScreen = null;
         }
-        return () -> {
+        return (a) -> {
             synchronized (wm.mGlobalLock) {
                 activity.removeChild(window);
                 activity.mStartingWindow = null;
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
index 2c2c09a..01c503e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
@@ -547,7 +547,8 @@
             }
 
             @Override
-            public void removeStartingWindow(int taskId) { }
+            public void removeStartingWindow(int taskId, SurfaceControl leash, Rect frame,
+                    boolean playRevealAnimation) { }
 
             @Override
             public void copySplashScreenView(int taskId) { }
@@ -614,7 +615,8 @@
 
             }
             @Override
-            public void removeStartingWindow(int taskId) { }
+            public void removeStartingWindow(int taskId, SurfaceControl leash, Rect frame,
+                    boolean playRevealAnimation) { }
             @Override
             public void copySplashScreenView(int taskId) { }
             @Override
@@ -688,7 +690,8 @@
             }
 
             @Override
-            public void removeStartingWindow(int taskId) { }
+            public void removeStartingWindow(int taskId, SurfaceControl leash, Rect frame,
+                    boolean playRevealAnimation) { }
             @Override
             public void copySplashScreenView(int taskId) { }
             @Override
@@ -832,7 +835,8 @@
         @Override
         public void addStartingWindow(StartingWindowInfo info, IBinder appToken) { }
         @Override
-        public void removeStartingWindow(int taskId) { }
+        public void removeStartingWindow(int taskId, SurfaceControl leash, Rect frame,
+                boolean playRevealAnimation) { }
         @Override
         public void copySplashScreenView(int taskId) { }
         @Override
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 827ff6c..4a7784c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -36,6 +36,7 @@
 import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
 import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
@@ -50,6 +51,7 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+import static com.android.server.wm.StartingSurfaceController.DEBUG_ENABLE_SHELL_DRAWER;
 import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
 import static com.android.server.wm.WindowStateAnimator.HAS_DRAWN;
 
@@ -67,6 +69,7 @@
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
+import android.graphics.Rect;
 import android.hardware.display.DisplayManager;
 import android.os.Build;
 import android.os.Bundle;
@@ -74,6 +77,7 @@
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.service.voice.IVoiceInteractionSession;
+import android.util.SparseArray;
 import android.view.Display;
 import android.view.DisplayInfo;
 import android.view.IDisplayWindowInsetsController;
@@ -100,6 +104,7 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
+import java.util.HashMap;
 
 /** Common base class for window manager unit test classes. */
 class WindowTestsBase extends SystemServiceTestsBase {
@@ -1123,6 +1128,88 @@
         }
     }
 
+    static class TestStartingWindowOrganizer extends ITaskOrganizer.Stub {
+        private final ActivityTaskManagerService mAtm;
+        private final WindowManagerService mWMService;
+        private final WindowState.PowerManagerWrapper mPowerManagerWrapper;
+
+        private Runnable mRunnableWhenAddingSplashScreen;
+        private final SparseArray<IBinder> mTaskAppMap = new SparseArray<>();
+        private final HashMap<IBinder, WindowState> mAppWindowMap = new HashMap<>();
+
+        TestStartingWindowOrganizer(ActivityTaskManagerService service,
+                WindowState.PowerManagerWrapper powerManagerWrapper) {
+            mAtm = service;
+            mWMService = mAtm.mWindowManager;
+            mPowerManagerWrapper = powerManagerWrapper;
+            if (DEBUG_ENABLE_SHELL_DRAWER) {
+                mAtm.mTaskOrganizerController.setDeferTaskOrgCallbacksConsumer(Runnable::run);
+                mAtm.mTaskOrganizerController.registerTaskOrganizer(this);
+            }
+        }
+
+        void setRunnableWhenAddingSplashScreen(Runnable r) {
+            if (DEBUG_ENABLE_SHELL_DRAWER) {
+                mRunnableWhenAddingSplashScreen = r;
+            } else {
+                ((TestWindowManagerPolicy) mWMService.mPolicy).setRunnableWhenAddingSplashScreen(r);
+            }
+        }
+
+        @Override
+        public void addStartingWindow(StartingWindowInfo info, IBinder appToken) {
+            synchronized (mWMService.mGlobalLock) {
+                final ActivityRecord activity = mWMService.mRoot.getActivityRecord(
+                        appToken);
+                IWindow iWindow = mock(IWindow.class);
+                doReturn(mock(IBinder.class)).when(iWindow).asBinder();
+                final WindowState window = WindowTestsBase.createWindow(null,
+                        TYPE_APPLICATION_STARTING, activity,
+                        "Starting window", 0 /* ownerId */, 0 /* userId*/,
+                        false /* internalWindows */, mWMService, mock(Session.class),
+                        iWindow,
+                        mPowerManagerWrapper);
+                activity.mStartingWindow = window;
+                mAppWindowMap.put(appToken, window);
+                mTaskAppMap.put(info.taskInfo.taskId, appToken);
+            }
+            if (mRunnableWhenAddingSplashScreen != null) {
+                mRunnableWhenAddingSplashScreen.run();
+                mRunnableWhenAddingSplashScreen = null;
+            }
+        }
+        @Override
+        public void removeStartingWindow(int taskId, SurfaceControl leash, Rect frame,
+                boolean playRevealAnimation) {
+            synchronized (mWMService.mGlobalLock) {
+                final IBinder appToken = mTaskAppMap.get(taskId);
+                if (appToken != null) {
+                    mTaskAppMap.remove(taskId);
+                    final ActivityRecord activity = mWMService.mRoot.getActivityRecord(
+                            appToken);
+                    WindowState win = mAppWindowMap.remove(appToken);
+                    activity.removeChild(win);
+                    activity.mStartingWindow = null;
+                }
+            }
+        }
+        @Override
+        public void copySplashScreenView(int taskId) {
+        }
+        @Override
+        public void onTaskAppeared(ActivityManager.RunningTaskInfo info, SurfaceControl leash) {
+        }
+        @Override
+        public void onTaskVanished(ActivityManager.RunningTaskInfo info) {
+        }
+        @Override
+        public void onTaskInfoChanged(ActivityManager.RunningTaskInfo info) {
+        }
+        @Override
+        public void onBackPressedOnTaskRoot(ActivityManager.RunningTaskInfo taskInfo) {
+        }
+    }
+
     static class TestSplitOrganizer extends ITaskOrganizer.Stub {
         final ActivityTaskManagerService mService;
         Task mPrimary;
@@ -1161,7 +1248,8 @@
         public void addStartingWindow(StartingWindowInfo info, IBinder appToken) {
         }
         @Override
-        public void removeStartingWindow(int taskId) {
+        public void removeStartingWindow(int taskId, SurfaceControl leash, Rect frame,
+                boolean playRevealAnimation) {
         }
         @Override
         public void copySplashScreenView(int taskId) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
index c82ba99..d967891 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
@@ -470,7 +470,7 @@
                 mWm, mockRunner, null, displayId);
         spyOn(controller);
         controller.mShouldAttachNavBarToAppDuringTransition = true;
-        doReturn(mNavBarWindow.mToken).when(controller).getNavigationBarWindowToken();
+        doReturn(mNavBarWindow).when(controller).getNavigationBarWindow();
         mWm.setRecentsAnimationController(controller);
 
         // set ime visible
diff --git a/telecomm/java/android/telecom/CallDiagnosticService.java b/telecomm/java/android/telecom/CallDiagnosticService.java
index 201c5db..809f2bc 100644
--- a/telecomm/java/android/telecom/CallDiagnosticService.java
+++ b/telecomm/java/android/telecom/CallDiagnosticService.java
@@ -19,9 +19,12 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SdkConstant;
+import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
 import android.app.Service;
 import android.content.Intent;
+import android.os.Handler;
+import android.os.HandlerExecutor;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.util.ArrayMap;
@@ -30,6 +33,7 @@
 import com.android.internal.telecom.ICallDiagnosticServiceAdapter;
 
 import java.util.Map;
+import java.util.concurrent.Executor;
 
 /**
  * The platform supports a single OEM provided {@link CallDiagnosticService}, as defined by the
@@ -51,6 +55,11 @@
  * </service>
  * }
  * </pre>
+ * <p>
+ * <h2>Threading Model</h2>
+ * By default, all incoming IPC from Telecom in this service and in the {@link DiagnosticCall}
+ * instances will take place on the main thread.  You can override {@link #getExecutor()} in your
+ * implementation to provide your own {@link Executor}.
  * @hide
  */
 @SystemApi
@@ -83,7 +92,7 @@
 
         @Override
         public void updateCallAudioState(CallAudioState callAudioState) throws RemoteException {
-            onCallAudioStateChanged(callAudioState);
+            getExecutor().execute(() -> onCallAudioStateChanged(callAudioState));
         }
 
         @Override
@@ -133,8 +142,18 @@
      */
     private final Map<String, Call.Details> mCallByTelecomCallId = new ArrayMap<>();
     private final Map<String, DiagnosticCall> mDiagnosticCallByTelecomCallId = new ArrayMap<>();
+    private final Object mLock = new Object();
     private ICallDiagnosticServiceAdapter mAdapter;
 
+    /**
+     * Handles binding to the {@link CallDiagnosticService}.
+     *
+     * @param intent The Intent that was used to bind to this service,
+     * as given to {@link android.content.Context#bindService
+     * Context.bindService}.  Note that any extras that were included with
+     * the Intent at that point will <em>not</em> be seen here.
+     * @return
+     */
     @Nullable
     @Override
     public IBinder onBind(@NonNull Intent intent) {
@@ -143,11 +162,29 @@
     }
 
     /**
+     * Returns the {@link Executor} to use for incoming IPS from Telecom into your service
+     * implementation.
+     * <p>
+     * Override this method in your {@link CallDiagnosticService} implementation to provide the
+     * executor you want to use for incoming IPC.
+     *
+     * @return the {@link Executor} to use for incoming IPC from Telecom to
+     * {@link CallDiagnosticService} and {@link DiagnosticCall}.
+     */
+    @SuppressLint("OnNameExpected")
+    @NonNull public Executor getExecutor() {
+        return new HandlerExecutor(Handler.createAsync(getMainLooper()));
+    }
+
+    /**
      * Telecom calls this method on the {@link CallDiagnosticService} with details about a new call
      * which was added to Telecom.
      * <p>
      * The {@link CallDiagnosticService} returns an implementation of {@link DiagnosticCall} to be
      * used for the lifespan of this call.
+     * <p>
+     * Calls to this method will use the {@link CallDiagnosticService}'s {@link Executor}; see
+     * {@link CallDiagnosticService#getExecutor()} for more information.
      *
      * @param call The details of the new call.
      * @return An instance of {@link DiagnosticCall} which the {@link CallDiagnosticService}
@@ -160,6 +197,10 @@
     /**
      * Telecom calls this method when a previous created {@link DiagnosticCall} is no longer needed.
      * This happens when Telecom is no longer tracking the call in question.
+     * <p>
+     * Calls to this method will use the {@link CallDiagnosticService}'s {@link Executor}; see
+     * {@link CallDiagnosticService#getExecutor()} for more information.
+     *
      * @param call The diagnostic call which is no longer tracked by Telecom.
      */
     public abstract void onRemoveDiagnosticCall(@NonNull DiagnosticCall call);
@@ -169,6 +210,9 @@
      * changes.
      * <p>
      * Audio state is common to all calls.
+     * <p>
+     * Calls to this method will use the {@link CallDiagnosticService}'s {@link Executor}; see
+     * {@link CallDiagnosticService#getExecutor()} for more information.
      *
      * @param audioState The new audio state.
      */
@@ -178,6 +222,10 @@
     /**
      * Telecom calls this method when a {@link BluetoothCallQualityReport} is received from the
      * bluetooth stack.
+     * <p>
+     * Calls to this method will use the {@link CallDiagnosticService}'s {@link Executor}; see
+     * {@link CallDiagnosticService#getExecutor()} for more information.
+     *
      * @param qualityReport the {@link BluetoothCallQualityReport}.
      */
     public abstract void onBluetoothCallQualityReportReceived(
@@ -199,15 +247,22 @@
         String telecomCallId = parcelableCall.getId();
         Log.i(this, "handleCallAdded: callId=%s - added", telecomCallId);
         Call.Details newCallDetails = Call.Details.createFromParcelableCall(parcelableCall);
-        mCallByTelecomCallId.put(telecomCallId, newCallDetails);
-
-        DiagnosticCall diagnosticCall = onInitializeDiagnosticCall(newCallDetails);
-        if (diagnosticCall == null) {
-            throw new IllegalArgumentException("A valid DiagnosticCall instance was not provided.");
+        synchronized (mLock) {
+            mCallByTelecomCallId.put(telecomCallId, newCallDetails);
         }
-        diagnosticCall.setListener(mDiagnosticCallListener);
-        diagnosticCall.setCallId(telecomCallId);
-        mDiagnosticCallByTelecomCallId.put(telecomCallId, diagnosticCall);
+
+        getExecutor().execute(() -> {
+            DiagnosticCall diagnosticCall = onInitializeDiagnosticCall(newCallDetails);
+            if (diagnosticCall == null) {
+                throw new IllegalArgumentException(
+                        "A valid DiagnosticCall instance was not provided.");
+            }
+            synchronized (mLock) {
+                diagnosticCall.setListener(mDiagnosticCallListener);
+                diagnosticCall.setCallId(telecomCallId);
+                mDiagnosticCallByTelecomCallId.put(telecomCallId, diagnosticCall);
+            }
+        });
     }
 
     /**
@@ -220,10 +275,12 @@
         String telecomCallId = parcelableCall.getId();
         Log.i(this, "handleCallUpdated: callId=%s - updated", telecomCallId);
         Call.Details newCallDetails = Call.Details.createFromParcelableCall(parcelableCall);
-
-        DiagnosticCall diagnosticCall = mDiagnosticCallByTelecomCallId.get(telecomCallId);
-        mCallByTelecomCallId.put(telecomCallId, newCallDetails);
-        diagnosticCall.handleCallUpdated(newCallDetails);
+        DiagnosticCall diagnosticCall;
+        synchronized (mLock) {
+            diagnosticCall = mDiagnosticCallByTelecomCallId.get(telecomCallId);
+            mCallByTelecomCallId.put(telecomCallId, newCallDetails);
+        }
+        getExecutor().execute(() -> diagnosticCall.handleCallUpdated(newCallDetails));
     }
 
     /**
@@ -236,10 +293,19 @@
         if (mCallByTelecomCallId.containsKey(telecomCallId)) {
             mCallByTelecomCallId.remove(telecomCallId);
         }
-        if (mDiagnosticCallByTelecomCallId.containsKey(telecomCallId)) {
-            DiagnosticCall call = mDiagnosticCallByTelecomCallId.remove(telecomCallId);
-            // Inform the service of the removed call.
-            onRemoveDiagnosticCall(call);
+
+        DiagnosticCall diagnosticCall;
+        synchronized (mLock) {
+            if (mDiagnosticCallByTelecomCallId.containsKey(telecomCallId)) {
+                diagnosticCall = mDiagnosticCallByTelecomCallId.remove(telecomCallId);
+            } else {
+                diagnosticCall = null;
+            }
+        }
+
+        // Inform the service of the removed call.
+        if (diagnosticCall != null) {
+            getExecutor().execute(() -> onRemoveDiagnosticCall(diagnosticCall));
         }
     }
 
@@ -252,8 +318,14 @@
      */
     private void handleReceivedD2DMessage(@NonNull String callId, int message, int value) {
         Log.i(this, "handleReceivedD2DMessage: callId=%s, msg=%d/%d", callId, message, value);
-        DiagnosticCall diagnosticCall = mDiagnosticCallByTelecomCallId.get(callId);
-        diagnosticCall.onReceiveDeviceToDeviceMessage(message, value);
+        DiagnosticCall diagnosticCall;
+        synchronized (mLock) {
+            diagnosticCall = mDiagnosticCallByTelecomCallId.get(callId);
+        }
+        if (diagnosticCall != null) {
+            getExecutor().execute(
+                    () -> diagnosticCall.onReceiveDeviceToDeviceMessage(message, value));
+        }
     }
 
     /**
@@ -265,7 +337,7 @@
     private void handleBluetoothCallQualityReport(@NonNull BluetoothCallQualityReport
             qualityReport) {
         Log.i(this, "handleBluetoothCallQualityReport; report=%s", qualityReport);
-        onBluetoothCallQualityReportReceived(qualityReport);
+        getExecutor().execute(() -> onBluetoothCallQualityReportReceived(qualityReport));
     }
 
     /**
diff --git a/telecomm/java/android/telecom/DiagnosticCall.java b/telecomm/java/android/telecom/DiagnosticCall.java
index a495289..af46b77 100644
--- a/telecomm/java/android/telecom/DiagnosticCall.java
+++ b/telecomm/java/android/telecom/DiagnosticCall.java
@@ -26,15 +26,27 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.concurrent.Executor;
 
 /**
  * A {@link DiagnosticCall} provides a way for a {@link CallDiagnosticService} to receive diagnostic
- * information about a mobile call on the device.  The {@link CallDiagnosticService} can generate
- * mid-call diagnostic messages using the {@link #displayDiagnosticMessage(int, CharSequence)} API
- * which provides the user with valuable information about conditions impacting their call and
- * corrective actions.  For example, if the {@link CallDiagnosticService} determines that conditions
- * on the call are degrading, it can inform the user that the call may soon drop and that they
- * can try using a different calling method (e.g. VOIP or WIFI).
+ * information about a mobile call on the device.  A {@link DiagnosticCall} is similar to a
+ * {@link Call}, however it does not expose call control capabilities and exposes extra diagnostic
+ * and messaging capabilities not present on a {@link Call}.  The {@link CallDiagnosticService}
+ * creates a {@link DiagnosticCall} for each {@link Call} on the device.  This means that for each
+ * in progress call on the device, the {@link CallDiagnosticService} will create an instance of
+ * {@link DiagnosticCall}.
+ * <p>
+ * The {@link CallDiagnosticService} can generate mid-call diagnostic messages using the
+ * {@link #displayDiagnosticMessage(int, CharSequence)} API which provides the user with valuable
+ * information about conditions impacting their call and corrective actions.  For example, if the
+ * {@link CallDiagnosticService} determines that conditions on the call are degrading, it can inform
+ * the user that the call may soon drop and that they can try using a different calling method
+ * (e.g. VOIP or WIFI).
+ * <h2>Threading Model</h2>
+ * All incoming IPC from Telecom in this class will use the same {@link Executor} as the
+ * {@link CallDiagnosticService}. See {@link CallDiagnosticService#setExecutor(Executor)} for more
+ * information.
  * @hide
  */
 @SystemApi
@@ -53,15 +65,19 @@
     /**
      * Device to device message sent via {@link #sendDeviceToDeviceMessage(int, int)} (received via
      * {@link #onReceiveDeviceToDeviceMessage(int, int)}) which communicates the radio access type
-     * used for the current call.  Based loosely on the
-     * {@link android.telephony.TelephonyManager#getNetworkType(int)} for the call, provides a
-     * high level summary of the call radio access type.
+     * used for the current call.  The call network type communicated here is an intentional
+     * simplification of the {@link android.telephony.TelephonyManager#getNetworkType(int)} which
+     * removes some of the resolution inherent in those values; the
+     * {@link android.telephony.TelephonyManager#NETWORK_TYPE_LTE_CA} value, for example is
+     * collapsed into the {@link android.telephony.TelephonyManager#NETWORK_TYPE_LTE} value for
+     * efficiency of transport.  For a discussion on the necessity of this simplification, see
+     * {@link #sendDeviceToDeviceMessage(int, int)}.
      * <p>
-     * Valid values:
+     * Valid values are below:
      * <UL>
-     *     <LI>{@link #NETWORK_TYPE_LTE}</LI>
-     *     <LI>{@link #NETWORK_TYPE_IWLAN}</LI>
-     *     <LI>{@link #NETWORK_TYPE_NR}</LI>
+     *     <LI>{@link android.telephony.TelephonyManager#NETWORK_TYPE_LTE}</LI>
+     *     <LI>{@link android.telephony.TelephonyManager#NETWORK_TYPE_IWLAN}</LI>
+     *     <LI>{@link android.telephony.TelephonyManager#NETWORK_TYPE_NR}</LI>
      * </UL>
      */
     public static final int MESSAGE_CALL_NETWORK_TYPE = 1;
@@ -69,14 +85,21 @@
     /**
      * Device to device message sent via {@link #sendDeviceToDeviceMessage(int, int)} (received via
      * {@link #onReceiveDeviceToDeviceMessage(int, int)}) which communicates the call audio codec
-     * used for the current call.  Based loosely on the {@link Connection#EXTRA_AUDIO_CODEC} for a
-     * call.
+     * used for the current call.
+     * <p>
+     * The audio codec communicated here is an intentional simplification of the
+     * {@link Connection#EXTRA_AUDIO_CODEC} for a call and focuses on communicating the most common
+     * variants of these audio codecs.  Other variants of these codecs are reported as the next
+     * closest variant.  For example, the {@link Connection#AUDIO_CODEC_EVS_FB} full band codec
+     * is reported via device to device communication as {@link Connection#AUDIO_CODEC_EVS_WB}.
+     * For a discussion on the necessity of this simplification, see
+     * {@link #sendDeviceToDeviceMessage(int, int)}.
      * <p>
      * Valid values:
      * <UL>
-     *     <LI>{@link #AUDIO_CODEC_EVS}</LI>
-     *     <LI>{@link #AUDIO_CODEC_AMR_WB}</LI>
-     *     <LI>{@link #AUDIO_CODEC_AMR_NB}</LI>
+     *     <LI>{@link Connection#AUDIO_CODEC_EVS_WB}</LI>
+     *     <LI>{@link Connection#AUDIO_CODEC_AMR_WB}</LI>
+     *     <LI>{@link Connection#AUDIO_CODEC_AMR}</LI>
      * </UL>
      */
     public static final int MESSAGE_CALL_AUDIO_CODEC = 2;
@@ -122,41 +145,6 @@
     public @interface MessageType {}
 
     /**
-     * Used with {@link #MESSAGE_CALL_NETWORK_TYPE} to indicate an LTE network is being used for the
-     * call.
-     */
-    public static final int NETWORK_TYPE_LTE = 1;
-
-    /**
-     * Used with {@link #MESSAGE_CALL_NETWORK_TYPE} to indicate WIFI calling is in use for the call.
-     */
-    public static final int NETWORK_TYPE_IWLAN = 2;
-
-    /**
-     * Used with {@link #MESSAGE_CALL_NETWORK_TYPE} to indicate a 5G NR (new radio) network is in
-     * used for the call.
-     */
-    public static final int NETWORK_TYPE_NR = 3;
-
-    /**
-     * Used with {@link #MESSAGE_CALL_AUDIO_CODEC} to indicate call audio is using the
-     * Enhanced Voice Services (EVS) codec for the call.
-     */
-    public static final int AUDIO_CODEC_EVS = 1;
-
-    /**
-     * Used with {@link #MESSAGE_CALL_AUDIO_CODEC} to indicate call audio is using the AMR
-     * (adaptive multi-rate) WB (wide band) audio codec.
-     */
-    public static final int AUDIO_CODEC_AMR_WB = 2;
-
-    /**
-     * Used with {@link #MESSAGE_CALL_AUDIO_CODEC} to indicate call audio is using the AMR
-     * (adaptive multi-rate) NB (narrow band) audio codec.
-     */
-    public static final int AUDIO_CODEC_AMR_NB = 3;
-
-    /**
      * Used with {@link #MESSAGE_DEVICE_BATTERY_STATE} to indicate that the battery is low.
      */
     public static final int BATTERY_STATE_LOW = 1;
@@ -183,7 +171,6 @@
 
     private Listener mListener;
     private String mCallId;
-    private Call.Details mCallDetails;
 
     /**
      * @hide
@@ -210,16 +197,10 @@
     }
 
     /**
-     * Returns the latest {@link Call.Details} associated with this {@link DiagnosticCall} as
-     * reported by {@link #onCallDetailsChanged(Call.Details)}.
-     * @return The latest {@link Call.Details}.
-     */
-    public @NonNull Call.Details getCallDetails() {
-        return mCallDetails;
-    }
-
-    /**
      * Telecom calls this method when the details of a call changes.
+     * <p>
+     * Calls to this method will use the same {@link Executor} as the {@link CallDiagnosticService};
+     * see {@link CallDiagnosticService#getExecutor()} for more information.
      */
     public abstract void onCallDetailsChanged(@NonNull android.telecom.Call.Details details);
 
@@ -234,6 +215,9 @@
      * devices communicating are using a different version of the protocol, messages the recipient
      * are not aware of are silently discarded.  This means an older client talking to a new client
      * will not receive newer messages and values sent by the new client.
+     * <p>
+     * Calls to this method will use the same {@link Executor} as the {@link CallDiagnosticService};
+     * see {@link CallDiagnosticService#getExecutor()} for more information.
      */
     public abstract void onReceiveDeviceToDeviceMessage(
             @MessageType int message,
@@ -253,39 +237,19 @@
      * platform due to the extreme bandwidth constraints inherent with underlying device to device
      * communication transports used by the telephony framework.  Device to device communication is
      * either accomplished by adding RFC8285 compliant RTP header extensions to the audio packets
-     * for a call, or using the DTMF digits A-D as a communication pathway.  Signalling requirements
-     * for DTMF digits place a significant limitation on the amount of information which can be
-     * communicated during a call.
+     * for a call, or using the DTMF digits A-D as a communication pathway.  RTP header extension
+     * packets ride alongside a the audio for a call, and are thus limited to roughly a byte for
+     * a message.  Signalling requirements for DTMF digits place even more significant limitations
+     * on the amount of information which can be communicated during a call, offering only a few
+     * bits of potential information per message.  The messages and values are constrained in order
+     * to meet the limited bandwidth inherent with DTMF signalling.
      * <p>
-     * Allowed message types and values are:
+     * Allowed message types are:
      * <ul>
-     *     <li>{@link #MESSAGE_CALL_NETWORK_TYPE}
-     *         <ul>
-     *             <li>{@link #NETWORK_TYPE_LTE}</li>
-     *             <li>{@link #NETWORK_TYPE_IWLAN}</li>
-     *             <li>{@link #NETWORK_TYPE_NR}</li>
-     *         </ul>
-     *     </li>
-     *     <li>{@link #MESSAGE_CALL_AUDIO_CODEC}
-     *         <ul>
-     *             <li>{@link #AUDIO_CODEC_EVS}</li>
-     *             <li>{@link #AUDIO_CODEC_AMR_WB}</li>
-     *             <li>{@link #AUDIO_CODEC_AMR_NB}</li>
-     *         </ul>
-     *     </li>
-     *     <li>{@link #MESSAGE_DEVICE_BATTERY_STATE}
-     *         <ul>
-     *             <li>{@link #BATTERY_STATE_LOW}</li>
-     *             <li>{@link #BATTERY_STATE_GOOD}</li>
-     *             <li>{@link #BATTERY_STATE_CHARGING}</li>
-     *         </ul>
-     *     </li>
-     *     <li>{@link #MESSAGE_DEVICE_NETWORK_COVERAGE}
-     *         <ul>
-     *             <li>{@link #COVERAGE_POOR}</li>
-     *             <li>{@link #COVERAGE_GOOD}</li>
-     *         </ul>
-     *     </li>
+     *     <li>{@link #MESSAGE_CALL_NETWORK_TYPE}</LI>
+     *     <li>{@link #MESSAGE_CALL_AUDIO_CODEC}</LI>
+     *     <li>{@link #MESSAGE_DEVICE_BATTERY_STATE}</LI>
+     *     <li>{@link #MESSAGE_DEVICE_NETWORK_COVERAGE}</LI>
      * </ul>
      * @param message The message type to send.
      * @param value The message value corresponding to the type.
@@ -307,6 +271,9 @@
      * @param preciseDisconnectCause the precise disconnect cause for the call.
      * @return the disconnect message to use in place of the default Telephony message, or
      * {@code null} if the default message will not be overridden.
+     * <p>
+     * Calls to this method will use the same {@link Executor} as the {@link CallDiagnosticService};
+     * see {@link CallDiagnosticService#getExecutor()} for more information.
      */
     // TODO: Wire in Telephony support for this.
     public abstract @Nullable CharSequence onCallDisconnected(
@@ -323,6 +290,9 @@
      * @param disconnectReason The {@link ImsReasonInfo} associated with the call disconnection.
      * @return A user-readable call disconnect message to use in place of the platform-generated
      * disconnect message, or {@code null} if the disconnect message should not be overridden.
+     * <p>
+     * Calls to this method will use the same {@link Executor} as the {@link CallDiagnosticService};
+     * see {@link CallDiagnosticService#getExecutor()} for more information.
      */
     // TODO: Wire in Telephony support for this.
     public abstract @Nullable CharSequence onCallDisconnected(
@@ -332,6 +302,9 @@
      * Telecom calls this method when a {@link CallQuality} report is received from the telephony
      * stack for a call.
      * @param callQuality The call quality report for this call.
+     * <p>
+     * Calls to this method will use the same {@link Executor} as the {@link CallDiagnosticService};
+     * see {@link CallDiagnosticService#getExecutor()} for more information.
      */
     public abstract void onCallQualityReceived(@NonNull CallQuality callQuality);
 
@@ -375,7 +348,6 @@
      * @hide
      */
     public void handleCallUpdated(@NonNull Call.Details newDetails) {
-        mCallDetails = newDetails;
         onCallDetailsChanged(newDetails);
     }
 }
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 17749e8..1677c8c 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -314,8 +314,8 @@
     public static final String EXTRA_HAS_PICTURE = "android.telecom.extra.HAS_PICTURE";
 
     /**
-     * A URI representing the picture that was downloaded when a call is received or uploaded
-     * when a call is placed.
+     * A {@link Uri} representing the picture that was downloaded when a call is received or
+     * uploaded when a call is placed.
      *
      * This is a content URI within the call log provider which can be used to open a file
      * descriptor. This could be set a short time after a call is added to the Dialer app if the
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 705e93f..1a71f80 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -27,6 +27,7 @@
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.Context;
+import android.net.ipsec.ike.SaProposal;
 import android.os.Build;
 import android.os.PersistableBundle;
 import android.os.RemoteException;
@@ -4170,9 +4171,11 @@
                 KEY_PREFIX + "child_sa_rekey_soft_timer_sec_int";
 
         /**
-         * Supported DH groups for IKE negotiation. Possible values are {@link #DH_GROUP_NONE},
-         * {@link #DH_GROUP_1024_BIT_MODP}, {@link #DH_GROUP_1536_BIT_MODP}, {@link
-         * #DH_GROUP_2048_BIT_MODP}
+         * Supported DH groups for IKE negotiation. Possible values are:
+         * {@link android.net.ipsec.ike.SaProposal#DH_GROUP_NONE},
+         * {@link android.net.ipsec.ike.SaProposal#DH_GROUP_1024_BIT_MODP},
+         * {@link android.net.ipsec.ike.SaProposal#DH_GROUP_1536_BIT_MODP},
+         * {@link android.net.ipsec.ike.SaProposal#DH_GROUP_2048_BIT_MODP}
          */
         public static final String KEY_DIFFIE_HELLMAN_GROUPS_INT_ARRAY =
                 KEY_PREFIX + "diffie_hellman_groups_int_array";
@@ -4208,23 +4211,29 @@
 
         /**
          * List of supported key sizes for AES Cipher Block Chaining (CBC) encryption mode of child
-         * session. Possible values are {@link #KEY_LEN_UNUSED}, {@link #KEY_LEN_AES_128}, {@link
-         * #KEY_LEN_AES_192}, {@link #KEY_LEN_AES_256}
+         * session. Possible values are:
+         * {@link android.net.ipsec.ike.SaProposal#KEY_LEN_UNUSED},
+         * {@link android.net.ipsec.ike.SaProposal#KEY_LEN_AES_128},
+         * {@link android.net.ipsec.ike.SaProposal#KEY_LEN_AES_192},
+         * {@link android.net.ipsec.ike.SaProposal#KEY_LEN_AES_256}
          */
         public static final String KEY_CHILD_SESSION_AES_CBC_KEY_SIZE_INT_ARRAY =
                 KEY_PREFIX + "child_session_aes_cbc_key_size_int_array";
 
         /**
          * List of supported key sizes for AES Counter (CTR) encryption mode of child session.
-         * Possible values are {@link #KEY_LEN_UNUSED},
-         * {@link #KEY_LEN_AES_128}, {@link #KEY_LEN_AES_192}, {@link #KEY_LEN_AES_256}
+         * Possible values are:
+         * {@link android.net.ipsec.ike.SaProposal#KEY_LEN_UNUSED},
+         * {@link android.net.ipsec.ike.SaProposal#KEY_LEN_AES_128},
+         * {@link android.net.ipsec.ike.SaProposal#KEY_LEN_AES_192},
+         * {@link android.net.ipsec.ike.SaProposal#KEY_LEN_AES_256}
          */
         public static final String KEY_CHILD_SESSION_AES_CTR_KEY_SIZE_INT_ARRAY =
                 KEY_PREFIX + "child_session_aes_ctr_key_size_int_array";
 
         /**
          * List of supported encryption algorithms for child session. Possible values are
-         * {@link #ENCRYPTION_ALGORITHM_AES_CBC}
+         * {@link android.net.ipsec.ike.SaProposal#ENCRYPTION_ALGORITHM_AES_CBC}
          */
         public static final String KEY_SUPPORTED_CHILD_SESSION_ENCRYPTION_ALGORITHMS_INT_ARRAY =
                 KEY_PREFIX + "supported_child_session_encryption_algorithms_int_array";
@@ -4245,8 +4254,11 @@
 
         /**
          * List of supported key sizes for AES Cipher Block Chaining (CBC) encryption mode of IKE
-         * session. Possible values - {@link #KEY_LEN_UNUSED}, {@link #KEY_LEN_AES_128}, {@link
-         * #KEY_LEN_AES_192}, {@link #KEY_LEN_AES_256}
+         * session. Possible values:
+         * {@link android.net.ipsec.ike.SaProposal#KEY_LEN_UNUSED},
+         * {@link android.net.ipsec.ike.SaProposal#KEY_LEN_AES_128},
+         * {@link android.net.ipsec.ike.SaProposal#KEY_LEN_AES_192},
+         * {@link android.net.ipsec.ike.SaProposal#KEY_LEN_AES_256}
          */
         public static final String KEY_IKE_SESSION_AES_CBC_KEY_SIZE_INT_ARRAY =
                 KEY_PREFIX + "ike_session_encryption_aes_cbc_key_size_int_array";
@@ -4254,24 +4266,31 @@
 
         /**
          * List of supported key sizes for AES Counter (CTR) encryption mode of IKE session.
-         * Possible values - {@link #KEY_LEN_UNUSED}, {@link #KEY_LEN_AES_128},
-         * {@link #KEY_LEN_AES_192}, {@link #KEY_LEN_AES_256}
+         * Possible values -
+         * {@link android.net.ipsec.ike.SaProposal#KEY_LEN_UNUSED},
+         * {@link android.net.ipsec.ike.SaProposal#KEY_LEN_AES_128},
+         * {@link android.net.ipsec.ike.SaProposal#KEY_LEN_AES_192},
+         * {@link android.net.ipsec.ike.SaProposal#KEY_LEN_AES_256}
          */
          public static final String KEY_IKE_SESSION_AES_CTR_KEY_SIZE_INT_ARRAY =
                  KEY_PREFIX + "ike_session_encryption_aes_ctr_key_size_int_array";
 
         /**
          * List of supported encryption algorithms for IKE session. Possible values are
-         * {@link #ENCRYPTION_ALGORITHM_AES_CBC}, {@link #ENCRYPTION_ALGORITHM_AES_CTR}
+         * {@link android.net.ipsec.ike.SaProposal#ENCRYPTION_ALGORITHM_AES_CBC},
+         * {@link android.net.ipsec.ike.SaProposal#ENCRYPTION_ALGORITHM_AES_CTR}
          */
         public static final String KEY_SUPPORTED_IKE_SESSION_ENCRYPTION_ALGORITHMS_INT_ARRAY =
                 KEY_PREFIX + "supported_ike_session_encryption_algorithms_int_array";
 
         /**
-         * List of supported integrity algorithms for IKE session Possible values are {@link
-         * #INTEGRITY_ALGORITHM_NONE}, {@link #INTEGRITY_ALGORITHM_HMAC_SHA1_96}, {@link
-         * #INTEGRITY_ALGORITHM_AES_XCBC_96}, {@link #INTEGRITY_ALGORITHM_HMAC_SHA2_256_128}, {@link
-         * #INTEGRITY_ALGORITHM_HMAC_SHA2_384_192}, {@link #INTEGRITY_ALGORITHM_HMAC_SHA2_512_256}
+         * List of supported integrity algorithms for IKE session. Possible values are
+         * {@link android.net.ipsec.ike.SaProposal#INTEGRITY_ALGORITHM_NONE},
+         * {@link android.net.ipsec.ike.SaProposal#INTEGRITY_ALGORITHM_HMAC_SHA1_96},
+         * {@link android.net.ipsec.ike.SaProposal#INTEGRITY_ALGORITHM_AES_XCBC_96},
+         * {@link android.net.ipsec.ike.SaProposal#INTEGRITY_ALGORITHM_HMAC_SHA2_256_128},
+         * {@link android.net.ipsec.ike.SaProposal#INTEGRITY_ALGORITHM_HMAC_SHA2_384_192},
+         * {@link android.net.ipsec.ike.SaProposal#INTEGRITY_ALGORITHM_HMAC_SHA2_512_256}
          */
         public static final String KEY_SUPPORTED_INTEGRITY_ALGORITHMS_INT_ARRAY =
                 KEY_PREFIX + "supported_integrity_algorithms_int_array";
@@ -4291,9 +4310,11 @@
 
         /**
          * List of supported pseudo random function algorithms for IKE session. Possible values are
-         * {@link #PSEUDORANDOM_FUNCTION_HMAC_SHA1}, {@link #PSEUDORANDOM_FUNCTION_AES128_XCBC},
-         * {@link #PSEUDORANDOM_FUNCTION_SHA2_256}, {@link #PSEUDORANDOM_FUNCTION_SHA2_384},
-         * {@link #PSEUDORANDOM_FUNCTION_SHA2_512}
+         * {@link android.net.ipsec.ike.SaProposal#PSEUDORANDOM_FUNCTION_HMAC_SHA1},
+         * {@link android.net.ipsec.ike.SaProposal#PSEUDORANDOM_FUNCTION_AES128_XCBC},
+         * {@link android.net.ipsec.ike.SaProposal#PSEUDORANDOM_FUNCTION_SHA2_256},
+         * {@link android.net.ipsec.ike.SaProposal#PSEUDORANDOM_FUNCTION_SHA2_384},
+         * {@link android.net.ipsec.ike.SaProposal#PSEUDORANDOM_FUNCTION_SHA2_512}
          */
         public static final String KEY_SUPPORTED_PRF_ALGORITHMS_INT_ARRAY =
                 KEY_PREFIX + "supported_prf_algorithms_int_array";
@@ -4366,182 +4387,6 @@
         public static final int EPDG_ADDRESS_CELLULAR_LOC = 3;
 
         /** @hide */
-        @IntDef({KEY_LEN_UNUSED, KEY_LEN_AES_128, KEY_LEN_AES_192, KEY_LEN_AES_256})
-        public @interface EncrpytionKeyLengthType {}
-
-        public static final int KEY_LEN_UNUSED = 0;
-        /** AES Encryption/Ciphering Algorithm key length 128 bits. */
-        public static final int KEY_LEN_AES_128 = 128;
-        /** AES Encryption/Ciphering Algorithm key length 192 bits. */
-        public static final int KEY_LEN_AES_192 = 192;
-        /** AES Encryption/Ciphering Algorithm key length 256 bits. */
-        public static final int KEY_LEN_AES_256 = 256;
-
-        /** @hide */
-        @IntDef({
-            DH_GROUP_NONE,
-            DH_GROUP_1024_BIT_MODP,
-            DH_GROUP_1536_BIT_MODP,
-            DH_GROUP_2048_BIT_MODP,
-            DH_GROUP_3072_BIT_MODP,
-            DH_GROUP_4096_BIT_MODP
-        })
-        public @interface DhGroup {}
-
-        /** None Diffie-Hellman Group. */
-        public static final int DH_GROUP_NONE = 0;
-        /**
-         * 1024-bit MODP Diffie-Hellman Group.
-         *
-         * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key
-         *     Exchange Protocol Version 2 (IKEv2)</a>
-         */
-        public static final int DH_GROUP_1024_BIT_MODP = 2;
-        /**
-         * 1536-bit MODP Diffie-Hellman Group.
-         *
-         * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key
-         *     Exchange Protocol Version 2 (IKEv2)</a>
-         */
-        public static final int DH_GROUP_1536_BIT_MODP = 5;
-        /**
-         * 2048-bit MODP Diffie-Hellman Group.
-         *
-         * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key
-         *     Exchange Protocol Version 2 (IKEv2)</a>
-         */
-        public static final int DH_GROUP_2048_BIT_MODP = 14;
-        /**
-         * 3072-bit MODP Diffie-Hellman Group.
-         *
-         * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key
-         *     Exchange Protocol Version 2 (IKEv2)</a>
-         */
-        public static final int DH_GROUP_3072_BIT_MODP = 15;
-        /**
-         * 4096-bit MODP Diffie-Hellman Group.
-         *
-         * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key
-         *     Exchange Protocol Version 2 (IKEv2)</a>
-         */
-        public static final int DH_GROUP_4096_BIT_MODP = 16;
-
-        /** @hide */
-        @IntDef({ENCRYPTION_ALGORITHM_AES_CBC, ENCRYPTION_ALGORITHM_AES_CTR})
-        public @interface EncryptionAlgorithm {}
-
-        /**
-         * AES-CBC Encryption/Ciphering Algorithm.
-         *
-         * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key
-         *     Exchange Protocol Version 2 (IKEv2)</a>
-         */
-        public static final int ENCRYPTION_ALGORITHM_AES_CBC = 12;
-
-        /**
-         * AES-CTR Encryption/Ciphering Algorithm.
-         *
-         * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key
-         *     Exchange Protocol Version 2 (IKEv2)</a>
-         */
-        public static final int ENCRYPTION_ALGORITHM_AES_CTR = 13;
-
-        /** @hide */
-        @IntDef({
-            INTEGRITY_ALGORITHM_NONE,
-            INTEGRITY_ALGORITHM_HMAC_SHA1_96,
-            INTEGRITY_ALGORITHM_AES_XCBC_96,
-            INTEGRITY_ALGORITHM_HMAC_SHA2_256_128,
-            INTEGRITY_ALGORITHM_HMAC_SHA2_384_192,
-            INTEGRITY_ALGORITHM_HMAC_SHA2_512_256
-        })
-        public @interface IntegrityAlgorithm {}
-
-        /** None Authentication/Integrity Algorithm. */
-        public static final int INTEGRITY_ALGORITHM_NONE = 0;
-        /**
-         * HMAC-SHA1 Authentication/Integrity Algorithm.
-         *
-         * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key
-         *     Exchange Protocol Version 2 (IKEv2)</a>
-         */
-        public static final int INTEGRITY_ALGORITHM_HMAC_SHA1_96 = 2;
-        /**
-         * AES-XCBC-96 Authentication/Integrity Algorithm.
-         *
-         * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key
-         *     Exchange Protocol Version 2 (IKEv2)</a>
-         */
-        public static final int INTEGRITY_ALGORITHM_AES_XCBC_96 = 5;
-        /**
-         * HMAC-SHA256 Authentication/Integrity Algorithm with 128-bit truncation.
-         *
-         * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key
-         *     Exchange Protocol Version 2 (IKEv2)</a>
-         */
-        public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_256_128 = 12;
-        /**
-         * HMAC-SHA384 Authentication/Integrity Algorithm with 192-bit truncation.
-         *
-         * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key
-         *     Exchange Protocol Version 2 (IKEv2)</a>
-         */
-        public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_384_192 = 13;
-        /**
-         * HMAC-SHA512 Authentication/Integrity Algorithm with 256-bit truncation.
-         *
-         * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key
-         *     Exchange Protocol Version 2 (IKEv2)</a>
-         */
-        public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_512_256 = 14;
-
-        /** @hide */
-        @IntDef({
-            PSEUDORANDOM_FUNCTION_HMAC_SHA1,
-            PSEUDORANDOM_FUNCTION_AES128_XCBC,
-            PSEUDORANDOM_FUNCTION_SHA2_256,
-            PSEUDORANDOM_FUNCTION_SHA2_384,
-            PSEUDORANDOM_FUNCTION_SHA2_512
-        })
-        public @interface PseudorandomFunction {}
-
-        /**
-         * HMAC-SHA1 Pseudorandom Function.
-         *
-         * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key
-         *     Exchange Protocol Version 2 (IKEv2)</a>
-         */
-        public static final int PSEUDORANDOM_FUNCTION_HMAC_SHA1 = 2;
-        /**
-         * AES128-XCBC Pseudorandom Function.
-         *
-         * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key
-         *     Exchange Protocol Version 2 (IKEv2)</a>
-         */
-        public static final int PSEUDORANDOM_FUNCTION_AES128_XCBC = 4;
-        /**
-         * HMAC-SHA2-256 Pseudorandom Function.
-         *
-         * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key
-         *     Exchange Protocol Version 2 (IKEv2)</a>
-         */
-        public static final int PSEUDORANDOM_FUNCTION_SHA2_256 = 5;
-        /**
-         * HMAC-SHA2-384 Pseudorandom Function.
-         *
-         * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key
-         *     Exchange Protocol Version 2 (IKEv2)</a>
-         */
-        public static final int PSEUDORANDOM_FUNCTION_SHA2_384 = 6;
-        /**
-         * HMAC-SHA2-384 Pseudorandom Function.
-         *
-         * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key
-         *     Exchange Protocol Version 2 (IKEv2)</a>
-         */
-        public static final int PSEUDORANDOM_FUNCTION_SHA2_512 = 7;
-
-        /** @hide */
         @IntDef({ID_TYPE_FQDN, ID_TYPE_RFC822_ADDR, ID_TYPE_KEY_ID})
         public @interface IkeIdType {}
 
@@ -4582,31 +4427,33 @@
             defaults.putIntArray(
                     KEY_DIFFIE_HELLMAN_GROUPS_INT_ARRAY,
                     new int[] {
-                        DH_GROUP_1024_BIT_MODP, DH_GROUP_1536_BIT_MODP, DH_GROUP_2048_BIT_MODP
+                        SaProposal.DH_GROUP_1024_BIT_MODP,
+                        SaProposal.DH_GROUP_1536_BIT_MODP,
+                        SaProposal.DH_GROUP_2048_BIT_MODP
                     });
             defaults.putIntArray(
                     KEY_SUPPORTED_IKE_SESSION_ENCRYPTION_ALGORITHMS_INT_ARRAY,
-                    new int[] {ENCRYPTION_ALGORITHM_AES_CBC});
+                    new int[] {SaProposal.ENCRYPTION_ALGORITHM_AES_CBC});
             defaults.putIntArray(
                     KEY_SUPPORTED_CHILD_SESSION_ENCRYPTION_ALGORITHMS_INT_ARRAY,
-                    new int[] {ENCRYPTION_ALGORITHM_AES_CBC});
+                    new int[] {SaProposal.ENCRYPTION_ALGORITHM_AES_CBC});
             defaults.putIntArray(
                     KEY_SUPPORTED_INTEGRITY_ALGORITHMS_INT_ARRAY,
                     new int[] {
-                        INTEGRITY_ALGORITHM_AES_XCBC_96,
-                        INTEGRITY_ALGORITHM_HMAC_SHA1_96,
-                        INTEGRITY_ALGORITHM_HMAC_SHA2_256_128,
-                        INTEGRITY_ALGORITHM_HMAC_SHA2_384_192,
-                        INTEGRITY_ALGORITHM_HMAC_SHA2_512_256,
+                        SaProposal.INTEGRITY_ALGORITHM_AES_XCBC_96,
+                        SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96,
+                        SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_256_128,
+                        SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_384_192,
+                        SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_512_256,
                     });
             defaults.putIntArray(
                     KEY_SUPPORTED_PRF_ALGORITHMS_INT_ARRAY,
                     new int[] {
-                        PSEUDORANDOM_FUNCTION_HMAC_SHA1,
-                        PSEUDORANDOM_FUNCTION_AES128_XCBC,
-                        PSEUDORANDOM_FUNCTION_SHA2_256,
-                        PSEUDORANDOM_FUNCTION_SHA2_384,
-                        PSEUDORANDOM_FUNCTION_SHA2_512
+                        SaProposal.PSEUDORANDOM_FUNCTION_HMAC_SHA1,
+                        SaProposal.PSEUDORANDOM_FUNCTION_AES128_XCBC,
+                        SaProposal.PSEUDORANDOM_FUNCTION_SHA2_256,
+                        SaProposal.PSEUDORANDOM_FUNCTION_SHA2_384,
+                        SaProposal.PSEUDORANDOM_FUNCTION_SHA2_512
                     });
 
             defaults.putInt(KEY_EPDG_AUTHENTICATION_METHOD_INT, AUTHENTICATION_METHOD_EAP_ONLY);
@@ -4616,16 +4463,28 @@
             defaults.putInt(KEY_NATT_KEEP_ALIVE_TIMER_SEC_INT, 20);
             defaults.putIntArray(
                     KEY_IKE_SESSION_AES_CBC_KEY_SIZE_INT_ARRAY,
-                    new int[] {KEY_LEN_AES_128, KEY_LEN_AES_192, KEY_LEN_AES_256});
+                    new int[] {
+                      SaProposal.KEY_LEN_AES_128,
+                      SaProposal.KEY_LEN_AES_192,
+                      SaProposal.KEY_LEN_AES_256});
             defaults.putIntArray(
                     KEY_CHILD_SESSION_AES_CBC_KEY_SIZE_INT_ARRAY,
-                    new int[] {KEY_LEN_AES_128, KEY_LEN_AES_192, KEY_LEN_AES_256});
+                    new int[] {
+                      SaProposal.KEY_LEN_AES_128,
+                      SaProposal.KEY_LEN_AES_192,
+                      SaProposal.KEY_LEN_AES_256});
             defaults.putIntArray(
                     KEY_IKE_SESSION_AES_CTR_KEY_SIZE_INT_ARRAY,
-                    new int[] {KEY_LEN_AES_128, KEY_LEN_AES_192, KEY_LEN_AES_256});
+                    new int[] {
+                      SaProposal.KEY_LEN_AES_128,
+                      SaProposal.KEY_LEN_AES_192,
+                      SaProposal.KEY_LEN_AES_256});
             defaults.putIntArray(
                     KEY_CHILD_SESSION_AES_CTR_KEY_SIZE_INT_ARRAY,
-                    new int[] {KEY_LEN_AES_128, KEY_LEN_AES_192, KEY_LEN_AES_256});
+                    new int[] {
+                      SaProposal.KEY_LEN_AES_128,
+                      SaProposal.KEY_LEN_AES_192,
+                      SaProposal.KEY_LEN_AES_256});
             defaults.putIntArray(
                     KEY_EPDG_ADDRESS_PRIORITY_INT_ARRAY,
                     new int[] {EPDG_ADDRESS_PLMN, EPDG_ADDRESS_STATIC});
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 2d5f5fb..f7580d7 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -602,6 +602,43 @@
     public @interface SimDisplayNameSource {}
 
     /**
+     * Device status is not shared to a remote party.
+     */
+    public static final int D2D_SHARING_DISABLED = 0;
+
+    /**
+     * Device status is shared with all numbers in the user's contacts.
+     */
+    public static final int D2D_SHARING_ALL_CONTACTS = 1;
+
+    /**
+     * Device status is shared with all starred contacts.
+     */
+    public static final int D2D_SHARING_STARRED_CONTACTS = 2;
+
+    /**
+     * Device status is shared whenever possible.
+     */
+    public static final int D2D_SHARING_ALL = 3;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"D2D_SHARING_"},
+            value = {
+                    D2D_SHARING_DISABLED,
+                    D2D_SHARING_ALL_CONTACTS,
+                    D2D_SHARING_STARRED_CONTACTS,
+                    D2D_SHARING_ALL
+            })
+    public @interface DeviceToDeviceStatusSharing {}
+
+    /**
+     * TelephonyProvider column name for device to device sharing status.
+     * <P>Type: INTEGER (int)</P>
+     */
+    public static final String D2D_STATUS_SHARING = SimInfo.COLUMN_D2D_STATUS_SHARING;
+
+    /**
      * TelephonyProvider column name for the color of a SIM.
      * <P>Type: INTEGER (int)</P>
      */
@@ -3374,6 +3411,36 @@
     }
 
     /**
+     * Set the device to device status sharing user preference for a subscription ID. The setting
+     * app uses this method to indicate with whom they wish to share device to device status
+     * information.
+     * @param sharing the status sharing preference
+     * @param subId the unique Subscription ID in database
+     */
+    @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
+    public void setDeviceToDeviceStatusSharing(@DeviceToDeviceStatusSharing int sharing,
+            int subId) {
+        if (VDBG) {
+            logd("[setDeviceToDeviceStatusSharing] + sharing: " + sharing + " subId: " + subId);
+        }
+        setSubscriptionPropertyHelper(subId, "setDeviceToDeviceSharingStatus",
+                (iSub)->iSub.setDeviceToDeviceStatusSharing(sharing, subId));
+    }
+
+    /**
+     * Returns the user-chosen device to device status sharing preference
+     * @param subId Subscription id of subscription
+     * @return The device to device status sharing preference
+     */
+    public @DeviceToDeviceStatusSharing int getDeviceToDeviceStatusSharing(int subId) {
+        if (VDBG) {
+            logd("[getDeviceToDeviceStatusSharing] + subId: " + subId);
+        }
+        return getIntegerSubscriptionProperty(subId, D2D_STATUS_SHARING, D2D_SHARING_DISABLED,
+                mContext);
+    }
+
+    /**
      * DO NOT USE.
      * This API is designed for features that are not finished at this point. Do not call this API.
      * @hide
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 3cb72b5..4dc6c7c 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -139,6 +139,8 @@
 import java.util.UUID;
 import java.util.concurrent.Executor;
 import java.util.function.Consumer;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
 
 /**
  * Provides access to information about the telephony services on
@@ -3147,6 +3149,10 @@
                 return NETWORK_TYPE_BITMASK_LTE_CA;
             case NETWORK_TYPE_NR:
                 return NETWORK_TYPE_BITMASK_NR;
+            case NETWORK_TYPE_IWLAN:
+                return NETWORK_TYPE_BITMASK_IWLAN;
+            case NETWORK_TYPE_IDEN:
+                return (1 << (NETWORK_TYPE_IDEN - 1));
             default:
                 return NETWORK_TYPE_BITMASK_UNKNOWN;
         }
@@ -8642,8 +8648,8 @@
     public static final int ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G = 3;
 
     /**
-     * Set the allowed network types of the device and
-     * provide the reason triggering the allowed network change.
+     * Set the allowed network types of the device and provide the reason triggering the allowed
+     * network change.
      * This can be called for following reasons
      * <ol>
      * <li>Allowed network types control by USER {@link #ALLOWED_NETWORK_TYPES_REASON_USER}
@@ -8655,10 +8661,15 @@
      * </ol>
      * This API will result in allowing an intersection of allowed network types for all reasons,
      * including the configuration done through other reasons.
+     *
+     * The functionality of this API with the parameter
+     * {@link #ALLOWED_NETWORK_TYPES_REASON_CARRIER} is the same as the API
+     * {@link TelephonyManager#setAllowedNetworkTypes}. Use this API instead of
+     * {@link TelephonyManager#setAllowedNetworkTypes}.
      * <p>
      * If {@link android.telephony.TelephonyManager#isRadioInterfaceCapabilitySupported}
      * ({@link TelephonyManager#CAPABILITY_ALLOWED_NETWORK_TYPES_USED}) returns true, then
-     * setAllowedNetworkTypesBitmap is used on the radio interface.  Otherwise,
+     * setAllowedNetworkTypesBitmap is used on the radio interface. Otherwise,
      * setPreferredNetworkTypesBitmap is used instead.
      *
      * @param reason the reason the allowed network type change is taking place
@@ -8698,21 +8709,17 @@
      * {@link #getAllowedNetworkTypesForReason} returns allowed network type for a
      * specific reason.
      *
-     * <p>Requires Permission:
-     * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE READ_PRIVILEGED_PHONE_STATE}
-     * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
-     *
      * @param reason the reason the allowed network type change is taking place
      * @return the allowed network type bitmask
      * @throws IllegalStateException    if the Telephony process is not currently available.
      * @throws IllegalArgumentException if invalid AllowedNetworkTypesReason is passed.
      * @hide
      */
-    @SystemApi
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     @RequiresFeature(
             enforcement = "android.telephony.TelephonyManager#isRadioInterfaceCapabilitySupported",
             value = TelephonyManager.CAPABILITY_ALLOWED_NETWORK_TYPES_USED)
+    @SystemApi
     public @NetworkTypeBitMask long getAllowedNetworkTypesForReason(
             @AllowedNetworkTypesReason int reason) {
         if (!isValidAllowedNetworkTypesReason(reason)) {
@@ -8757,6 +8764,25 @@
     }
 
     /**
+     * Returns a string representation of the allowed network types{@link NetworkTypeBitMask}.
+     *
+     * @param networkTypeBitmask The bitmask of allowed network types.
+     * @return the name of the allowed network types
+     * @hide
+     */
+    public static String convertNetworkTypeBitmaskToString(
+            @NetworkTypeBitMask long networkTypeBitmask) {
+        String networkTypeName = IntStream.rangeClosed(NETWORK_TYPE_GPRS, NETWORK_TYPE_NR)
+                .filter(x -> {
+                    return (networkTypeBitmask & getBitMaskForNetworkType(x))
+                            == getBitMaskForNetworkType(x);
+                })
+                .mapToObj(x -> getNetworkTypeName(x))
+                .collect(Collectors.joining("|"));
+        return TextUtils.isEmpty(networkTypeName) ? "UNKNOWN" : networkTypeName;
+    }
+
+    /**
      * Set the preferred network type to global mode which includes LTE, CDMA, EvDo and GSM/WCDMA.
      *
      * <p>Requires that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
@@ -9135,9 +9161,7 @@
     /**
      * Set the user-set status for enriched calling with call composer.
      *
-     * @param status user-set status for enriched calling with call composer;
-     *               it must be either {@link #CALL_COMPOSER_STATUS_ON} or
-     *               {@link #CALL_COMPOSER_STATUS_OFF}.
+     * @param status user-set status for enriched calling with call composer.
      *
      * <p>If this object has been created with {@link #createForSubscriptionId}, applies to the
      * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultSubscriptionId()}
@@ -12579,6 +12603,7 @@
                     NETWORK_TYPE_BITMASK_LTE,
                     NETWORK_TYPE_BITMASK_LTE_CA,
                     NETWORK_TYPE_BITMASK_NR,
+                    NETWORK_TYPE_BITMASK_IWLAN
             })
     public @interface NetworkTypeBitMask {}
 
@@ -15218,13 +15243,17 @@
      * </ul>
      * @param appType icc application type, like {@link #APPTYPE_USIM} or {@link
      * #APPTYPE_ISIM} or {@link#APPTYPE_UNKNOWN}
-     * @param nafId Network Application Function(NAF) fully qualified domain name and
-     * the selected GBA mode. It shall contain two parts delimited by "@" sign. The first
-     * part is the constant string "3GPP-bootstrapping" (GBA_ME),
-     * "3GPP-bootstrapping-uicc" (GBA_ U), or "3GPP-bootstrapping-digest" (GBA_Digest),
-     * and the latter part shall be the FQDN of the NAF (e.g.
-     * "3GPP-bootstrapping@naf1.operator.com" or "3GPP-bootstrapping-uicc@naf1.operator.com",
-     * or "3GPP-bootstrapping-digest@naf1.operator.com").
+     * @param nafId A URI to specify Network Application Function(NAF) fully qualified domain
+     * name (FQDN) and the selected GBA mode. The authority of the URI must contain two parts
+     * delimited by "@" sign. The first part is the constant string "3GPP-bootstrapping" (GBA_ME),
+     * "3GPP-bootstrapping-uicc" (GBA_ U), or "3GPP-bootstrapping-digest" (GBA_Digest).
+     * The second part shall be the FQDN of the NAF. The scheme of the URI is not actually used
+     * for the authentication, which may be set the same as the resource that the application is
+     * going to access. For example, the nafId can be
+     * "https://3GPP-bootstrapping@naf1.operator.com",
+     * "https://3GPP-bootstrapping-uicc@naf1.operator.com",
+     * "https://3GPP-bootstrapping-digest@naf1.operator.com",
+     * "ftps://3GPP-bootstrapping-digest@naf1.operator.com".
      * @param securityProtocol Security protocol identifier between UE and NAF.  See
      * 3GPP TS 33.220 Annex H. Application can use
      * {@link UaSecurityProtocolIdentifier#createDefaultUaSpId},
diff --git a/telephony/java/android/telephony/data/DataCallResponse.java b/telephony/java/android/telephony/data/DataCallResponse.java
index a764229..ffe5399 100644
--- a/telephony/java/android/telephony/data/DataCallResponse.java
+++ b/telephony/java/android/telephony/data/DataCallResponse.java
@@ -18,6 +18,7 @@
 package android.telephony.data;
 
 import android.annotation.IntDef;
+import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
@@ -29,6 +30,7 @@
 import android.telephony.data.ApnSetting.ProtocolType;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.Preconditions;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -812,11 +814,19 @@
 
         /**
          * Set pdu session id.
+         * <p/>
+         * The id must be between 1 and 15 when linked to a pdu session.  If no pdu session
+         * exists for the current data call, the id must be set to {@link PDU_SESSION_ID_NOT_SET}.
          *
          * @param pduSessionId Pdu Session Id of the data call.
          * @return The same instance of the builder.
          */
-        public @NonNull Builder setPduSessionId(int pduSessionId) {
+        public @NonNull Builder setPduSessionId(
+                @IntRange(from = PDU_SESSION_ID_NOT_SET, to = 15) int pduSessionId) {
+            Preconditions.checkArgument(pduSessionId >= PDU_SESSION_ID_NOT_SET,
+                    "pduSessionId must be greater than or equal to" + PDU_SESSION_ID_NOT_SET);
+            Preconditions.checkArgument(pduSessionId <= 15,
+                    "pduSessionId must be less than or equal to 15.");
             mPduSessionId = pduSessionId;
             return this;
         }
diff --git a/telephony/java/android/telephony/data/DataService.java b/telephony/java/android/telephony/data/DataService.java
index f5f29c6..048b329 100644
--- a/telephony/java/android/telephony/data/DataService.java
+++ b/telephony/java/android/telephony/data/DataService.java
@@ -41,6 +41,7 @@
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Objects;
 
 /**
  * Base class of data service. Services that extend DataService must register the service in
@@ -284,11 +285,11 @@
          *
          * Any resources being transferred cannot be released while a
          * handover is underway.
-         *
+         * <p/>
          * If a handover was unsuccessful, then the framework calls
          * {@link DataService#cancelHandover}.  The target transport retains ownership over any of
          * the resources being transferred.
-         *
+         * <p/>
          * If a handover was successful, the framework calls {@link DataService#deactivateDataCall}
          * with reason {@link DataService.REQUEST_REASON_HANDOVER}. The target transport now owns
          * the transferred resources and is responsible for releasing them.
@@ -299,21 +300,27 @@
          * @hide
          */
         public void startHandover(int cid, @NonNull DataServiceCallback callback) {
+            Objects.requireNonNull(callback, "callback cannot be null");
             // The default implementation is to return unsupported.
-            if (callback != null) {
-                Log.d(TAG, "startHandover: " + cid);
-                callback.onHandoverStarted(DataServiceCallback.RESULT_ERROR_UNSUPPORTED);
-            } else {
-                Log.e(TAG, "startHandover: " + cid + ", callback is null");
-            }
+            Log.d(TAG, "startHandover: " + cid);
+            callback.onHandoverStarted(DataServiceCallback.RESULT_ERROR_UNSUPPORTED);
         }
 
         /**
          * Indicates that a handover was cancelled after a call to
          * {@link DataService#startHandover}. This is called on the source transport.
-         *
+         * <p/>
          * Since the handover was unsuccessful, the source transport retains ownership over any of
          * the resources being transferred and is still responsible for releasing them.
+         * <p/>
+         * The handover can be cancelled up until either:
+         * <ul><li>
+         *     The handover was successful after receiving a successful response from
+         *     {@link DataService#setupDataCall} on the target transport.
+         * </li><li>
+         *     The data call on the source transport was lost.
+         * </li>
+         * </ul>
          *
          * @param cid The identifier of the data call which is provided in {@link DataCallResponse}
          * @param callback The result callback for this request.
@@ -321,13 +328,10 @@
          * @hide
          */
         public void cancelHandover(int cid, @NonNull DataServiceCallback callback) {
+            Objects.requireNonNull(callback, "callback cannot be null");
             // The default implementation is to return unsupported.
-            if (callback != null) {
-                Log.d(TAG, "cancelHandover: " + cid);
-                callback.onHandoverCancelled(DataServiceCallback.RESULT_ERROR_UNSUPPORTED);
-            } else {
-                Log.e(TAG, "cancelHandover: " + cid + ", callback is null");
-            }
+            Log.d(TAG, "cancelHandover: " + cid);
+            callback.onHandoverCancelled(DataServiceCallback.RESULT_ERROR_UNSUPPORTED);
         }
 
         /**
diff --git a/telephony/java/android/telephony/ims/ImsCallProfile.java b/telephony/java/android/telephony/ims/ImsCallProfile.java
index 9bb4db8..486f746 100644
--- a/telephony/java/android/telephony/ims/ImsCallProfile.java
+++ b/telephony/java/android/telephony/ims/ImsCallProfile.java
@@ -277,6 +277,10 @@
      * server infrastructure to get the picture. It can be set via
      * {@link #setCallExtra(String, String)}.
      *
+     * Note that this URL is not intended to be parsed by the IMS stack -- it should be sent
+     * directly to the network for consumption by the called party or forwarded directly from the
+     * network to the platform for caching and download.
+     *
      * Reference: RCC.20 Section 2.4.3.2
      */
     public static final String EXTRA_PICTURE_URL = "android.telephony.ims.extra.PICTURE_URL";
@@ -729,6 +733,10 @@
 
     /**
      * Set the call extra value (Parcelable), given the call extra name.
+     *
+     * Note that the {@link Parcelable} provided must be a class defined in the Android API surface,
+     * as opposed to a class defined by your app.
+     *
      * @param name call extra name
      * @param parcelable call extra value
      */
diff --git a/telephony/java/android/telephony/ims/ProvisioningManager.java b/telephony/java/android/telephony/ims/ProvisioningManager.java
index 85cd81b..abc5606 100644
--- a/telephony/java/android/telephony/ims/ProvisioningManager.java
+++ b/telephony/java/android/telephony/ims/ProvisioningManager.java
@@ -1010,6 +1010,16 @@
                 }
             }
 
+            @Override
+            public void onPreProvisioningReceived(byte[] configXml) {
+                final long identity = Binder.clearCallingIdentity();
+                try {
+                    mExecutor.execute(() -> mLocalCallback.onPreProvisioningReceived(configXml));
+                } finally {
+                    Binder.restoreCallingIdentity(identity);
+                }
+            }
+
             private void setExecutor(Executor executor) {
                 mExecutor = executor;
             }
@@ -1022,7 +1032,7 @@
          * due to various triggers defined in GSMA RCC.14 for ACS(auto configuration
          * 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
+         * invoked with the current configuration.
          * @param configXml The RCS configuration XML received by OTA. It is defined
          * by GSMA RCC.07.
          */
@@ -1055,6 +1065,20 @@
          */
         public void onRemoved() {}
 
+        /**
+         * Some carriers using ACS (auto configuration server) may send a carrier-specific
+         * pre-provisioning configuration XML if the user has not been provisioned for RCS
+         * services yet. When this provisioning XML is received, the framework will move
+         * into a "not provisioned" state for RCS. In order for provisioning to proceed,
+         * the application must parse this configuration XML and perform the carrier specific
+         * opt-in flow for RCS services. If the user accepts, {@link #triggerRcsReconfiguration}
+         * must be called in order for the device to move out of this state and try to fetch
+         * the RCS provisioning information.
+         *
+         * @param configXml the pre-provisioning config in carrier specified format.
+         */
+        public void onPreProvisioningReceived(@NonNull byte[] configXml) {}
+
         /**@hide*/
         public final IRcsConfigCallback getBinder() {
             return mBinder;
diff --git a/telephony/java/android/telephony/ims/RcsContactPresenceTuple.java b/telephony/java/android/telephony/ims/RcsContactPresenceTuple.java
index cedf48b..9c28c36 100644
--- a/telephony/java/android/telephony/ims/RcsContactPresenceTuple.java
+++ b/telephony/java/android/telephony/ims/RcsContactPresenceTuple.java
@@ -25,7 +25,6 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
-import android.util.Log;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -389,22 +388,6 @@
          * The optional timestamp indicating the data and time of the status change of this tuple.
          * Per RFC3863 section 4.1.7, the timestamp is formatted as an IMPP datetime format
          * string per RFC3339.
-         * @hide
-         */
-        public @NonNull Builder setTimestamp(@NonNull String timestamp) {
-            try {
-                mPresenceTuple.mTimestamp =
-                        DateTimeFormatter.ISO_OFFSET_DATE_TIME.parse(timestamp, Instant::from);
-            } catch (DateTimeParseException e) {
-                Log.d(LOG_TAG, "Parse timestamp failed " + e);
-            }
-            return this;
-        }
-
-        /**
-         * The optional timestamp indicating the data and time of the status change of this tuple.
-         * Per RFC3863 section 4.1.7, the timestamp is formatted as an IMPP datetime format
-         * string per RFC3339.
          */
         public @NonNull Builder setTime(@NonNull Instant timestamp) {
             mPresenceTuple.mTimestamp = timestamp;
@@ -534,14 +517,6 @@
         return mContactUri;
     }
 
-    /**
-     * @return the timestamp element contained in the tuple if it exists
-     * @hide
-     */
-    public @Nullable String getTimestamp() {
-        return (mTimestamp == null) ? null : mTimestamp.toString();
-    }
-
     /** @return the timestamp element contained in the tuple if it exists */
     public @Nullable Instant getTime() {
         return mTimestamp;
diff --git a/telephony/java/android/telephony/ims/RcsUceAdapter.java b/telephony/java/android/telephony/ims/RcsUceAdapter.java
index 815c08d..dd91026 100644
--- a/telephony/java/android/telephony/ims/RcsUceAdapter.java
+++ b/telephony/java/android/telephony/ims/RcsUceAdapter.java
@@ -439,8 +439,7 @@
 
         /**
          * The pending request has resulted in an error and may need to be retried, depending on the
-         * error code. The callback {@link #onCapabilitiesReceived(List)}
-         * for each contacts is required to be called before {@link #onError} is called.
+         * error code.
          * @param errorCode The reason for the framework being unable to process the request.
          * @param retryIntervalMillis The time in milliseconds the requesting application should
          * wait before retrying, if non-zero.
@@ -487,93 +486,6 @@
      * becomes inactive. See {@link ImsException#getCode()} for more information on the error codes.
      * @hide
      */
-    @RequiresPermission(allOf = {Manifest.permission.ACCESS_RCS_USER_CAPABILITY_EXCHANGE,
-            Manifest.permission.READ_CONTACTS})
-    public void requestCapabilities(@NonNull List<Uri> contactNumbers,
-            @NonNull @CallbackExecutor Executor executor,
-            @NonNull CapabilitiesCallback c) throws ImsException {
-        if (c == null) {
-            throw new IllegalArgumentException("Must include a non-null CapabilitiesCallback.");
-        }
-        if (executor == null) {
-            throw new IllegalArgumentException("Must include a non-null Executor.");
-        }
-        if (contactNumbers == null) {
-            throw new IllegalArgumentException("Must include non-null contact number list.");
-        }
-
-        IImsRcsController imsRcsController = getIImsRcsController();
-        if (imsRcsController == null) {
-            Log.e(TAG, "requestCapabilities: IImsRcsController is null");
-            throw new ImsException("Can not find remote IMS service",
-                    ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
-        }
-
-        IRcsUceControllerCallback internalCallback = new IRcsUceControllerCallback.Stub() {
-            @Override
-            public void onCapabilitiesReceived(List<RcsContactUceCapability> contactCapabilities) {
-                final long callingIdentity = Binder.clearCallingIdentity();
-                try {
-                    executor.execute(() -> c.onCapabilitiesReceived(contactCapabilities));
-                } finally {
-                    restoreCallingIdentity(callingIdentity);
-                }
-            }
-            @Override
-            public void onComplete() {
-                final long callingIdentity = Binder.clearCallingIdentity();
-                try {
-                    executor.execute(() -> c.onComplete());
-                } finally {
-                    restoreCallingIdentity(callingIdentity);
-                }
-            }
-            @Override
-            public void onError(int errorCode, long retryAfterMilliseconds) {
-                final long callingIdentity = Binder.clearCallingIdentity();
-                try {
-                    executor.execute(() -> c.onError(errorCode, retryAfterMilliseconds));
-                } finally {
-                    restoreCallingIdentity(callingIdentity);
-                }
-            }
-        };
-
-        try {
-            imsRcsController.requestCapabilities(mSubId, mContext.getOpPackageName(),
-                    mContext.getAttributionTag(), contactNumbers, internalCallback);
-        } catch (ServiceSpecificException e) {
-            throw new ImsException(e.toString(), e.errorCode);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Error calling IImsRcsController#requestCapabilities", e);
-            throw new ImsException("Remote IMS Service is not available",
-                    ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
-        }
-    }
-
-    /**
-     * Request the User Capability Exchange capabilities for one or more contacts.
-     * <p>
-     * This will return the cached capabilities of the contact and will not perform a capability
-     * poll on the network unless there are contacts being queried with stale information.
-     * <p>
-     * Be sure to check the availability of this feature using
-     * {@link ImsRcsManager#isAvailable(int, int)} and ensuring
-     * {@link RcsFeature.RcsImsCapabilities#CAPABILITY_TYPE_OPTIONS_UCE} or
-     * {@link RcsFeature.RcsImsCapabilities#CAPABILITY_TYPE_PRESENCE_UCE} is enabled or else
-     * this operation will fail with {@link #ERROR_NOT_AVAILABLE} or {@link #ERROR_NOT_ENABLED}.
-     *
-     * @param contactNumbers A list of numbers that the capabilities are being requested for.
-     * @param executor The executor that will be used when the request is completed and the
-     *         {@link CapabilitiesCallback} is called.
-     * @param c A one-time callback for when the request for capabilities completes or there is an
-     *         error processing the request.
-     * @throws ImsException if the subscription associated with this instance of
-     * {@link RcsUceAdapter} is valid, but the ImsService associated with the subscription is not
-     * available. This can happen if the ImsService has crashed, for example, or if the subscription
-     * becomes inactive. See {@link ImsException#getCode()} for more information on the error codes.
-     * @hide
-     */
     @SystemApi
     @RequiresPermission(allOf = {Manifest.permission.ACCESS_RCS_USER_CAPABILITY_EXCHANGE,
             Manifest.permission.READ_CONTACTS})
diff --git a/telephony/java/android/telephony/ims/aidl/IRcsConfigCallback.aidl b/telephony/java/android/telephony/ims/aidl/IRcsConfigCallback.aidl
index 5a8973e..d0853d1 100644
--- a/telephony/java/android/telephony/ims/aidl/IRcsConfigCallback.aidl
+++ b/telephony/java/android/telephony/ims/aidl/IRcsConfigCallback.aidl
@@ -25,5 +25,6 @@
     void onAutoConfigurationErrorReceived(int errorCode, String errorString);
     void onConfigurationReset();
     void onRemoved();
+    void onPreProvisioningReceived(in byte[] config);
 }
 
diff --git a/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java b/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
index 21aeb64..d75da90 100644
--- a/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
@@ -552,11 +552,34 @@
         }
         mRcsCallbacks.broadcastAction(c -> {
             try {
-                //TODO compressed by default?
                 c.onAutoConfigurationErrorReceived(errorCode, errorString);
             } catch (RemoteException e) {
                 Log.w(TAG, "dead binder in notifyAutoConfigurationErrorReceived, skipping.");
             }
         });
     }
+
+    /**
+     * Notifies application that pre-provisioning config is received.
+     *
+     * <p>Some carriers using ACS (auto configuration server) may send a carrier-specific
+     * pre-provisioning configuration XML if the user has not been provisioned for RCS
+     * services yet. When such provisioning XML is received, ACS client must call this
+     * method to notify the application with the XML.
+     *
+     * @param configXml the pre-provisioning config in carrier specified format.
+     */
+    public final void notifyPreProvisioningReceived(@NonNull byte[] configXml) {
+        // can be null in testing
+        if (mRcsCallbacks == null) {
+            return;
+        }
+        mRcsCallbacks.broadcastAction(c -> {
+            try {
+                c.onPreProvisioningReceived(configXml);
+            } catch (RemoteException e) {
+                Log.w(TAG, "dead binder in notifyPreProvisioningReceived, skipping.");
+            }
+        });
+    }
 }
diff --git a/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java b/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java
index 00c9168..03e17fb 100644
--- a/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java
@@ -386,41 +386,6 @@
      * {@link SubscribeResponseCallback#onTerminated(String, long)} must be called for the
      * framework to finish listening for NOTIFY responses.
      *
-     * @param uris A {@link List} of the {@link Uri}s that the framework is requesting the UCE
-     * capabilities for.
-     * @param cb The callback of the subscribe request.
-     * @hide
-     */
-    // executor used is defined in the constructor.
-    @SuppressLint("ExecutorRegistration")
-    public void subscribeForCapabilities(@NonNull List<Uri> uris,
-            @NonNull SubscribeResponseCallback cb) {
-        // Stub - to be implemented by service
-        Log.w(LOG_TAG, "subscribeForCapabilities called with no implementation.");
-        try {
-            cb.onCommandError(COMMAND_CODE_NOT_SUPPORTED);
-        } catch (ImsException e) {
-            // Do not do anything, this is a stub implementation.
-        }
-    }
-
-    /**
-     * The user capabilities of one or multiple contacts have been requested by the framework.
-     * <p>
-     * The implementer must follow up this call with an
-     * {@link SubscribeResponseCallback#onCommandError} call to indicate this operation has failed.
-     * The response from the network to the SUBSCRIBE request must be sent back to the framework
-     * using {@link SubscribeResponseCallback#onNetworkResponse(int, String)}.
-     * As NOTIFY requests come in from the network, the requested contact’s capabilities should be
-     * sent back to the framework using
-     * {@link SubscribeResponseCallback#onNotifyCapabilitiesUpdate(List<String>}) and
-     * {@link SubscribeResponseCallback#onResourceTerminated(List<Pair<Uri, String>>)}
-     * should be called with the presence information for the contacts specified.
-     * <p>
-     * Once the subscription is terminated,
-     * {@link SubscribeResponseCallback#onTerminated(String, long)} must be called for the
-     * framework to finish listening for NOTIFY responses.
-     *
      * @param uris A {@link Collection} of the {@link Uri}s that the framework is requesting the
      * UCE capabilities for.
      * @param cb The callback of the subscribe request.
diff --git a/telephony/java/com/android/internal/telephony/ISub.aidl b/telephony/java/com/android/internal/telephony/ISub.aidl
index 571efce..9493c76 100755
--- a/telephony/java/com/android/internal/telephony/ISub.aidl
+++ b/telephony/java/com/android/internal/telephony/ISub.aidl
@@ -300,4 +300,6 @@
     boolean canDisablePhysicalSubscription();
 
     int setUiccApplicationsEnabled(boolean enabled, int subscriptionId);
+
+    int setDeviceToDeviceStatusSharing(int sharing, int subId);
 }
diff --git a/tests/FlickerTests/AndroidTest.xml b/tests/FlickerTests/AndroidTest.xml
index b2719fb..896ec9a 100644
--- a/tests/FlickerTests/AndroidTest.xml
+++ b/tests/FlickerTests/AndroidTest.xml
@@ -11,6 +11,8 @@
         <option name="force-skip-system-props" value="true" />
         <!-- set WM tracing verbose level to all -->
         <option name="run-command" value="cmd window tracing level all" />
+        <!-- set WM tracing to frame (avoid incomplete states) -->
+        <option name="run-command" value="cmd window tracing frame" />
         <!-- restart launcher to activate TAPL -->
         <option name="run-command" value="setprop ro.test_harness 1 ; am force-stop com.google.android.apps.nexuslauncher" />
     </target_preparer>
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
index fbf18d4..c92d40c 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
@@ -16,37 +16,12 @@
 
 package com.android.server.wm.flicker.close
 
-import android.app.Instrumentation
-import android.platform.test.annotations.Presubmit
-import android.view.Surface
-import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
-import androidx.test.platform.app.InstrumentationRegistry
-import com.android.server.wm.flicker.FlickerBuilderProvider
 import com.android.server.wm.flicker.FlickerParametersRunnerFactory
 import com.android.server.wm.flicker.FlickerTestParameter
 import com.android.server.wm.flicker.FlickerTestParameterFactory
 import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.SimpleAppHelper
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
-import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
-import com.android.server.wm.flicker.launcherReplacesAppWindowAsTopWindow
-import com.android.server.wm.flicker.wallpaperWindowBecomesVisible
-import com.android.server.wm.flicker.wallpaperLayerReplacesAppLayer
-import com.android.server.wm.flicker.noUncoveredRegions
-import com.android.server.wm.flicker.navBarLayerRotatesAndScales
-import com.android.server.wm.flicker.statusBarLayerRotatesScales
-import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry
-import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry
-import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
-import com.android.server.wm.flicker.helpers.setRotation
-import com.android.server.wm.flicker.repetitions
-import com.android.server.wm.flicker.startRotation
-import org.junit.Assume
 import org.junit.FixMethodOrder
-import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.MethodSorters
 import org.junit.runners.Parameterized
@@ -59,110 +34,15 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class CloseAppBackButtonTest(private val testSpec: FlickerTestParameter) {
-    private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
-    private val testApp = SimpleAppHelper(instrumentation)
-
-    @FlickerBuilderProvider
-    fun buildFlicker(): FlickerBuilder {
-        return FlickerBuilder(instrumentation).apply {
-            withTestName { testSpec.name }
-            repeat { testSpec.config.repetitions }
-            setup {
-                test {
-                    device.wakeUpAndGoToHomeScreen()
-                }
-                eachRun {
-                    this.setRotation(testSpec.config.startRotation)
-                    testApp.launchViaIntent(wmHelper)
-                }
-            }
+class CloseAppBackButtonTest(testSpec: FlickerTestParameter) : CloseAppTransition(testSpec) {
+    override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
+        get() = {
+            super.transition(this, it)
             transitions {
                 device.pressBack()
                 wmHelper.waitForHomeActivityVisible()
             }
-            teardown {
-                eachRun {
-                    this.setRotation(Surface.ROTATION_0)
-                }
-                test {
-                    testApp.exit()
-                }
-            }
         }
-    }
-
-    @Presubmit
-    @Test
-    fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
-
-    @Presubmit
-    @Test
-    fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
-
-    @Presubmit
-    @Test
-    fun launcherReplacesAppWindowAsTopWindow() =
-        testSpec.launcherReplacesAppWindowAsTopWindow(testApp)
-
-    @Presubmit
-    @Test
-    fun wallpaperWindowBecomesVisible() = testSpec.wallpaperWindowBecomesVisible()
-
-    @Presubmit
-    @Test
-    fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation,
-        Surface.ROTATION_0)
-
-    @Presubmit
-    @Test
-    fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
-
-    @Presubmit
-    @Test
-    fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
-
-    @Presubmit
-    @Test
-    fun wallpaperLayerReplacesAppLayer() = testSpec.wallpaperLayerReplacesAppLayer(testApp)
-
-    @Presubmit
-    @Test
-    fun navBarLayerRotatesAndScales() {
-        Assume.assumeFalse(testSpec.isRotated)
-        testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0)
-    }
-
-    @FlakyTest
-    @Test
-    fun navBarLayerRotatesAndScales_Flaky() {
-        Assume.assumeTrue(testSpec.isRotated)
-        testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0)
-    }
-
-    @Presubmit
-    @Test
-    fun statusBarLayerRotatesScales() {
-        Assume.assumeFalse(testSpec.isRotated)
-        testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0)
-    }
-
-    @FlakyTest
-    @Test
-    fun statusBarLayerRotatesScales_Flaky() {
-        Assume.assumeTrue(testSpec.isRotated)
-        testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0)
-    }
-
-    @FlakyTest(bugId = 173684672)
-    @Test
-    fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
-        testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry()
-
-    @FlakyTest(bugId = 173684672)
-    @Test
-    fun visibleLayersShownMoreThanOneConsecutiveEntry() =
-        testSpec.visibleLayersShownMoreThanOneConsecutiveEntry()
 
     companion object {
         @Parameterized.Parameters(name = "{0}")
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
index 08d2b7c..1f880f6 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
@@ -16,37 +16,12 @@
 
 package com.android.server.wm.flicker.close
 
-import android.app.Instrumentation
-import android.platform.test.annotations.Presubmit
-import android.view.Surface
-import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
-import androidx.test.platform.app.InstrumentationRegistry
-import com.android.server.wm.flicker.FlickerBuilderProvider
 import com.android.server.wm.flicker.FlickerParametersRunnerFactory
 import com.android.server.wm.flicker.FlickerTestParameter
 import com.android.server.wm.flicker.FlickerTestParameterFactory
 import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.SimpleAppHelper
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
-import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
-import com.android.server.wm.flicker.launcherReplacesAppWindowAsTopWindow
-import com.android.server.wm.flicker.wallpaperWindowBecomesVisible
-import com.android.server.wm.flicker.wallpaperLayerReplacesAppLayer
-import com.android.server.wm.flicker.noUncoveredRegions
-import com.android.server.wm.flicker.navBarLayerRotatesAndScales
-import com.android.server.wm.flicker.statusBarLayerRotatesScales
-import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry
-import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry
-import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
-import com.android.server.wm.flicker.helpers.setRotation
-import com.android.server.wm.flicker.repetitions
-import com.android.server.wm.flicker.startRotation
-import org.junit.Assume
 import org.junit.FixMethodOrder
-import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.MethodSorters
 import org.junit.runners.Parameterized
@@ -59,110 +34,15 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class CloseAppHomeButtonTest(private val testSpec: FlickerTestParameter) {
-    private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
-    private val testApp = SimpleAppHelper(instrumentation)
-
-    @FlickerBuilderProvider
-    fun buildFlicker(): FlickerBuilder {
-        return FlickerBuilder(instrumentation).apply {
-            withTestName { testSpec.name }
-            repeat { testSpec.config.repetitions }
-            setup {
-                test {
-                    device.wakeUpAndGoToHomeScreen()
-                }
-                eachRun {
-                    testApp.launchViaIntent(wmHelper)
-                    this.setRotation(testSpec.config.startRotation)
-                }
-            }
+class CloseAppHomeButtonTest(testSpec: FlickerTestParameter) : CloseAppTransition(testSpec) {
+    override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
+        get() = {
+            super.transition(this, it)
             transitions {
                 device.pressHome()
                 wmHelper.waitForHomeActivityVisible()
             }
-            teardown {
-                eachRun {
-                    this.setRotation(Surface.ROTATION_0)
-                }
-                test {
-                    testApp.exit()
-                }
-            }
         }
-    }
-
-    @Presubmit
-    @Test
-    fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
-
-    @Presubmit
-    @Test
-    fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
-
-    @Presubmit
-    @Test
-    fun launcherReplacesAppWindowAsTopWindow() =
-        testSpec.launcherReplacesAppWindowAsTopWindow(testApp)
-
-    @Presubmit
-    @Test
-    fun wallpaperWindowBecomesVisible() = testSpec.wallpaperWindowBecomesVisible()
-
-    @Presubmit
-    @Test
-    fun noUncoveredRegions() = testSpec.noUncoveredRegions(
-        testSpec.config.startRotation, Surface.ROTATION_0)
-
-    @Presubmit
-    @Test
-    fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
-
-    @Presubmit
-    @Test
-    fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
-
-    @Presubmit
-    @Test
-    fun wallpaperLayerReplacesAppLayer() = testSpec.wallpaperLayerReplacesAppLayer(testApp)
-
-    @Presubmit
-    @Test
-    fun navBarLayerRotatesAndScales() {
-        Assume.assumeFalse(testSpec.isRotated)
-        testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0)
-    }
-
-    @FlakyTest
-    @Test
-    fun navBarLayerRotatesAndScales_Flaky() {
-        Assume.assumeTrue(testSpec.isRotated)
-        testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0)
-    }
-
-    @Presubmit
-    @Test
-    fun statusBarLayerRotatesScales() {
-        Assume.assumeFalse(testSpec.isRotated)
-        testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0)
-    }
-
-    @FlakyTest
-    @Test
-    fun statusBarLayerRotatesScales_Flaky() {
-        Assume.assumeTrue(testSpec.isRotated)
-        testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0)
-    }
-
-    @FlakyTest(bugId = 173689015)
-    @Test
-    fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
-        testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry()
-
-    @FlakyTest(bugId = 173689015)
-    @Test
-    fun visibleLayersShownMoreThanOneConsecutiveEntry() =
-        testSpec.visibleLayersShownMoreThanOneConsecutiveEntry()
 
     companion object {
         @Parameterized.Parameters(name = "{0}")
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
new file mode 100644
index 0000000..fef49d9
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
@@ -0,0 +1,157 @@
+/*
+ * 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.wm.flicker.close
+
+import android.app.Instrumentation
+import android.platform.test.annotations.Presubmit
+import android.view.Surface
+import androidx.test.filters.FlakyTest
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.wm.flicker.FlickerBuilderProvider
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.helpers.SimpleAppHelper
+import com.android.server.wm.flicker.helpers.StandardAppHelper
+import com.android.server.wm.flicker.helpers.setRotation
+import com.android.server.wm.flicker.launcherReplacesAppWindowAsTopWindow
+import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerRotatesAndScales
+import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.noUncoveredRegions
+import com.android.server.wm.flicker.startRotation
+import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerRotatesScales
+import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry
+import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry
+import com.android.server.wm.flicker.wallpaperLayerReplacesAppLayer
+import com.android.server.wm.flicker.wallpaperWindowBecomesVisible
+import org.junit.Assume
+import org.junit.Test
+
+abstract class CloseAppTransition(protected val testSpec: FlickerTestParameter) {
+    protected val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+    protected open val testApp: StandardAppHelper = SimpleAppHelper(instrumentation)
+    protected open val transition: FlickerBuilder.(Map<String, Any?>) -> Unit = {
+        setup {
+            eachRun {
+                testApp.launchViaIntent(wmHelper)
+                this.setRotation(testSpec.config.startRotation)
+            }
+        }
+        teardown {
+            test {
+                testApp.exit()
+            }
+        }
+    }
+
+    @FlickerBuilderProvider
+    fun buildFlicker(): FlickerBuilder {
+        return FlickerBuilder(instrumentation).apply {
+            transition(testSpec.config)
+        }
+    }
+
+    @Presubmit
+    @Test
+    open fun navBarWindowIsAlwaysVisible() {
+        testSpec.navBarWindowIsAlwaysVisible()
+    }
+
+    @Presubmit
+    @Test
+    open fun statusBarWindowIsAlwaysVisible() {
+        testSpec.statusBarWindowIsAlwaysVisible()
+    }
+
+    @Presubmit
+    @Test
+    open fun navBarLayerIsAlwaysVisible() {
+        testSpec.navBarLayerIsAlwaysVisible()
+    }
+
+    @Presubmit
+    @Test
+    open fun statusBarLayerIsAlwaysVisible() {
+        testSpec.statusBarLayerIsAlwaysVisible()
+    }
+
+    @Presubmit
+    @Test
+    open fun navBarLayerRotatesAndScales() {
+        Assume.assumeFalse(testSpec.isRotated)
+        testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0)
+    }
+
+    @FlakyTest
+    @Test
+    open fun navBarLayerRotatesAndScales_Flaky() {
+        Assume.assumeTrue(testSpec.isRotated)
+        testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0)
+    }
+
+    @Presubmit
+    @Test
+    open fun statusBarLayerRotatesScales() {
+        Assume.assumeFalse(testSpec.isRotated)
+        testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0)
+    }
+
+    @FlakyTest
+    @Test
+    open fun statusBarLayerRotatesScales_Flaky() {
+        Assume.assumeTrue(testSpec.isRotated)
+        testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0)
+    }
+
+    @FlakyTest(bugId = 173689015)
+    @Test
+    open fun visibleWindowsShownMoreThanOneConsecutiveEntry() {
+        testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry()
+    }
+
+    @FlakyTest(bugId = 173689015)
+    @Test
+    open fun visibleLayersShownMoreThanOneConsecutiveEntry() {
+        testSpec.visibleLayersShownMoreThanOneConsecutiveEntry()
+    }
+
+    @Presubmit
+    @Test
+    open fun noUncoveredRegions() {
+        testSpec.noUncoveredRegions(testSpec.config.startRotation, Surface.ROTATION_0)
+    }
+
+    @Presubmit
+    @Test
+    open fun launcherReplacesAppWindowAsTopWindow() {
+        testSpec.launcherReplacesAppWindowAsTopWindow(testApp)
+    }
+
+    @Presubmit
+    @Test
+    open fun wallpaperWindowBecomesVisible() {
+        testSpec.wallpaperWindowBecomesVisible()
+    }
+
+    @Presubmit
+    @Test
+    open fun wallpaperLayerReplacesAppLayer() {
+        testSpec.wallpaperLayerReplacesAppLayer(testApp)
+    }
+}
\ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
index 74f002d..56ed21b 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
@@ -16,37 +16,14 @@
 
 package com.android.server.wm.flicker.launch
 
-import android.app.Instrumentation
-import android.platform.test.annotations.Presubmit
-import android.view.Surface
-import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
-import androidx.test.platform.app.InstrumentationRegistry
-import com.android.server.wm.flicker.FlickerBuilderProvider
 import com.android.server.wm.flicker.FlickerParametersRunnerFactory
 import com.android.server.wm.flicker.FlickerTestParameter
 import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.focusChanges
 import com.android.server.wm.flicker.helpers.setRotation
-import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
-import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
-import com.android.server.wm.flicker.navBarLayerRotatesAndScales
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.noUncoveredRegions
-import com.android.server.wm.flicker.repetitions
 import com.android.server.wm.flicker.startRotation
-import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
-import com.android.server.wm.flicker.statusBarLayerRotatesScales
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry
-import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry
-import com.android.server.wm.flicker.wallpaperWindowBecomesInvisible
-import com.android.server.wm.flicker.appLayerReplacesWallpaperLayer
 import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.SimpleAppHelper
-import org.junit.Assume
 import org.junit.FixMethodOrder
-import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.MethodSorters
 import org.junit.runners.Parameterized
@@ -59,114 +36,25 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class OpenAppColdTest(private val testSpec: FlickerTestParameter) {
-    private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
-    private val testApp = SimpleAppHelper(instrumentation)
-
-    @FlickerBuilderProvider
-    fun buildFlicker(): FlickerBuilder {
-        return FlickerBuilder(instrumentation).apply {
-            withTestName { testSpec.name }
-            repeat { testSpec.config.repetitions }
+class OpenAppColdTest(testSpec: FlickerTestParameter) : OpenAppTransition(testSpec) {
+    override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
+        get() = {
+            super.transition(this, it)
             setup {
-                test {
-                    device.wakeUpAndGoToHomeScreen()
-                }
                 eachRun {
                     this.setRotation(testSpec.config.startRotation)
                 }
             }
-            transitions {
-                testApp.launchViaIntent(wmHelper)
-                // wmHelper.waitForFullScreenApp(testApp.component)
-            }
             teardown {
                 eachRun {
-                    testApp.exit()
-                    wmHelper.waitForAppTransitionIdle()
-                    this.setRotation(Surface.ROTATION_0)
+                    testApp.exit(wmHelper)
                 }
             }
+            transitions {
+                testApp.launchViaIntent(wmHelper)
+                wmHelper.waitForFullScreenApp(testApp.component)
+            }
         }
-    }
-
-    @Presubmit
-    @Test
-    fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
-
-    @Presubmit
-    @Test
-    fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
-
-    @Presubmit
-    @Test
-    fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
-        testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry()
-
-    @Presubmit
-    @Test
-    fun appWindowReplacesLauncherAsTopWindow() =
-        testSpec.appWindowReplacesLauncherAsTopWindow(testApp)
-
-    @Presubmit
-    @Test
-    fun wallpaperWindowBecomesInvisible() = testSpec.wallpaperWindowBecomesInvisible()
-
-    @Presubmit
-    @Test
-    // During testing the launcher is always in portrait mode
-    fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation,
-        Surface.ROTATION_0)
-
-    @Presubmit
-    @Test
-    fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
-
-    @Presubmit
-    @Test
-    fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
-
-    @Presubmit
-    @Test
-    fun appLayerReplacesWallpaperLayer() =
-        testSpec.appLayerReplacesWallpaperLayer(testApp.`package`)
-
-    @Presubmit
-    @Test
-    fun navBarLayerRotatesAndScales() {
-        Assume.assumeFalse(testSpec.isRotated)
-        testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0)
-    }
-
-    @FlakyTest
-    @Test
-    fun navBarLayerRotatesAndScales_Flaky() {
-        Assume.assumeTrue(testSpec.isRotated)
-        testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0)
-    }
-
-    @Presubmit
-    @Test
-    fun statusBarLayerRotatesScales() {
-        Assume.assumeFalse(testSpec.isRotated)
-        testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0)
-    }
-
-    @FlakyTest
-    @Test
-    fun statusBarLayerRotatesScales_Flaky() {
-        Assume.assumeTrue(testSpec.isRotated)
-        testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0)
-    }
-
-    @Presubmit
-    @Test
-    fun focusChanges() = testSpec.focusChanges("NexusLauncherActivity", testApp.`package`)
-
-    @FlakyTest
-    @Test
-    fun visibleLayersShownMoreThanOneConsecutiveEntry() =
-        testSpec.visibleLayersShownMoreThanOneConsecutiveEntry()
 
     companion object {
         @Parameterized.Parameters(name = "{0}")
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
index 18fac6a..4a32a9e 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
@@ -16,36 +16,19 @@
 
 package com.android.server.wm.flicker.launch
 
-import android.app.Instrumentation
 import android.platform.test.annotations.Presubmit
-import android.view.Surface
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
-import androidx.test.platform.app.InstrumentationRegistry
-import com.android.server.wm.flicker.FlickerBuilderProvider
 import com.android.server.wm.flicker.FlickerParametersRunnerFactory
 import com.android.server.wm.flicker.FlickerTestParameter
 import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.endRotation
-import com.android.server.wm.flicker.focusChanges
 import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry
 import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry
 import com.android.server.wm.flicker.helpers.reopenAppFromOverview
 import com.android.server.wm.flicker.helpers.setRotation
-import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
-import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
-import com.android.server.wm.flicker.navBarLayerRotatesAndScales
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.noUncoveredRegions
-import com.android.server.wm.flicker.repetitions
 import com.android.server.wm.flicker.startRotation
-import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
-import com.android.server.wm.flicker.statusBarLayerRotatesScales
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
 import com.android.server.wm.flicker.wallpaperWindowBecomesInvisible
-import com.android.server.wm.flicker.appLayerReplacesWallpaperLayer
 import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.SimpleAppHelper
 import org.junit.Assume
 import org.junit.FixMethodOrder
 import org.junit.Test
@@ -61,18 +44,12 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class OpenAppFromOverviewTest(private val testSpec: FlickerTestParameter) {
-    private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
-    private val testApp = SimpleAppHelper(instrumentation)
-
-    @FlickerBuilderProvider
-    fun buildFlicker(): FlickerBuilder {
-        return FlickerBuilder(instrumentation).apply {
-            withTestName { testSpec.name }
-            repeat { testSpec.config.repetitions }
+class OpenAppFromOverviewTest(testSpec: FlickerTestParameter) : OpenAppTransition(testSpec) {
+    override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
+        get() = {
+            super.transition(this, it)
             setup {
                 test {
-                    device.wakeUpAndGoToHomeScreen()
                     testApp.launchViaIntent(wmHelper)
                 }
                 eachRun {
@@ -87,71 +64,50 @@
                 device.reopenAppFromOverview(wmHelper)
                 wmHelper.waitForFullScreenApp(testApp.component)
             }
-            teardown {
-                test {
-                    testApp.exit()
-                }
-            }
         }
+
+    @Test
+    override fun appWindowReplacesLauncherAsTopWindow() =
+        super.appWindowReplacesLauncherAsTopWindow()
+
+    @Test
+    override fun wallpaperWindowBecomesInvisible() {
+        testSpec.wallpaperWindowBecomesInvisible()
     }
 
     @Presubmit
     @Test
-    fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
-
-    @Presubmit
-    @Test
-    fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
-
-    @Test
-    fun appWindowReplacesLauncherAsTopWindow() =
-        testSpec.appWindowReplacesLauncherAsTopWindow(testApp)
-
-    @Test
-    fun wallpaperWindowBecomesInvisible() = testSpec.wallpaperWindowBecomesInvisible()
-
-    @Presubmit
-    @Test
-    fun appLayerReplacesWallpaperLayer() =
-        testSpec.appLayerReplacesWallpaperLayer(testApp.`package`)
-
-    @Presubmit
-    @Test
-    fun navBarLayerRotatesAndScales() {
-        Assume.assumeFalse(testSpec.isRotated)
-        testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0)
-    }
-
-    @Presubmit
-    @Test
-    fun statusBarLayerRotatesScales() {
-        Assume.assumeFalse(testSpec.isRotated)
-        testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0)
-    }
-
-    @Presubmit
-    @Test
-    fun statusBarLayerIsAlwaysVisible() {
+    override fun statusBarLayerIsAlwaysVisible() {
         Assume.assumeTrue(testSpec.isRotated)
-        testSpec.statusBarLayerIsAlwaysVisible()
+        super.statusBarLayerIsAlwaysVisible()
     }
 
     @Presubmit
     @Test
-    fun navBarLayerIsAlwaysVisible() {
+    override fun navBarLayerIsAlwaysVisible() {
         Assume.assumeTrue(testSpec.isRotated)
-        testSpec.navBarLayerIsAlwaysVisible()
+        super.navBarLayerIsAlwaysVisible()
+    }
+
+    @FlakyTest
+    @Test
+    fun statusBarLayerIsAlwaysVisible_Flaky() {
+        Assume.assumeFalse(testSpec.isRotated)
+        super.statusBarLayerIsAlwaysVisible()
+    }
+
+    @FlakyTest
+    @Test
+    fun navBarLayerIsAlwaysVisible_Flaky() {
+        Assume.assumeFalse(testSpec.isRotated)
+        super.navBarLayerIsAlwaysVisible()
     }
 
     @Presubmit
     @Test
-    fun focusChanges() = testSpec.focusChanges("NexusLauncherActivity", testApp.`package`)
-
-    @Presubmit
-    @Test
-    fun visibleWindowsShownMoreThanOneConsecutiveEntry() {
+    override fun visibleWindowsShownMoreThanOneConsecutiveEntry() {
         Assume.assumeFalse(testSpec.isRotated)
-        testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry()
+        super.visibleWindowsShownMoreThanOneConsecutiveEntry()
     }
 
     @FlakyTest
@@ -163,9 +119,9 @@
 
     @Presubmit
     @Test
-    fun visibleLayersShownMoreThanOneConsecutiveEntry() {
+    override fun visibleLayersShownMoreThanOneConsecutiveEntry() {
         Assume.assumeFalse(testSpec.isRotated)
-        testSpec.visibleLayersShownMoreThanOneConsecutiveEntry()
+        super.visibleLayersShownMoreThanOneConsecutiveEntry()
     }
 
     @FlakyTest
@@ -175,11 +131,6 @@
         testSpec.visibleLayersShownMoreThanOneConsecutiveEntry()
     }
 
-    @Presubmit
-    @Test
-    fun noUncoveredRegions() = testSpec.noUncoveredRegions(Surface.ROTATION_0,
-        testSpec.config.endRotation)
-
     companion object {
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt
new file mode 100644
index 0000000..e9f0534
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt
@@ -0,0 +1,170 @@
+/*
+ * 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.wm.flicker.launch
+
+import android.app.Instrumentation
+import android.platform.test.annotations.Presubmit
+import android.view.Surface
+import androidx.test.filters.FlakyTest
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.wm.flicker.FlickerBuilderProvider
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.appLayerReplacesWallpaperLayer
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.endRotation
+import com.android.server.wm.flicker.focusChanges
+import com.android.server.wm.flicker.helpers.SimpleAppHelper
+import com.android.server.wm.flicker.helpers.StandardAppHelper
+import com.android.server.wm.flicker.helpers.setRotation
+import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
+import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerRotatesAndScales
+import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.noUncoveredRegions
+import com.android.server.wm.flicker.repetitions
+import com.android.server.wm.flicker.startRotation
+import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerRotatesScales
+import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry
+import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry
+import com.android.server.wm.flicker.wallpaperWindowBecomesInvisible
+import org.junit.Assume
+import org.junit.Test
+
+abstract class OpenAppTransition(protected val testSpec: FlickerTestParameter) {
+    protected val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+    protected val testApp: StandardAppHelper = SimpleAppHelper(instrumentation)
+
+    protected open val transition: FlickerBuilder.(Map<String, Any?>) -> Unit = {
+        withTestName { testSpec.name }
+        repeat { testSpec.config.repetitions }
+        setup {
+            test {
+                device.wakeUpAndGoToHomeScreen()
+                this.setRotation(testSpec.config.startRotation)
+            }
+        }
+        teardown {
+            test {
+                testApp.exit()
+            }
+        }
+    }
+
+    @FlickerBuilderProvider
+    fun buildFlicker(): FlickerBuilder {
+        return FlickerBuilder(instrumentation).apply {
+            transition(testSpec.config)
+        }
+    }
+
+    @Presubmit
+    @Test
+    open fun navBarWindowIsAlwaysVisible() {
+        testSpec.navBarWindowIsAlwaysVisible()
+    }
+
+    @Presubmit
+    @Test
+    open fun navBarLayerIsAlwaysVisible() {
+        testSpec.navBarLayerIsAlwaysVisible()
+    }
+
+    @Presubmit
+    @Test
+    open fun navBarLayerRotatesAndScales() {
+        Assume.assumeFalse(testSpec.isRotated)
+        testSpec.navBarLayerRotatesAndScales(Surface.ROTATION_0, testSpec.config.endRotation)
+    }
+
+    @FlakyTest
+    @Test
+    open fun navBarLayerRotatesAndScales_Flaky() {
+        Assume.assumeTrue(testSpec.isRotated)
+        testSpec.navBarLayerRotatesAndScales(Surface.ROTATION_0, testSpec.config.endRotation)
+    }
+
+    @Presubmit
+    @Test
+    open fun statusBarWindowIsAlwaysVisible() {
+        testSpec.statusBarWindowIsAlwaysVisible()
+    }
+
+    @Presubmit
+    @Test
+    open fun statusBarLayerIsAlwaysVisible() {
+        testSpec.statusBarLayerIsAlwaysVisible()
+    }
+
+    @Presubmit
+    @Test
+    open fun statusBarLayerRotatesScales() {
+        Assume.assumeFalse(testSpec.isRotated)
+        testSpec.statusBarLayerRotatesScales(Surface.ROTATION_0, testSpec.config.endRotation)
+    }
+
+    @FlakyTest
+    @Test
+    open fun statusBarLayerRotatesScales_Flaky() {
+        Assume.assumeTrue(testSpec.isRotated)
+        testSpec.statusBarLayerRotatesScales(Surface.ROTATION_0, testSpec.config.endRotation)
+    }
+
+    @Presubmit
+    @Test
+    open fun visibleWindowsShownMoreThanOneConsecutiveEntry() {
+        testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry()
+    }
+
+    @FlakyTest
+    @Test
+    open fun visibleLayersShownMoreThanOneConsecutiveEntry() {
+        testSpec.visibleLayersShownMoreThanOneConsecutiveEntry()
+    }
+
+    @Presubmit
+    @Test
+    // During testing the launcher is always in portrait mode
+    open fun noUncoveredRegions() {
+        testSpec.noUncoveredRegions(Surface.ROTATION_0, testSpec.config.endRotation)
+    }
+
+    @Presubmit
+    @Test
+    open fun focusChanges() {
+        testSpec.focusChanges("NexusLauncherActivity", testApp.`package`)
+    }
+
+    @Presubmit
+    @Test
+    open fun appLayerReplacesWallpaperLayer() {
+        testSpec.appLayerReplacesWallpaperLayer(testApp.`package`)
+    }
+
+    @Presubmit
+    @Test
+    open fun appWindowReplacesLauncherAsTopWindow() {
+        testSpec.appWindowReplacesLauncherAsTopWindow(testApp)
+    }
+
+    @Presubmit
+    @Test
+    open fun wallpaperWindowBecomesInvisible() {
+        testSpec.wallpaperWindowBecomesInvisible()
+    }
+}
\ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
index b61310a..a8b5ea1 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
@@ -16,34 +16,14 @@
 
 package com.android.server.wm.flicker.launch
 
-import android.app.Instrumentation
-import android.platform.test.annotations.Presubmit
-import android.view.Surface
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
-import androidx.test.platform.app.InstrumentationRegistry
-import com.android.server.wm.flicker.FlickerBuilderProvider
 import com.android.server.wm.flicker.FlickerParametersRunnerFactory
 import com.android.server.wm.flicker.FlickerTestParameter
 import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.focusChanges
 import com.android.server.wm.flicker.helpers.setRotation
-import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
-import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
-import com.android.server.wm.flicker.navBarLayerRotatesAndScales
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.noUncoveredRegions
-import com.android.server.wm.flicker.repetitions
 import com.android.server.wm.flicker.startRotation
-import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
-import com.android.server.wm.flicker.statusBarLayerRotatesScales
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry
-import com.android.server.wm.flicker.wallpaperWindowBecomesInvisible
-import com.android.server.wm.flicker.appLayerReplacesWallpaperLayer
 import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.SimpleAppHelper
-import org.junit.Assume
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -58,20 +38,13 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class OpenAppWarmTest(private val testSpec: FlickerTestParameter) {
-    private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
-    private val testApp = SimpleAppHelper(instrumentation)
-
-    @FlickerBuilderProvider
-    fun buildFlicker(): FlickerBuilder {
-        return FlickerBuilder(instrumentation).apply {
-            withTestName { testSpec.name }
-            repeat { testSpec.config.repetitions }
+class OpenAppWarmTest(testSpec: FlickerTestParameter) : OpenAppTransition(testSpec) {
+    override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
+        get() = {
+            super.transition(this, it)
             setup {
                 test {
-                    device.wakeUpAndGoToHomeScreen()
                     testApp.launchViaIntent(wmHelper)
-                    // wmHelper.waitForFullScreenApp(testApp.component)
                 }
                 eachRun {
                     device.pressHome()
@@ -79,93 +52,21 @@
                     this.setRotation(testSpec.config.startRotation)
                 }
             }
+            teardown {
+                eachRun {
+                    testApp.exit(wmHelper)
+                }
+            }
             transitions {
                 testApp.launchViaIntent(wmHelper)
                 wmHelper.waitForFullScreenApp(testApp.component)
             }
-            teardown {
-                eachRun {
-                    this.setRotation(Surface.ROTATION_0)
-                }
-                test {
-                    testApp.exit()
-                }
-            }
         }
-    }
-
-    @Presubmit
-    @Test
-    fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
-
-    @Presubmit
-    @Test
-    fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
 
     @FlakyTest
     @Test
-    fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
-        testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry()
-
-    @Presubmit
-    @Test
-    fun appWindowReplacesLauncherAsTopWindow() =
-        testSpec.appWindowReplacesLauncherAsTopWindow(testApp)
-
-    @Presubmit
-    @Test
-    fun wallpaperWindowBecomesInvisible() = testSpec.wallpaperWindowBecomesInvisible()
-
-    @Presubmit
-    @Test
-    // During testing the launcher is always in portrait mode
-    fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation,
-        Surface.ROTATION_0)
-
-    @Presubmit
-    @Test
-    fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
-
-    @Presubmit
-    @Test
-    fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
-
-    @Presubmit
-    @Test
-    fun appLayerReplacesWallpaperLayer() =
-        testSpec.appLayerReplacesWallpaperLayer(testApp.`package`)
-
-    @Presubmit
-    @Test
-    fun navBarLayerRotatesAndScales() {
-        Assume.assumeFalse(testSpec.isRotated)
-        testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0)
-    }
-
-    @FlakyTest
-    @Test
-    fun navBarLayerRotatesAndScales_Flaky() {
-        Assume.assumeTrue(testSpec.isRotated)
-        testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0)
-    }
-
-    @Presubmit
-    @Test
-    fun statusBarLayerRotatesScales() {
-        Assume.assumeFalse(testSpec.isRotated)
-        testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0)
-    }
-
-    @FlakyTest
-    @Test
-    fun statusBarLayerRotatesScales_Flaky() {
-        Assume.assumeTrue(testSpec.isRotated)
-        testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0)
-    }
-
-    @Presubmit
-    @Test
-    fun focusChanges() = testSpec.focusChanges("NexusLauncherActivity", testApp.`package`)
+    override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
+        super.visibleWindowsShownMoreThanOneConsecutiveEntry()
 
     companion object {
         @Parameterized.Parameters(name = "{0}")
diff --git a/tests/Input/Android.bp b/tests/Input/Android.bp
index 335c8d0..eacf5b2 100644
--- a/tests/Input/Android.bp
+++ b/tests/Input/Android.bp
@@ -9,14 +9,17 @@
 
 android_test {
     name: "InputTests",
-    srcs: ["src/**/*.kt"],
+    srcs: [
+        "src/**/*.java",
+        "src/**/*.kt",
+    ],
     platform_apis: true,
     certificate: "platform",
     static_libs: [
-            "androidx.test.ext.junit",
-            "androidx.test.rules",
-            "truth-prebuilt",
-            "ub-uiautomator",
-        ],
+        "androidx.test.ext.junit",
+        "androidx.test.rules",
+        "truth-prebuilt",
+        "ub-uiautomator",
+    ],
     test_suites: ["device-tests"],
 }
diff --git a/tests/Input/src/com/android/test/input/InputDeviceTest.java b/tests/Input/src/com/android/test/input/InputDeviceTest.java
new file mode 100644
index 0000000..6350077
--- /dev/null
+++ b/tests/Input/src/com/android/test/input/InputDeviceTest.java
@@ -0,0 +1,98 @@
+/*
+ * 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;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.os.Parcel;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class InputDeviceTest {
+    private static final float DELTA = 0.01f;
+    private static final int DEVICE_ID = 1000;
+
+    private void assertMotionRangeEquals(InputDevice.MotionRange range,
+            InputDevice.MotionRange outRange) {
+        assertEquals(range.getAxis(), outRange.getAxis());
+        assertEquals(range.getSource(), outRange.getSource());
+        assertEquals(range.getMin(), outRange.getMin(), DELTA);
+        assertEquals(range.getMax(), outRange.getMax(), DELTA);
+        assertEquals(range.getFlat(), outRange.getFlat(), DELTA);
+        assertEquals(range.getFuzz(), outRange.getFuzz(), DELTA);
+        assertEquals(range.getResolution(), outRange.getResolution(), DELTA);
+    }
+
+    private void assertDeviceEquals(InputDevice device, InputDevice outDevice) {
+        assertEquals(device.getId(), outDevice.getId());
+        assertEquals(device.getGeneration(), outDevice.getGeneration());
+        assertEquals(device.getControllerNumber(), outDevice.getControllerNumber());
+        assertEquals(device.getName(), outDevice.getName());
+        assertEquals(device.getVendorId(), outDevice.getVendorId());
+        assertEquals(device.getProductId(), outDevice.getProductId());
+        assertEquals(device.getDescriptor(), outDevice.getDescriptor());
+        assertEquals(device.isExternal(), outDevice.isExternal());
+        assertEquals(device.getSources(), outDevice.getSources());
+        assertEquals(device.getKeyboardType(), outDevice.getKeyboardType());
+        assertEquals(device.getMotionRanges().size(), outDevice.getMotionRanges().size());
+
+        KeyCharacterMap keyCharacterMap = device.getKeyCharacterMap();
+        KeyCharacterMap outKeyCharacterMap = outDevice.getKeyCharacterMap();
+        assertTrue("keyCharacterMap not equal", keyCharacterMap.equals(outKeyCharacterMap));
+
+        for (int j = 0; j < device.getMotionRanges().size(); j++) {
+            assertMotionRangeEquals(device.getMotionRanges().get(j),
+                    outDevice.getMotionRanges().get(j));
+        }
+    }
+
+    private void assertInputDeviceParcelUnparcel(KeyCharacterMap keyCharacterMap) {
+        final InputDevice device =
+                new InputDevice(DEVICE_ID, 0 /* generation */, 0 /* controllerNumber */, "name",
+                0 /* vendorId */, 0 /* productId */, "descriptor", true /* isExternal */,
+                0 /* sources */, 0 /* keyboardType */, keyCharacterMap,
+                false /* hasVibrator */, false /* hasMicrophone */, false /* hasButtonUnderpad */,
+                true /* hasSensor */, false /* hasBattery */);
+
+        Parcel parcel = Parcel.obtain();
+        device.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+
+        InputDevice outDevice = InputDevice.CREATOR.createFromParcel(parcel);
+        assertDeviceEquals(device, outDevice);
+    }
+
+    @Test
+    public void testParcelUnparcelInputDevice_VirtualCharacterMap() {
+        final KeyCharacterMap keyCharacterMap =
+                KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD);
+        assertInputDeviceParcelUnparcel(keyCharacterMap);
+    }
+
+    @Test
+    public void testParcelUnparcelInputDevice_EmptyCharacterMap() {
+        final KeyCharacterMap keyCharacterMap = KeyCharacterMap.obtainEmptyMap(DEVICE_ID);
+        assertInputDeviceParcelUnparcel(keyCharacterMap);
+    }
+}
diff --git a/tests/Input/src/com/android/test/input/InputEventAssignerTest.kt b/tests/Input/src/com/android/test/input/InputEventAssignerTest.kt
index 2e985fb..b9b347b 100644
--- a/tests/Input/src/com/android/test/input/InputEventAssignerTest.kt
+++ b/tests/Input/src/com/android/test/input/InputEventAssignerTest.kt
@@ -43,7 +43,7 @@
             xPrecision, yPrecision, deviceId, edgeFlags, source, displayId)
 }
 
-fun createKeyEvent(action: Int, eventTime: Long): KeyEvent {
+private fun createKeyEvent(action: Int, eventTime: Long): KeyEvent {
     val code = KeyEvent.KEYCODE_A
     val repeat = 0
     return KeyEvent(eventTime, eventTime, action, code, repeat)
diff --git a/tests/Input/src/com/android/test/input/InputEventSenderAndReceiverTest.kt b/tests/Input/src/com/android/test/input/InputEventSenderAndReceiverTest.kt
new file mode 100644
index 0000000..4f95ce5
--- /dev/null
+++ b/tests/Input/src/com/android/test/input/InputEventSenderAndReceiverTest.kt
@@ -0,0 +1,123 @@
+/*
+ * 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.test.input
+
+import android.os.HandlerThread
+import android.os.Looper
+import android.view.InputChannel
+import android.view.InputEvent
+import android.view.InputEventReceiver
+import android.view.InputEventSender
+import android.view.KeyEvent
+import android.view.MotionEvent
+import java.util.concurrent.CountDownLatch
+import org.junit.Assert.assertEquals
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+
+private fun assertKeyEvent(expected: KeyEvent, received: KeyEvent) {
+    assertEquals(expected.action, received.action)
+    assertEquals(expected.deviceId, received.deviceId)
+    assertEquals(expected.downTime, received.downTime)
+    assertEquals(expected.eventTime, received.eventTime)
+    assertEquals(expected.keyCode, received.keyCode)
+    assertEquals(expected.scanCode, received.scanCode)
+    assertEquals(expected.repeatCount, received.repeatCount)
+    assertEquals(expected.metaState, received.metaState)
+    assertEquals(expected.flags, received.flags)
+    assertEquals(expected.source, received.source)
+    assertEquals(expected.displayId, received.displayId)
+}
+
+class TestInputEventReceiver(channel: InputChannel, looper: Looper) :
+        InputEventReceiver(channel, looper) {
+    companion object {
+        const val TAG = "TestInputEventReceiver"
+    }
+
+    var lastEvent: InputEvent? = null
+
+    override fun onInputEvent(event: InputEvent) {
+        lastEvent = when (event) {
+            is KeyEvent -> KeyEvent.obtain(event)
+            is MotionEvent -> MotionEvent.obtain(event)
+            else -> throw Exception("Received $event is neither a key nor a motion")
+        }
+        finishInputEvent(event, true /*handled*/)
+    }
+}
+
+class TestInputEventSender(channel: InputChannel, looper: Looper) :
+        InputEventSender(channel, looper) {
+    companion object {
+        const val TAG = "TestInputEventSender"
+    }
+    data class FinishedResult(val seq: Int, val handled: Boolean)
+
+    private var mFinishedSignal = CountDownLatch(1)
+    override fun onInputEventFinished(seq: Int, handled: Boolean) {
+        finishedResult = FinishedResult(seq, handled)
+        mFinishedSignal.countDown()
+    }
+    lateinit var finishedResult: FinishedResult
+
+    fun waitForFinish() {
+        mFinishedSignal.await()
+        mFinishedSignal = CountDownLatch(1) // Ready for next event
+    }
+}
+
+class InputEventSenderAndReceiverTest {
+    companion object {
+        private const val TAG = "InputEventSenderAndReceiverTest"
+    }
+    private val mHandlerThread = HandlerThread("Process input events")
+    private lateinit var mReceiver: TestInputEventReceiver
+    private lateinit var mSender: TestInputEventSender
+
+    @Before
+    fun setUp() {
+        val channels = InputChannel.openInputChannelPair("TestChannel")
+        mHandlerThread.start()
+
+        val looper = mHandlerThread.getLooper()
+        mSender = TestInputEventSender(channels[0], looper)
+        mReceiver = TestInputEventReceiver(channels[1], looper)
+    }
+
+    @After
+    fun tearDown() {
+        mHandlerThread.quitSafely()
+    }
+
+    @Test
+    fun testSendAndReceiveKey() {
+        val key = KeyEvent(1 /*downTime*/, 1 /*eventTime*/, KeyEvent.ACTION_DOWN,
+                KeyEvent.KEYCODE_A, 0 /*repeat*/)
+        val seq = 10
+        mSender.sendInputEvent(seq, key)
+        mSender.waitForFinish()
+
+        // Check receiver
+        assertKeyEvent(key, mReceiver.lastEvent!! as KeyEvent)
+
+        // Check sender
+        assertEquals(seq, mSender.finishedResult.seq)
+        assertEquals(true, mSender.finishedResult.handled)
+    }
+}
diff --git a/tests/PlatformCompatGating/test-rules/src/android/compat/testing/PlatformCompatChangeRule.java b/tests/PlatformCompatGating/test-rules/src/android/compat/testing/PlatformCompatChangeRule.java
index d6846fa..e121b68 100644
--- a/tests/PlatformCompatGating/test-rules/src/android/compat/testing/PlatformCompatChangeRule.java
+++ b/tests/PlatformCompatGating/test-rules/src/android/compat/testing/PlatformCompatChangeRule.java
@@ -94,17 +94,16 @@
             if (platformCompat == null) {
                 throw new IllegalStateException("Could not get IPlatformCompat service!");
             }
-            uiAutomation.adoptShellPermissionIdentity(
-                    Manifest.permission.LOG_COMPAT_CHANGE,
-                    Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG,
-                    Manifest.permission.READ_COMPAT_CHANGE_CONFIG);
+            adoptShellPermissions(uiAutomation);
             Compatibility.setOverrides(mConfig);
             try {
                 platformCompat.setOverridesForTest(new CompatibilityChangeConfig(mConfig),
                         packageName);
                 try {
+                    uiAutomation.dropShellPermissionIdentity();
                     mTestStatement.evaluate();
                 } finally {
+                    adoptShellPermissions(uiAutomation);
                     platformCompat.clearOverridesForTest(packageName);
                 }
             } catch (RemoteException e) {
@@ -114,5 +113,12 @@
                 Compatibility.clearOverrides();
             }
         }
+
+        private static void adoptShellPermissions(UiAutomation uiAutomation) {
+            uiAutomation.adoptShellPermissionIdentity(
+                    Manifest.permission.LOG_COMPAT_CHANGE,
+                    Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG,
+                    Manifest.permission.READ_COMPAT_CHANGE_CONFIG);
+        }
     }
 }
diff --git a/tests/RollbackTest/MultiUserRollbackTest.xml b/tests/RollbackTest/MultiUserRollbackTest.xml
index 2f62af1..8fa0510 100644
--- a/tests/RollbackTest/MultiUserRollbackTest.xml
+++ b/tests/RollbackTest/MultiUserRollbackTest.xml
@@ -20,6 +20,8 @@
         <option name="run-command" value="pm uninstall com.android.cts.install.lib.testapp.B" />
         <option name="teardown-command" value="pm uninstall com.android.cts.install.lib.testapp.A" />
         <option name="teardown-command" value="pm uninstall com.android.cts.install.lib.testapp.B" />
+        <option name="run-command" value="setprop persist.rollback.is_test 1" />
+        <option name="teardown-command" value="setprop persist.rollback.is_test 0" />
     </target_preparer>
     <test class="com.android.tradefed.testtype.HostTest" >
         <option name="class" value="com.android.tests.rollback.host.MultiUserRollbackTest" />
diff --git a/tests/RollbackTest/NetworkStagedRollbackTest.xml b/tests/RollbackTest/NetworkStagedRollbackTest.xml
index 2ab907a..13f6031 100644
--- a/tests/RollbackTest/NetworkStagedRollbackTest.xml
+++ b/tests/RollbackTest/NetworkStagedRollbackTest.xml
@@ -24,6 +24,8 @@
         <option name="run-command" value="am broadcast -a 'com.google.android.gms.phenotype.FLAG_OVERRIDE' --es package &quot;com.google.android.gms.platformconfigurator&quot; --es user '\\*' --esa flags &quot;ModuleConfig__versioned_immediate_commit_packages&quot; --esa types &quot;bytes&quot; --esa values &quot;Cm5vdGFwYWNrYWdlOgA=&quot; com.google.android.gms" />
         <option name="teardown-command" value="am broadcast -a 'com.google.android.gms.phenotype.FLAG_OVERRIDE' --es action delete --es package &quot;com.google.android.gms.platformconfigurator&quot; --es user '\*' --esa flag &quot;ModuleConfig__immediate_commit_packages&quot; com.google.android.gms" />
         <option name="teardown-command" value="am broadcast -a 'com.google.android.gms.phenotype.FLAG_OVERRIDE' --es action delete --es package &quot;com.google.android.gms.platformconfigurator&quot; --es user '\*' --esa flag &quot;ModuleConfig__versioned_immediate_commit_packages&quot; com.google.android.gms" />
+        <option name="run-command" value="setprop persist.rollback.is_test 1" />
+        <option name="teardown-command" value="setprop persist.rollback.is_test 0" />
     </target_preparer>
     <test class="com.android.tradefed.testtype.HostTest" >
         <option name="class" value="com.android.tests.rollback.host.NetworkStagedRollbackTest" />
diff --git a/tests/RollbackTest/RollbackTest.xml b/tests/RollbackTest/RollbackTest.xml
index 7b85cc8..fbb6e46 100644
--- a/tests/RollbackTest/RollbackTest.xml
+++ b/tests/RollbackTest/RollbackTest.xml
@@ -27,6 +27,8 @@
         <option name="run-command" value="pm uninstall com.android.cts.install.lib.testapp.B" />
         <option name="teardown-command" value="pm uninstall com.android.cts.install.lib.testapp.A" />
         <option name="teardown-command" value="pm uninstall com.android.cts.install.lib.testapp.B" />
+        <option name="run-command" value="setprop persist.rollback.is_test 1" />
+        <option name="teardown-command" value="setprop persist.rollback.is_test 0" />
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="com.android.tests.rollback" />
diff --git a/tests/RollbackTest/StagedRollbackTest.xml b/tests/RollbackTest/StagedRollbackTest.xml
index 83fef8e..0ca4daf 100644
--- a/tests/RollbackTest/StagedRollbackTest.xml
+++ b/tests/RollbackTest/StagedRollbackTest.xml
@@ -24,6 +24,8 @@
         <option name="run-command" value="pm uninstall com.android.cts.install.lib.testapp.B" />
         <option name="teardown-command" value="pm uninstall com.android.cts.install.lib.testapp.A" />
         <option name="teardown-command" value="pm uninstall com.android.cts.install.lib.testapp.B" />
+        <option name="run-command" value="setprop persist.rollback.is_test 1" />
+        <option name="teardown-command" value="setprop persist.rollback.is_test 0" />
     </target_preparer>
     <test class="com.android.tradefed.testtype.HostTest" >
         <option name="class" value="com.android.tests.rollback.host.StagedRollbackTest" />
diff --git a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
index e84b992..0dfec75 100644
--- a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
+++ b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
@@ -28,6 +28,7 @@
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PAID;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE;
@@ -44,6 +45,10 @@
 import static android.net.NetworkCapabilities.UNRESTRICTED_CAPABILITIES;
 import static android.os.Process.INVALID_UID;
 
+import static com.android.modules.utils.build.SdkLevel.isAtLeastR;
+import static com.android.modules.utils.build.SdkLevel.isAtLeastS;
+import static com.android.testutils.MiscAsserts.assertEmpty;
+import static com.android.testutils.MiscAsserts.assertThrows;
 import static com.android.testutils.ParcelUtils.assertParcelSane;
 import static com.android.testutils.ParcelUtils.assertParcelingIsLossless;
 import static com.android.testutils.ParcelUtils.parcelingRoundTrip;
@@ -67,7 +72,6 @@
 
 import androidx.test.runner.AndroidJUnit4;
 
-import com.android.modules.utils.build.SdkLevel;
 import com.android.testutils.CompatUtil;
 import com.android.testutils.DevSdkIgnoreRule;
 import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
@@ -85,6 +89,9 @@
 public class NetworkCapabilitiesTest {
     private static final String TEST_SSID = "TEST_SSID";
     private static final String DIFFERENT_TEST_SSID = "DIFFERENT_TEST_SSID";
+    private static final int TEST_SUBID1 = 1;
+    private static final int TEST_SUBID2 = 2;
+    private static final int TEST_SUBID3 = 3;
 
     @Rule
     public DevSdkIgnoreRule mDevSdkIgnoreRule = new DevSdkIgnoreRule();
@@ -92,14 +99,6 @@
     private DiscoverySession mDiscoverySession = Mockito.mock(DiscoverySession.class);
     private PeerHandle mPeerHandle = Mockito.mock(PeerHandle.class);
 
-    private boolean isAtLeastR() {
-        return SdkLevel.isAtLeastR();
-    }
-
-    private boolean isAtLeastS() {
-        return SdkLevel.isAtLeastS();
-    }
-
     @Test
     public void testMaybeMarkCapabilitiesRestricted() {
         // verify EIMS is restricted
@@ -305,7 +304,9 @@
             .setUids(uids)
             .addCapability(NET_CAPABILITY_EIMS)
             .addCapability(NET_CAPABILITY_NOT_METERED);
-        if (isAtLeastR()) {
+        if (isAtLeastS()) {
+            netCap.setSubIds(Set.of(TEST_SUBID1, TEST_SUBID2));
+        } else if (isAtLeastR()) {
             netCap.setOwnerUid(123);
             netCap.setAdministratorUids(new int[] {5, 11});
         }
@@ -380,7 +381,7 @@
 
     private void testParcelSane(NetworkCapabilities cap) {
         if (isAtLeastS()) {
-            assertParcelSane(cap, 16);
+            assertParcelSane(cap, 17);
         } else if (isAtLeastR()) {
             assertParcelSane(cap, 15);
         } else {
@@ -614,6 +615,20 @@
         assertFalse(nc2.appliesToUid(12));
         assertTrue(nc1.appliesToUid(22));
         assertTrue(nc2.appliesToUid(22));
+
+        // Verify the subscription id list can be combined only when they are equal.
+        if (isAtLeastS()) {
+            nc1.setSubIds(Set.of(TEST_SUBID1, TEST_SUBID2));
+            nc2.setSubIds(Set.of(TEST_SUBID2));
+            assertThrows(IllegalStateException.class, () -> nc2.combineCapabilities(nc1));
+
+            nc2.setSubIds(Set.of());
+            assertThrows(IllegalStateException.class, () -> nc2.combineCapabilities(nc1));
+
+            nc2.setSubIds(Set.of(TEST_SUBID2, TEST_SUBID1));
+            nc2.combineCapabilities(nc1);
+            assertEquals(Set.of(TEST_SUBID2, TEST_SUBID1), nc2.getSubIds());
+        }
     }
 
     @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
@@ -762,6 +777,24 @@
         nc1.setUids(uidRange(10, 13));
         nc2.set(nc1);  // Overwrites, as opposed to combineCapabilities
         assertEquals(nc1, nc2);
+
+        if (isAtLeastS()) {
+            assertThrows(NullPointerException.class, () -> nc1.setSubIds(null));
+            nc1.setSubIds(Set.of());
+            nc2.set(nc1);
+            assertEquals(nc1, nc2);
+
+            nc1.setSubIds(Set.of(TEST_SUBID1));
+            nc2.set(nc1);
+            assertEquals(nc1, nc2);
+
+            nc2.setSubIds(Set.of(TEST_SUBID2, TEST_SUBID1));
+            nc2.set(nc1);
+            assertEquals(nc1, nc2);
+
+            nc2.setSubIds(Set.of(TEST_SUBID3, TEST_SUBID2));
+            assertNotEquals(nc1, nc2);
+        }
     }
 
     @Test
@@ -842,6 +875,50 @@
         } catch (NullPointerException expected) { }
     }
 
+    private static NetworkCapabilities capsWithSubIds(Integer ... subIds) {
+        // Since the NetworkRequest would put NOT_VCN_MANAGED capabilities in general, for
+        // every NetworkCapabilities that simulates networks needs to add it too in order to
+        // satisfy these requests.
+        final NetworkCapabilities nc = new NetworkCapabilities.Builder()
+                .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
+                .setSubIds(new ArraySet<>(subIds)).build();
+        assertEquals(new ArraySet<>(subIds), nc.getSubIds());
+        return nc;
+    }
+
+    @Test @IgnoreUpTo(Build.VERSION_CODES.R)
+    public void testSubIds() throws Exception {
+        final NetworkCapabilities ncWithoutId = capsWithSubIds();
+        final NetworkCapabilities ncWithId = capsWithSubIds(TEST_SUBID1);
+        final NetworkCapabilities ncWithOtherIds = capsWithSubIds(TEST_SUBID1, TEST_SUBID3);
+        final NetworkCapabilities ncWithoutRequestedIds = capsWithSubIds(TEST_SUBID3);
+
+        final NetworkRequest requestWithoutId = new NetworkRequest.Builder().build();
+        assertEmpty(requestWithoutId.networkCapabilities.getSubIds());
+        final NetworkRequest requestWithIds = new NetworkRequest.Builder()
+                .setSubIds(Set.of(TEST_SUBID1, TEST_SUBID2)).build();
+        assertEquals(Set.of(TEST_SUBID1, TEST_SUBID2),
+                requestWithIds.networkCapabilities.getSubIds());
+
+        assertFalse(requestWithIds.canBeSatisfiedBy(ncWithoutId));
+        assertTrue(requestWithIds.canBeSatisfiedBy(ncWithOtherIds));
+        assertFalse(requestWithIds.canBeSatisfiedBy(ncWithoutRequestedIds));
+        assertTrue(requestWithIds.canBeSatisfiedBy(ncWithId));
+        assertTrue(requestWithoutId.canBeSatisfiedBy(ncWithoutId));
+        assertTrue(requestWithoutId.canBeSatisfiedBy(ncWithId));
+    }
+
+    @Test @IgnoreUpTo(Build.VERSION_CODES.R)
+    public void testEqualsSubIds() throws Exception {
+        assertEquals(capsWithSubIds(), capsWithSubIds());
+        assertNotEquals(capsWithSubIds(), capsWithSubIds(TEST_SUBID1));
+        assertEquals(capsWithSubIds(TEST_SUBID1), capsWithSubIds(TEST_SUBID1));
+        assertNotEquals(capsWithSubIds(TEST_SUBID1), capsWithSubIds(TEST_SUBID2));
+        assertNotEquals(capsWithSubIds(TEST_SUBID1), capsWithSubIds(TEST_SUBID2, TEST_SUBID1));
+        assertEquals(capsWithSubIds(TEST_SUBID1, TEST_SUBID2),
+                capsWithSubIds(TEST_SUBID2, TEST_SUBID1));
+    }
+
     @Test
     public void testLinkBandwidthKbps() {
         final NetworkCapabilities nc = new NetworkCapabilities();
@@ -1022,5 +1099,11 @@
             fail("Should not set null into NetworkCapabilities.Builder");
         } catch (NullPointerException expected) { }
         assertEquals(nc, new NetworkCapabilities.Builder(nc).build());
+
+        if (isAtLeastS()) {
+            final NetworkCapabilities nc2 = new NetworkCapabilities.Builder()
+                    .setSubIds(Set.of(TEST_SUBID1)).build();
+            assertEquals(Set.of(TEST_SUBID1), nc2.getSubIds());
+        }
     }
 }
diff --git a/tests/net/java/android/net/ConnectivityManagerTest.java b/tests/net/java/android/net/ConnectivityManagerTest.java
index 098b029..6fc605e 100644
--- a/tests/net/java/android/net/ConnectivityManagerTest.java
+++ b/tests/net/java/android/net/ConnectivityManagerTest.java
@@ -220,7 +220,7 @@
 
         // register callback
         when(mService.requestNetwork(any(), anyInt(), captor.capture(), anyInt(), any(), anyInt(),
-                any(), nullable(String.class))).thenReturn(request);
+                anyInt(), any(), nullable(String.class))).thenReturn(request);
         manager.requestNetwork(request, callback, handler);
 
         // callback triggers
@@ -248,7 +248,7 @@
 
         // register callback
         when(mService.requestNetwork(any(), anyInt(), captor.capture(), anyInt(), any(), anyInt(),
-                any(), nullable(String.class))).thenReturn(req1);
+                anyInt(), any(), nullable(String.class))).thenReturn(req1);
         manager.requestNetwork(req1, callback, handler);
 
         // callback triggers
@@ -266,7 +266,7 @@
 
         // callback can be registered again
         when(mService.requestNetwork(any(), anyInt(), captor.capture(), anyInt(), any(), anyInt(),
-                any(), nullable(String.class))).thenReturn(req2);
+                anyInt(), any(), nullable(String.class))).thenReturn(req2);
         manager.requestNetwork(req2, callback, handler);
 
         // callback triggers
@@ -289,8 +289,8 @@
         info.targetSdkVersion = VERSION_CODES.N_MR1 + 1;
 
         when(mCtx.getApplicationInfo()).thenReturn(info);
-        when(mService.requestNetwork(any(), anyInt(), any(), anyInt(), any(), anyInt(), any(),
-                nullable(String.class))).thenReturn(request);
+        when(mService.requestNetwork(any(), anyInt(), any(), anyInt(), any(), anyInt(), anyInt(),
+                any(), nullable(String.class))).thenReturn(request);
 
         Handler handler = new Handler(Looper.getMainLooper());
         manager.requestNetwork(request, callback, handler);
@@ -358,34 +358,34 @@
 
         manager.requestNetwork(request, callback);
         verify(mService).requestNetwork(eq(request.networkCapabilities),
-                eq(REQUEST.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE),
+                eq(REQUEST.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), anyInt(),
                 eq(testPkgName), eq(testAttributionTag));
         reset(mService);
 
         // Verify that register network callback does not calls requestNetwork at all.
         manager.registerNetworkCallback(request, callback);
-        verify(mService, never()).requestNetwork(any(), anyInt(), any(), anyInt(), any(),
+        verify(mService, never()).requestNetwork(any(), anyInt(), any(), anyInt(), any(), anyInt(),
                 anyInt(), any(), any());
-        verify(mService).listenForNetwork(eq(request.networkCapabilities), any(), any(),
+        verify(mService).listenForNetwork(eq(request.networkCapabilities), any(), any(), anyInt(),
                 eq(testPkgName), eq(testAttributionTag));
         reset(mService);
 
         manager.registerDefaultNetworkCallback(callback);
         verify(mService).requestNetwork(eq(null),
-                eq(TRACK_DEFAULT.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE),
+                eq(TRACK_DEFAULT.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), anyInt(),
                 eq(testPkgName), eq(testAttributionTag));
         reset(mService);
 
         Handler handler = new Handler(ConnectivityThread.getInstanceLooper());
         manager.requestBackgroundNetwork(request, handler, callback);
         verify(mService).requestNetwork(eq(request.networkCapabilities),
-                eq(BACKGROUND_REQUEST.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE),
+                eq(BACKGROUND_REQUEST.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), anyInt(),
                 eq(testPkgName), eq(testAttributionTag));
         reset(mService);
 
         manager.registerSystemDefaultNetworkCallback(callback, handler);
         verify(mService).requestNetwork(eq(null),
-                eq(TRACK_SYSTEM_DEFAULT.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE),
+                eq(TRACK_SYSTEM_DEFAULT.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), anyInt(),
                 eq(testPkgName), eq(testAttributionTag));
         reset(mService);
     }
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 9db5854..fadd1ea 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -1450,6 +1450,8 @@
         applicationInfo.targetSdkVersion = Build.VERSION_CODES.Q;
         when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), any()))
                 .thenReturn(applicationInfo);
+        when(mPackageManager.getTargetSdkVersion(anyString()))
+                .thenReturn(applicationInfo.targetSdkVersion);
         when(mSystemConfigManager.getSystemPermissionUids(anyString())).thenReturn(new int[0]);
 
         // InstrumentationTestRunner prepares a looper, but AndroidJUnitRunner does not.
@@ -3756,8 +3758,8 @@
             networkCapabilities.addTransportType(TRANSPORT_WIFI)
                     .setNetworkSpecifier(new MatchAllNetworkSpecifier());
             mService.requestNetwork(networkCapabilities, NetworkRequest.Type.REQUEST.ordinal(),
-                    null, 0, null, ConnectivityManager.TYPE_WIFI, mContext.getPackageName(),
-                    getAttributionTag());
+                    null, 0, null, ConnectivityManager.TYPE_WIFI, NetworkCallback.FLAG_NONE,
+                    mContext.getPackageName(), getAttributionTag());
         });
 
         class NonParcelableSpecifier extends NetworkSpecifier {
@@ -8763,6 +8765,7 @@
         applicationInfo.targetSdkVersion = targetSdk;
         when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), any()))
                 .thenReturn(applicationInfo);
+        when(mPackageManager.getTargetSdkVersion(any())).thenReturn(targetSdk);
 
         when(mLocationManager.isLocationEnabledForUser(any())).thenReturn(locationToggle);
 
@@ -8777,102 +8780,183 @@
         }
     }
 
-    private int getOwnerUidNetCapsForCallerPermission(int ownerUid, int callerUid) {
+    private int getOwnerUidNetCapsPermission(int ownerUid, int callerUid,
+            boolean includeLocationSensitiveInfo) {
         final NetworkCapabilities netCap = new NetworkCapabilities().setOwnerUid(ownerUid);
 
         return mService.createWithLocationInfoSanitizedIfNecessaryWhenParceled(
-                netCap, callerUid, mContext.getPackageName(), getAttributionTag()).getOwnerUid();
+                netCap, includeLocationSensitiveInfo, callerUid,
+                mContext.getPackageName(), getAttributionTag())
+                .getOwnerUid();
     }
 
-    private void verifyWifiInfoCopyNetCapsForCallerPermission(
-            int callerUid, boolean shouldMakeCopyWithLocationSensitiveFieldsParcelable) {
+    private void verifyWifiInfoCopyNetCapsPermission(
+            int callerUid, boolean includeLocationSensitiveInfo,
+            boolean shouldMakeCopyWithLocationSensitiveFieldsParcelable) {
         final WifiInfo wifiInfo = mock(WifiInfo.class);
         when(wifiInfo.hasLocationSensitiveFields()).thenReturn(true);
         final NetworkCapabilities netCap = new NetworkCapabilities().setTransportInfo(wifiInfo);
 
         mService.createWithLocationInfoSanitizedIfNecessaryWhenParceled(
-                netCap, callerUid, mContext.getPackageName(), getAttributionTag());
+                netCap, includeLocationSensitiveInfo, callerUid,
+                mContext.getPackageName(), getAttributionTag());
         verify(wifiInfo).makeCopy(eq(shouldMakeCopyWithLocationSensitiveFieldsParcelable));
     }
 
+    private void verifyOwnerUidAndWifiInfoNetCapsPermission(
+            boolean shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag,
+            boolean shouldInclLocationSensitiveOwnerUidWithIncludeFlag,
+            boolean shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag,
+            boolean shouldInclLocationSensitiveWifiInfoWithIncludeFlag) {
+        final int myUid = Process.myUid();
+
+        final int expectedOwnerUidWithoutIncludeFlag =
+                shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag
+                        ? Process.myUid() : INVALID_UID;
+        assertEquals(expectedOwnerUidWithoutIncludeFlag, getOwnerUidNetCapsPermission(
+                myUid, myUid, false /* includeLocationSensitiveInfo */));
+
+        final int expectedOwnerUidWithIncludeFlag =
+                shouldInclLocationSensitiveOwnerUidWithIncludeFlag ? myUid : INVALID_UID;
+        assertEquals(expectedOwnerUidWithIncludeFlag, getOwnerUidNetCapsPermission(
+                myUid, myUid, true /* includeLocationSensitiveInfo */));
+
+        verifyWifiInfoCopyNetCapsPermission(myUid,
+                false, /* includeLocationSensitiveInfo */
+                shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag);
+
+        verifyWifiInfoCopyNetCapsPermission(myUid,
+                true, /* includeLocationSensitiveInfo */
+                shouldInclLocationSensitiveWifiInfoWithIncludeFlag);
+
+    }
+
     @Test
-    public void testCreateForCallerWithLocationInfoSanitizedWithFineLocationAfterQ()
+    public void testCreateWithLocationInfoSanitizedWithFineLocationAfterQ()
             throws Exception {
         setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
                 Manifest.permission.ACCESS_FINE_LOCATION);
 
-        final int myUid = Process.myUid();
-        assertEquals(myUid, getOwnerUidNetCapsForCallerPermission(myUid, myUid));
-
-        verifyWifiInfoCopyNetCapsForCallerPermission(myUid,
-                true /* shouldMakeCopyWithLocationSensitiveFieldsParcelable */);
+        verifyOwnerUidAndWifiInfoNetCapsPermission(
+                // Ensure that we include owner uid even if the request asks to remove it since the
+                // app has necessary permissions and targetSdk < S.
+                true, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
+                true, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
+                false, /* shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag */
+                // Ensure that we remove location info if the request asks to remove it even if the
+                // app has necessary permissions.
+                true /* shouldInclLocationSensitiveWifiInfoWithIncludeFlag */
+        );
     }
 
     @Test
-    public void testCreateForCallerWithLocationInfoSanitizedWithCoarseLocationPreQ()
+    public void testCreateWithLocationInfoSanitizedWithFineLocationPreSWithAndWithoutCallbackFlag()
+            throws Exception {
+        setupLocationPermissions(Build.VERSION_CODES.R, true, AppOpsManager.OPSTR_FINE_LOCATION,
+                Manifest.permission.ACCESS_FINE_LOCATION);
+
+        verifyOwnerUidAndWifiInfoNetCapsPermission(
+                // Ensure that we include owner uid even if the request asks to remove it since the
+                // app has necessary permissions and targetSdk < S.
+                true, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
+                true, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
+                false, /* shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag */
+                // Ensure that we remove location info if the request asks to remove it even if the
+                // app has necessary permissions.
+                true /* shouldInclLocationSensitiveWifiInfoWithIncludeFlag */
+        );
+    }
+
+    @Test
+    public void
+            testCreateWithLocationInfoSanitizedWithFineLocationAfterSWithAndWithoutCallbackFlag()
+            throws Exception {
+        setupLocationPermissions(Build.VERSION_CODES.S, true, AppOpsManager.OPSTR_FINE_LOCATION,
+                Manifest.permission.ACCESS_FINE_LOCATION);
+
+        verifyOwnerUidAndWifiInfoNetCapsPermission(
+                // Ensure that we owner UID if the request asks us to remove it even if the app
+                // has necessary permissions since targetSdk >= S.
+                false, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
+                true, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
+                false, /* shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag */
+                // Ensure that we remove location info if the request asks to remove it even if the
+                // app has necessary permissions.
+                true /* shouldInclLocationSensitiveWifiInfoWithIncludeFlag */
+        );
+    }
+
+    @Test
+    public void testCreateWithLocationInfoSanitizedWithCoarseLocationPreQ()
             throws Exception {
         setupLocationPermissions(Build.VERSION_CODES.P, true, AppOpsManager.OPSTR_COARSE_LOCATION,
                 Manifest.permission.ACCESS_COARSE_LOCATION);
 
-        final int myUid = Process.myUid();
-        assertEquals(myUid, getOwnerUidNetCapsForCallerPermission(myUid, myUid));
-
-        verifyWifiInfoCopyNetCapsForCallerPermission(myUid,
-                true /* shouldMakeCopyWithLocationSensitiveFieldsParcelable */);
+        verifyOwnerUidAndWifiInfoNetCapsPermission(
+                // Ensure that we owner UID if the request asks us to remove it even if the app
+                // has necessary permissions since targetSdk >= S.
+                true, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
+                true, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
+                false, /* shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag */
+                // Ensure that we remove location info if the request asks to remove it even if the
+                // app has necessary permissions.
+                true /* shouldInclLocationSensitiveWifiInfoWithIncludeFlag */
+        );
     }
 
     @Test
-    public void testCreateForCallerWithLocationInfoSanitizedLocationOff() throws Exception {
+    public void testCreateWithLocationInfoSanitizedLocationOff() throws Exception {
         // Test that even with fine location permission, and UIDs matching, the UID is sanitized.
         setupLocationPermissions(Build.VERSION_CODES.Q, false, AppOpsManager.OPSTR_FINE_LOCATION,
                 Manifest.permission.ACCESS_FINE_LOCATION);
 
-        final int myUid = Process.myUid();
-        assertEquals(Process.INVALID_UID, getOwnerUidNetCapsForCallerPermission(myUid, myUid));
-
-        verifyWifiInfoCopyNetCapsForCallerPermission(myUid,
-                false/* shouldMakeCopyWithLocationSensitiveFieldsParcelable */);
+        verifyOwnerUidAndWifiInfoNetCapsPermission(
+                false, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
+                false, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
+                false, /* shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag */
+                false /* shouldInclLocationSensitiveWifiInfoWithIncludeFlag */
+        );
     }
 
     @Test
-    public void testCreateForCallerWithLocationInfoSanitizedWrongUid() throws Exception {
+    public void testCreateWithLocationInfoSanitizedWrongUid() throws Exception {
         // Test that even with fine location permission, not being the owner leads to sanitization.
         setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
                 Manifest.permission.ACCESS_FINE_LOCATION);
 
         final int myUid = Process.myUid();
-        assertEquals(Process.INVALID_UID, getOwnerUidNetCapsForCallerPermission(myUid + 1, myUid));
-
-        verifyWifiInfoCopyNetCapsForCallerPermission(myUid,
-                true /* shouldMakeCopyWithLocationSensitiveFieldsParcelable */);
+        assertEquals(Process.INVALID_UID,
+                getOwnerUidNetCapsPermission(myUid + 1, myUid,
+                        true /* includeLocationSensitiveInfo */));
     }
 
     @Test
-    public void testCreateForCallerWithLocationInfoSanitizedWithCoarseLocationAfterQ()
+    public void testCreateWithLocationInfoSanitizedWithCoarseLocationAfterQ()
             throws Exception {
         // Test that not having fine location permission leads to sanitization.
         setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_COARSE_LOCATION,
                 Manifest.permission.ACCESS_COARSE_LOCATION);
 
-        // Test that without the location permission, the owner field is sanitized.
-        final int myUid = Process.myUid();
-        assertEquals(Process.INVALID_UID, getOwnerUidNetCapsForCallerPermission(myUid, myUid));
-
-        verifyWifiInfoCopyNetCapsForCallerPermission(myUid,
-                false/* shouldMakeCopyWithLocationSensitiveFieldsParcelable */);
+        verifyOwnerUidAndWifiInfoNetCapsPermission(
+                false, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
+                false, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
+                false, /* shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag */
+                false /* shouldInclLocationSensitiveWifiInfoWithIncludeFlag */
+        );
     }
 
     @Test
-    public void testCreateForCallerWithLocationInfoSanitizedWithoutLocationPermission()
+    public void testCreateWithLocationInfoSanitizedWithoutLocationPermission()
             throws Exception {
+        // Test that not having fine location permission leads to sanitization.
         setupLocationPermissions(Build.VERSION_CODES.Q, true, null /* op */, null /* perm */);
 
-        // Test that without the location permission, the owner field is sanitized.
-        final int myUid = Process.myUid();
-        assertEquals(Process.INVALID_UID, getOwnerUidNetCapsForCallerPermission(myUid, myUid));
-
-        verifyWifiInfoCopyNetCapsForCallerPermission(myUid,
-                false/* shouldMakeCopyWithLocationSensitiveFieldsParcelable */);
+        verifyOwnerUidAndWifiInfoNetCapsPermission(
+                false, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
+                false, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
+                false, /* shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag */
+                false /* shouldInclLocationSensitiveWifiInfoWithIncludeFlag */
+        );
     }
 
     private void setupConnectionOwnerUid(int vpnOwnerUid, @VpnManager.VpnType int vpnType)
@@ -9463,8 +9547,8 @@
             assertThrows("Expect throws for invalid request type " + reqTypeInt,
                     IllegalArgumentException.class,
                     () -> mService.requestNetwork(nc, reqTypeInt, null, 0, null,
-                            ConnectivityManager.TYPE_NONE, mContext.getPackageName(),
-                            getAttributionTag())
+                            ConnectivityManager.TYPE_NONE, NetworkCallback.FLAG_NONE,
+                            mContext.getPackageName(), getAttributionTag())
             );
         }
     }
diff --git a/tests/net/java/com/android/server/IpSecServiceTest.java b/tests/net/java/com/android/server/IpSecServiceTest.java
index f97eabf..6232423 100644
--- a/tests/net/java/com/android/server/IpSecServiceTest.java
+++ b/tests/net/java/com/android/server/IpSecServiceTest.java
@@ -35,6 +35,7 @@
 import static org.mockito.Mockito.when;
 
 import android.content.Context;
+import android.net.ConnectivityManager;
 import android.net.INetd;
 import android.net.IpSecAlgorithm;
 import android.net.IpSecConfig;
@@ -47,6 +48,7 @@
 import android.system.ErrnoException;
 import android.system.Os;
 import android.system.StructStat;
+import android.util.Range;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -647,9 +649,9 @@
 
     @Test
     public void testReserveNetId() {
-        int start = mIpSecService.TUN_INTF_NETID_START;
-        for (int i = 0; i < mIpSecService.TUN_INTF_NETID_RANGE; i++) {
-            assertEquals(start + i, mIpSecService.reserveNetId());
+        final Range<Integer> netIdRange = ConnectivityManager.getIpSecNetIdRange();
+        for (int netId = netIdRange.getLower(); netId <= netIdRange.getUpper(); netId++) {
+            assertEquals(netId, mIpSecService.reserveNetId());
         }
 
         // Check that resource exhaustion triggers an exception
@@ -661,7 +663,7 @@
 
         // Now release one and try again
         int releasedNetId =
-                mIpSecService.TUN_INTF_NETID_START + mIpSecService.TUN_INTF_NETID_RANGE / 2;
+                netIdRange.getLower() + (netIdRange.getUpper() - netIdRange.getLower()) / 2;
         mIpSecService.releaseNetId(releasedNetId);
         assertEquals(releasedNetId, mIpSecService.reserveNetId());
     }
diff --git a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
index e4e24b4..fec5ef3 100644
--- a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
@@ -48,18 +48,22 @@
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.content.BroadcastReceiver;
 import android.content.Context;
+import android.content.Intent;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
-import android.content.pm.PackageManagerInternal;
 import android.net.INetd;
 import android.net.UidRange;
+import android.net.Uri;
 import android.os.Build;
 import android.os.SystemConfigManager;
 import android.os.UserHandle;
@@ -70,12 +74,11 @@
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import com.android.server.LocalServices;
-import com.android.server.pm.PackageList;
-
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.AdditionalAnswers;
+import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.mockito.invocation.InvocationOnMock;
@@ -112,7 +115,6 @@
     @Mock private Context mContext;
     @Mock private PackageManager mPackageManager;
     @Mock private INetd mNetdService;
-    @Mock private PackageManagerInternal mMockPmi;
     @Mock private UserManager mUserManager;
     @Mock private PermissionMonitor.Dependencies mDeps;
     @Mock private SystemConfigManager mSystemConfigManager;
@@ -131,16 +133,14 @@
         when(mContext.getSystemService(Context.SYSTEM_CONFIG_SERVICE))
                 .thenReturn(mSystemConfigManager);
         when(mSystemConfigManager.getSystemPermissionUids(anyString())).thenReturn(new int[0]);
+        final Context asUserCtx = mock(Context.class, AdditionalAnswers.delegatesTo(mContext));
+        doReturn(UserHandle.ALL).when(asUserCtx).getUser();
+        when(mContext.createContextAsUser(eq(UserHandle.ALL), anyInt())).thenReturn(asUserCtx);
 
         mPermissionMonitor = spy(new PermissionMonitor(mContext, mNetdService, mDeps));
 
-        LocalServices.removeServiceForTest(PackageManagerInternal.class);
-        LocalServices.addService(PackageManagerInternal.class, mMockPmi);
-        when(mMockPmi.getPackageList(any())).thenReturn(new PackageList(new ArrayList<String>(),
-                  /* observer */ null));
         when(mPackageManager.getInstalledPackages(anyInt())).thenReturn(/* empty app list */ null);
         mPermissionMonitor.startMonitoring();
-        verify(mMockPmi).getPackageList(mPermissionMonitor);
     }
 
     private boolean hasRestrictedNetworkPermission(String partition, int targetSdkVersion, int uid,
@@ -770,4 +770,32 @@
                 INetd.PERMISSION_INTERNET | INetd.PERMISSION_UPDATE_DEVICE_STATS,
                 new int[]{ MOCK_UID2 });
     }
+
+    @Test
+    public void testIntentReceiver() throws Exception {
+        final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
+        final ArgumentCaptor<BroadcastReceiver> receiverCaptor =
+                ArgumentCaptor.forClass(BroadcastReceiver.class);
+        verify(mContext, times(1)).registerReceiver(receiverCaptor.capture(), any(), any(), any());
+        final BroadcastReceiver receiver = receiverCaptor.getValue();
+
+        // Verify receiving PACKAGE_ADDED intent.
+        final Intent addedIntent = new Intent(Intent.ACTION_PACKAGE_ADDED,
+                Uri.fromParts("package", MOCK_PACKAGE1, null /* fragment */));
+        addedIntent.putExtra(Intent.EXTRA_UID, MOCK_UID1);
+        setPackagePermissions(MOCK_PACKAGE1, MOCK_UID1,
+                new String[] { INTERNET, UPDATE_DEVICE_STATS });
+        receiver.onReceive(mContext, addedIntent);
+        mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
+                | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[] { MOCK_UID1 });
+
+        // Verify receiving PACKAGE_REMOVED intent.
+        when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(null);
+        final Intent removedIntent = new Intent(Intent.ACTION_PACKAGE_REMOVED,
+                Uri.fromParts("package", MOCK_PACKAGE1, null /* fragment */));
+        removedIntent.putExtra(Intent.EXTRA_UID, MOCK_UID1);
+        receiver.onReceive(mContext, removedIntent);
+        mNetdServiceMonitor.expectPermission(INetd.PERMISSION_UNINSTALLED, new int[] { MOCK_UID1 });
+    }
+
 }
diff --git a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
index 11498de..a0200275 100644
--- a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
+++ b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
@@ -593,6 +593,16 @@
         mVcnMgmtSvc.removeVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
     }
 
+    @Test(expected = SecurityException.class)
+    public void testRemoveVcnUnderlyingNetworkPolicyListenerInvalidPermission() {
+        doThrow(new SecurityException())
+                .when(mMockContext)
+                .enforceCallingOrSelfPermission(
+                        eq(android.Manifest.permission.NETWORK_FACTORY), any());
+
+        mVcnMgmtSvc.removeVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
+    }
+
     @Test
     public void testRemoveVcnUnderlyingNetworkPolicyListenerNeverRegistered() {
         mVcnMgmtSvc.removeVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);