Merge "Refactor A11yInteractionClient so every service has its own cache"
diff --git a/Android.bp b/Android.bp
index 241c418..731b9f6 100644
--- a/Android.bp
+++ b/Android.bp
@@ -82,6 +82,7 @@
         ":framework-mca-filterpacks-sources",
         ":framework-media-sources",
         ":framework-mms-sources",
+        ":framework-omapi-sources",
         ":framework-opengl-sources",
         ":framework-rs-sources",
         ":framework-sax-sources",
@@ -154,6 +155,7 @@
         "framework-scheduling.stubs.module_lib",
         "framework-sdkextensions.stubs.module_lib",
         "framework-statsd.stubs.module_lib",
+        "framework-supplementalprocess.stubs.module_lib",
         "framework-tethering.stubs.module_lib",
         "framework-uwb.stubs.module_lib",
         "framework-wifi.stubs.module_lib",
@@ -177,6 +179,7 @@
         "framework-scheduling.impl",
         "framework-sdkextensions.impl",
         "framework-statsd.impl",
+        "framework-supplementalprocess.impl",
         "framework-tethering.impl",
         "framework-uwb.impl",
         "framework-wifi.impl",
@@ -271,6 +274,7 @@
         "android.hardware.vibrator-V1.2-java",
         "android.hardware.vibrator-V1.3-java",
         "android.hardware.vibrator-V2-java",
+        "android.se.omapi-V1-java",
         "android.system.suspend.control.internal-java",
         "devicepolicyprotosnano",
 
@@ -331,6 +335,7 @@
         "TeleService-platform-compat-config",
         "documents-ui-compat-config",
         "calendar-provider-compat-config",
+        "contacts-provider-platform-compat-config",
     ],
     libs: [
         "app-compat-annotations",
diff --git a/ApiDocs.bp b/ApiDocs.bp
index 31f7f6e..7a4ef2a 100644
--- a/ApiDocs.bp
+++ b/ApiDocs.bp
@@ -126,6 +126,7 @@
         ":framework-scheduling-sources",
         ":framework-sdkextensions-sources",
         ":framework-statsd-sources",
+        ":framework-supplementalprocess-sources",
         ":framework-tethering-srcs",
         ":framework-uwb-updatable-sources",
         ":framework-wifi-updatable-sources",
@@ -172,6 +173,7 @@
         ":framework-scheduling{.public.stubs.source}",
         ":framework-sdkextensions{.public.stubs.source}",
         ":framework-statsd{.public.stubs.source}",
+        ":framework-supplementalprocess{.public.stubs.source}",
         ":framework-tethering{.public.stubs.source}",
         ":framework-uwb{.public.stubs.source}",
         ":framework-wifi{.public.stubs.source}",
@@ -211,6 +213,7 @@
         ":framework-scheduling{.public.annotations.zip}",
         ":framework-sdkextensions{.public.annotations.zip}",
         ":framework-statsd{.public.annotations.zip}",
+        ":framework-supplementalprocess{.public.annotations.zip}",
         ":framework-tethering{.public.annotations.zip}",
         ":framework-uwb{.public.annotations.zip}",
         ":framework-wifi{.public.annotations.zip}",
diff --git a/GAME_MANAGER_OWNERS b/GAME_MANAGER_OWNERS
new file mode 100644
index 0000000..502a9e36
--- /dev/null
+++ b/GAME_MANAGER_OWNERS
@@ -0,0 +1,2 @@
+lpy@google.com
+timvp@google.com
diff --git a/StubLibraries.bp b/StubLibraries.bp
index 3f94c89..3b11036 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -250,6 +250,7 @@
     "framework-scheduling.stubs",
     "framework-sdkextensions.stubs",
     "framework-statsd.stubs",
+    "framework-supplementalprocess.stubs",
     "framework-tethering.stubs",
     "framework-uwb.stubs",
     "framework-wifi.stubs",
@@ -271,6 +272,7 @@
     "framework-scheduling.stubs.system",
     "framework-sdkextensions.stubs.system",
     "framework-statsd.stubs.system",
+    "framework-supplementalprocess.stubs",
     "framework-tethering.stubs.system",
     "framework-uwb.stubs.system",
     "framework-wifi.stubs.system",
diff --git a/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java b/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java
index 8a6c60f..1cd5d96 100644
--- a/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java
+++ b/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java
@@ -138,6 +138,21 @@
     }
 
     @Test
+    public void testCreate_RandomText_NoStyled_Balanced_Hyphenation_Fast() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        while (state.keepRunning()) {
+            state.pauseTiming();
+            final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT);
+            state.resumeTiming();
+
+            StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH)
+                    .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL_FAST)
+                    .setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED)
+                    .build();
+        }
+    }
+
+    @Test
     public void testCreate_RandomText_Styled_Greedy_NoHyphenation() {
         final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
index b02e801..c147ef8 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
@@ -2012,9 +2012,8 @@
             if (DEBUG) {
                 Slog.v(TAG, "Starting to track " + jobStatus.toShortString());
             }
-            // Always track jobs, even when charging.
-            mRunningBgJobs.add(jobStatus);
-            if (shouldTrackLocked()) {
+            // Always maintain list of running jobs, even when quota is free.
+            if (mRunningBgJobs.add(jobStatus) && shouldTrackLocked()) {
                 mBgJobCount++;
                 if (mRegularJobTimer) {
                     incrementJobCountLocked(mPkg.userId, mPkg.packageName, 1);
diff --git a/api/Android.bp b/api/Android.bp
index 1bc50bd..1ec1b3c 100644
--- a/api/Android.bp
+++ b/api/Android.bp
@@ -106,6 +106,7 @@
         ":framework-scheduling{.public.api.txt}",
         ":framework-sdkextensions{.public.api.txt}",
         ":framework-statsd{.public.api.txt}",
+        ":framework-supplementalprocess{.public.api.txt}",
         ":framework-tethering{.public.api.txt}",
         ":framework-uwb{.public.api.txt}",
         ":framework-wifi{.public.api.txt}",
@@ -167,6 +168,7 @@
         ":framework-scheduling{.public.stubs.source}",
         ":framework-sdkextensions{.public.stubs.source}",
         ":framework-statsd{.public.stubs.source}",
+        ":framework-supplementalprocess{.public.stubs.source}",
         ":framework-tethering{.public.stubs.source}",
         ":framework-uwb{.public.stubs.source}",
         ":framework-wifi{.public.stubs.source}",
@@ -195,6 +197,7 @@
         ":framework-scheduling{.public.removed-api.txt}",
         ":framework-sdkextensions{.public.removed-api.txt}",
         ":framework-statsd{.public.removed-api.txt}",
+        ":framework-supplementalprocess{.public.removed-api.txt}",
         ":framework-tethering{.public.removed-api.txt}",
         ":framework-uwb{.public.removed-api.txt}",
         ":framework-wifi{.public.removed-api.txt}",
@@ -237,6 +240,7 @@
         ":framework-scheduling{.system.api.txt}",
         ":framework-sdkextensions{.system.api.txt}",
         ":framework-statsd{.system.api.txt}",
+        ":framework-supplementalprocess{.system.api.txt}",
         ":framework-tethering{.system.api.txt}",
         ":framework-uwb{.system.api.txt}",
         ":framework-wifi{.system.api.txt}",
@@ -297,6 +301,7 @@
         ":framework-scheduling{.system.removed-api.txt}",
         ":framework-sdkextensions{.system.removed-api.txt}",
         ":framework-statsd{.system.removed-api.txt}",
+        ":framework-supplementalprocess{.system.removed-api.txt}",
         ":framework-tethering{.system.removed-api.txt}",
         ":framework-uwb{.system.removed-api.txt}",
         ":framework-wifi{.system.removed-api.txt}",
@@ -339,6 +344,7 @@
         ":framework-scheduling{.module-lib.api.txt}",
         ":framework-sdkextensions{.module-lib.api.txt}",
         ":framework-statsd{.module-lib.api.txt}",
+        ":framework-supplementalprocess{.module-lib.api.txt}",
         ":framework-tethering{.module-lib.api.txt}",
         ":framework-uwb{.module-lib.api.txt}",
         ":framework-wifi{.module-lib.api.txt}",
@@ -401,6 +407,7 @@
         ":framework-scheduling{.module-lib.removed-api.txt}",
         ":framework-sdkextensions{.module-lib.removed-api.txt}",
         ":framework-statsd{.module-lib.removed-api.txt}",
+        ":framework-supplementalprocess{.module-lib.removed-api.txt}",
         ":framework-tethering{.module-lib.removed-api.txt}",
         ":framework-uwb{.module-lib.removed-api.txt}",
         ":framework-wifi{.module-lib.removed-api.txt}",
@@ -521,6 +528,7 @@
         ":framework-scheduling.stubs{.jar}",
         ":framework-sdkextensions.stubs{.jar}",
         ":framework-statsd.stubs{.jar}",
+        ":framework-supplementalprocess.stubs{.jar}",
         ":framework-tethering.stubs{.jar}",
         ":framework-uwb.stubs{.jar}",
         ":framework-wifi.stubs{.jar}",
diff --git a/boot/Android.bp b/boot/Android.bp
index d88e839..3273f2c 100644
--- a/boot/Android.bp
+++ b/boot/Android.bp
@@ -96,6 +96,10 @@
             module: "com.android.sdkext-bootclasspath-fragment",
         },
         {
+            apex: "com.android.supplementalprocess",
+            module: "com.android.supplementalprocess-bootclasspath-fragment",
+        },
+        {
             apex: "com.android.tethering",
             module: "com.android.tethering-bootclasspath-fragment",
         },
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index 59f602c..af4053f 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -1576,7 +1576,7 @@
                     int err;
                     do {
                         err = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &spec, nullptr);
-                    } while (err<0 && errno == EINTR);
+                    } while (err == EINTR);
                 }
 
                 checkExit();
diff --git a/core/api/current.txt b/core/api/current.txt
index f699bbe..32865ad 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -1204,6 +1204,7 @@
     field public static final int requiredSplitTypes;
     field public static final int requiresFadingEdge = 16843685; // 0x10103a5
     field public static final int requiresSmallestWidthDp = 16843620; // 0x1010364
+    field public static final int resetEnabledSettingsOnAppDataCleared;
     field public static final int resizeClip = 16843983; // 0x10104cf
     field public static final int resizeMode = 16843619; // 0x1010363
     field public static final int resizeable = 16843405; // 0x101028d
@@ -3254,19 +3255,41 @@
     method public boolean willContinue();
   }
 
+  public final class MagnificationConfig implements android.os.Parcelable {
+    method public int describeContents();
+    method public float getCenterX();
+    method public float getCenterY();
+    method public int getMode();
+    method public float getScale();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.accessibilityservice.MagnificationConfig> CREATOR;
+    field public static final int DEFAULT_MODE = 0; // 0x0
+    field public static final int FULLSCREEN_MODE = 1; // 0x1
+    field public static final int WINDOW_MODE = 2; // 0x2
+  }
+
+  public static final class MagnificationConfig.Builder {
+    ctor public MagnificationConfig.Builder();
+    method @NonNull public android.accessibilityservice.MagnificationConfig build();
+    method @NonNull public android.accessibilityservice.MagnificationConfig.Builder setCenterX(float);
+    method @NonNull public android.accessibilityservice.MagnificationConfig.Builder setCenterY(float);
+    method @NonNull public android.accessibilityservice.MagnificationConfig.Builder setMode(int);
+    method @NonNull public android.accessibilityservice.MagnificationConfig.Builder setScale(float);
+  }
+
   public final class TouchInteractionController {
-    method public void addListener(@Nullable java.util.concurrent.Executor, @NonNull android.accessibilityservice.TouchInteractionController.Listener);
     method public int getDisplayId();
     method public int getMaxPointerCount();
     method public int getState();
     method public void performClick();
     method public void performLongClickAndStartDrag();
-    method public void removeAllListeners();
-    method public boolean removeListener(@NonNull android.accessibilityservice.TouchInteractionController.Listener);
+    method public void registerCallback(@Nullable java.util.concurrent.Executor, @NonNull android.accessibilityservice.TouchInteractionController.Callback);
     method public void requestDelegating();
     method public void requestDragging(int);
     method public void requestTouchExploration();
     method @NonNull public static String stateToString(int);
+    method public void unregisterAllCallbacks();
+    method public boolean unregisterCallback(@NonNull android.accessibilityservice.TouchInteractionController.Callback);
     field public static final int STATE_CLEAR = 0; // 0x0
     field public static final int STATE_DELEGATING = 4; // 0x4
     field public static final int STATE_DRAGGING = 3; // 0x3
@@ -3274,7 +3297,7 @@
     field public static final int STATE_TOUCH_INTERACTING = 1; // 0x1
   }
 
-  public static interface TouchInteractionController.Listener {
+  public static interface TouchInteractionController.Callback {
     method public void onMotionEvent(@NonNull android.view.MotionEvent);
     method public void onStateChanged(int);
   }
@@ -9625,6 +9648,7 @@
     method public java.util.Map<android.os.ParcelUuid,byte[]> getServiceData();
     method @NonNull public java.util.List<android.os.ParcelUuid> getServiceSolicitationUuids();
     method public java.util.List<android.os.ParcelUuid> getServiceUuids();
+    method @NonNull public java.util.List<android.bluetooth.le.TransportDiscoveryData> getTransportDiscoveryData();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.le.AdvertiseData> CREATOR;
   }
@@ -9635,6 +9659,7 @@
     method public android.bluetooth.le.AdvertiseData.Builder addServiceData(android.os.ParcelUuid, byte[]);
     method @NonNull public android.bluetooth.le.AdvertiseData.Builder addServiceSolicitationUuid(@NonNull android.os.ParcelUuid);
     method public android.bluetooth.le.AdvertiseData.Builder addServiceUuid(android.os.ParcelUuid);
+    method @NonNull public android.bluetooth.le.AdvertiseData.Builder addTransportDiscoveryData(@NonNull android.bluetooth.le.TransportDiscoveryData);
     method public android.bluetooth.le.AdvertiseData build();
     method public android.bluetooth.le.AdvertiseData.Builder setIncludeDeviceName(boolean);
     method public android.bluetooth.le.AdvertiseData.Builder setIncludeTxPowerLevel(boolean);
@@ -9894,6 +9919,31 @@
     method public android.bluetooth.le.ScanSettings.Builder setScanMode(int);
   }
 
+  public final class TransportBlock implements android.os.Parcelable {
+    ctor public TransportBlock(int, int, int, @Nullable byte[]);
+    method public int describeContents();
+    method public int getOrgId();
+    method public int getTdsFlags();
+    method @Nullable public byte[] getTransportData();
+    method public int getTransportDataLength();
+    method @Nullable public byte[] toByteArray();
+    method public int totalBytes();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.le.TransportBlock> CREATOR;
+  }
+
+  public final class TransportDiscoveryData implements android.os.Parcelable {
+    ctor public TransportDiscoveryData(int, @NonNull java.util.List<android.bluetooth.le.TransportBlock>);
+    ctor public TransportDiscoveryData(@NonNull byte[]);
+    method public int describeContents();
+    method @NonNull public java.util.List<android.bluetooth.le.TransportBlock> getTransportBlocks();
+    method public int getTransportDataType();
+    method @Nullable public byte[] toByteArray();
+    method public int totalBytes();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.le.TransportDiscoveryData> CREATOR;
+  }
+
 }
 
 package android.companion {
@@ -10794,6 +10844,7 @@
     field public static final String STATUS_BAR_SERVICE = "statusbar";
     field public static final String STORAGE_SERVICE = "storage";
     field public static final String STORAGE_STATS_SERVICE = "storagestats";
+    field public static final String SUPPLEMENTAL_PROCESS_SERVICE = "supplemental_process";
     field public static final String SYSTEM_HEALTH_SERVICE = "systemhealth";
     field public static final String TELECOM_SERVICE = "telecom";
     field public static final String TELEPHONY_IMS_SERVICE = "telephony_ims";
@@ -17272,8 +17323,12 @@
     method @NonNull public android.graphics.text.MeasuredText.Builder appendReplacementRun(@NonNull android.graphics.Paint, @IntRange(from=0) int, @FloatRange(from=0) @Px float);
     method @NonNull public android.graphics.text.MeasuredText.Builder appendStyleRun(@NonNull android.graphics.Paint, @IntRange(from=0) int, boolean);
     method @NonNull public android.graphics.text.MeasuredText build();
-    method @NonNull public android.graphics.text.MeasuredText.Builder setComputeHyphenation(boolean);
+    method @Deprecated @NonNull public android.graphics.text.MeasuredText.Builder setComputeHyphenation(boolean);
+    method @NonNull public android.graphics.text.MeasuredText.Builder setComputeHyphenation(int);
     method @NonNull public android.graphics.text.MeasuredText.Builder setComputeLayout(boolean);
+    field public static final int HYPHENATION_MODE_FAST = 2; // 0x2
+    field public static final int HYPHENATION_MODE_NONE = 0; // 0x0
+    field public static final int HYPHENATION_MODE_NORMAL = 1; // 0x1
   }
 
   public final class PositionedGlyphs {
@@ -27605,6 +27660,7 @@
     field public static final String CATEGORY_PAYMENT = "payment";
     field public static final String EXTRA_CATEGORY = "category";
     field public static final String EXTRA_SERVICE_COMPONENT = "component";
+    field public static final String EXTRA_USERID = "android.nfc.cardemulation.extra.USERID";
     field public static final int SELECTION_MODE_ALWAYS_ASK = 1; // 0x1
     field public static final int SELECTION_MODE_ASK_IF_CONFLICT = 2; // 0x2
     field public static final int SELECTION_MODE_PREFER_DEFAULT = 0; // 0x0
@@ -32341,6 +32397,7 @@
   }
 
   public final class VibrationAttributes implements android.os.Parcelable {
+    method @NonNull public static android.os.VibrationAttributes createForUsage(int);
     method public int describeContents();
     method public int getFlags();
     method public int getUsage();
@@ -32366,6 +32423,7 @@
   public static final class VibrationAttributes.Builder {
     ctor public VibrationAttributes.Builder();
     ctor public VibrationAttributes.Builder(@Nullable android.os.VibrationAttributes);
+    ctor public VibrationAttributes.Builder(@NonNull android.media.AudioAttributes);
     method @NonNull public android.os.VibrationAttributes build();
     method @NonNull public android.os.VibrationAttributes.Builder setFlags(int, int);
     method @NonNull public android.os.VibrationAttributes.Builder setUsage(int);
@@ -32416,7 +32474,8 @@
     method @Deprecated @RequiresPermission(android.Manifest.permission.VIBRATE) public void vibrate(long[], int);
     method @Deprecated @RequiresPermission(android.Manifest.permission.VIBRATE) public void vibrate(long[], int, android.media.AudioAttributes);
     method @RequiresPermission(android.Manifest.permission.VIBRATE) public void vibrate(android.os.VibrationEffect);
-    method @RequiresPermission(android.Manifest.permission.VIBRATE) public void vibrate(android.os.VibrationEffect, android.media.AudioAttributes);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.VIBRATE) public void vibrate(android.os.VibrationEffect, android.media.AudioAttributes);
+    method @RequiresPermission(android.Manifest.permission.VIBRATE) public void vibrate(@NonNull android.os.VibrationEffect, @NonNull android.os.VibrationAttributes);
     field public static final int VIBRATION_EFFECT_SUPPORT_NO = 2; // 0x2
     field public static final int VIBRATION_EFFECT_SUPPORT_UNKNOWN = 0; // 0x0
     field public static final int VIBRATION_EFFECT_SUPPORT_YES = 1; // 0x1
@@ -40641,7 +40700,7 @@
     method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public java.util.List<android.telecom.PhoneAccountHandle> getCallCapablePhoneAccounts();
     method public String getDefaultDialerPackage();
     method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public android.telecom.PhoneAccountHandle getDefaultOutgoingPhoneAccount(String);
-    method @RequiresPermission(anyOf={android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.READ_SMS, android.Manifest.permission.READ_PHONE_NUMBERS}, conditional=true) public String getLine1Number(android.telecom.PhoneAccountHandle);
+    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.READ_SMS, android.Manifest.permission.READ_PHONE_NUMBERS}, conditional=true) public String getLine1Number(android.telecom.PhoneAccountHandle);
     method public android.telecom.PhoneAccount getPhoneAccount(android.telecom.PhoneAccountHandle);
     method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public java.util.List<android.telecom.PhoneAccountHandle> getSelfManagedPhoneAccounts();
     method public android.telecom.PhoneAccountHandle getSimCallManager();
@@ -42709,7 +42768,7 @@
     method @Nullable public String getMccString();
     method @Deprecated public int getMnc();
     method @Nullable public String getMncString();
-    method public String getNumber();
+    method @Deprecated public String getNumber();
     method public int getPortIndex();
     method public int getSimSlotIndex();
     method public int getSubscriptionId();
@@ -42964,7 +43023,7 @@
     method public String getIccAuthentication(int, int, String);
     method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getImei();
     method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getImei(int);
-    method @RequiresPermission(anyOf={android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.READ_SMS, android.Manifest.permission.READ_PHONE_NUMBERS}) public String getLine1Number();
+    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.READ_SMS, android.Manifest.permission.READ_PHONE_NUMBERS}) public String getLine1Number();
     method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public String getManualNetworkSelectionPlmn();
     method @Nullable public String getManufacturerCode();
     method @Nullable public String getManufacturerCode(int);
@@ -43049,7 +43108,7 @@
     method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataEnabled(boolean);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataEnabledForReason(int, boolean);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setForbiddenPlmns(@NonNull java.util.List<java.lang.String>);
-    method public boolean setLine1NumberForDisplay(String, String);
+    method @Deprecated public boolean setLine1NumberForDisplay(String, String);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setNetworkSelectionModeAutomatic();
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setNetworkSelectionModeManual(String, boolean);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setNetworkSelectionModeManual(@NonNull String, boolean, int);
@@ -43584,7 +43643,8 @@
     method public boolean isEnabled();
     method public boolean isSimPortAvailable(int);
     method public void startResolutionActivity(android.app.Activity, int, android.content.Intent, android.app.PendingIntent) throws android.content.IntentSender.SendIntentException;
-    method @RequiresPermission("android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS") public void switchToSubscription(int, android.app.PendingIntent);
+    method @Deprecated @RequiresPermission("android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS") public void switchToSubscription(int, android.app.PendingIntent);
+    method @RequiresPermission("android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS") public void switchToSubscription(int, int, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.euicc.EuiccManager.ResultListener);
     method @RequiresPermission("android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS") public void updateSubscriptionNickname(int, @Nullable String, @NonNull android.app.PendingIntent);
     field public static final String ACTION_MANAGE_EMBEDDED_SUBSCRIPTIONS = "android.telephony.euicc.action.MANAGE_EMBEDDED_SUBSCRIPTIONS";
     field public static final String ACTION_NOTIFY_CARRIER_SETUP_INCOMPLETE = "android.telephony.euicc.action.NOTIFY_CARRIER_SETUP_INCOMPLETE";
@@ -43630,6 +43690,10 @@
     field public static final int OPERATION_SYSTEM = 1; // 0x1
   }
 
+  public static interface EuiccManager.ResultListener {
+    method public void onComplete(int, @Nullable android.content.Intent);
+  }
+
 }
 
 package android.telephony.gsm {
@@ -44514,8 +44578,10 @@
     field public static final int DIR_LEFT_TO_RIGHT = 1; // 0x1
     field public static final int DIR_RIGHT_TO_LEFT = -1; // 0xffffffff
     field public static final int HYPHENATION_FREQUENCY_FULL = 2; // 0x2
+    field public static final int HYPHENATION_FREQUENCY_FULL_FAST = 4; // 0x4
     field public static final int HYPHENATION_FREQUENCY_NONE = 0; // 0x0
     field public static final int HYPHENATION_FREQUENCY_NORMAL = 1; // 0x1
+    field public static final int HYPHENATION_FREQUENCY_NORMAL_FAST = 3; // 0x3
     field public static final int JUSTIFICATION_MODE_INTER_WORD = 1; // 0x1
     field public static final int JUSTIFICATION_MODE_NONE = 0; // 0x0
   }
@@ -51379,14 +51445,18 @@
   public static final class AccessibilityNodeInfo.CollectionItemInfo {
     ctor public AccessibilityNodeInfo.CollectionItemInfo(int, int, int, int, boolean);
     ctor public AccessibilityNodeInfo.CollectionItemInfo(int, int, int, int, boolean, boolean);
+    ctor public AccessibilityNodeInfo.CollectionItemInfo(@Nullable String, int, int, @Nullable String, int, int, boolean, boolean);
     method public int getColumnIndex();
     method public int getColumnSpan();
+    method @Nullable public String getColumnTitle();
     method public int getRowIndex();
     method public int getRowSpan();
+    method @Nullable public String getRowTitle();
     method @Deprecated public boolean isHeading();
     method public boolean isSelected();
     method public static android.view.accessibility.AccessibilityNodeInfo.CollectionItemInfo obtain(int, int, int, int, boolean);
     method public static android.view.accessibility.AccessibilityNodeInfo.CollectionItemInfo obtain(int, int, int, int, boolean, boolean);
+    method @NonNull public static android.view.accessibility.AccessibilityNodeInfo.CollectionItemInfo obtain(@Nullable String, int, int, @Nullable String, int, int, boolean, boolean);
   }
 
   public static final class AccessibilityNodeInfo.ExtraRenderingInfo {
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
old mode 100755
new mode 100644
index 4d6c1c8..fb325a2
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -32,6 +32,7 @@
     field public static final String AMBIENT_WALLPAPER = "android.permission.AMBIENT_WALLPAPER";
     field public static final String APPROVE_INCIDENT_REPORTS = "android.permission.APPROVE_INCIDENT_REPORTS";
     field public static final String ASSOCIATE_COMPANION_DEVICES = "android.permission.ASSOCIATE_COMPANION_DEVICES";
+    field public static final String AUTOMOTIVE_GNSS_CONTROLS = "android.permission.AUTOMOTIVE_GNSS_CONTROLS";
     field public static final String BACKGROUND_CAMERA = "android.permission.BACKGROUND_CAMERA";
     field public static final String BACKUP = "android.permission.BACKUP";
     field public static final String BATTERY_PREDICTION = "android.permission.BATTERY_PREDICTION";
@@ -960,20 +961,20 @@
     method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public boolean getBluetoothContactSharingDisabled(@NonNull android.os.UserHandle);
     method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public String getDeviceOwner();
     method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS}) public android.content.ComponentName getDeviceOwnerComponentOnAnyUser();
-    method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public String getDeviceOwnerNameOnAnyUser();
+    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS}) public String getDeviceOwnerNameOnAnyUser();
     method @Nullable public CharSequence getDeviceOwnerOrganizationName();
     method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public android.os.UserHandle getDeviceOwnerUser();
     method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public java.util.List<java.lang.String> getPermittedAccessibilityServices(int);
     method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public java.util.List<java.lang.String> getPermittedInputMethodsForCurrentUser();
     method @Nullable public android.content.ComponentName getProfileOwner() throws java.lang.IllegalArgumentException;
-    method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public String getProfileOwnerNameAsUser(int) throws java.lang.IllegalArgumentException;
-    method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public int getUserProvisioningState();
+    method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS}) public String getProfileOwnerNameAsUser(int) throws java.lang.IllegalArgumentException;
+    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS}) public int getUserProvisioningState();
     method public boolean isDeviceManaged();
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isDeviceProvisioned();
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isDeviceProvisioningConfigApplied();
-    method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isManagedKiosk();
+    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS}) public boolean isManagedKiosk();
     method public boolean isSecondaryLockscreenEnabled(@NonNull android.os.UserHandle);
-    method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isUnattendedManagedKiosk();
+    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS}) public boolean isUnattendedManagedKiosk();
     method @RequiresPermission("android.permission.NOTIFY_PENDING_SYSTEM_UPDATE") public void notifyPendingSystemUpdate(long);
     method @RequiresPermission("android.permission.NOTIFY_PENDING_SYSTEM_UPDATE") public void notifyPendingSystemUpdate(long, boolean);
     method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public boolean packageHasActiveAdmins(String);
@@ -5106,6 +5107,7 @@
     method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public android.location.Location getLastKnownLocation(@NonNull String, @NonNull android.location.LastLocationRequest);
     method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public void injectGnssMeasurementCorrections(@NonNull android.location.GnssMeasurementCorrections);
     method public boolean isAdasGnssLocationEnabled();
+    method @RequiresPermission(android.Manifest.permission.AUTOMOTIVE_GNSS_CONTROLS) public boolean isAutoGnssSuspended();
     method public boolean isExtraLocationControllerPackageEnabled();
     method public boolean isLocationEnabledForUser(@NonNull android.os.UserHandle);
     method public boolean isProviderEnabledForUser(@NonNull String, @NonNull android.os.UserHandle);
@@ -5118,6 +5120,7 @@
     method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener);
     method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.app.PendingIntent);
     method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void setAdasGnssLocationEnabled(boolean);
+    method @RequiresPermission(android.Manifest.permission.AUTOMOTIVE_GNSS_CONTROLS) public void setAutoGnssSuspended(boolean);
     method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void setExtraLocationControllerPackage(@Nullable String);
     method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void setExtraLocationControllerPackageEnabled(boolean);
     method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void setLocationEnabledForUser(boolean, @NonNull android.os.UserHandle);
@@ -6362,14 +6365,14 @@
   }
 
   public class Filter implements java.lang.AutoCloseable {
+    method @Nullable public String acquireSharedFilterToken();
     method public void close();
     method public int configure(@NonNull android.media.tv.tuner.filter.FilterConfiguration);
-    method @Nullable public String createSharedFilter();
     method public int flush();
+    method public void freeSharedFilterToken(@NonNull String);
     method @Deprecated public int getId();
     method public long getIdLong();
     method public int read(@NonNull byte[], long, long);
-    method public void releaseSharedFilter(@NonNull String);
     method public int setDataSource(@Nullable android.media.tv.tuner.filter.Filter);
     method public int setMonitorEventMask(int);
     method public int start();
@@ -8677,6 +8680,36 @@
     method public boolean hasSingleFileDescriptor();
   }
 
+  public final class NewUserRequest {
+    method @Nullable public String getAccountName();
+    method @Nullable public android.os.PersistableBundle getAccountOptions();
+    method @Nullable public String getAccountType();
+    method @Nullable public String getName();
+    method @Nullable public android.graphics.Bitmap getUserIcon();
+    method @NonNull public String getUserType();
+    method public boolean isAdmin();
+    method public boolean isEphemeral();
+  }
+
+  public static final class NewUserRequest.Builder {
+    ctor public NewUserRequest.Builder();
+    method @NonNull public android.os.NewUserRequest build();
+    method @NonNull public android.os.NewUserRequest.Builder setAccountName(@Nullable String);
+    method @NonNull public android.os.NewUserRequest.Builder setAccountOptions(@Nullable android.os.PersistableBundle);
+    method @NonNull public android.os.NewUserRequest.Builder setAccountType(@Nullable String);
+    method @NonNull public android.os.NewUserRequest.Builder setAdmin();
+    method @NonNull public android.os.NewUserRequest.Builder setEphemeral();
+    method @NonNull public android.os.NewUserRequest.Builder setName(@Nullable String);
+    method @NonNull public android.os.NewUserRequest.Builder setUserIcon(@Nullable android.graphics.Bitmap);
+    method @NonNull public android.os.NewUserRequest.Builder setUserType(@NonNull String);
+  }
+
+  public final class NewUserResponse {
+    method public int getOperationResult();
+    method @Nullable public android.os.UserHandle getUser();
+    method public boolean isSuccessful();
+  }
+
   public interface Parcelable {
     field public static final int PARCELABLE_STABILITY_LOCAL = 0; // 0x0
     field public static final int PARCELABLE_STABILITY_VINTF = 1; // 0x1
@@ -8913,6 +8946,7 @@
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean canHaveRestrictedProfile();
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public void clearSeedAccountData();
     method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public android.os.UserHandle createProfile(@NonNull String, @NonNull String, @NonNull java.util.Set<java.lang.String>) throws android.os.UserManager.UserOperationException;
+    method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public android.os.NewUserResponse createUser(@NonNull android.os.NewUserRequest);
     method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}, conditional=true) public java.util.List<android.os.UserHandle> getAllProfiles();
     method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}, conditional=true) public java.util.List<android.os.UserHandle> getEnabledProfiles();
     method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}) public android.os.UserHandle getProfileParent(@NonNull android.os.UserHandle);
@@ -8944,6 +8978,7 @@
     method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public boolean removeUser(@NonNull android.os.UserHandle);
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public void setUserIcon(@NonNull android.graphics.Bitmap) throws android.os.UserManager.UserOperationException;
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public void setUserName(@Nullable String);
+    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public boolean someUserHasAccount(@NonNull String, @NonNull String);
     field public static final String ACTION_USER_RESTRICTIONS_CHANGED = "android.os.action.USER_RESTRICTIONS_CHANGED";
     field @Deprecated public static final String DISALLOW_OEM_UNLOCK = "no_oem_unlock";
     field public static final String DISALLOW_RUN_IN_BACKGROUND = "no_run_in_background";
@@ -8955,6 +8990,7 @@
     field public static final int SWITCHABILITY_STATUS_SYSTEM_USER_LOCKED = 4; // 0x4
     field public static final int SWITCHABILITY_STATUS_USER_IN_CALL = 1; // 0x1
     field public static final int SWITCHABILITY_STATUS_USER_SWITCH_DISALLOWED = 2; // 0x2
+    field public static final int USER_OPERATION_ERROR_USER_ACCOUNT_ALREADY_EXISTS = 7; // 0x7
     field public static final String USER_TYPE_FULL_GUEST = "android.os.usertype.full.GUEST";
     field public static final String USER_TYPE_FULL_SECONDARY = "android.os.usertype.full.SECONDARY";
     field public static final String USER_TYPE_FULL_SYSTEM = "android.os.usertype.full.SYSTEM";
@@ -10300,7 +10336,8 @@
     method @android.telephony.euicc.EuiccManager.OtaStatus public abstract int onGetOtaStatus(int);
     method public abstract int onRetainSubscriptionsForFactoryReset(int);
     method public abstract void onStartOtaIfNecessary(int, android.service.euicc.EuiccService.OtaStatusChangedCallback);
-    method public abstract int onSwitchToSubscription(int, @Nullable String, boolean);
+    method @Deprecated public abstract int onSwitchToSubscription(int, @Nullable String, boolean);
+    method public int onSwitchToSubscriptionWithPort(int, int, @Nullable String, boolean);
     method public abstract int onUpdateSubscriptionNickname(int, String, String);
     field public static final String ACTION_BIND_CARRIER_PROVISIONING_SERVICE = "android.service.euicc.action.BIND_CARRIER_PROVISIONING_SERVICE";
     field public static final String ACTION_DELETE_SUBSCRIPTION_PRIVILEGED = "android.service.euicc.action.DELETE_SUBSCRIPTION_PRIVILEGED";
@@ -10322,6 +10359,7 @@
     field public static final String EXTRA_RESOLUTION_CONFIRMATION_CODE = "android.service.euicc.extra.RESOLUTION_CONFIRMATION_CODE";
     field public static final String EXTRA_RESOLUTION_CONFIRMATION_CODE_RETRIED = "android.service.euicc.extra.RESOLUTION_CONFIRMATION_CODE_RETRIED";
     field public static final String EXTRA_RESOLUTION_CONSENT = "android.service.euicc.extra.RESOLUTION_CONSENT";
+    field public static final String EXTRA_RESOLUTION_PORT_INDEX = "android.service.euicc.extra.RESOLUTION_PORT_INDEX";
     field public static final String EXTRA_RESOLVABLE_ERRORS = "android.service.euicc.extra.RESOLVABLE_ERRORS";
     field public static final int RESOLVABLE_ERROR_CONFIRMATION_CODE = 1; // 0x1
     field public static final int RESOLVABLE_ERROR_POLICY_RULES = 2; // 0x2
@@ -13136,6 +13174,7 @@
     method @NonNull public java.util.Set<android.telephony.ims.FeatureTagState> getDeregisteredFeatureTags();
     method @NonNull public java.util.Set<android.telephony.ims.FeatureTagState> getDeregisteringFeatureTags();
     method @NonNull public java.util.Set<java.lang.String> getRegisteredFeatureTags();
+    method @NonNull public java.util.Set<java.lang.String> getRegisteringFeatureTags();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.DelegateRegistrationState> CREATOR;
     field public static final int DEREGISTERED_REASON_NOT_PROVISIONED = 1; // 0x1
@@ -13153,6 +13192,7 @@
     method @NonNull public android.telephony.ims.DelegateRegistrationState.Builder addDeregisteringFeatureTag(@NonNull String, int);
     method @NonNull public android.telephony.ims.DelegateRegistrationState.Builder addRegisteredFeatureTag(@NonNull String);
     method @NonNull public android.telephony.ims.DelegateRegistrationState.Builder addRegisteredFeatureTags(@NonNull java.util.Set<java.lang.String>);
+    method @NonNull public android.telephony.ims.DelegateRegistrationState.Builder addRegisteringFeatureTags(@NonNull java.util.Set<java.lang.String>);
     method @NonNull public android.telephony.ims.DelegateRegistrationState build();
   }
 
diff --git a/core/api/system-lint-baseline.txt b/core/api/system-lint-baseline.txt
index b435acf..716f43e 100644
--- a/core/api/system-lint-baseline.txt
+++ b/core/api/system-lint-baseline.txt
@@ -31,6 +31,10 @@
 
 
 
+MissingGetterMatchingBuilder: android.os.NewUserRequest.Builder#setAdmin():
+    android.os.NewUserRequest does not declare a `getAdmin()` method matching method android.os.NewUserRequest.Builder.setAdmin()
+MissingGetterMatchingBuilder: android.os.NewUserRequest.Builder#setEphemeral():
+    android.os.NewUserRequest does not declare a `getEphemeral()` method matching method android.os.NewUserRequest.Builder.setEphemeral()
 MissingGetterMatchingBuilder: android.security.keystore.KeyGenParameterSpec.Builder#setUid(int):
     android.security.keystore.KeyGenParameterSpec does not declare a `getUid()` method matching method android.security.keystore.KeyGenParameterSpec.Builder.setUid(int)
 MissingGetterMatchingBuilder: android.service.autofill.Dataset.Builder#setFieldInlinePresentation(android.view.autofill.AutofillId, android.view.autofill.AutofillValue, java.util.regex.Pattern, android.service.autofill.InlinePresentation):
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index c4b2011..ba0b6aa 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -1835,7 +1835,8 @@
   }
 
   public static final class VibrationAttributes.Builder {
-    ctor public VibrationAttributes.Builder(@NonNull android.media.AudioAttributes, @Nullable android.os.VibrationEffect);
+    ctor public VibrationAttributes.Builder(@NonNull android.media.AudioAttributes, @NonNull android.os.VibrationEffect);
+    ctor public VibrationAttributes.Builder(@NonNull android.os.VibrationAttributes, @NonNull android.os.VibrationEffect);
   }
 
   public abstract class VibrationEffect implements android.os.Parcelable {
@@ -3249,12 +3250,6 @@
     field @NonNull public static final android.os.Parcelable.Creator<android.window.TaskAppearedInfo> CREATOR;
   }
 
-  public final class TaskFragmentAppearedInfo implements android.os.Parcelable {
-    method @NonNull public android.view.SurfaceControl getLeash();
-    method @NonNull public android.window.TaskFragmentInfo getTaskFragmentInfo();
-    field @NonNull public static final android.os.Parcelable.Creator<android.window.TaskFragmentAppearedInfo> CREATOR;
-  }
-
   public final class TaskFragmentCreationParams implements android.os.Parcelable {
     method @NonNull public android.os.IBinder getFragmentToken();
     method @NonNull public android.graphics.Rect getInitialBounds();
@@ -3291,7 +3286,7 @@
     ctor public TaskFragmentOrganizer(@NonNull java.util.concurrent.Executor);
     method @NonNull public java.util.concurrent.Executor getExecutor();
     method @NonNull public android.window.TaskFragmentOrganizerToken getOrganizerToken();
-    method public void onTaskFragmentAppeared(@NonNull android.window.TaskFragmentAppearedInfo);
+    method public void onTaskFragmentAppeared(@NonNull android.window.TaskFragmentInfo);
     method public void onTaskFragmentError(@NonNull android.os.IBinder, @NonNull Throwable);
     method public void onTaskFragmentInfoChanged(@NonNull android.window.TaskFragmentInfo);
     method public void onTaskFragmentParentInfoChanged(@NonNull android.os.IBinder, @NonNull android.content.res.Configuration);
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FlagWriter.kt b/core/java/android/accessibilityservice/MagnificationConfig.aidl
similarity index 84%
copy from packages/SystemUI/src/com/android/systemui/flags/FlagWriter.kt
copy to core/java/android/accessibilityservice/MagnificationConfig.aidl
index bacc66b..fe415a8 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FlagWriter.kt
+++ b/core/java/android/accessibilityservice/MagnificationConfig.aidl
@@ -14,8 +14,6 @@
  * limitations under the License.
  */
 
-package com.android.systemui.flags
+package android.accessibilityservice;
 
-interface FlagWriter {
-    fun setEnabled(key: Int, value: Boolean) {}
-}
\ No newline at end of file
+parcelable MagnificationConfig;
diff --git a/core/java/android/accessibilityservice/MagnificationConfig.java b/core/java/android/accessibilityservice/MagnificationConfig.java
new file mode 100644
index 0000000..8884508
--- /dev/null
+++ b/core/java/android/accessibilityservice/MagnificationConfig.java
@@ -0,0 +1,250 @@
+/*
+ * 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.accessibilityservice;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * This class describes the magnification config for {@link AccessibilityService} to control the
+ * magnification.
+ *
+ * <p>
+ * When the magnification config uses {@link #DEFAULT_MODE},
+ * {@link AccessibilityService} will be able to control the activated magnifier on the display.
+ * If there is no magnifier activated, it controls the last-activated magnification mode.
+ * If there is no magnifier activated before, it controls full-screen magnifier by default.
+ * </p>
+ *
+ * <p>
+ * When the magnification config uses {@link #FULLSCREEN_MODE}. {@link AccessibilityService} will
+ * be able to control full-screen magnifier on the display.
+ * </p>
+ *
+ * <p>
+ * When the magnification config uses {@link #WINDOW_MODE}. {@link AccessibilityService} will be
+ * able to control the activated window magnifier on the display.
+ * </p>
+ *
+ * <p>
+ * If the other magnification configs, scale centerX and centerY, are not set by the
+ * {@link Builder}, the configs should be current values or default values. And the center
+ * position ordinarily is the center of the screen.
+ * </p>
+ */
+public final class MagnificationConfig implements Parcelable {
+
+    /** The controlling magnification mode. It controls the activated magnifier. */
+    public static final int DEFAULT_MODE = 0;
+    /** The controlling magnification mode. It controls fullscreen magnifier. */
+    public static final int FULLSCREEN_MODE = 1;
+    /** The controlling magnification mode. It controls window magnifier. */
+    public static final int WINDOW_MODE = 2;
+
+    @IntDef(prefix = {"MAGNIFICATION_MODE"}, value = {
+            DEFAULT_MODE,
+            FULLSCREEN_MODE,
+            WINDOW_MODE,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    @interface MAGNIFICATION_MODE {
+    }
+
+    private int mMode = DEFAULT_MODE;
+    private float mScale = Float.NaN;
+    private float mCenterX = Float.NaN;
+    private float mCenterY = Float.NaN;
+
+    private MagnificationConfig() {
+        /* do nothing */
+    }
+
+    private MagnificationConfig(@NonNull Parcel parcel) {
+        mMode = parcel.readInt();
+        mScale = parcel.readFloat();
+        mCenterX = parcel.readFloat();
+        mCenterY = parcel.readFloat();
+    }
+
+    /**
+     * Returns the magnification mode that is the current activated mode or the controlling mode of
+     * the config.
+     *
+     * @return The magnification mode
+     */
+    public int getMode() {
+        return mMode;
+    }
+
+    /**
+     * Returns the magnification scale of the controlling magnifier
+     *
+     * @return the scale If the controlling magnifier is not activated, it returns 1 by default
+     */
+    public float getScale() {
+        return mScale;
+    }
+
+    /**
+     * Returns the screen-relative X coordinate of the center of the magnification viewport.
+     *
+     * @return the X coordinate. If the controlling magnifier is {@link #WINDOW_MODE} but not
+     * enabled, it returns {@link Float#NaN}. If the controlling magnifier is {@link
+     * #FULLSCREEN_MODE} but not enabled, it returns 0
+     */
+    public float getCenterX() {
+        return mCenterX;
+    }
+
+    /**
+     * Returns the screen-relative Y coordinate of the center of the magnification viewport.
+     *
+     * @return the Y coordinate If the controlling magnifier is {@link #WINDOW_MODE} but not
+     * enabled, it returns {@link Float#NaN}. If the controlling magnifier is {@link
+     * #FULLSCREEN_MODE} but not enabled, it returns 0
+     */
+    public float getCenterY() {
+        return mCenterY;
+    }
+
+    @NonNull
+    @Override
+    public String toString() {
+        StringBuilder stringBuilder = new StringBuilder("MagnificationConfig[");
+        stringBuilder.append("mode: ").append(getMode());
+        stringBuilder.append(", ");
+        stringBuilder.append("scale: ").append(getScale());
+        stringBuilder.append(", ");
+        stringBuilder.append("centerX: ").append(getCenterX());
+        stringBuilder.append(", ");
+        stringBuilder.append("centerY: ").append(getCenterY());
+        stringBuilder.append("] ");
+        return stringBuilder.toString();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel parcel, int flags) {
+        parcel.writeInt(mMode);
+        parcel.writeFloat(mScale);
+        parcel.writeFloat(mCenterX);
+        parcel.writeFloat(mCenterY);
+    }
+
+    /**
+     * Builder for creating {@link MagnificationConfig} objects.
+     */
+    public static final class Builder {
+
+        private int mMode = DEFAULT_MODE;
+        private float mScale = Float.NaN;
+        private float mCenterX = Float.NaN;
+        private float mCenterY = Float.NaN;
+
+        /**
+         * Creates a new Builder.
+         */
+        public Builder() {
+        }
+
+        /**
+         * Sets the magnification mode.
+         *
+         * @param mode The magnification mode
+         * @return This builder
+         */
+        @NonNull
+        public MagnificationConfig.Builder setMode(@MAGNIFICATION_MODE int mode) {
+            mMode = mode;
+            return this;
+        }
+
+        /**
+         * Sets the magnification scale.
+         *
+         * @param scale The magnification scale
+         * @return This builder
+         */
+        @NonNull
+        public MagnificationConfig.Builder setScale(float scale) {
+            mScale = scale;
+            return this;
+        }
+
+        /**
+         * Sets the X coordinate of the center of the magnification viewport.
+         *
+         * @param centerX the screen-relative X coordinate around which to
+         *                center and scale, or {@link Float#NaN} to leave unchanged
+         * @return This builder
+         */
+        @NonNull
+        public MagnificationConfig.Builder setCenterX(float centerX) {
+            mCenterX = centerX;
+            return this;
+        }
+
+        /**
+         * Sets the Y coordinate of the center of the magnification viewport.
+         *
+         * @param centerY the screen-relative Y coordinate around which to
+         *                center and scale, or {@link Float#NaN} to leave unchanged
+         * @return This builder
+         */
+        @NonNull
+        public MagnificationConfig.Builder setCenterY(float centerY) {
+            mCenterY = centerY;
+            return this;
+        }
+
+        /**
+         * Builds and returns a {@link MagnificationConfig}
+         */
+        @NonNull
+        public MagnificationConfig build() {
+            MagnificationConfig magnificationConfig = new MagnificationConfig();
+            magnificationConfig.mMode = mMode;
+            magnificationConfig.mScale = mScale;
+            magnificationConfig.mCenterX = mCenterX;
+            magnificationConfig.mCenterY = mCenterY;
+            return magnificationConfig;
+        }
+    }
+
+    /**
+     * @see Parcelable.Creator
+     */
+    public static final @NonNull Parcelable.Creator<MagnificationConfig> CREATOR =
+            new Parcelable.Creator<MagnificationConfig>() {
+                public MagnificationConfig createFromParcel(Parcel parcel) {
+                    return new MagnificationConfig(parcel);
+                }
+
+                public MagnificationConfig[] newArray(int size) {
+                    return new MagnificationConfig[size];
+                }
+            };
+}
diff --git a/core/java/android/accessibilityservice/TouchInteractionController.java b/core/java/android/accessibilityservice/TouchInteractionController.java
index d9be49a..a8ba1d3 100644
--- a/core/java/android/accessibilityservice/TouchInteractionController.java
+++ b/core/java/android/accessibilityservice/TouchInteractionController.java
@@ -100,8 +100,8 @@
     private final Object mLock;
     private final int mDisplayId;
     private boolean mServiceDetectsGestures;
-    /** Map of listeners to executors. Lazily created when adding the first listener. */
-    private ArrayMap<Listener, Executor> mListeners;
+    /** Map of callbacks to executors. Lazily created when adding the first callback. */
+    private ArrayMap<Callback, Executor> mCallbacks;
 
     // The current state of the display.
     private int mState = STATE_CLEAR;
@@ -114,38 +114,38 @@
     }
 
     /**
-     * Adds the specified change listener to the list of motion event listeners. The callback will
+     * Adds the specified callback to the list of callbacks. The callback will
      * run using on the specified {@link Executor}', or on the service's main thread if the
      * Executor is {@code null}.
-     * @param listener the listener to add, must be non-null
+     * @param callback the callback to add, must be non-null
      * @param executor the executor for this callback, or {@code null} to execute on the service's
      *     main thread
      */
-    public void addListener(@Nullable Executor executor, @NonNull Listener listener) {
+    public void registerCallback(@Nullable Executor executor, @NonNull Callback callback) {
         synchronized (mLock) {
-            if (mListeners == null) {
-                mListeners = new ArrayMap<>();
+            if (mCallbacks == null) {
+                mCallbacks = new ArrayMap<>();
             }
-            mListeners.put(listener, executor);
-            if (mListeners.size() == 1) {
+            mCallbacks.put(callback, executor);
+            if (mCallbacks.size() == 1) {
                 setServiceDetectsGestures(true);
             }
         }
     }
 
     /**
-     * Removes the specified listener from the list of motion event listeners.
+     * Unregisters the specified callback.
      *
-     * @param listener the listener to remove, must be non-null
-     * @return {@code true} if the listener was removed, {@code false} otherwise
+     * @param callback the callback to remove, must be non-null
+     * @return {@code true} if the callback was removed, {@code false} otherwise
      */
-    public boolean removeListener(@NonNull Listener listener) {
-        if (mListeners == null) {
+    public boolean unregisterCallback(@NonNull Callback callback) {
+        if (mCallbacks == null) {
             return false;
         }
         synchronized (mLock) {
-            boolean result = mListeners.remove(listener) != null;
-            if (result && mListeners.size() == 0) {
+            boolean result = mCallbacks.remove(callback) != null;
+            if (result && mCallbacks.size() == 0) {
                 setServiceDetectsGestures(false);
             }
             return result;
@@ -153,60 +153,60 @@
     }
 
     /**
-     * Removes all listeners and returns control of touch interactions to the framework.
+     * Removes all callbacks and returns control of touch interactions to the framework.
      */
-    public void removeAllListeners() {
-        if (mListeners != null) {
+    public void unregisterAllCallbacks() {
+        if (mCallbacks != null) {
             synchronized (mLock) {
-                mListeners.clear();
+                mCallbacks.clear();
                 setServiceDetectsGestures(false);
             }
         }
     }
 
     /**
-     * Dispatches motion events to any registered listeners. This should be called on the service's
+     * Dispatches motion events to any registered callbacks. This should be called on the service's
      * main thread.
      */
     void onMotionEvent(MotionEvent event) {
-        final ArrayMap<Listener, Executor> entries;
+        final ArrayMap<Callback, Executor> entries;
         synchronized (mLock) {
-            // Listeners may remove themselves. Perform a shallow copy to avoid concurrent
+            // callbacks may remove themselves. Perform a shallow copy to avoid concurrent
             // modification.
-            entries = new ArrayMap<>(mListeners);
+            entries = new ArrayMap<>(mCallbacks);
         }
         for (int i = 0, count = entries.size(); i < count; i++) {
-            final Listener listener = entries.keyAt(i);
+            final Callback callback = entries.keyAt(i);
             final Executor executor = entries.valueAt(i);
             if (executor != null) {
-                executor.execute(() -> listener.onMotionEvent(event));
+                executor.execute(() -> callback.onMotionEvent(event));
             } else {
-                // We're already on the main thread, just run the listener.
-                listener.onMotionEvent(event);
+                // We're already on the main thread, just run the callback.
+                callback.onMotionEvent(event);
             }
         }
     }
 
     /**
-     * Dispatches motion events to any registered listeners. This should be called on the service's
+     * Dispatches motion events to any registered callbacks. This should be called on the service's
      * main thread.
      */
     void onStateChanged(@State int state) {
         mState = state;
-        final ArrayMap<Listener, Executor> entries;
+        final ArrayMap<Callback, Executor> entries;
         synchronized (mLock) {
-            // Listeners may remove themselves. Perform a shallow copy to avoid concurrent
+            // callbacks may remove themselves. Perform a shallow copy to avoid concurrent
             // modification.
-            entries = new ArrayMap<>(mListeners);
+            entries = new ArrayMap<>(mCallbacks);
         }
         for (int i = 0, count = entries.size(); i < count; i++) {
-            final Listener listener = entries.keyAt(i);
+            final Callback callback = entries.keyAt(i);
             final Executor executor = entries.valueAt(i);
             if (executor != null) {
-                executor.execute(() -> listener.onStateChanged(state));
+                executor.execute(() -> callback.onStateChanged(state));
             } else {
-                // We're already on the main thread, just run the listener.
-                listener.onStateChanged(state);
+                // We're already on the main thread, just run the callback.
+                callback.onStateChanged(state);
             }
         }
     }
@@ -238,7 +238,7 @@
 
     /**
      * If {@link AccessibilityServiceInfo#FLAG_REQUEST_TOUCH_EXPLORATION_MODE} is enabled and at
-     * least one listener has been added for this display this function tells the framework to
+     * least one callback has been added for this display this function tells the framework to
      * initiate touch exploration. Touch exploration will continue for the duration of this
      * interaction.
      */
@@ -259,7 +259,7 @@
     /**
      * If {@link AccessibilityServiceInfo#FLAG_REQUEST_TOUCH_EXPLORATION_MODE} and {@link If
      * {@link AccessibilityServiceInfo#FLAG_REQUEST_TOUCH_EXPLORATION_MODE} is enabled and at least
-     * one listener has been added, this function tells the framework to initiate a dragging
+     * one callback has been added, this function tells the framework to initiate a dragging
      * interaction using the specified pointer. The pointer's movements will be passed through to
      * the rest of the input pipeline. Dragging is often used to perform two-finger scrolling.
      *
@@ -287,7 +287,7 @@
     /**
      * If {@link AccessibilityServiceInfo#FLAG_REQUEST_TOUCH_EXPLORATION_MODE} and {@link If
      * {@link AccessibilityServiceInfo#FLAG_REQUEST_TOUCH_EXPLORATION_MODE} is enabled and at least
-     * one listener has been added, this function tells the framework to initiate a delegating
+     * one callback has been added, this function tells the framework to initiate a delegating
      * interaction. Motion events will be passed through as-is to the rest of the input pipeline for
      * the duration of this interaction.
      */
@@ -308,7 +308,7 @@
     /**
      * If {@link AccessibilityServiceInfo#FLAG_REQUEST_TOUCH_EXPLORATION_MODE} and {@link If
      * {@link AccessibilityServiceInfo#FLAG_REQUEST_TOUCH_EXPLORATION_MODE} is enabled and at least
-     * one listener has been added, this function tells the framework to perform a click.
+     * one callback has been added, this function tells the framework to perform a click.
      * The framework will first try to perform
      * {@link AccessibilityNodeInfo.AccessibilityAction#ACTION_CLICK} on the item with
      * accessibility focus. If that fails, the framework will simulate a click using motion events
@@ -330,7 +330,7 @@
     /**
      * If {@link AccessibilityServiceInfo#FLAG_REQUEST_TOUCH_EXPLORATION_MODE} and {@link If
      * {@link AccessibilityServiceInfo#FLAG_REQUEST_TOUCH_EXPLORATION_MODE} is enabled and at least
-     * one listener has been added, this function tells the framework to perform a long click.
+     * one callback has been added, this function tells the framework to perform a long click.
      * The framework will simulate a long click using motion events on the last location with
      * accessibility focus and will delegate any movements to the rest of the input pipeline. This
      * allows a user to double-tap and hold to trigger a drag and then execute that drag by moving
@@ -350,9 +350,9 @@
     }
 
     private void checkState() {
-        if (!mServiceDetectsGestures || mListeners.size() == 0) {
+        if (!mServiceDetectsGestures || mCallbacks.size() == 0) {
             throw new IllegalStateException(
-                    "State transitions are not allowed without first adding a listener.");
+                    "State transitions are not allowed without first adding a callback.");
         }
         if (mState != STATE_TOUCH_INTERACTING) {
             throw new IllegalStateException(
@@ -402,8 +402,8 @@
         }
     }
 
-    /** Listeners allow services to receive motion events and state change updates. */
-    public interface Listener {
+    /** callbacks allow services to receive motion events and state change updates. */
+    public interface Callback {
         /**
          * Called when the framework has sent a motion event to the service.
          *
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index f9cc323..9f8d246 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -4082,6 +4082,34 @@
     }
 
     /**
+     * Gets the message that is shown when a user is switched from.
+     *
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.MANAGE_USERS)
+    public @Nullable String getSwitchingFromUserMessage() {
+        try {
+            return getService().getSwitchingFromUserMessage();
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Gets the message that is shown when a user is switched to.
+     *
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.MANAGE_USERS)
+    public @Nullable String getSwitchingToUserMessage() {
+        try {
+            return getService().getSwitchingToUserMessage();
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Uses the value defined by the platform.
      *
      * @hide
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index ffa7cf1..c89e8b0 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -41,6 +41,12 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UptimeMillisLong;
+import android.app.RemoteServiceException.BadForegroundServiceNotificationException;
+import android.app.RemoteServiceException.CannotDeliverBroadcastException;
+import android.app.RemoteServiceException.CannotPostForegroundServiceNotificationException;
+import android.app.RemoteServiceException.CrashedByAdbException;
+import android.app.RemoteServiceException.ForegroundServiceDidNotStartInTimeException;
+import android.app.RemoteServiceException.MissingRequestPasswordComplexityPermissionException;
 import android.app.assist.AssistContent;
 import android.app.assist.AssistStructure;
 import android.app.backup.BackupAgent;
@@ -1929,11 +1935,27 @@
     private void throwRemoteServiceException(String message, int typeId) {
         // Use a switch to ensure all the type IDs are unique.
         switch (typeId) {
-            case ForegroundServiceDidNotStartInTimeException.TYPE_ID: // 1
+            case ForegroundServiceDidNotStartInTimeException.TYPE_ID:
                 throw new ForegroundServiceDidNotStartInTimeException(message);
-            case RemoteServiceException.TYPE_ID: // 0
+
+            case CannotDeliverBroadcastException.TYPE_ID:
+                throw new CannotDeliverBroadcastException(message);
+
+            case CannotPostForegroundServiceNotificationException.TYPE_ID:
+                throw new CannotPostForegroundServiceNotificationException(message);
+
+            case BadForegroundServiceNotificationException.TYPE_ID:
+                throw new BadForegroundServiceNotificationException(message);
+
+            case MissingRequestPasswordComplexityPermissionException.TYPE_ID:
+                throw new MissingRequestPasswordComplexityPermissionException(message);
+
+            case CrashedByAdbException.TYPE_ID:
+                throw new CrashedByAdbException(message);
+
             default:
-                throw new RemoteServiceException(message);
+                throw new RemoteServiceException(message
+                        + " (with unwknown typeId:" + typeId + ")");
         }
     }
 
diff --git a/core/java/android/app/ForegroundServiceDidNotStartInTimeException.java b/core/java/android/app/ForegroundServiceDidNotStartInTimeException.java
deleted file mode 100644
index 364291e..0000000
--- a/core/java/android/app/ForegroundServiceDidNotStartInTimeException.java
+++ /dev/null
@@ -1,33 +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.app;
-
-/**
- * Exception used to crash an app process when it didn't call {@link Service#startForeground}
- * in time after the service was started with
- * {@link android.content.Context#startForegroundService}.
- *
- * @hide
- */
-public class ForegroundServiceDidNotStartInTimeException extends RemoteServiceException {
-    /** The type ID passed to {@link IApplicationThread#scheduleCrash}. */
-    public static final int TYPE_ID = 1;
-
-    public ForegroundServiceDidNotStartInTimeException(String msg) {
-        super(msg);
-    }
-}
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 853d5e8..183e714 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -330,8 +330,6 @@
     void handleApplicationStrictModeViolation(in IBinder app, int penaltyMask,
             in StrictMode.ViolationInfo crashInfo);
     boolean isTopActivityImmersive();
-    void crashApplication(int uid, int initialPid, in String packageName, int userId,
-            in String message, boolean force);
     void crashApplicationWithType(int uid, int initialPid, in String packageName, int userId,
             in String message, boolean force, int exceptionTypeId);
     /** @deprecated -- use getProviderMimeTypeAsync */
@@ -351,6 +349,8 @@
     void setPackageScreenCompatMode(in String packageName, int mode);
     @UnsupportedAppUsage
     boolean switchUser(int userid);
+    String getSwitchingFromUserMessage();
+    String getSwitchingToUserMessage();
     @UnsupportedAppUsage
     void setStopUserOnSwitch(int value);
     boolean removeTask(int taskId);
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 6bfde9a..af907af 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -6791,7 +6791,7 @@
 
         // We show these sorts of notifications immediately in the absence of
         // any explicit app declaration
-        if (isMediaNotification() || hasMediaSession()
+        if (isMediaNotification()
                     || CATEGORY_CALL.equals(category)
                     || CATEGORY_NAVIGATION.equals(category)
                     || (actions != null && actions.length > 0)) {
@@ -6811,14 +6811,6 @@
     }
 
     /**
-     * @return whether this notification has a media session attached
-     * @hide
-     */
-    public boolean hasMediaSession() {
-        return extras.getParcelable(Notification.EXTRA_MEDIA_SESSION) != null;
-    }
-
-    /**
      * @return the style class of this notification
      * @hide
      */
@@ -6861,18 +6853,20 @@
     }
 
     /**
-     * @return true if this is a media notification
+     * @return true if this is a media style notification with a media session
      *
      * @hide
      */
     public boolean isMediaNotification() {
         Class<? extends Style> style = getNotificationStyle();
-        if (MediaStyle.class.equals(style)) {
-            return true;
-        } else if (DecoratedMediaCustomViewStyle.class.equals(style)) {
-            return true;
-        }
-        return false;
+        boolean isMediaStyle = (MediaStyle.class.equals(style)
+                || DecoratedMediaCustomViewStyle.class.equals(style));
+
+        boolean hasMediaSession = (extras.getParcelable(Notification.EXTRA_MEDIA_SESSION) != null
+                && extras.getParcelable(Notification.EXTRA_MEDIA_SESSION)
+                instanceof MediaSession.Token);
+
+        return isMediaStyle && hasMediaSession;
     }
 
     /**
diff --git a/core/java/android/app/OWNERS b/core/java/android/app/OWNERS
index 1da0a74..e099716 100644
--- a/core/java/android/app/OWNERS
+++ b/core/java/android/app/OWNERS
@@ -30,6 +30,8 @@
 per-file SystemServiceRegistry.java = file:/services/core/java/com/android/server/am/OWNERS
 per-file *UserSwitchObserver* = file:/services/core/java/com/android/server/am/OWNERS
 per-file UiAutomation.java = file:/services/accessibility/OWNERS
+per-file GameManager* = file:/GAME_MANAGER_OWNERS
+per-file IGameManager* = file:/GAME_MANAGER_OWNERS
 
 # ActivityThread
 per-file ActivityThread.java = file:/services/core/java/com/android/server/am/OWNERS
diff --git a/core/java/android/app/RemoteServiceException.java b/core/java/android/app/RemoteServiceException.java
index 4b32463..1038530 100644
--- a/core/java/android/app/RemoteServiceException.java
+++ b/core/java/android/app/RemoteServiceException.java
@@ -19,20 +19,109 @@
 import android.util.AndroidRuntimeException;
 
 /**
- * Exception used by {@link ActivityThread} to crash an app process.
+ * Exception used by {@link ActivityThread} to crash an app process for an unknown cause.
+ * An exception of this class is no longer supposed to be thrown. Instead, we use fine-grained
+ * sub-exceptions.
+ *
+ * Subclasses must be registered in
+ * {@link android.app.ActivityThread#throwRemoteServiceException(java.lang.String, int)}.
  *
  * @hide
  */
 public class RemoteServiceException extends AndroidRuntimeException {
-    /**
-     * The type ID passed to {@link IApplicationThread#scheduleCrash}.
-     *
-     * Assign a unique ID to each subclass. See the above method for the numbers that are already
-     * taken.
-     */
-    public static final int TYPE_ID = 0;
-
     public RemoteServiceException(String msg) {
         super(msg);
     }
+
+    /**
+     * Exception used to crash an app process when it didn't call {@link Service#startForeground}
+     * in time after the service was started with
+     * {@link android.content.Context#startForegroundService}.
+     *
+     * @hide
+     */
+    public static class ForegroundServiceDidNotStartInTimeException extends RemoteServiceException {
+        /** The type ID passed to {@link IApplicationThread#scheduleCrash}. */
+        public static final int TYPE_ID = 1;
+
+        public ForegroundServiceDidNotStartInTimeException(String msg) {
+            super(msg);
+        }
+    }
+
+    /**
+     * Exception used to crash an app process when the system received a RemoteException
+     * while delivering a broadcast to an app process.
+     *
+     * @hide
+     */
+    public static class CannotDeliverBroadcastException extends RemoteServiceException {
+        /** The type ID passed to {@link IApplicationThread#scheduleCrash}. */
+        public static final int TYPE_ID = 2;
+
+        public CannotDeliverBroadcastException(String msg) {
+            super(msg);
+        }
+    }
+
+    /**
+     * Exception used to crash an app process when the system received a RemoteException
+     * while posting a notification of a foreground service.
+     *
+     * @hide
+     */
+    public static class CannotPostForegroundServiceNotificationException
+            extends RemoteServiceException {
+        /** The type ID passed to {@link IApplicationThread#scheduleCrash}. */
+        public static final int TYPE_ID = 3;
+
+        public CannotPostForegroundServiceNotificationException(String msg) {
+            super(msg);
+        }
+    }
+
+    /**
+     * Exception used to crash an app process when the system finds an error in a foreground service
+     * notification.
+     *
+     * @hide
+     */
+    public static class BadForegroundServiceNotificationException extends RemoteServiceException {
+        /** The type ID passed to {@link IApplicationThread#scheduleCrash}. */
+        public static final int TYPE_ID = 4;
+
+        public BadForegroundServiceNotificationException(String msg) {
+            super(msg);
+        }
+    }
+
+    /**
+     * Exception used to crash an app process when it calls a setting activity that requires
+     * the {@code REQUEST_PASSWORD_COMPLEXITY} permission.
+     *
+     * @hide
+     */
+    public static class MissingRequestPasswordComplexityPermissionException
+            extends RemoteServiceException {
+        /** The type ID passed to {@link IApplicationThread#scheduleCrash}. */
+        public static final int TYPE_ID = 5;
+
+        public MissingRequestPasswordComplexityPermissionException(String msg) {
+            super(msg);
+        }
+    }
+
+    /**
+     * Exception used to crash an app process by {@code adb shell am crash}.
+     *
+     * @hide
+     */
+    public static class CrashedByAdbException extends RemoteServiceException {
+        /** The type ID passed to {@link IApplicationThread#scheduleCrash}. */
+        public static final int TYPE_ID = 6;
+
+        public CrashedByAdbException(String msg) {
+            super(msg);
+        }
+    }
 }
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index fc40179..74e2858 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -204,6 +204,7 @@
 import android.service.persistentdata.IPersistentDataBlockService;
 import android.service.persistentdata.PersistentDataBlockManager;
 import android.service.vr.IVrManager;
+import android.supplementalprocess.SupplementalProcessFrameworkInitializer;
 import android.telecom.TelecomManager;
 import android.telephony.MmsManager;
 import android.telephony.TelephonyFrameworkInitializer;
@@ -1527,6 +1528,7 @@
             MediaFrameworkInitializer.registerServiceWrappers();
             RoleFrameworkInitializer.registerServiceWrappers();
             SchedulingFrameworkInitializer.registerServiceWrappers();
+            SupplementalProcessFrameworkInitializer.registerServiceWrappers();
             UwbFrameworkInitializer.registerServiceWrappers();
         } finally {
             // If any of the above code throws, we're in a pretty bad shape and the process
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index d2963fb..57b3196 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -684,8 +684,9 @@
      * A String extra holding the time zone {@link android.app.AlarmManager} that the device
      * will be set to.
      *
-     * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
-     * provisioning via an NFC bump.
+     * <p>Use only for device owner provisioning. This extra can be returned by the admin app when
+     * performing the admin-integrated provisioning flow as a result of the {@link
+     * #ACTION_GET_PROVISIONING_MODE} activity.
      */
     public static final String EXTRA_PROVISIONING_TIME_ZONE
         = "android.app.extra.PROVISIONING_TIME_ZONE";
@@ -694,8 +695,9 @@
      * A Long extra holding the wall clock time (in milliseconds) to be set on the device's
      * {@link android.app.AlarmManager}.
      *
-     * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
-     * provisioning via an NFC bump.
+     * <p>Use only for device owner provisioning. This extra can be returned by the admin app when
+     * performing the admin-integrated provisioning flow as a result of the {@link
+     * #ACTION_GET_PROVISIONING_MODE} activity.
      */
     public static final String EXTRA_PROVISIONING_LOCAL_TIME
         = "android.app.extra.PROVISIONING_LOCAL_TIME";
@@ -704,8 +706,9 @@
      * A String extra holding the {@link java.util.Locale} that the device will be set to.
      * Format: xx_yy, where xx is the language code, and yy the country code.
      *
-     * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
-     * provisioning via an NFC bump.
+     * <p>Use only for device owner provisioning. This extra can be returned by the admin app when
+     * performing the admin-integrated provisioning flow as a result of the {@link
+     * #ACTION_GET_PROVISIONING_MODE} activity.
      */
     public static final String EXTRA_PROVISIONING_LOCALE
         = "android.app.extra.PROVISIONING_LOCALE";
@@ -1001,7 +1004,10 @@
      * The default for this extra is {@code false} - by default, the admin of a fully-managed
      * device has the ability to grant sensors-related permissions.
      *
-     * <p>Use only for device owner provisioning.
+     * <p>Use only for device owner provisioning. This extra can be returned by the
+     * admin app when performing the admin-integrated provisioning flow as a result of the
+     * {@link #ACTION_GET_PROVISIONING_MODE} activity.
+     *
      * @see #ACTION_GET_PROVISIONING_MODE
      */
     public static final String EXTRA_PROVISIONING_SENSORS_PERMISSION_GRANT_OPT_OUT =
@@ -1070,6 +1076,9 @@
      *
      * <p>From {@link android.os.Build.VERSION_CODES#N} onwards, this is also supported for an
      * intent with action {@link #ACTION_PROVISION_MANAGED_PROFILE}.
+     *
+     * <p>This extra can also be returned by the admin app when performing the admin-integrated
+     * provisioning flow as a result of the {@link #ACTION_GET_PROVISIONING_MODE} activity.
      */
     public static final String EXTRA_PROVISIONING_SKIP_ENCRYPTION =
              "android.app.extra.PROVISIONING_SKIP_ENCRYPTION";
@@ -1109,8 +1118,9 @@
      *
      * <p> Maximum 3 key-value pairs can be specified. The rest will be ignored.
      *
-     * <p> Use in an intent with action {@link #ACTION_PROVISION_MANAGED_PROFILE} or
-     * {@link #ACTION_PROVISION_MANAGED_DEVICE}
+     * <p> Can be used in an intent with action {@link #ACTION_PROVISION_MANAGED_PROFILE}. This
+     * extra can also be returned by the admin app when performing the admin-integrated
+     * provisioning flow as a result of the {@link #ACTION_GET_PROVISIONING_MODE} activity.
      */
     public static final String EXTRA_PROVISIONING_DISCLAIMERS =
             "android.app.extra.PROVISIONING_DISCLAIMERS";
@@ -7857,7 +7867,7 @@
     @SystemApi
     @RequiresPermission(anyOf = {
             android.Manifest.permission.MANAGE_USERS,
-            android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS,
+            android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS
     })
     public ComponentName getDeviceOwnerComponentOnAnyUser() {
         return getDeviceOwnerComponentInner(/* callingUserOnly =*/ false);
@@ -7970,8 +7980,8 @@
      * Called by the system to find out whether the device is managed by a Device Owner.
      *
      * @return whether the device is managed by a Device Owner.
-     * @throws SecurityException if the caller is not the device owner, does not hold the
-     *         MANAGE_USERS permission and is not the system.
+     * @throws SecurityException if the caller is not the device owner, does not hold
+     *         MANAGE_USERS or MANAGE_PROFILE_AND_DEVICE_OWNERS permissions and is not the system.
      *
      * @hide
      */
@@ -7992,7 +8002,10 @@
      * @hide
      */
     @SystemApi
-    @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.MANAGE_USERS,
+            android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS
+    })
     public String getDeviceOwnerNameOnAnyUser() {
         throwIfParentInstance("getDeviceOwnerNameOnAnyUser");
         if (mService != null) {
@@ -8382,7 +8395,10 @@
      * @throws IllegalArgumentException if the userId is invalid.
      */
     @SystemApi
-    @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.MANAGE_USERS,
+            android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS
+    })
     public @Nullable String getProfileOwnerNameAsUser(int userId) throws IllegalArgumentException {
         throwIfParentInstance("getProfileOwnerNameAsUser");
         if (mService != null) {
@@ -11920,7 +11936,10 @@
      * @hide
      */
     @SystemApi
-    @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.MANAGE_USERS,
+            android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS
+    })
     @UserProvisioningState
     public int getUserProvisioningState() {
         throwIfParentInstance("getUserProvisioningState");
@@ -13429,7 +13448,10 @@
      * @hide
      */
     @SystemApi
-    @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.MANAGE_USERS,
+            android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS
+    })
     public boolean isManagedKiosk() {
         throwIfParentInstance("isManagedKiosk");
         if (mService != null) {
@@ -13458,7 +13480,10 @@
      * @hide
      */
     @SystemApi
-    @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.MANAGE_USERS,
+            android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS
+    })
     public boolean isUnattendedManagedKiosk() {
         throwIfParentInstance("isUnattendedManagedKiosk");
         if (mService != null) {
diff --git a/core/java/android/app/communal/OWNERS b/core/java/android/app/communal/OWNERS
new file mode 100644
index 0000000..b02883d
--- /dev/null
+++ b/core/java/android/app/communal/OWNERS
@@ -0,0 +1,4 @@
+brycelee@google.com
+justinkoh@google.com
+lusilva@google.com
+xilei@google.com
\ No newline at end of file
diff --git a/core/java/android/bluetooth/le/AdvertiseData.java b/core/java/android/bluetooth/le/AdvertiseData.java
index cec6580..fdf62ec 100644
--- a/core/java/android/bluetooth/le/AdvertiseData.java
+++ b/core/java/android/bluetooth/le/AdvertiseData.java
@@ -25,6 +25,7 @@
 import android.util.SparseArray;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
@@ -47,6 +48,9 @@
     @NonNull
     private final List<ParcelUuid> mServiceSolicitationUuids;
 
+    @Nullable
+    private final List<TransportDiscoveryData> mTransportDiscoveryData;
+
     private final SparseArray<byte[]> mManufacturerSpecificData;
     private final Map<ParcelUuid, byte[]> mServiceData;
     private final boolean mIncludeTxPowerLevel;
@@ -54,12 +58,14 @@
 
     private AdvertiseData(List<ParcelUuid> serviceUuids,
             List<ParcelUuid> serviceSolicitationUuids,
+            List<TransportDiscoveryData> transportDiscoveryData,
             SparseArray<byte[]> manufacturerData,
             Map<ParcelUuid, byte[]> serviceData,
             boolean includeTxPowerLevel,
             boolean includeDeviceName) {
         mServiceUuids = serviceUuids;
         mServiceSolicitationUuids = serviceSolicitationUuids;
+        mTransportDiscoveryData = transportDiscoveryData;
         mManufacturerSpecificData = manufacturerData;
         mServiceData = serviceData;
         mIncludeTxPowerLevel = includeTxPowerLevel;
@@ -83,6 +89,17 @@
     }
 
     /**
+     * Returns a list of {@link TransportDiscoveryData} within the advertisement.
+     */
+    @NonNull
+    public List<TransportDiscoveryData> getTransportDiscoveryData() {
+        if (mTransportDiscoveryData == null) {
+            return Collections.emptyList();
+        }
+        return mTransportDiscoveryData;
+    }
+
+    /**
      * Returns an array of manufacturer Id and the corresponding manufacturer specific data. The
      * manufacturer id is a non-negative number assigned by Bluetooth SIG.
      */
@@ -116,8 +133,8 @@
      */
     @Override
     public int hashCode() {
-        return Objects.hash(mServiceUuids, mServiceSolicitationUuids, mManufacturerSpecificData,
-                mServiceData, mIncludeDeviceName, mIncludeTxPowerLevel);
+        return Objects.hash(mServiceUuids, mServiceSolicitationUuids, mTransportDiscoveryData,
+                mManufacturerSpecificData, mServiceData, mIncludeDeviceName, mIncludeTxPowerLevel);
     }
 
     /**
@@ -134,6 +151,7 @@
         AdvertiseData other = (AdvertiseData) obj;
         return Objects.equals(mServiceUuids, other.mServiceUuids)
                 && Objects.equals(mServiceSolicitationUuids, other.mServiceSolicitationUuids)
+                && Objects.equals(mTransportDiscoveryData, other.mTransportDiscoveryData)
                 && BluetoothLeUtils.equals(mManufacturerSpecificData,
                     other.mManufacturerSpecificData)
                 && BluetoothLeUtils.equals(mServiceData, other.mServiceData)
@@ -144,7 +162,8 @@
     @Override
     public String toString() {
         return "AdvertiseData [mServiceUuids=" + mServiceUuids + ", mServiceSolicitationUuids="
-                + mServiceSolicitationUuids + ", mManufacturerSpecificData="
+                + mServiceSolicitationUuids + ", mTransportDiscoveryData="
+                + mTransportDiscoveryData + ", mManufacturerSpecificData="
                 + BluetoothLeUtils.toString(mManufacturerSpecificData) + ", mServiceData="
                 + BluetoothLeUtils.toString(mServiceData)
                 + ", mIncludeTxPowerLevel=" + mIncludeTxPowerLevel + ", mIncludeDeviceName="
@@ -162,6 +181,8 @@
         dest.writeTypedArray(mServiceSolicitationUuids.toArray(
                 new ParcelUuid[mServiceSolicitationUuids.size()]), flags);
 
+        dest.writeTypedList(mTransportDiscoveryData);
+
         // mManufacturerSpecificData could not be null.
         dest.writeInt(mManufacturerSpecificData.size());
         for (int i = 0; i < mManufacturerSpecificData.size(); ++i) {
@@ -197,6 +218,12 @@
                         builder.addServiceSolicitationUuid(uuid);
                     }
 
+                    List<TransportDiscoveryData> transportDiscoveryData =
+                            in.createTypedArrayList(TransportDiscoveryData.CREATOR);
+                    for (TransportDiscoveryData tdd : transportDiscoveryData) {
+                        builder.addTransportDiscoveryData(tdd);
+                    }
+
                     int manufacturerSize = in.readInt();
                     for (int i = 0; i < manufacturerSize; ++i) {
                         int manufacturerId = in.readInt();
@@ -223,6 +250,9 @@
         private List<ParcelUuid> mServiceUuids = new ArrayList<ParcelUuid>();
         @NonNull
         private List<ParcelUuid> mServiceSolicitationUuids = new ArrayList<ParcelUuid>();
+        @Nullable
+        private List<TransportDiscoveryData> mTransportDiscoveryData =
+                new ArrayList<TransportDiscoveryData>();
         private SparseArray<byte[]> mManufacturerSpecificData = new SparseArray<byte[]>();
         private Map<ParcelUuid, byte[]> mServiceData = new ArrayMap<ParcelUuid, byte[]>();
         private boolean mIncludeTxPowerLevel;
@@ -256,6 +286,7 @@
             mServiceSolicitationUuids.add(serviceSolicitationUuid);
             return this;
         }
+
         /**
          * Add service data to advertise data.
          *
@@ -274,6 +305,23 @@
         }
 
         /**
+         * Add Transport Discovery Data to advertise data.
+         *
+         * @param transportDiscoveryData Transport Discovery Data, consisting of one or more
+         * Transport Blocks. Transport Discovery Data AD Type Code is already included.
+         * @throws IllegalArgumentException If the {@code transportDiscoveryData} is empty
+         */
+        @NonNull
+        public Builder addTransportDiscoveryData(
+                @NonNull TransportDiscoveryData transportDiscoveryData) {
+            if (transportDiscoveryData == null) {
+                throw new IllegalArgumentException("transportDiscoveryData is null");
+            }
+            mTransportDiscoveryData.add(transportDiscoveryData);
+            return this;
+        }
+
+        /**
          * Add manufacturer specific data.
          * <p>
          * Please refer to the Bluetooth Assigned Numbers document provided by the <a
@@ -319,8 +367,8 @@
          */
         public AdvertiseData build() {
             return new AdvertiseData(mServiceUuids, mServiceSolicitationUuids,
-                    mManufacturerSpecificData, mServiceData, mIncludeTxPowerLevel,
-                    mIncludeDeviceName);
+                    mTransportDiscoveryData, mManufacturerSpecificData, mServiceData,
+                    mIncludeTxPowerLevel, mIncludeDeviceName);
         }
     }
 }
diff --git a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
index 5802974..b9f8a57 100644
--- a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
+++ b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
@@ -567,6 +567,9 @@
                         + num128BitUuids * BluetoothUuid.UUID_BYTES_128_BIT;
             }
         }
+        for (TransportDiscoveryData transportDiscoveryData : data.getTransportDiscoveryData()) {
+            size += OVERHEAD_BYTES_PER_FIELD + transportDiscoveryData.totalBytes();
+        }
         for (ParcelUuid uuid : data.getServiceData().keySet()) {
             int uuidLen = BluetoothUuid.uuidToBytes(uuid).length;
             size += OVERHEAD_BYTES_PER_FIELD + uuidLen
diff --git a/core/java/android/bluetooth/le/TransportBlock.java b/core/java/android/bluetooth/le/TransportBlock.java
new file mode 100644
index 0000000..b388bed
--- /dev/null
+++ b/core/java/android/bluetooth/le/TransportBlock.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth.le;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+
+import java.nio.BufferOverflowException;
+import java.nio.ByteBuffer;
+
+/**
+ * Wrapper for Transport Discovery Data Transport Blocks.
+ * This class represents a Transport Block from a Transport Discovery Data.
+ *
+ * @see TransportDiscoveryData
+ * @see AdvertiseData
+ */
+public final class TransportBlock implements Parcelable {
+    private static final String TAG = "TransportBlock";
+    private final int mOrgId;
+    private final int mTdsFlags;
+    private final int mTransportDataLength;
+    private final byte[] mTransportData;
+
+    /**
+     * Creates an instance of TransportBlock from raw data.
+     *
+     * @param orgId the Organization ID
+     * @param tdsFlags the TDS flags
+     * @param transportDataLength the total length of the Transport Data
+     * @param transportData the Transport Data
+     */
+    public TransportBlock(int orgId, int tdsFlags, int transportDataLength,
+            @Nullable byte[] transportData) {
+        mOrgId = orgId;
+        mTdsFlags = tdsFlags;
+        mTransportDataLength = transportDataLength;
+        mTransportData = transportData;
+    }
+
+    private TransportBlock(Parcel in) {
+        mOrgId = in.readInt();
+        mTdsFlags = in.readInt();
+        mTransportDataLength = in.readInt();
+        mTransportData = new byte[mTransportDataLength];
+        in.readByteArray(mTransportData);
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeInt(mOrgId);
+        dest.writeInt(mTdsFlags);
+        dest.writeInt(mTransportDataLength);
+        dest.writeByteArray(mTransportData);
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    public static final @NonNull Creator<TransportBlock> CREATOR = new Creator<TransportBlock>() {
+        @Override
+        public TransportBlock createFromParcel(Parcel in) {
+            return new TransportBlock(in);
+        }
+
+        @Override
+        public TransportBlock[] newArray(int size) {
+            return new TransportBlock[size];
+        }
+    };
+
+    /**
+     * Gets the Organization ID of the Transport Block which corresponds to one of the
+     * the Bluetooth SIG Assigned Numbers.
+     */
+    public int getOrgId() {
+        return mOrgId;
+    }
+
+    /**
+     * Gets the TDS flags of the Transport Block which represents the role of the device and
+     * information about its state and supported features.
+     */
+    public int getTdsFlags() {
+        return mTdsFlags;
+    }
+
+    /**
+     * Gets the total number of octets in the Transport Data field in this Transport Block.
+     */
+    public int getTransportDataLength() {
+        return mTransportDataLength;
+    }
+
+    /**
+     * Gets the Transport Data of the Transport Block which contains organization-specific data.
+     */
+    @Nullable
+    public byte[] getTransportData() {
+        return mTransportData;
+    }
+
+    /**
+     * Converts this TransportBlock to byte array
+     *
+     * @return byte array representation of this Transport Block or null if the conversion failed
+     */
+    @Nullable
+    public byte[] toByteArray() {
+        try {
+            ByteBuffer buffer = ByteBuffer.allocate(totalBytes());
+            buffer.put((byte) mOrgId);
+            buffer.put((byte) mTdsFlags);
+            buffer.put((byte) mTransportDataLength);
+            if (mTransportData != null) {
+                buffer.put(mTransportData);
+            }
+            return buffer.array();
+        } catch (BufferOverflowException e) {
+            Log.e(TAG, "Error converting to byte array: " + e.toString());
+            return null;
+        }
+    }
+
+    /**
+     * @return total byte count of this TransportBlock
+     */
+    public int totalBytes() {
+        // 3 uint8 + byte[] length
+        int size = 3 + mTransportDataLength;
+        return size;
+    }
+}
diff --git a/core/java/android/bluetooth/le/TransportDiscoveryData.java b/core/java/android/bluetooth/le/TransportDiscoveryData.java
new file mode 100644
index 0000000..c8e97f9
--- /dev/null
+++ b/core/java/android/bluetooth/le/TransportDiscoveryData.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth.le;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+
+import java.nio.BufferOverflowException;
+import java.nio.BufferUnderflowException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Wrapper for Transport Discovery Data AD Type.
+ * This class contains the Transport Discovery Data AD Type Code as well as
+ * a list of potential Transport Blocks.
+ *
+ * @see AdvertiseData
+ */
+public final class TransportDiscoveryData implements Parcelable {
+    private static final String TAG = "TransportDiscoveryData";
+    private final int mTransportDataType;
+    private final List<TransportBlock> mTransportBlocks;
+
+    /**
+     * Creates a TransportDiscoveryData instance.
+     *
+     * @param transportDataType the Transport Discovery Data AD Type
+     * @param transportBlocks the list of Transport Blocks
+     */
+    public TransportDiscoveryData(int transportDataType,
+            @NonNull List<TransportBlock> transportBlocks) {
+        mTransportDataType = transportDataType;
+        mTransportBlocks = transportBlocks;
+    }
+
+    /**
+     * Creates a TransportDiscoveryData instance from byte arrays.
+     *
+     * Uses the transport discovery data bytes and parses them into an usable class.
+     *
+     * @param transportDiscoveryData the raw discovery data
+     */
+    public TransportDiscoveryData(@NonNull byte[] transportDiscoveryData) {
+        ByteBuffer byteBuffer = ByteBuffer.wrap(transportDiscoveryData);
+        mTransportBlocks = new ArrayList();
+        if (byteBuffer.remaining() > 0) {
+            mTransportDataType = byteBuffer.get();
+        } else {
+            mTransportDataType = -1;
+        }
+        try {
+            while (byteBuffer.remaining() > 0) {
+                int orgId = byteBuffer.get();
+                int tdsFlags = byteBuffer.get();
+                int transportDataLength = byteBuffer.get();
+                byte[] transportData = new byte[transportDataLength];
+                byteBuffer.get(transportData, 0, transportDataLength);
+                mTransportBlocks.add(new TransportBlock(orgId, tdsFlags,
+                        transportDataLength, transportData));
+            }
+        } catch (BufferUnderflowException e) {
+            Log.e(TAG, "Error while parsing data: " + e.toString());
+        }
+    }
+
+    private TransportDiscoveryData(Parcel in) {
+        mTransportDataType = in.readInt();
+        mTransportBlocks = in.createTypedArrayList(TransportBlock.CREATOR);
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeInt(mTransportDataType);
+        dest.writeTypedList(mTransportBlocks);
+    }
+
+    public static final @NonNull Creator<TransportDiscoveryData> CREATOR =
+            new Creator<TransportDiscoveryData>() {
+                @Override
+                public TransportDiscoveryData createFromParcel(Parcel in) {
+                    return new TransportDiscoveryData(in);
+                }
+
+                @Override
+                public TransportDiscoveryData[] newArray(int size) {
+                    return new TransportDiscoveryData[size];
+                }
+    };
+
+    /**
+     * Gets the transport data type.
+     */
+    public int getTransportDataType() {
+        return mTransportDataType;
+    }
+
+    /**
+     * @return the list of {@link TransportBlock} in this TransportDiscoveryData
+     *         or an empty list if there are no Transport Blocks
+     */
+    @NonNull
+    public List<TransportBlock> getTransportBlocks() {
+        if (mTransportBlocks == null) {
+            return Collections.emptyList();
+        }
+        return mTransportBlocks;
+    }
+
+    /**
+     * Converts this TransportDiscoveryData to byte array
+     *
+     * @return byte array representation of this Transport Discovery Data or null if the
+     *         conversion failed
+     */
+    @Nullable
+    public byte[] toByteArray() {
+        try {
+            ByteBuffer buffer = ByteBuffer.allocate(totalBytes());
+            buffer.put((byte) mTransportDataType);
+            for (TransportBlock transportBlock : getTransportBlocks()) {
+                buffer.put(transportBlock.toByteArray());
+            }
+            return buffer.array();
+        } catch (BufferOverflowException e) {
+            Log.e(TAG, "Error converting to byte array: " + e.toString());
+            return null;
+        }
+    }
+
+    /**
+     * @return total byte count of this TransportDataDiscovery
+     */
+    public int totalBytes() {
+        int size = 1; // Counting Transport Data Type here.
+        for (TransportBlock transportBlock : getTransportBlocks()) {
+            size += transportBlock.totalBytes();
+        }
+        return size;
+    }
+}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index e6df79e..25d1d53 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3004,10 +3004,11 @@
      * {@link android.os.Build.VERSION_CODES#TIRAMISU},
      *              either {@link #RECEIVER_EXPORTED} or
      * {@link #RECEIVER_NOT_EXPORTED} must be specified if the receiver isn't being registered
-     *              for protected broadcasts or an exception will be thrown. If
+     *              for
+     *              <a href="https://developer.android.com/guide/components/broadcasts#system-broadcasts">system broadcasts</a> or an exception will be thrown. If
      *              {@link #RECEIVER_EXPORTED} is specified, a receiver may additionally
      *              specify {@link #RECEIVER_VISIBLE_TO_INSTANT_APPS}. For a complete list of
-     *              protected broadcast actions, see the BROADCAST_ACTIONS.TXT file in the
+     *              system broadcast actions, see the BROADCAST_ACTIONS.TXT file in the
      *              Android SDK. If both {@link #RECEIVER_EXPORTED} and
      *              {@link #RECEIVER_NOT_EXPORTED} are specified, an exception will be thrown as
      *              well.
@@ -3082,12 +3083,18 @@
      *      no permission is required.
      * @param scheduler Handler identifying the thread that will receive
      *      the Intent.  If null, the main thread of the process will be used.
-     * @param flags Additional options for the receiver. As of
-     * Android T, either {@link #RECEIVER_EXPORTED} or
+     * @param flags Additional options for the receiver. For apps targeting
+     * {@link android.os.Build.VERSION_CODES#TIRAMISU},
+     *              either {@link #RECEIVER_EXPORTED} or
      * {@link #RECEIVER_NOT_EXPORTED} must be specified if the receiver isn't being registered
-     *            for protected broadcasts, and may additionally specify
-     *            {@link #RECEIVER_VISIBLE_TO_INSTANT_APPS} if {@link #RECEIVER_EXPORTED} is
-     *            specified.
+     *              for
+     *              <a href="https://developer.android.com/guide/components/broadcasts#system-broadcasts">system broadcasts</a> or an exception will be thrown. If
+     *              {@link #RECEIVER_EXPORTED} is specified, a receiver may additionally
+     *              specify {@link #RECEIVER_VISIBLE_TO_INSTANT_APPS}. For a complete list of
+     *              system broadcast actions, see the BROADCAST_ACTIONS.TXT file in the
+     *              Android SDK. If both {@link #RECEIVER_EXPORTED} and
+     *              {@link #RECEIVER_NOT_EXPORTED} are specified, an exception will be thrown as
+     *              well.
      *
      * @return The first sticky intent found that matches <var>filter</var>,
      *         or null if there are none.
@@ -3146,10 +3153,18 @@
      *      no permission is required.
      * @param scheduler Handler identifying the thread that will receive
      *      the Intent. If {@code null}, the main thread of the process will be used.
-     * @param flags Additional options for the receiver. As of
-     *      Android T, either {@link #RECEIVER_EXPORTED} or
-     *      {@link #RECEIVER_NOT_EXPORTED} must be specified if the receiver isn't being
-     *      registered for protected broadcasts
+     * @param flags Additional options for the receiver. For apps targeting
+     * {@link android.os.Build.VERSION_CODES#TIRAMISU},
+     *              either {@link #RECEIVER_EXPORTED} or
+     * {@link #RECEIVER_NOT_EXPORTED} must be specified if the receiver isn't being registered
+     *              for
+     *              <a href="https://developer.android.com/guide/components/broadcasts#system-broadcasts">system broadcasts</a> or an exception will be thrown. If
+     *              {@link #RECEIVER_EXPORTED} is specified, a receiver may additionally
+     *              specify {@link #RECEIVER_VISIBLE_TO_INSTANT_APPS}. For a complete list of
+     *              system broadcast actions, see the BROADCAST_ACTIONS.TXT file in the
+     *              Android SDK. If both {@link #RECEIVER_EXPORTED} and
+     *              {@link #RECEIVER_NOT_EXPORTED} are specified, an exception will be thrown as
+     *              well.
      *
      * @return The first sticky intent found that matches <var>filter</var>,
      *         or {@code null} if there are none.
@@ -3213,10 +3228,18 @@
      *      no permission is required.
      * @param scheduler Handler identifying the thread that will receive
      *      the Intent.  If null, the main thread of the process will be used.
-     * @param flags Additional options for the receiver. As of
-     *      Android T, either {@link #RECEIVER_EXPORTED} or
-     *      {@link #RECEIVER_NOT_EXPORTED} must be specified if the receiver isn't being
-     *      registered for protected broadcasts
+     * @param flags Additional options for the receiver. For apps targeting
+     * {@link android.os.Build.VERSION_CODES#TIRAMISU},
+     *              either {@link #RECEIVER_EXPORTED} or
+     * {@link #RECEIVER_NOT_EXPORTED} must be specified if the receiver isn't being registered
+     *              for
+     *              <a href="https://developer.android.com/guide/components/broadcasts#system-broadcasts">system broadcasts</a> or an exception will be thrown. If
+     *              {@link #RECEIVER_EXPORTED} is specified, a receiver may additionally
+     *              specify {@link #RECEIVER_VISIBLE_TO_INSTANT_APPS}. For a complete list of
+     *              system broadcast actions, see the BROADCAST_ACTIONS.TXT file in the
+     *              Android SDK. If both {@link #RECEIVER_EXPORTED} and
+     *              {@link #RECEIVER_NOT_EXPORTED} are specified, an exception will be thrown as
+     *              well.
      *
      * @return The first sticky intent found that matches <var>filter</var>,
      *         or null if there are none.
@@ -3818,6 +3841,7 @@
             //@hide: SPEECH_RECOGNITION_SERVICE,
             UWB_SERVICE,
             MEDIA_METRICS_SERVICE,
+            SUPPLEMENTAL_PROCESS_SERVICE,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface ServiceName {}
@@ -5505,6 +5529,12 @@
     public static final String STATS_COMPANION_SERVICE = "statscompanion";
 
     /**
+     * Service to assist statsd in logging atoms from bootstrap atoms.
+     * @hide
+     */
+    public static final String STATS_BOOTSTRAP_ATOM_SERVICE = "statsbootstrap";
+
+    /**
      * Use with {@link #getSystemService(String)} to retrieve an {@link android.app.StatsManager}.
      * @hide
      */
@@ -5834,6 +5864,13 @@
     public static final String LOCALE_SERVICE = "locale";
 
     /**
+     * Use with {@link #getSystemService(String)} to retrieve a Supplemental Process Manager.
+     *
+     * @see #getSystemService(String)
+     */
+    public static final String SUPPLEMENTAL_PROCESS_SERVICE = "supplemental_process";
+
+    /**
      * Determine whether the given permission is allowed for a particular
      * process and user ID running in the system.
      *
@@ -6507,30 +6544,24 @@
             @NonNull Configuration overrideConfiguration);
 
     /**
-     * Return a new Context object for the current Context but whose resources
-     * are adjusted to match the metrics of the given Display.  Each call to this method
-     * returns a new instance of a Context object; Context objects are not
-     * shared, however common state (ClassLoader, other Resources for the
-     * same configuration) may be so the Context itself can be fairly lightweight.
-     *
-     * To obtain an instance of a {@link WindowManager} (see {@link #getSystemService(String)}) that
-     * is configured to show windows on the given display call
-     * {@link #createWindowContext(int, Bundle)} on the returned display Context or use an
-     * {@link android.app.Activity}.
-     *
+     * Returns a new <code>Context</code> object from the current context but with resources
+     * adjusted to match the metrics of <code>display</code>. Each call to this method
+     * returns a new instance of a context object. Context objects are not shared; however,
+     * common state (such as the {@link ClassLoader} and other resources for the same
+     * configuration) can be shared, so the <code>Context</code> itself is lightweight.
      * <p>
-     * Note that invoking #createDisplayContext(Display) from an UI context is not regarded
-     * as an UI context. In other words, it is not suggested to access UI components (such as
-     * obtain a {@link WindowManager} by {@link #getSystemService(String)})
-     * from the context created from #createDisplayContext(Display).
-     * </p>
+     * To obtain an instance of {@link WindowManager} configured to show windows on the given
+     * display, call {@link #createWindowContext(int, Bundle)} on the returned display context,
+     * then call {@link #getSystemService(String)} or {@link #getSystemService(Class)} on the
+     * returned window context.
+     * <p>
+     * <b>Note:</b> The context returned by <code>createDisplayContext(Display)</code> is not a UI
+     * context. Do not access UI components or obtain a {@link WindowManager} from the context
+     * created by <code>createDisplayContext(Display)</code>.
      *
-     * @param display A {@link Display} object specifying the display for whose metrics the
-     * Context's resources should be tailored.
+     * @param display The display to which the current context's resources are adjusted.
      *
-     * @return A {@link Context} for the display.
-     *
-     * @see #getSystemService(String)
+     * @return A context for the display.
      */
     @DisplayContext
     public abstract Context createDisplayContext(@NonNull Display display);
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 3c9b1f8..2b8681a 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -5522,8 +5522,8 @@
 
     /**
      * A boolean extra, when used with {@link #ACTION_VIEW_PERMISSION_USAGE_FOR_PERIOD},
-     * that specifies whether the system displayed attribution information in the
-     * permission usage system UI for the chosen entry.
+     * that specifies whether the permission usage system UI is showing attribution information
+     * for the chosen entry.
      *
      * <p> The extra can only be true if application has specified attributionsAreUserVisible
      * in its manifest. </p>
@@ -6415,6 +6415,7 @@
             FLAG_RECEIVER_FROM_SHELL,
             FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS,
             FLAG_RECEIVER_OFFLOAD,
+            FLAG_RECEIVER_OFFLOAD_FOREGROUND,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface Flags {}
@@ -6460,6 +6461,7 @@
             FLAG_RECEIVER_FROM_SHELL,
             FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS,
             FLAG_RECEIVER_OFFLOAD,
+            FLAG_RECEIVER_OFFLOAD_FOREGROUND,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface MutableFlags {}
@@ -6914,6 +6916,14 @@
      */
     public static final int FLAG_RECEIVER_OFFLOAD = 0x80000000;
     /**
+    /**
+     * If set, when sending a broadcast the recipient will run on the system dedicated queue.
+     *
+     * @hide
+     */
+    public static final int FLAG_RECEIVER_OFFLOAD_FOREGROUND = 0x00000800;
+
+    /**
      * If this is an ordered broadcast, don't allow receivers to abort the broadcast.
      * They can still propagate results through to later receivers, but they can not prevent
      * later receivers from seeing the broadcast.
diff --git a/core/java/android/content/pm/parsing/ParsingPackage.java b/core/java/android/content/pm/parsing/ParsingPackage.java
index 14d69cc..056f99f 100644
--- a/core/java/android/content/pm/parsing/ParsingPackage.java
+++ b/core/java/android/content/pm/parsing/ParsingPackage.java
@@ -362,6 +362,9 @@
 
     ParsingPackage setAttributionsAreUserVisible(boolean attributionsAreUserVisible);
 
+    ParsingPackage setResetEnabledSettingsOnAppDataCleared(
+            boolean resetEnabledSettingsOnAppDataCleared);
+
     // TODO(b/135203078): This class no longer has access to ParsedPackage, find a replacement
     //  for moving to the next step
     @CallSuper
diff --git a/core/java/android/content/pm/parsing/ParsingPackageImpl.java b/core/java/android/content/pm/parsing/ParsingPackageImpl.java
index edddf40..f07f382 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageImpl.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageImpl.java
@@ -517,6 +517,7 @@
         private static final long DISALLOW_PROFILING = 1L << 45;
         private static final long REQUEST_FOREGROUND_SERVICE_EXEMPTION = 1L << 46;
         private static final long ATTRIBUTIONS_ARE_USER_VISIBLE = 1L << 47;
+        private static final long RESET_ENABLED_SETTINGS_ON_APP_DATA_CLEARED = 1L << 48;
     }
 
     private ParsingPackageImpl setBoolean(@Booleans.Values long flag, boolean value) {
@@ -2216,6 +2217,11 @@
     }
 
     @Override
+    public boolean isResetEnabledSettingsOnAppDataCleared() {
+        return getBoolean(Booleans.RESET_ENABLED_SETTINGS_ON_APP_DATA_CLEARED);
+    }
+
+    @Override
     public ParsingPackageImpl setBaseRevisionCode(int value) {
         baseRevisionCode = value;
         return this;
@@ -2771,4 +2777,12 @@
         setBoolean(Booleans.ATTRIBUTIONS_ARE_USER_VISIBLE, attributionsAreUserVisible);
         return this;
     }
+
+    @Override
+    public ParsingPackage setResetEnabledSettingsOnAppDataCleared(
+            boolean resetEnabledSettingsOnAppDataCleared) {
+        setBoolean(Booleans.RESET_ENABLED_SETTINGS_ON_APP_DATA_CLEARED,
+                resetEnabledSettingsOnAppDataCleared);
+        return this;
+    }
 }
diff --git a/core/java/android/content/pm/parsing/ParsingPackageRead.java b/core/java/android/content/pm/parsing/ParsingPackageRead.java
index 4a249bb..2933f95 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageRead.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageRead.java
@@ -297,4 +297,12 @@
      * @see R.styleable#AndroidManifestService_visibleToInstantApps
      */
     boolean isVisibleToInstantApps();
+
+    /**
+     * Whether the enabled settings of components in the application should be reset to the default,
+     * when the application's user data is cleared.
+     *
+     * @see R.styleable#AndroidManifestApplication_resetEnabledSettingsOnAppDataCleared
+     */
+    boolean isResetEnabledSettingsOnAppDataCleared();
 }
diff --git a/core/java/android/content/pm/parsing/ParsingPackageUtils.java b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
index e3a5de5..d2ac8739 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageUtils.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
@@ -2288,6 +2288,9 @@
                 .setVmSafeMode(bool(false, R.styleable.AndroidManifestApplication_vmSafeMode, sa))
                 .setAutoRevokePermissions(anInt(R.styleable.AndroidManifestApplication_autoRevokePermissions, sa))
                 .setAttributionsAreUserVisible(bool(false, R.styleable.AndroidManifestApplication_attributionsAreUserVisible, sa))
+                .setResetEnabledSettingsOnAppDataCleared(bool(false,
+                    R.styleable.AndroidManifestApplication_resetEnabledSettingsOnAppDataCleared,
+                    sa))
                 // targetSdkVersion gated
                 .setAllowAudioPlaybackCapture(bool(targetSdk >= Build.VERSION_CODES.Q, R.styleable.AndroidManifestApplication_allowAudioPlaybackCapture, sa))
                 .setBaseHardwareAccelerated(bool(targetSdk >= Build.VERSION_CODES.ICE_CREAM_SANDWICH, R.styleable.AndroidManifestApplication_hardwareAccelerated, sa))
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 96a18dc..3c8b6e9 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -1323,7 +1323,7 @@
      * <p>Maximum flashlight brightness level.</p>
      * <p>If this value is greater than 1, then the device supports controlling the
      * flashlight brightness level via
-     * {android.hardware.camera2.CameraManager#setTorchStrengthLevel}.
+     * {android.hardware.camera2.CameraManager#turnOnTorchWithStrengthLevel}.
      * If this value is equal to 1, flashlight brightness control is not supported.
      * The value for this key will be null for devices with no flash unit.</p>
      * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
@@ -1335,7 +1335,7 @@
 
     /**
      * <p>Default flashlight brightness level to be set via
-     * {android.hardware.camera2.CameraManager#setTorchStrengthLevel}.</p>
+     * {android.hardware.camera2.CameraManager#turnOnTorchWithStrengthLevel}.</p>
      * <p>If flash unit is available this will be greater than or equal to 1 and less
      * or equal to <code>{@link CameraCharacteristics#FLASH_INFO_STRENGTH_MAXIMUM_LEVEL android.flash.info.strengthMaximumLevel}</code>.</p>
      * <p>Setting flashlight brightness above the default level
diff --git a/core/java/android/hardware/display/AmbientDisplayConfiguration.java b/core/java/android/hardware/display/AmbientDisplayConfiguration.java
index 2b52e96..7d71984 100644
--- a/core/java/android/hardware/display/AmbientDisplayConfiguration.java
+++ b/core/java/android/hardware/display/AmbientDisplayConfiguration.java
@@ -109,7 +109,9 @@
 
     /** {@hide} */
     public boolean quickPickupSensorEnabled(int user) {
-        return !TextUtils.isEmpty(quickPickupSensorType()) && !alwaysOnEnabled(user);
+        return !TextUtils.isEmpty(quickPickupSensorType())
+                && pickupGestureEnabled(user)
+                && !alwaysOnEnabled(user);
     }
 
     /** {@hide} */
diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java
index fd34fa4..83e1061 100644
--- a/core/java/android/hardware/display/DisplayManagerInternal.java
+++ b/core/java/android/hardware/display/DisplayManagerInternal.java
@@ -30,6 +30,7 @@
 import android.view.DisplayInfo;
 import android.view.SurfaceControl;
 import android.view.SurfaceControl.Transaction;
+import android.window.DisplayWindowPolicyController;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -379,6 +380,14 @@
     public abstract void onEarlyInteractivityChange(boolean interactive);
 
     /**
+     * Get {@link DisplayWindowPolicyController} associated to the {@link DisplayInfo#displayId}
+     *
+     * @param displayId The id of the display.
+     * @return The associated {@link DisplayWindowPolicyController}.
+     */
+    public abstract DisplayWindowPolicyController getDisplayWindowPolicyController(int displayId);
+
+    /**
      * Describes the requested power state of the display.
      *
      * This object is intended to describe the general characteristics of the
diff --git a/core/java/android/hardware/input/InputDeviceVibrator.java b/core/java/android/hardware/input/InputDeviceVibrator.java
index 653c622..ce6b523 100644
--- a/core/java/android/hardware/input/InputDeviceVibrator.java
+++ b/core/java/android/hardware/input/InputDeviceVibrator.java
@@ -174,8 +174,8 @@
      * @hide
      */
     @Override
-    public void vibrate(int uid, String opPkg, @NonNull VibrationEffect effect,
-            String reason, @NonNull VibrationAttributes attributes) {
+    public void vibrate(int uid, String opPkg, @NonNull VibrationEffect effect, String reason,
+            @NonNull VibrationAttributes attributes) {
         mInputManager.vibrate(mDeviceId, effect, mToken);
     }
 
diff --git a/core/java/android/net/nsd/INsdManager.aidl b/core/java/android/net/nsd/INsdManager.aidl
index e9e8935..89e9cdb 100644
--- a/core/java/android/net/nsd/INsdManager.aidl
+++ b/core/java/android/net/nsd/INsdManager.aidl
@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2012, The Android Open Source Project
+ * Copyright (c) 2021, The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,16 +16,15 @@
 
 package android.net.nsd;
 
+import android.net.nsd.INsdManagerCallback;
+import android.net.nsd.INsdServiceConnector;
 import android.os.Messenger;
 
 /**
- * Interface that NsdService implements
+ * Interface that NsdService implements to connect NsdManager clients.
  *
  * {@hide}
  */
-interface INsdManager
-{
-    @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
-    Messenger getMessenger();
-    void setEnabled(boolean enable);
+interface INsdManager {
+    INsdServiceConnector connect(INsdManagerCallback cb);
 }
diff --git a/core/java/android/net/nsd/INsdManagerCallback.aidl b/core/java/android/net/nsd/INsdManagerCallback.aidl
new file mode 100644
index 0000000..1a262ec
--- /dev/null
+++ b/core/java/android/net/nsd/INsdManagerCallback.aidl
@@ -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.net.nsd;
+
+import android.os.Messenger;
+import android.net.nsd.NsdServiceInfo;
+
+/**
+ * Callbacks from NsdService to NsdManager
+ * @hide
+ */
+oneway interface INsdManagerCallback {
+    void onDiscoverServicesStarted(int listenerKey, in NsdServiceInfo info);
+    void onDiscoverServicesFailed(int listenerKey, int error);
+    void onServiceFound(int listenerKey, in NsdServiceInfo info);
+    void onServiceLost(int listenerKey, in NsdServiceInfo info);
+    void onStopDiscoveryFailed(int listenerKey, int error);
+    void onStopDiscoverySucceeded(int listenerKey);
+    void onRegisterServiceFailed(int listenerKey, int error);
+    void onRegisterServiceSucceeded(int listenerKey, in NsdServiceInfo info);
+    void onUnregisterServiceFailed(int listenerKey, int error);
+    void onUnregisterServiceSucceeded(int listenerKey);
+    void onResolveServiceFailed(int listenerKey, int error);
+    void onResolveServiceSucceeded(int listenerKey, in NsdServiceInfo info);
+}
diff --git a/core/java/android/net/nsd/INsdServiceConnector.aidl b/core/java/android/net/nsd/INsdServiceConnector.aidl
new file mode 100644
index 0000000..b06ae55
--- /dev/null
+++ b/core/java/android/net/nsd/INsdServiceConnector.aidl
@@ -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 android.net.nsd;
+
+import android.net.nsd.INsdManagerCallback;
+import android.net.nsd.NsdServiceInfo;
+import android.os.Messenger;
+
+/**
+ * Interface that NsdService implements for each NsdManager client.
+ *
+ * {@hide}
+ */
+interface INsdServiceConnector {
+    void registerService(int listenerKey, in NsdServiceInfo serviceInfo);
+    void unregisterService(int listenerKey);
+    void discoverServices(int listenerKey, in NsdServiceInfo serviceInfo);
+    void stopDiscovery(int listenerKey);
+    void resolveService(int listenerKey, in NsdServiceInfo serviceInfo);
+    void startDaemon();
+}
\ No newline at end of file
diff --git a/core/java/android/net/nsd/NsdManager.java b/core/java/android/net/nsd/NsdManager.java
index ae8d010..6c597e2 100644
--- a/core/java/android/net/nsd/NsdManager.java
+++ b/core/java/android/net/nsd/NsdManager.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 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.
@@ -31,17 +31,13 @@
 import android.os.HandlerThread;
 import android.os.Looper;
 import android.os.Message;
-import android.os.Messenger;
 import android.os.RemoteException;
 import android.util.Log;
 import android.util.SparseArray;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.AsyncChannel;
 import com.android.internal.util.Protocol;
 
-import java.util.concurrent.CountDownLatch;
-
 /**
  * The Network Service Discovery Manager class provides the API to discover services
  * on a network. As an example, if device A and device B are connected over a Wi-Fi
@@ -234,6 +230,11 @@
     /** @hide */
     public static final int NATIVE_DAEMON_EVENT                     = BASE + 26;
 
+    /** @hide */
+    public static final int REGISTER_CLIENT                         = BASE + 27;
+    /** @hide */
+    public static final int UNREGISTER_CLIENT                       = BASE + 28;
+
     /** Dns based service discovery protocol */
     public static final int PROTOCOL_DNS_SD = 0x0001;
 
@@ -274,7 +275,7 @@
 
     private static final int FIRST_LISTENER_KEY = 1;
 
-    private final INsdManager mService;
+    private final INsdServiceConnector mService;
     private final Context mContext;
 
     private int mListenerKey = FIRST_LISTENER_KEY;
@@ -282,9 +283,7 @@
     private final SparseArray<NsdServiceInfo> mServiceMap = new SparseArray<>();
     private final Object mMapLock = new Object();
 
-    private final AsyncChannel mAsyncChannel = new AsyncChannel();
-    private ServiceHandler mHandler;
-    private final CountDownLatch mConnected = new CountDownLatch(1);
+    private final ServiceHandler mHandler;
 
     /**
      * Create a new Nsd instance. Applications use
@@ -295,18 +294,108 @@
      * is a system private class.
      */
     public NsdManager(Context context, INsdManager service) {
-        mService = service;
         mContext = context;
-        init();
+
+        HandlerThread t = new HandlerThread("NsdManager");
+        t.start();
+        mHandler = new ServiceHandler(t.getLooper());
+
+        try {
+            mService = service.connect(new NsdCallbackImpl(mHandler));
+        } catch (RemoteException e) {
+            throw new RuntimeException("Failed to connect to NsdService");
+        }
+
+        // Only proactively start the daemon if the target SDK < S, otherwise the internal service
+        // would automatically start/stop the native daemon as needed.
+        if (!CompatChanges.isChangeEnabled(RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS)) {
+            try {
+                mService.startDaemon();
+            } catch (RemoteException e) {
+                Log.e(TAG, "Failed to proactively start daemon");
+                // Continue: the daemon can still be started on-demand later
+            }
+        }
     }
 
-    /**
-     * @hide
-     */
-    @VisibleForTesting
-    public void disconnect() {
-        mAsyncChannel.disconnect();
-        mHandler.getLooper().quitSafely();
+    private static class NsdCallbackImpl extends INsdManagerCallback.Stub {
+        private final Handler mServHandler;
+
+        NsdCallbackImpl(Handler serviceHandler) {
+            mServHandler = serviceHandler;
+        }
+
+        private void sendInfo(int message, int listenerKey, NsdServiceInfo info) {
+            mServHandler.sendMessage(mServHandler.obtainMessage(message, 0, listenerKey, info));
+        }
+
+        private void sendError(int message, int listenerKey, int error) {
+            mServHandler.sendMessage(mServHandler.obtainMessage(message, error, listenerKey));
+        }
+
+        private void sendNoArg(int message, int listenerKey) {
+            mServHandler.sendMessage(mServHandler.obtainMessage(message, 0, listenerKey));
+        }
+
+        @Override
+        public void onDiscoverServicesStarted(int listenerKey, NsdServiceInfo info) {
+            sendInfo(DISCOVER_SERVICES_STARTED, listenerKey, info);
+        }
+
+        @Override
+        public void onDiscoverServicesFailed(int listenerKey, int error) {
+            sendError(DISCOVER_SERVICES_FAILED, listenerKey, error);
+        }
+
+        @Override
+        public void onServiceFound(int listenerKey, NsdServiceInfo info) {
+            sendInfo(SERVICE_FOUND, listenerKey, info);
+        }
+
+        @Override
+        public void onServiceLost(int listenerKey, NsdServiceInfo info) {
+            sendInfo(SERVICE_LOST, listenerKey, info);
+        }
+
+        @Override
+        public void onStopDiscoveryFailed(int listenerKey, int error) {
+            sendError(STOP_DISCOVERY_FAILED, listenerKey, error);
+        }
+
+        @Override
+        public void onStopDiscoverySucceeded(int listenerKey) {
+            sendNoArg(STOP_DISCOVERY_SUCCEEDED, listenerKey);
+        }
+
+        @Override
+        public void onRegisterServiceFailed(int listenerKey, int error) {
+            sendError(REGISTER_SERVICE_FAILED, listenerKey, error);
+        }
+
+        @Override
+        public void onRegisterServiceSucceeded(int listenerKey, NsdServiceInfo info) {
+            sendInfo(REGISTER_SERVICE_SUCCEEDED, listenerKey, info);
+        }
+
+        @Override
+        public void onUnregisterServiceFailed(int listenerKey, int error) {
+            sendError(UNREGISTER_SERVICE_FAILED, listenerKey, error);
+        }
+
+        @Override
+        public void onUnregisterServiceSucceeded(int listenerKey) {
+            sendNoArg(UNREGISTER_SERVICE_SUCCEEDED, listenerKey);
+        }
+
+        @Override
+        public void onResolveServiceFailed(int listenerKey, int error) {
+            sendError(RESOLVE_SERVICE_FAILED, listenerKey, error);
+        }
+
+        @Override
+        public void onResolveServiceSucceeded(int listenerKey, NsdServiceInfo info) {
+            sendInfo(RESOLVE_SERVICE_SUCCEEDED, listenerKey, info);
+        }
     }
 
     /**
@@ -376,19 +465,6 @@
         public void handleMessage(Message message) {
             final int what = message.what;
             final int key = message.arg2;
-            switch (what) {
-                case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
-                    mAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
-                    return;
-                case AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED:
-                    mConnected.countDown();
-                    return;
-                case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
-                    Log.e(TAG, "Channel lost");
-                    return;
-                default:
-                    break;
-            }
             final Object listener;
             final NsdServiceInfo ns;
             synchronized (mMapLock) {
@@ -504,36 +580,6 @@
     }
 
     /**
-     * Initialize AsyncChannel
-     */
-    private void init() {
-        final Messenger messenger = getMessenger();
-        if (messenger == null) {
-            fatal("Failed to obtain service Messenger");
-        }
-        HandlerThread t = new HandlerThread("NsdManager");
-        t.start();
-        mHandler = new ServiceHandler(t.getLooper());
-        mAsyncChannel.connect(mContext, mHandler, messenger);
-        try {
-            mConnected.await();
-        } catch (InterruptedException e) {
-            fatal("Interrupted wait at init");
-        }
-        if (CompatChanges.isChangeEnabled(RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS)) {
-            return;
-        }
-        // Only proactively start the daemon if the target SDK < S, otherwise the internal service
-        // would automatically start/stop the native daemon as needed.
-        mAsyncChannel.sendMessage(DAEMON_STARTUP);
-    }
-
-    private static void fatal(String msg) {
-        Log.e(TAG, msg);
-        throw new RuntimeException(msg);
-    }
-
-    /**
      * Register a service to be discovered by other services.
      *
      * <p> The function call immediately returns after sending a request to register service
@@ -556,7 +602,11 @@
         checkServiceInfo(serviceInfo);
         checkProtocol(protocolType);
         int key = putListener(listener, serviceInfo);
-        mAsyncChannel.sendMessage(REGISTER_SERVICE, 0, key, serviceInfo);
+        try {
+            mService.registerService(key, serviceInfo);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
     }
 
     /**
@@ -574,7 +624,11 @@
      */
     public void unregisterService(RegistrationListener listener) {
         int id = getListenerKey(listener);
-        mAsyncChannel.sendMessage(UNREGISTER_SERVICE, 0, id);
+        try {
+            mService.unregisterService(id);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
     }
 
     /**
@@ -613,7 +667,11 @@
         s.setServiceType(serviceType);
 
         int key = putListener(listener, s);
-        mAsyncChannel.sendMessage(DISCOVER_SERVICES, 0, key, s);
+        try {
+            mService.discoverServices(key, s);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
     }
 
     /**
@@ -634,7 +692,11 @@
      */
     public void stopServiceDiscovery(DiscoveryListener listener) {
         int id = getListenerKey(listener);
-        mAsyncChannel.sendMessage(STOP_DISCOVERY, 0, id);
+        try {
+            mService.stopDiscovery(id);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
     }
 
     /**
@@ -649,29 +711,10 @@
     public void resolveService(NsdServiceInfo serviceInfo, ResolveListener listener) {
         checkServiceInfo(serviceInfo);
         int key = putListener(listener, serviceInfo);
-        mAsyncChannel.sendMessage(RESOLVE_SERVICE, 0, key, serviceInfo);
-    }
-
-    /** Internal use only @hide */
-    public void setEnabled(boolean enabled) {
         try {
-            mService.setEnabled(enabled);
+            mService.resolveService(key, serviceInfo);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * Get a reference to NsdService handler. This is used to establish
-     * an AsyncChannel communication with the service
-     *
-     * @return Messenger pointing to the NsdService handler
-     */
-    private Messenger getMessenger() {
-        try {
-            return mService.getMessenger();
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            e.rethrowFromSystemServer();
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FlagWriter.kt b/core/java/android/net/nsd/NsdServiceInfo.aidl
similarity index 84%
copy from packages/SystemUI/src/com/android/systemui/flags/FlagWriter.kt
copy to core/java/android/net/nsd/NsdServiceInfo.aidl
index bacc66b..657bdd1 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FlagWriter.kt
+++ b/core/java/android/net/nsd/NsdServiceInfo.aidl
@@ -14,8 +14,6 @@
  * limitations under the License.
  */
 
-package com.android.systemui.flags
+package android.net.nsd;
 
-interface FlagWriter {
-    fun setEnabled(key: Int, value: Boolean) {}
-}
\ No newline at end of file
+@JavaOnlyStableParcelable parcelable NsdServiceInfo;
\ No newline at end of file
diff --git a/core/java/android/nfc/cardemulation/ApduServiceInfo.java b/core/java/android/nfc/cardemulation/ApduServiceInfo.java
index 0af322e..0954013 100644
--- a/core/java/android/nfc/cardemulation/ApduServiceInfo.java
+++ b/core/java/android/nfc/cardemulation/ApduServiceInfo.java
@@ -528,6 +528,7 @@
     public String toString() {
         StringBuilder out = new StringBuilder("ApduService: ");
         out.append(getComponent());
+        out.append(", UID: " + mUid);
         out.append(", description: " + mDescription);
         out.append(", Static AID Groups: ");
         for (AidGroup aidGroup : mStaticAidGroups.values()) {
@@ -546,7 +547,8 @@
         if (!(o instanceof ApduServiceInfo)) return false;
         ApduServiceInfo thatService = (ApduServiceInfo) o;
 
-        return thatService.getComponent().equals(this.getComponent());
+        return thatService.getComponent().equals(this.getComponent())
+                && thatService.getUid() == this.getUid();
     }
 
     @Override
@@ -619,8 +621,9 @@
     };
 
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        pw.println("    " + getComponent() +
-                " (Description: " + getDescription() + ")");
+        pw.println("    " + getComponent()
+                + " (Description: " + getDescription() + ")"
+                + " (UID: " + getUid() + ")");
         if (mOnHost) {
             pw.println("    On Host Service");
         } else {
diff --git a/core/java/android/nfc/cardemulation/CardEmulation.java b/core/java/android/nfc/cardemulation/CardEmulation.java
index d498535..0a9fe90 100644
--- a/core/java/android/nfc/cardemulation/CardEmulation.java
+++ b/core/java/android/nfc/cardemulation/CardEmulation.java
@@ -30,6 +30,7 @@
 import android.nfc.INfcCardEmulation;
 import android.nfc.NfcAdapter;
 import android.os.RemoteException;
+import android.os.UserHandle;
 import android.provider.Settings;
 import android.provider.Settings.SettingNotFoundException;
 import android.util.Log;
@@ -83,6 +84,13 @@
     public static final String EXTRA_SERVICE_COMPONENT = "component";
 
     /**
+     * The caller userId extra for {@link #ACTION_CHANGE_DEFAULT}.
+     *
+     * @see #ACTION_CHANGE_DEFAULT
+     */
+    public static final String EXTRA_USERID = "android.nfc.cardemulation.extra.USERID";
+
+    /**
      * Category used for NFC payment services.
      */
     public static final String CATEGORY_PAYMENT = "payment";
@@ -269,8 +277,8 @@
         if (CATEGORY_PAYMENT.equals(category)) {
             boolean preferForeground = false;
             try {
-                preferForeground = Settings.Secure.getInt(mContext.getContentResolver(),
-                        Settings.Secure.NFC_PAYMENT_FOREGROUND) != 0;
+                preferForeground = Settings.Secure.getIntForUser(mContext.getContentResolver(),
+                        Settings.Secure.NFC_PAYMENT_FOREGROUND, UserHandle.myUserId()) != 0;
             } catch (SettingNotFoundException e) {
             }
             return preferForeground;
@@ -829,6 +837,28 @@
     /**
      * @hide
      */
+    public boolean setDefaultForNextTap(int userId, ComponentName service) {
+        try {
+            return sService.setDefaultForNextTap(userId, service);
+        } catch (RemoteException e) {
+            // Try one more time
+            recoverService();
+            if (sService == null) {
+                Log.e(TAG, "Failed to recover CardEmulationService.");
+                return false;
+            }
+            try {
+                return sService.setDefaultForNextTap(userId, service);
+            } catch (RemoteException ee) {
+                Log.e(TAG, "Failed to reach CardEmulationService.");
+                return false;
+            }
+        }
+    }
+
+    /**
+     * @hide
+     */
     public List<ApduServiceInfo> getServices(String category) {
         try {
             return sService.getServices(mContext.getUserId(), category);
@@ -849,6 +879,28 @@
     }
 
     /**
+     * @hide
+     */
+    public List<ApduServiceInfo> getServices(String category, int userId) {
+        try {
+            return sService.getServices(userId, category);
+        } catch (RemoteException e) {
+            // Try one more time
+            recoverService();
+            if (sService == null) {
+                Log.e(TAG, "Failed to recover CardEmulationService.");
+                return null;
+            }
+            try {
+                return sService.getServices(userId, category);
+            } catch (RemoteException ee) {
+                Log.e(TAG, "Failed to reach CardEmulationService.");
+                return null;
+            }
+        }
+    }
+
+    /**
      * A valid AID according to ISO/IEC 7816-4:
      * <ul>
      * <li>Has >= 5 bytes and <=16 bytes (>=10 hex chars and <= 32 hex chars)
diff --git a/core/java/android/nfc/cardemulation/NfcFCardEmulation.java b/core/java/android/nfc/cardemulation/NfcFCardEmulation.java
index 80e8579..557e41a 100644
--- a/core/java/android/nfc/cardemulation/NfcFCardEmulation.java
+++ b/core/java/android/nfc/cardemulation/NfcFCardEmulation.java
@@ -25,7 +25,6 @@
 import android.nfc.INfcFCardEmulation;
 import android.nfc.NfcAdapter;
 import android.os.RemoteException;
-import android.os.UserHandle;
 import android.util.Log;
 
 import java.util.HashMap;
diff --git a/core/java/android/nfc/cardemulation/NfcFServiceInfo.java b/core/java/android/nfc/cardemulation/NfcFServiceInfo.java
index c2b33dd..f8f7dfe 100644
--- a/core/java/android/nfc/cardemulation/NfcFServiceInfo.java
+++ b/core/java/android/nfc/cardemulation/NfcFServiceInfo.java
@@ -237,6 +237,7 @@
     public String toString() {
         StringBuilder out = new StringBuilder("NfcFService: ");
         out.append(getComponent());
+        out.append(", UID: " + mUid);
         out.append(", description: " + mDescription);
         out.append(", System Code: " + mSystemCode);
         if (mDynamicSystemCode != null) {
@@ -257,6 +258,7 @@
         NfcFServiceInfo thatService = (NfcFServiceInfo) o;
 
         if (!thatService.getComponent().equals(this.getComponent())) return false;
+        if (thatService.getUid() != this.getUid()) return false;
         if (!thatService.mSystemCode.equalsIgnoreCase(this.mSystemCode)) return false;
         if (!thatService.mNfcid2.equalsIgnoreCase(this.mNfcid2)) return false;
         if (!thatService.mT3tPmm.equalsIgnoreCase(this.mT3tPmm)) return false;
@@ -321,8 +323,9 @@
     };
 
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        pw.println("    " + getComponent() +
-                " (Description: " + getDescription() + ")");
+        pw.println("    " + getComponent()
+                + " (Description: " + getDescription() + ")"
+                + " (UID: " + getUid() + ")");
         pw.println("    System Code: " + getSystemCode());
         pw.println("    NFCID2: " + getNfcid2());
         pw.println("    T3tPmm: " + getT3tPmm());
diff --git a/core/java/android/os/ExternalVibration.java b/core/java/android/os/ExternalVibration.java
index 0686dd6..4e0995f 100644
--- a/core/java/android/os/ExternalVibration.java
+++ b/core/java/android/os/ExternalVibration.java
@@ -99,7 +99,7 @@
     }
 
     public VibrationAttributes getVibrationAttributes() {
-        return new VibrationAttributes.Builder(mAttrs, null).build();
+        return new VibrationAttributes.Builder(mAttrs).build();
     }
 
     /**
diff --git a/core/java/android/os/IStatsBootstrapAtomService.aidl b/core/java/android/os/IStatsBootstrapAtomService.aidl
new file mode 100644
index 0000000..9d1df67
--- /dev/null
+++ b/core/java/android/os/IStatsBootstrapAtomService.aidl
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * 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;
+
+import android.os.StatsBootstrapAtom;
+
+/**
+ * IBootstrapAtomService interface exposes an interface for processes that launch in the
+ * bootstrap namespace to push atoms to statsd.
+ *
+ * @hide
+ */
+oneway interface IStatsBootstrapAtomService {
+    /**
+     * Push an atom to StatsBootstrapAtomService, which will forward it to statsd.
+     *
+     * @param atom - parcelled representation of the atom to log.
+     *
+     * Errors are reported as service specific errors.
+     */
+    void reportBootstrapAtom(in StatsBootstrapAtom atom);
+}
\ No newline at end of file
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index b839706..50ca9ff 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -20,6 +20,7 @@
 import android.os.Bundle;
 import android.os.IUserRestrictionsListener;
 import android.os.PersistableBundle;
+import android.os.UserHandle;
 import android.os.UserManager;
 import android.content.pm.UserInfo;
 import android.content.IntentSender;
@@ -91,6 +92,9 @@
     boolean markGuestForDeletion(int userId);
     UserInfo findCurrentGuestUser();
     boolean isQuietModeEnabled(int userId);
+    UserHandle createUserWithAttributes(in String userName, in String userType, int flags,
+            in Bitmap userIcon,
+            in String accountName, in String accountType, in PersistableBundle accountOptions);
     void setSeedAccountData(int userId, in String accountName,
             in String accountType, in PersistableBundle accountOptions, boolean persist);
     String getSeedAccountName(int userId);
@@ -98,6 +102,7 @@
     PersistableBundle getSeedAccountOptions(int userId);
     void clearSeedAccountData(int userId);
     boolean someUserHasSeedAccount(in String accountName, in String accountType);
+    boolean someUserHasAccount(in String accountName, in String accountType);
     boolean isProfile(int userId);
     boolean isManagedProfile(int userId);
     boolean isCloneProfile(int userId);
diff --git a/core/java/android/os/NewUserRequest.java b/core/java/android/os/NewUserRequest.java
new file mode 100644
index 0000000..b0e1f91
--- /dev/null
+++ b/core/java/android/os/NewUserRequest.java
@@ -0,0 +1,298 @@
+/*
+ * 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;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.annotation.SystemApi;
+import android.content.pm.UserInfo;
+import android.graphics.Bitmap;
+import android.text.TextUtils;
+
+/**
+ * Contains necessary information to create user using
+ * {@link UserManager#createUser(NewUserRequest)}.
+ *
+ * @hide
+ */
+@SystemApi
+@SuppressLint("PackageLayering")
+public final class NewUserRequest {
+    @Nullable
+    private final String mName;
+    private final boolean mAdmin;
+    private final boolean mEphemeral;
+    @NonNull
+    private final String mUserType;
+    private final Bitmap mUserIcon;
+    private final String mAccountName;
+    private final String mAccountType;
+    private final PersistableBundle mAccountOptions;
+
+    private NewUserRequest(Builder builder) {
+        mName = builder.mName;
+        mAdmin = builder.mAdmin;
+        mEphemeral = builder.mEphemeral;
+        mUserType = builder.mUserType;
+        mUserIcon = builder.mUserIcon;
+        mAccountName = builder.mAccountName;
+        mAccountType = builder.mAccountType;
+        mAccountOptions = builder.mAccountOptions;
+    }
+
+    /**
+     * Returns the name of the user.
+     */
+    @Nullable
+    public String getName() {
+        return mName;
+    }
+
+    /**
+     * Returns whether the user is ephemeral.
+     *
+     * <p> Ephemeral user will be removed after leaving the foreground.
+     */
+    public boolean isEphemeral() {
+        return mEphemeral;
+    }
+
+    /**
+     * Returns whether the user is an admin.
+     *
+     * <p> Admin user is with administrative privileges and such user can create and
+     * delete users.
+     */
+    public boolean isAdmin() {
+        return mAdmin;
+    }
+
+    /**
+     * Returns the calculated flags for user creation.
+     */
+    int getFlags() {
+        int flags = 0;
+        if (isAdmin()) flags |= UserInfo.FLAG_ADMIN;
+        if (isEphemeral()) flags |= UserInfo.FLAG_EPHEMERAL;
+        return flags;
+    }
+
+    /**
+     * Returns the user type.
+     *
+     * <p> Supported types are {@link UserManager.USER_TYPE_FULL_SECONDARY} and
+     * {@link USER_TYPE_FULL_GUEST}
+     */
+    @NonNull
+    public String getUserType() {
+        return mUserType;
+    }
+
+    /**
+     * Returns the user icon.
+     */
+    @Nullable
+    public Bitmap getUserIcon() {
+        return mUserIcon;
+    }
+
+    /**
+     * Returns the account name.
+     */
+    @Nullable
+    public String getAccountName() {
+        return mAccountName;
+    }
+
+    /**
+     * Returns the account type.
+     */
+    @Nullable
+    public String getAccountType() {
+        return mAccountType;
+    }
+
+    /**
+     * Returns the account options.
+     */
+    @SuppressLint("NullableCollection")
+    @Nullable
+    public PersistableBundle getAccountOptions() {
+        return mAccountOptions;
+    }
+
+    @Override
+    public String toString() {
+        return "NewUserRequest{"
+                + "mName='" + mName + '\''
+                + ", mAdmin=" + mAdmin
+                + ", mEphemeral=" + mEphemeral
+                + ", mUserType='" + mUserType + '\''
+                + ", mAccountName='" + mAccountName + '\''
+                + ", mAccountType='" + mAccountType + '\''
+                + ", mAccountOptions=" + mAccountOptions
+                + '}';
+    }
+
+    /**
+     * Builder for building {@link NewUserRequest}
+     */
+    @SuppressLint("PackageLayering")
+    public static final class Builder {
+
+        private String mName;
+        private boolean mAdmin;
+        private boolean mEphemeral;
+        private String mUserType = UserManager.USER_TYPE_FULL_SECONDARY;
+        private Bitmap mUserIcon;
+        private String mAccountName;
+        private String mAccountType;
+        private PersistableBundle mAccountOptions;
+
+        /**
+         * Sets user name.
+         *
+         * @return This object for method chaining.
+         */
+        @NonNull
+        public Builder setName(@Nullable String name) {
+            mName = name;
+            return this;
+        }
+
+        /**
+         * Sets user as admin.
+         *
+         * <p> Admin user is with administrative privileges and such user can create
+         * and delete users.
+         *
+         * @return This object for method chaining.
+         */
+        @NonNull
+        public Builder setAdmin() {
+            mAdmin = true;
+            return this;
+        }
+
+        /**
+         * Sets user as ephemeral.
+         *
+         * <p> Ephemeral user will be removed after leaving the foreground.
+         *
+         * @return This object for method chaining.
+         */
+        @NonNull
+        public Builder setEphemeral() {
+            mEphemeral = true;
+            return this;
+        }
+
+        /**
+         * Sets user type.
+         * <p>
+         * Supported types are {@link UserManager.USER_TYPE_FULL_SECONDARY} and
+         * {@link UserManager.USER_TYPE_FULL_GUEST}. Default value is
+         * {@link UserManager.USER_TYPE_FULL_SECONDARY}.
+         *
+         * @return This object for method chaining.
+         */
+        @NonNull
+        public Builder setUserType(@NonNull String type) {
+            mUserType = type;
+            return this;
+        }
+
+        /**
+         * Sets user icon.
+         *
+         * @return This object for method chaining.
+         */
+        @NonNull
+        public Builder setUserIcon(@Nullable Bitmap userIcon) {
+            mUserIcon = userIcon;
+            return this;
+        }
+
+        /**
+         * Sets account name that will be used by the setup wizard to initialize the user.
+         *
+         * @see android.accounts.Account
+         * @return This object for method chaining.
+         */
+        @NonNull
+        public Builder setAccountName(@Nullable String accountName) {
+            mAccountName = accountName;
+            return this;
+        }
+
+        /**
+         * Sets account type for the account to be created. This is required if the account name
+         * is not null. This will be used by the setup wizard to initialize the user.
+         *
+         * @see android.accounts.Account
+         * @return This object for method chaining.
+         */
+        @NonNull
+        public Builder setAccountType(@Nullable String accountType) {
+            mAccountType = accountType;
+            return this;
+        }
+
+        /**
+         * Sets account options that can contain account-specific extra information
+         * to be used by setup wizard to initialize the account for the user.
+         *
+         * @return This object for method chaining.
+         */
+        @NonNull
+        public Builder setAccountOptions(@Nullable PersistableBundle accountOptions) {
+            mAccountOptions = accountOptions;
+            return this;
+        }
+
+        /**
+         * Builds {@link NewUserRequest}
+         *
+         * @throws IllegalStateException if builder is configured with incompatible properties and
+         * it is not possible to create such user. For example - a guest admin user.
+         */
+        @NonNull
+        public NewUserRequest build() {
+            checkIfPropertiesAreCompatible();
+            return new NewUserRequest(this);
+        }
+
+        private void checkIfPropertiesAreCompatible() {
+            // Conditions which can't be true simultaneously
+            // A guest user can't be admin user
+            if (mAdmin && mUserType == UserManager.USER_TYPE_FULL_GUEST) {
+                throw new IllegalStateException("A guest user can't be admin.");
+            }
+
+            // check for only supported user types
+            if (mUserType != UserManager.USER_TYPE_FULL_SECONDARY
+                    && mUserType != UserManager.USER_TYPE_FULL_GUEST) {
+                throw new IllegalStateException("Unsupported user type: " + mUserType);
+            }
+
+            if (TextUtils.isEmpty(mAccountName) != TextUtils.isEmpty(mAccountType)) {
+                throw new IllegalStateException(
+                        "Account name and account type should be provided together.");
+            }
+        }
+    }
+}
diff --git a/core/java/android/os/NewUserResponse.java b/core/java/android/os/NewUserResponse.java
new file mode 100644
index 0000000..3869559
--- /dev/null
+++ b/core/java/android/os/NewUserResponse.java
@@ -0,0 +1,59 @@
+/*
+ * 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;
+
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+
+/**
+ * Contains the response of the call {@link UserManager#createUser(NewUserRequest)}.
+ *
+ * @hide
+ */
+@SystemApi
+public final class NewUserResponse {
+
+    private final @Nullable UserHandle mUser;
+    private final @UserManager.UserOperationResult int mOperationResult;
+
+    NewUserResponse(@Nullable UserHandle user,
+            @UserManager.UserOperationResult int operationResult) {
+        mUser = user;
+        mOperationResult = operationResult;
+    }
+
+    /**
+     * Is user creation successful?
+     */
+    public boolean isSuccessful() {
+        return mUser != null;
+    }
+
+    // TODO(b/199446283): If UserHandle.NULL is systemAPI, that can be returned here instead of null
+    /**
+     * Gets the created user handle.
+     */
+    public @Nullable UserHandle getUser() {
+        return mUser;
+    }
+
+    /**
+     * Gets operation results.
+     */
+    public @UserManager.UserOperationResult int getOperationResult() {
+        return mOperationResult;
+    }
+}
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index c9670ff..742a542 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -742,7 +742,8 @@
     public static final native long getElapsedCpuTime();
 
     /**
-     * Return the {@link SystemClock#elapsedRealtime()} at which this process was started.
+     * Return the {@link SystemClock#elapsedRealtime()} at which this process was started,
+     * but before any of the application code was executed.
      */
     @ElapsedRealtimeLong
     public static long getStartElapsedRealtime() {
@@ -750,7 +751,8 @@
     }
 
     /**
-     * Return the {@link SystemClock#uptimeMillis()} at which this process was started.
+     * Return the {@link SystemClock#uptimeMillis()} at which this process was started,
+     * but before any of the application code was executed.
      */
     @UptimeMillisLong
     public static long getStartUptimeMillis() {
@@ -758,8 +760,12 @@
     }
 
     /**
-     * Return the {@link SystemClock#elapsedRealtime()} at which the system decides to start
-     * this process.
+     * Return the {@link SystemClock#elapsedRealtime()} at which the system was about to
+     * start this process. i.e. before a zygote fork.
+     *
+     * <p>More precisely, the system may start app processes before there's a start request,
+     * in order to reduce the process start up latency, in which case this is set when the system
+     * decides to "specialize" the process into a requested app.
      */
     @ElapsedRealtimeLong
     public static long getStartRequestedElapsedRealtime() {
@@ -767,8 +773,12 @@
     }
 
     /**
-     * Return the {@link SystemClock#uptimeMillis()} at which the system decides to start
-     * this process.
+     * Return the {@link SystemClock#uptimeMillis()} at which the system was about to
+     * start this process. i.e. before a zygote fork.
+     *
+     * <p>More precisely, the system may start app processes before there's a start request,
+     * in order to reduce the process start up latency, in which case this is set when the system
+     * decides to "specialize" the process into a requested app.
      */
     @UptimeMillisLong
     public static long getStartRequestedUptimeMillis() {
@@ -1195,7 +1205,8 @@
     private static native void setArgV0Native(String text);
 
     /**
-     * Return the name of this process.
+     * Return the name of this process. By default, the process name is the same as the app's
+     * package name, but this can be changed using {@code android:process}.
      */
     @NonNull
     public static String myProcessName() {
diff --git a/core/java/android/os/StatsBootstrapAtom.aidl b/core/java/android/os/StatsBootstrapAtom.aidl
new file mode 100644
index 0000000..47500af
--- /dev/null
+++ b/core/java/android/os/StatsBootstrapAtom.aidl
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * 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;
+
+import android.os.StatsBootstrapAtomValue;
+
+/*
+ * Generic encapsulation of an atom for bootstrap processes to log.
+ *
+ * @hide
+ */
+parcelable StatsBootstrapAtom {
+    /*
+     * Atom ID. Must be between 1 - 10,000.
+     */
+    int atomId;
+    /*
+     * Vector of fields in the order of the atom definition.
+     */
+    StatsBootstrapAtomValue[] values;
+ }
\ No newline at end of file
diff --git a/packages/overlays/OneHandedModeGesturalOverlay/res/values/dimens.xml b/core/java/android/os/StatsBootstrapAtomValue.aidl
similarity index 65%
rename from packages/overlays/OneHandedModeGesturalOverlay/res/values/dimens.xml
rename to core/java/android/os/StatsBootstrapAtomValue.aidl
index 3986119..a90dfa4 100644
--- a/packages/overlays/OneHandedModeGesturalOverlay/res/values/dimens.xml
+++ b/core/java/android/os/StatsBootstrapAtomValue.aidl
@@ -1,7 +1,5 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/**
- * Copyright (c) 2020, The Android Open Source Project
+/*
+ * Copyright 2021, The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -15,8 +13,17 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
--->
-<resources>
-    <!-- The height of the bottom navigation gesture area. -->
-    <dimen name="navigation_bar_gesture_larger_height">80dp</dimen>
-</resources>
+package android.os;
+/*
+ * Supported field types.
+ *
+ * @hide
+ */
+union StatsBootstrapAtomValue {
+    boolean boolValue;
+    int intValue;
+    long longValue;
+    float floatValue;
+    String stringValue;
+    byte[] bytesValue;
+}
\ No newline at end of file
diff --git a/core/java/android/os/SystemVibrator.java b/core/java/android/os/SystemVibrator.java
index a243453..a828268 100644
--- a/core/java/android/os/SystemVibrator.java
+++ b/core/java/android/os/SystemVibrator.java
@@ -20,7 +20,6 @@
 import android.annotation.NonNull;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
-import android.media.AudioAttributes;
 import android.util.ArrayMap;
 import android.util.Log;
 import android.util.SparseArray;
@@ -180,14 +179,13 @@
 
     @Override
     public boolean setAlwaysOnEffect(int uid, String opPkg, int alwaysOnId, VibrationEffect effect,
-            AudioAttributes attributes) {
+            VibrationAttributes attrs) {
         if (mVibratorManager == null) {
             Log.w(TAG, "Failed to set always-on effect; no vibrator manager.");
             return false;
         }
-        VibrationAttributes attr = new VibrationAttributes.Builder(attributes, effect).build();
         CombinedVibration combinedEffect = CombinedVibration.createParallel(effect);
-        return mVibratorManager.setAlwaysOnEffect(uid, opPkg, alwaysOnId, combinedEffect, attr);
+        return mVibratorManager.setAlwaysOnEffect(uid, opPkg, alwaysOnId, combinedEffect, attrs);
     }
 
     @Override
@@ -198,6 +196,9 @@
             return;
         }
         CombinedVibration combinedEffect = CombinedVibration.createParallel(effect);
+        // TODO(b/185351540): move this into VibratorManagerService once the touch vibration
+        // heuristics is fixed and works for CombinedVibration. Make sure it's always applied.
+        attributes = new VibrationAttributes.Builder(attributes, effect).build();
         mVibratorManager.vibrate(uid, opPkg, combinedEffect, reason, attributes);
     }
 
diff --git a/core/java/android/os/SystemVibratorManager.java b/core/java/android/os/SystemVibratorManager.java
index 0416556..e5622a3 100644
--- a/core/java/android/os/SystemVibratorManager.java
+++ b/core/java/android/os/SystemVibratorManager.java
@@ -20,7 +20,6 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
-import android.media.AudioAttributes;
 import android.util.ArrayMap;
 import android.util.Log;
 import android.util.SparseArray;
@@ -210,14 +209,12 @@
 
         @Override
         public boolean setAlwaysOnEffect(int uid, String opPkg, int alwaysOnId,
-                @Nullable VibrationEffect effect, @Nullable AudioAttributes attributes) {
-            VibrationAttributes attr = new VibrationAttributes.Builder(
-                    attributes, effect).build();
+                @Nullable VibrationEffect effect, @Nullable VibrationAttributes attrs) {
             CombinedVibration combined = CombinedVibration.startParallel()
                     .addVibrator(mVibratorInfo.getId(), effect)
                     .combine();
             return SystemVibratorManager.this.setAlwaysOnEffect(uid, opPkg, alwaysOnId, combined,
-                    attr);
+                    attrs);
         }
 
         @Override
@@ -226,6 +223,9 @@
             CombinedVibration combined = CombinedVibration.startParallel()
                     .addVibrator(mVibratorInfo.getId(), vibe)
                     .combine();
+            // TODO(b/185351540): move this into VibratorManagerService once the touch vibration
+            // heuristics is fixed and works for CombinedVibration. Make sure it's always applied.
+            attributes = new VibrationAttributes.Builder(attributes, vibe).build();
             SystemVibratorManager.this.vibrate(uid, opPkg, combined, reason, attributes);
         }
 
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 447102b..cf4ce9b 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -70,6 +70,7 @@
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Objects;
 import java.util.Set;
 
 /**
@@ -1661,6 +1662,14 @@
     public static final int USER_OPERATION_ERROR_MAX_USERS = 6;
 
     /**
+     * Indicates user operation failed because a user with that account already exists.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int USER_OPERATION_ERROR_USER_ACCOUNT_ALREADY_EXISTS = 7;
+
+    /**
      * Result returned from various user operations.
      *
      * @hide
@@ -1673,7 +1682,8 @@
             USER_OPERATION_ERROR_MAX_RUNNING_USERS,
             USER_OPERATION_ERROR_CURRENT_USER,
             USER_OPERATION_ERROR_LOW_STORAGE,
-            USER_OPERATION_ERROR_MAX_USERS
+            USER_OPERATION_ERROR_MAX_USERS,
+            USER_OPERATION_ERROR_USER_ACCOUNT_ALREADY_EXISTS
     })
     public @interface UserOperationResult {}
 
@@ -3149,6 +3159,37 @@
     }
 
     /**
+     * Creates a user with the specified {@link NewUserRequest}.
+     *
+     * @param newUserRequest specify the user information
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS,
+            Manifest.permission.CREATE_USERS})
+    public @NonNull NewUserResponse createUser(@NonNull NewUserRequest newUserRequest) {
+        try {
+            final UserHandle userHandle = mService.createUserWithAttributes(
+                    newUserRequest.getName(),
+                    newUserRequest.getUserType(),
+                    newUserRequest.getFlags(),
+                    newUserRequest.getUserIcon(),
+                    newUserRequest.getAccountName(),
+                    newUserRequest.getAccountType(),
+                    newUserRequest.getAccountOptions());
+
+            return new NewUserResponse(userHandle, USER_OPERATION_SUCCESS);
+
+        } catch (ServiceSpecificException e) {
+            Log.w(TAG, "Exception while creating user " + newUserRequest, e);
+            return new NewUserResponse(null, e.errorCode);
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Pre-creates a user of the specified type. Default user restrictions will be applied.
      *
      * <p>This method can be used by OEMs to "warm" up the user creation by pre-creating some users
@@ -4880,12 +4921,12 @@
     }
 
     /**
-     * @hide
      * Checks if any uninitialized user has the specific seed account name and type.
      *
      * @param accountName The account name to check for
      * @param accountType The account type of the account to check for
      * @return whether the seed account was found
+     * @hide
      */
     @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
     public boolean someUserHasSeedAccount(String accountName, String accountType) {
@@ -4897,6 +4938,29 @@
     }
 
     /**
+     * Checks if any initialized or uninitialized user has the specific account name and type.
+     *
+     * @param accountName The account name to check for
+     * @param accountType The account type of the account to check for
+     * @return whether the account was found
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS,
+            Manifest.permission.CREATE_USERS})
+    public boolean someUserHasAccount(
+            @NonNull String accountName, @NonNull String accountType) {
+        Objects.requireNonNull(accountName, "accountName must not be null");
+        Objects.requireNonNull(accountType, "accountType must not be null");
+
+        try {
+            return mService.someUserHasAccount(accountName, accountType);
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * @hide
      * User that enforces a restriction.
      *
diff --git a/core/java/android/os/VibrationAttributes.java b/core/java/android/os/VibrationAttributes.java
index 9f799f9e..e986036 100644
--- a/core/java/android/os/VibrationAttributes.java
+++ b/core/java/android/os/VibrationAttributes.java
@@ -145,6 +145,11 @@
     // If a vibration is playing for longer than 5s, it's probably not haptic feedback
     private static final long MAX_HAPTIC_FEEDBACK_DURATION = 5000;
 
+    /** Creates a new {@link VibrationAttributes} instance with given usage. */
+    public static @NonNull VibrationAttributes createForUsage(int usage) {
+        return new VibrationAttributes.Builder().setUsage(usage).build();
+    }
+
     private final int mUsage;
     private final int mFlags;
     private final int mOriginalAudioUsage;
@@ -326,12 +331,29 @@
 
         /**
          * Constructs a new Builder from AudioAttributes.
+         */
+        public Builder(@NonNull AudioAttributes audio) {
+            setUsage(audio);
+            setFlags(audio);
+        }
+
+        /**
+         * Constructs a new Builder from AudioAttributes and a VibrationEffect to infer usage.
          * @hide
          */
         @TestApi
-        public Builder(@NonNull AudioAttributes audio, @Nullable VibrationEffect effect) {
-            setUsage(audio);
-            setFlags(audio);
+        public Builder(@NonNull AudioAttributes audio, @NonNull VibrationEffect effect) {
+            this(audio);
+            applyHapticFeedbackHeuristics(effect);
+        }
+
+        /**
+         * Constructs a new Builder from VibrationAttributes and a VibrationEffect to infer usage.
+         * @hide
+         */
+        @TestApi
+        public Builder(@NonNull VibrationAttributes vib, @NonNull VibrationEffect effect) {
+            this(vib);
             applyHapticFeedbackHeuristics(effect);
         }
 
diff --git a/core/java/android/os/Vibrator.java b/core/java/android/os/Vibrator.java
index aa9028e..75234db 100644
--- a/core/java/android/os/Vibrator.java
+++ b/core/java/android/os/Vibrator.java
@@ -330,16 +330,15 @@
      *
      * @param alwaysOnId The board-specific always-on ID to configure.
      * @param effect     Vibration effect to assign to always-on id. Passing null will disable it.
-     * @param attributes {@link AudioAttributes} corresponding to the vibration. For example,
-     *                   specify {@link AudioAttributes#USAGE_ALARM} for alarm vibrations or
-     *                   {@link AudioAttributes#USAGE_NOTIFICATION_RINGTONE} for
-     *                   vibrations associated with incoming calls. May only be null when effect is
-     *                   null.
+     * @param attributes {@link VibrationAttributes} corresponding to the vibration. For example,
+     *                   specify {@link VibrationAttributes#USAGE_ALARM} for alarm vibrations or
+     *                   {@link VibrationAttributes#USAGE_RINGTONE} for vibrations associated with
+     *                   incoming calls. May only be null when effect is null.
      * @hide
      */
     @RequiresPermission(android.Manifest.permission.VIBRATE_ALWAYS_ON)
     public boolean setAlwaysOnEffect(int alwaysOnId, @Nullable VibrationEffect effect,
-            @Nullable AudioAttributes attributes) {
+            @Nullable VibrationAttributes attributes) {
         return setAlwaysOnEffect(Process.myUid(), mPackageName, alwaysOnId, effect, attributes);
     }
 
@@ -348,7 +347,7 @@
      */
     @RequiresPermission(android.Manifest.permission.VIBRATE_ALWAYS_ON)
     public boolean setAlwaysOnEffect(int uid, String opPkg, int alwaysOnId,
-            @Nullable VibrationEffect effect, @Nullable AudioAttributes attributes) {
+            @Nullable VibrationEffect effect, @Nullable VibrationAttributes attributes) {
         Log.w(TAG, "Always-on effects aren't supported");
         return false;
     }
@@ -378,7 +377,7 @@
      *                     specify {@link AudioAttributes#USAGE_ALARM} for alarm vibrations or
      *                     {@link AudioAttributes#USAGE_NOTIFICATION_RINGTONE} for
      *                     vibrations associated with incoming calls.
-     * @deprecated Use {@link #vibrate(VibrationEffect, AudioAttributes)} instead.
+     * @deprecated Use {@link #vibrate(VibrationEffect, VibrationAttributes)} instead.
      */
     @Deprecated
     @RequiresPermission(android.Manifest.permission.VIBRATE)
@@ -444,7 +443,7 @@
      *                   specify {@link AudioAttributes#USAGE_ALARM} for alarm vibrations or
      *                   {@link AudioAttributes#USAGE_NOTIFICATION_RINGTONE} for
      *                   vibrations associated with incoming calls.
-     * @deprecated Use {@link #vibrate(VibrationEffect, AudioAttributes)} instead.
+     * @deprecated Use {@link #vibrate(VibrationEffect, VibrationAttributes)} instead.
      */
     @Deprecated
     @RequiresPermission(android.Manifest.permission.VIBRATE)
@@ -473,7 +472,7 @@
      */
     @RequiresPermission(android.Manifest.permission.VIBRATE)
     public void vibrate(VibrationEffect vibe) {
-        vibrate(vibe, null);
+        vibrate(vibe, new VibrationAttributes.Builder().build());
     }
 
     /**
@@ -487,35 +486,40 @@
      *                   specify {@link AudioAttributes#USAGE_ALARM} for alarm vibrations or
      *                   {@link AudioAttributes#USAGE_NOTIFICATION_RINGTONE} for
      *                   vibrations associated with incoming calls.
+     * @deprecated Use {@link #vibrate(VibrationEffect, VibrationAttributes)} instead.
      */
     @RequiresPermission(android.Manifest.permission.VIBRATE)
     public void vibrate(VibrationEffect vibe, AudioAttributes attributes) {
+        vibrate(vibe,
+                attributes == null
+                        ? new VibrationAttributes.Builder().build()
+                        : new VibrationAttributes.Builder(attributes, vibe).build());
+    }
+
+    /**
+     * Vibrate with a given effect.
+     *
+     * <p>The app should be in foreground for the vibration to happen. Background apps should
+     * specify a ringtone, notification or alarm usage in order to vibrate.</p>
+     *
+     * @param vibe       {@link VibrationEffect} describing the vibration to be performed.
+     * @param attributes {@link VibrationAttributes} corresponding to the vibration. For example,
+     *                   specify {@link VibrationAttributes#USAGE_ALARM} for alarm vibrations or
+     *                   {@link VibrationAttributes#USAGE_RINGTONE} for vibrations associated with
+     *                   incoming calls.
+     */
+    @RequiresPermission(android.Manifest.permission.VIBRATE)
+    public void vibrate(@NonNull VibrationEffect vibe, @NonNull VibrationAttributes attributes) {
         vibrate(Process.myUid(), mPackageName, vibe, null, attributes);
     }
 
     /**
-     * Like {@link #vibrate(VibrationEffect, AudioAttributes)}, but allows the
+     * Like {@link #vibrate(VibrationEffect, VibrationAttributes)}, but allows the
      * caller to specify the vibration is owned by someone else and set reason for vibration.
      *
      * @hide
      */
     @RequiresPermission(android.Manifest.permission.VIBRATE)
-    public final void vibrate(int uid, String opPkg, VibrationEffect vibe,
-            String reason, AudioAttributes attributes) {
-        if (attributes == null) {
-            attributes = new AudioAttributes.Builder().build();
-        }
-        VibrationAttributes attr = new VibrationAttributes.Builder(attributes, vibe).build();
-        vibrate(uid, opPkg, vibe, reason, attr);
-    }
-
-    /**
-     * Like {@link #vibrate(int, String, VibrationEffect, String, AudioAttributes)}, but allows the
-     * caller to specify {@link VibrationAttributes} instead of {@link AudioAttributes}.
-     *
-     * @hide
-     */
-    @RequiresPermission(android.Manifest.permission.VIBRATE)
     public abstract void vibrate(int uid, String opPkg, @NonNull VibrationEffect vibe,
             String reason, @NonNull VibrationAttributes attributes);
 
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 3d7c026..cc95c1f 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -379,6 +379,21 @@
             "android.settings.REDUCE_BRIGHT_COLORS_SETTINGS";
 
     /**
+     * Activity Action: Show settings to allow configuration of Color inversion.
+     * <p>
+     * In some cases, a matching Activity may not exist, so ensure you
+     * safeguard against this.
+     * <p>
+     * Input: Nothing.
+     * <p>
+     * Output: Nothing.
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_COLOR_INVERSION_SETTINGS =
+            "android.settings.COLOR_INVERSION_SETTINGS";
+
+    /**
      * Activity Action: Show settings to control access to usage information.
      * <p>
      * In some cases, a matching Activity may not exist, so ensure you
@@ -4522,6 +4537,25 @@
                 "haptic_feedback_intensity";
 
         /**
+         * The intensity of haptic feedback vibrations for interaction with hardware components from
+         * the device, like buttons and sensors, if configurable.
+         *
+         * Not all devices are capable of changing their feedback intensity; on these devices
+         * there will likely be no difference between the various vibration intensities except for
+         * intensity 0 (off) and the rest.
+         *
+         * <b>Values:</b><br/>
+         * 0 - Vibration is disabled<br/>
+         * 1 - Weak vibrations<br/>
+         * 2 - Medium vibrations<br/>
+         * 3 - Strong vibrations
+         * @hide
+         */
+        @Readable
+        public static final String HARDWARE_HAPTIC_FEEDBACK_INTENSITY =
+                "hardware_haptic_feedback_intensity";
+
+        /**
          * Ringer volume. This is used internally, changing this value will not
          * change the volume. See AudioManager.
          *
@@ -9658,6 +9692,14 @@
         public static final String LOCKSCREEN_SHOW_WALLET = "lockscreen_show_wallet";
 
         /**
+         * Whether to use the lockscreen double-line clock
+         *
+         * @hide
+         */
+        public static final String LOCKSCREEN_USE_DOUBLE_LINE_CLOCK =
+                "lockscreen_use_double_line_clock";
+
+        /**
          * Specifies whether the web action API is enabled.
          *
          * @hide
@@ -16667,12 +16709,6 @@
             public static final String AMBIENT_FORCE_WHEN_DOCKED = "ambient_force_when_docked";
 
             /**
-             * The id of the gesture sensor.
-             * @hide
-             */
-            public static final String AMBIENT_GESTURE_SENSOR_ID = "ambient_gesture_sensor_id";
-
-            /**
              * Whether the ambient low bit mode is enabled.
              * @hide
              */
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index 1b38f59..5d84af0 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -3584,6 +3584,23 @@
                 "content://telephony/carriers/enforce_managed");
 
         /**
+         * The {@code content://} style URL for the perferred APN used for internet.
+         *
+         * @hide
+         */
+        public static final Uri PREFERRED_APN_URI = Uri.parse(
+                "content://telephony/carriers/preferapn/subId/");
+
+        /**
+         * The {@code content://} style URL for the perferred APN set id.
+         *
+         * @hide
+         */
+        public static final Uri PREFERRED_APN_SET_URI = Uri.parse(
+                "content://telephony/carriers/preferapnset/subId/");
+
+
+        /**
          * The column name for ENFORCE_MANAGED_URI, indicates whether DPC-owned APNs are enforced.
          * @hide
          */
diff --git a/core/java/android/service/wallpaper/EngineWindowPage.java b/core/java/android/service/wallpaper/EngineWindowPage.java
index 5ed0ad6..006e3cd 100644
--- a/core/java/android/service/wallpaper/EngineWindowPage.java
+++ b/core/java/android/service/wallpaper/EngineWindowPage.java
@@ -24,7 +24,6 @@
 
 import java.util.Map;
 import java.util.Set;
-import java.util.function.Consumer;
 
 /**
  * This class represents a page of a launcher page used by the wallpaper
@@ -84,11 +83,6 @@
         return mCallbackAreas;
     }
 
-    /** run operations on this page */
-    public synchronized void execSync(Consumer<EngineWindowPage> run) {
-        run.accept(this);
-    }
-
     /** nullify the area color */
     public void removeColor(RectF colorArea) {
         mRectFColors.remove(colorArea);
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index c77399f..7b8410b 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -1490,7 +1490,7 @@
             //below is the default implementation
             if (xOffset % xOffsetStep > MIN_PAGE_ALLOWED_MARGIN
                     || !mSurfaceHolder.getSurface().isValid()) return;
-            int xPage;
+            int xCurrentPage;
             int xPages;
             if (!validStep(xOffsetStep)) {
                 if (DEBUG) {
@@ -1498,30 +1498,34 @@
                 }
                 xOffset = 0;
                 xOffsetStep = 1;
-                xPage = 0;
+                xCurrentPage = 0;
                 xPages = 1;
             } else {
                 xPages = Math.round(1 / xOffsetStep) + 1;
                 xOffsetStep = (float) 1 / (float) xPages;
                 float shrink = (float) (xPages - 1) / (float) xPages;
                 xOffset *= shrink;
-                xPage = Math.round(xOffset / xOffsetStep);
+                xCurrentPage = Math.round(xOffset / xOffsetStep);
             }
             if (DEBUG) {
-                Log.d(TAG, "xPages " + xPages + " xPage " + xPage);
+                Log.d(TAG, "xPages " + xPages + " xPage " + xCurrentPage);
                 Log.d(TAG, "xOffsetStep " + xOffsetStep + " xOffset " + xOffset);
             }
-            EngineWindowPage current;
-            synchronized (mLock) {
+
+            float finalXOffsetStep = xOffsetStep;
+            float finalXOffset = xOffset;
+            mHandler.post(() -> {
+                int xPage = xCurrentPage;
+                EngineWindowPage current;
                 if (mWindowPages.length == 0 || (mWindowPages.length != xPages)) {
                     mWindowPages = new EngineWindowPage[xPages];
-                    initWindowPages(mWindowPages, xOffsetStep);
+                    initWindowPages(mWindowPages, finalXOffsetStep);
                 }
                 if (mLocalColorsToAdd.size() != 0) {
                     for (RectF colorArea : mLocalColorsToAdd) {
                         if (!isValid(colorArea)) continue;
                         mLocalColorAreas.add(colorArea);
-                        int colorPage = getRectFPage(colorArea, xOffsetStep);
+                        int colorPage = getRectFPage(colorArea, finalXOffsetStep);
                         EngineWindowPage currentPage = mWindowPages[colorPage];
                         if (currentPage == null) {
                             currentPage = new EngineWindowPage();
@@ -1539,7 +1543,8 @@
                         Log.e(TAG, "error xPage >= mWindowPages.length page: " + xPage);
                         Log.e(TAG, "error on page " + xPage + " out of " + xPages);
                         Log.e(TAG,
-                                "error on xOffsetStep " + xOffsetStep + " xOffset " + xOffset);
+                                "error on xOffsetStep " + finalXOffsetStep
+                                        + " xOffset " + finalXOffset);
                     }
                     xPage = mWindowPages.length - 1;
                 }
@@ -1547,13 +1552,14 @@
                 if (current == null) {
                     if (DEBUG) Log.d(TAG, "making page " + xPage + " out of " + xPages);
                     if (DEBUG) {
-                        Log.d(TAG, "xOffsetStep " + xOffsetStep + " xOffset " + xOffset);
+                        Log.d(TAG, "xOffsetStep " + finalXOffsetStep + " xOffset "
+                                + finalXOffset);
                     }
                     current = new EngineWindowPage();
                     mWindowPages[xPage] = current;
                 }
-            }
-            updatePage(current, xPage, xPages, xOffsetStep);
+                updatePage(current, xPage, xPages, finalXOffsetStep);
+            });
         }
 
         private void initWindowPages(EngineWindowPage[] windowPages, float step) {
@@ -1603,10 +1609,8 @@
                 if (DEBUG) Log.d(TAG, "result of pixel copy is " + res);
                 if (res != PixelCopy.SUCCESS) {
                     Bitmap lastBitmap = currentPage.getBitmap();
-                    currentPage.execSync((p) -> {
-                        // assign the last bitmap taken for now
-                        p.setBitmap(mLastScreenshot);
-                    });
+                    // assign the last bitmap taken for now
+                    currentPage.setBitmap(mLastScreenshot);
                     Bitmap lastScreenshot = mLastScreenshot;
                     if (lastScreenshot != null && !lastScreenshot.isRecycled()
                             && !Objects.equals(lastBitmap, lastScreenshot)) {
@@ -1615,10 +1619,8 @@
                 } else {
                     mLastScreenshot = finalScreenShot;
                     // going to hold this lock for a while
-                    currentPage.execSync((p) -> {
-                        p.setBitmap(finalScreenShot);
-                        p.setLastUpdateTime(current);
-                    });
+                    currentPage.setBitmap(finalScreenShot);
+                    currentPage.setLastUpdateTime(current);
                     updatePageColors(currentPage, pageIndx, numPages, xOffsetStep);
                 }
             }, mHandler);
@@ -1698,16 +1700,14 @@
         private void resetWindowPages() {
             if (supportsLocalColorExtraction()) return;
             mLastWindowPage = -1;
-            synchronized (mLock) {
+            mHandler.post(() -> {
                 for (int i = 0; i < mWindowPages.length; i++) {
                     EngineWindowPage page = mWindowPages[i];
                     if (page != null) {
-                        page.execSync((p) -> {
-                            p.setLastUpdateTime(0L);
-                        });
+                        page.setLastUpdateTime(0L);
                     }
                 }
-            }
+            });
         }
 
         private int getRectFPage(RectF area, float step) {
@@ -1730,10 +1730,10 @@
             if (DEBUG) {
                 Log.d(TAG, "addLocalColorsAreas adding local color areas " + regions);
             }
-            float step = mPendingXOffsetStep;
 
             List<WallpaperColors> colors = getLocalWallpaperColors(regions);
-            synchronized (mLock) {
+            mHandler.post(() -> {
+                float step = mPendingXOffsetStep;
                 if (!validStep(step)) {
                     step = 0;
                 }
@@ -1749,26 +1749,25 @@
                         page.addArea(area);
                         WallpaperColors color = colors.get(i);
                         if (color != null && !color.equals(page.getColors(area))) {
-                            page.execSync(p -> {
-                                p.addWallpaperColors(area, color);
-                            });
+                            page.addWallpaperColors(area, color);
                         }
                     } else {
                         mLocalColorsToAdd.add(area);
                     }
                 }
-            }
-
-            for (int i = 0; i < colors.size() && colors.get(i) != null; i++) {
-                try {
-                    mConnection.onLocalWallpaperColorsChanged(regions.get(i), colors.get(i),
-                            mDisplayContext.getDisplayId());
-                } catch (RemoteException e) {
-                    Log.e(TAG, "Error calling Connection.onLocalWallpaperColorsChanged", e);
-                    return;
+                for (int i = 0; i < colors.size() && colors.get(i) != null; i++) {
+                    try {
+                        mConnection.onLocalWallpaperColorsChanged(regions.get(i), colors.get(i),
+                                mDisplayContext.getDisplayId());
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "Error calling Connection.onLocalWallpaperColorsChanged", e);
+                        return;
+                    }
                 }
-            }
-            processLocalColors(mPendingXOffset, mPendingYOffset);
+                processLocalColors(mPendingXOffset, mPendingYOffset);
+            });
+
+
         }
 
         /**
@@ -1778,7 +1777,7 @@
          */
         public void removeLocalColorsAreas(@NonNull List<RectF> regions) {
             if (supportsLocalColorExtraction()) return;
-            synchronized (mLock) {
+            mHandler.post(() -> {
                 float step = mPendingXOffsetStep;
                 mLocalColorsToAdd.removeAll(regions);
                 mLocalColorAreas.removeAll(regions);
@@ -1792,12 +1791,10 @@
                     // no page should be null
                     EngineWindowPage page = mWindowPages[pageInx];
                     if (page != null) {
-                        page.execSync(p -> {
-                            p.removeArea(area);
-                        });
+                        page.removeArea(area);
                     }
                 }
-            }
+            });
         }
 
         private @NonNull List<WallpaperColors> getLocalWallpaperColors(@NonNull List<RectF> areas) {
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index 505f400..da3e9b6 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -82,7 +82,9 @@
     /** @hide */
     @IntDef(prefix = { "HYPHENATION_FREQUENCY_" }, value = {
             HYPHENATION_FREQUENCY_NORMAL,
+            HYPHENATION_FREQUENCY_NORMAL_FAST,
             HYPHENATION_FREQUENCY_FULL,
+            HYPHENATION_FREQUENCY_FULL_FAST,
             HYPHENATION_FREQUENCY_NONE
     })
     @Retention(RetentionPolicy.SOURCE)
@@ -95,21 +97,40 @@
      * layout and there is otherwise no valid break. Soft hyphens are ignored and will not be used
      * as suggestions for potential line breaks.
      */
-    public static final int HYPHENATION_FREQUENCY_NONE = LineBreaker.HYPHENATION_FREQUENCY_NONE;
+    public static final int HYPHENATION_FREQUENCY_NONE = 0;
 
     /**
      * Value for hyphenation frequency indicating a light amount of automatic hyphenation, which
      * is a conservative default. Useful for informal cases, such as short sentences or chat
      * messages.
      */
-    public static final int HYPHENATION_FREQUENCY_NORMAL = LineBreaker.HYPHENATION_FREQUENCY_NORMAL;
+    public static final int HYPHENATION_FREQUENCY_NORMAL = 1;
 
     /**
      * Value for hyphenation frequency indicating the full amount of automatic hyphenation, typical
      * in typography. Useful for running text and where it's important to put the maximum amount of
      * text in a screen with limited space.
      */
-    public static final int HYPHENATION_FREQUENCY_FULL = LineBreaker.HYPHENATION_FREQUENCY_FULL;
+    public static final int HYPHENATION_FREQUENCY_FULL = 2;
+
+    /**
+     * Value for hyphenation frequency indicating a light amount of automatic hyphenation with
+     * using faster algorithm.
+     *
+     * This option is useful for informal cases, such as short sentences or chat messages. To make
+     * text rendering faster with hyphenation, this algorithm ignores some hyphen character related
+     * typographic features, e.g. kerning.
+     */
+    public static final int HYPHENATION_FREQUENCY_NORMAL_FAST = 3;
+    /**
+     * Value for hyphenation frequency indicating the full amount of automatic hyphenation with
+     * using faster algorithm.
+     *
+     * This option is useful for running text and where it's important to put the maximum amount of
+     * text in a screen with limited space. To make text rendering faster with hyphenation, this
+     * algorithm ignores some hyphen character related typographic features, e.g. kerning.
+     */
+    public static final int HYPHENATION_FREQUENCY_FULL_FAST = 4;
 
     private static final ParagraphStyle[] NO_PARA_SPANS =
         ArrayUtils.emptyArray(ParagraphStyle.class);
diff --git a/core/java/android/text/MeasuredParagraph.java b/core/java/android/text/MeasuredParagraph.java
index 7e41878..6a3c618 100644
--- a/core/java/android/text/MeasuredParagraph.java
+++ b/core/java/android/text/MeasuredParagraph.java
@@ -377,7 +377,7 @@
      * @param start the inclusive start offset of the target region in the text
      * @param end the exclusive end offset of the target region in the text
      * @param textDir the text direction
-     * @param computeHyphenation true if need to compute hyphenation, otherwise false
+     * @param hyphenationMode a hyphenation mode
      * @param computeLayout true if need to compute full layout, otherwise false.
      * @param hint pass if you already have measured paragraph.
      * @param recycle pass existing MeasuredParagraph if you want to recycle it.
@@ -390,7 +390,7 @@
             @IntRange(from = 0) int start,
             @IntRange(from = 0) int end,
             @NonNull TextDirectionHeuristic textDir,
-            boolean computeHyphenation,
+            int hyphenationMode,
             boolean computeLayout,
             @Nullable MeasuredParagraph hint,
             @Nullable MeasuredParagraph recycle) {
@@ -399,7 +399,7 @@
         final MeasuredText.Builder builder;
         if (hint == null) {
             builder = new MeasuredText.Builder(mt.mCopiedBuffer)
-                    .setComputeHyphenation(computeHyphenation)
+                    .setComputeHyphenation(hyphenationMode)
                     .setComputeLayout(computeLayout);
         } else {
             builder = new MeasuredText.Builder(hint.mMeasuredText);
diff --git a/core/java/android/text/PrecomputedText.java b/core/java/android/text/PrecomputedText.java
index 08741d6..152570f 100644
--- a/core/java/android/text/PrecomputedText.java
+++ b/core/java/android/text/PrecomputedText.java
@@ -22,6 +22,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.graphics.Rect;
+import android.graphics.text.MeasuredText;
 import android.text.style.MetricAffectingSpan;
 
 import com.android.internal.util.Preconditions;
@@ -395,17 +396,30 @@
         return new PrecomputedText(text, 0, text.length(), params, paraInfo);
     }
 
+    private static boolean isFastHyphenation(int frequency) {
+        return frequency == Layout.HYPHENATION_FREQUENCY_FULL_FAST
+                || frequency == Layout.HYPHENATION_FREQUENCY_NORMAL_FAST;
+    }
+
     private static ParagraphInfo[] createMeasuredParagraphsFromPrecomputedText(
             @NonNull PrecomputedText pct, @NonNull Params params, boolean computeLayout) {
         final boolean needHyphenation = params.getBreakStrategy() != Layout.BREAK_STRATEGY_SIMPLE
                 && params.getHyphenationFrequency() != Layout.HYPHENATION_FREQUENCY_NONE;
+        final int hyphenationMode;
+        if (needHyphenation) {
+            hyphenationMode = isFastHyphenation(params.getHyphenationFrequency())
+                    ? MeasuredText.Builder.HYPHENATION_MODE_FAST :
+                    MeasuredText.Builder.HYPHENATION_MODE_NORMAL;
+        } else {
+            hyphenationMode = MeasuredText.Builder.HYPHENATION_MODE_NONE;
+        }
         ArrayList<ParagraphInfo> result = new ArrayList<>();
         for (int i = 0; i < pct.getParagraphCount(); ++i) {
             final int paraStart = pct.getParagraphStart(i);
             final int paraEnd = pct.getParagraphEnd(i);
             result.add(new ParagraphInfo(paraEnd, MeasuredParagraph.buildForStaticLayout(
                     params.getTextPaint(), pct, paraStart, paraEnd, params.getTextDirection(),
-                    needHyphenation, computeLayout, pct.getMeasuredParagraph(i),
+                    hyphenationMode, computeLayout, pct.getMeasuredParagraph(i),
                     null /* no recycle */)));
         }
         return result.toArray(new ParagraphInfo[result.size()]);
@@ -421,6 +435,14 @@
         Preconditions.checkNotNull(params);
         final boolean needHyphenation = params.getBreakStrategy() != Layout.BREAK_STRATEGY_SIMPLE
                 && params.getHyphenationFrequency() != Layout.HYPHENATION_FREQUENCY_NONE;
+        final int hyphenationMode;
+        if (needHyphenation) {
+            hyphenationMode = isFastHyphenation(params.getHyphenationFrequency())
+                    ? MeasuredText.Builder.HYPHENATION_MODE_FAST :
+                    MeasuredText.Builder.HYPHENATION_MODE_NORMAL;
+        } else {
+            hyphenationMode = MeasuredText.Builder.HYPHENATION_MODE_NONE;
+        }
 
         int paraEnd = 0;
         for (int paraStart = start; paraStart < end; paraStart = paraEnd) {
@@ -435,8 +457,7 @@
 
             result.add(new ParagraphInfo(paraEnd, MeasuredParagraph.buildForStaticLayout(
                     params.getTextPaint(), text, paraStart, paraEnd, params.getTextDirection(),
-                    needHyphenation, computeLayout, null /* no hint */,
-                    null /* no recycle */)));
+                    hyphenationMode, computeLayout, null /* no hint */, null /* no recycle */)));
         }
         return result.toArray(new ParagraphInfo[result.size()]);
     }
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index f99d430..6984e4d 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -591,6 +591,20 @@
         generate(b, b.mIncludePad, b.mIncludePad);
     }
 
+    private static int getBaseHyphenationFrequency(int frequency) {
+        switch (frequency) {
+            case Layout.HYPHENATION_FREQUENCY_FULL:
+            case Layout.HYPHENATION_FREQUENCY_FULL_FAST:
+                return LineBreaker.HYPHENATION_FREQUENCY_FULL;
+            case Layout.HYPHENATION_FREQUENCY_NORMAL:
+            case Layout.HYPHENATION_FREQUENCY_NORMAL_FAST:
+                return LineBreaker.HYPHENATION_FREQUENCY_NORMAL;
+            case Layout.HYPHENATION_FREQUENCY_NONE:
+            default:
+                return LineBreaker.HYPHENATION_FREQUENCY_NONE;
+        }
+    }
+
     /* package */ void generate(Builder b, boolean includepad, boolean trackpad) {
         final CharSequence source = b.mText;
         final int bufStart = b.mStart;
@@ -641,7 +655,7 @@
 
         final LineBreaker lineBreaker = new LineBreaker.Builder()
                 .setBreakStrategy(b.mBreakStrategy)
-                .setHyphenationFrequency(b.mHyphenationFrequency)
+                .setHyphenationFrequency(getBaseHyphenationFrequency(b.mHyphenationFrequency))
                 // TODO: Support more justification mode, e.g. letter spacing, stretching.
                 .setJustificationMode(b.mJustificationMode)
                 .setIndents(indents)
diff --git a/core/java/android/view/HapticFeedbackConstants.java b/core/java/android/view/HapticFeedbackConstants.java
index ec613ed..c5bc99d 100644
--- a/core/java/android/view/HapticFeedbackConstants.java
+++ b/core/java/android/view/HapticFeedbackConstants.java
@@ -153,11 +153,20 @@
 
     /**
      * Invocation of the voice assistant via hardware button.
+     * This is a private constant.  Feel free to renumber as desired.
      * @hide
      */
     public static final int ASSISTANT_BUTTON = 10002;
 
     /**
+     * The user has performed a long press on the power button hardware that is resulting
+     * in an action being performed.
+     * This is a private constant.  Feel free to renumber as desired.
+     * @hide
+     */
+    public static final int LONG_PRESS_POWER_BUTTON = 10003;
+
+    /**
      * Flag for {@link View#performHapticFeedback(int, int)
      * View.performHapticFeedback(int, int)}: Ignore the setting in the
      * view for whether to perform haptic feedback, do it always.
diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl
index fceda20..12421ed 100644
--- a/core/java/android/view/IWindow.aidl
+++ b/core/java/android/view/IWindow.aidl
@@ -94,12 +94,6 @@
     void dispatchAppVisibility(boolean visible);
     void dispatchGetNewSurface();
 
-    /**
-     * Tell the window that it is either gaining or losing focus.  Keep it up
-     * to date on the current state showing navigational focus too.
-     */
-    void windowFocusChanged(boolean hasFocus);
-
     void closeSystemDialogs(String reason);
 
     /**
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index 1460cb2..c3a638c 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -295,7 +295,8 @@
     /** Key code constant: Fast Forward media key. */
     public static final int KEYCODE_MEDIA_FAST_FORWARD = 90;
     /** Key code constant: Mute key.
-     * Mutes the microphone, unlike {@link #KEYCODE_VOLUME_MUTE}. */
+     * Mute key for the microphone (unlike {@link #KEYCODE_VOLUME_MUTE}, which is the speaker mute
+     * key). */
     public static final int KEYCODE_MUTE            = 91;
     /** Key code constant: Page Up key. */
     public static final int KEYCODE_PAGE_UP         = 92;
@@ -482,9 +483,10 @@
     /** Key code constant: Numeric keypad ')' key. */
     public static final int KEYCODE_NUMPAD_RIGHT_PAREN = 163;
     /** Key code constant: Volume Mute key.
-     * Mutes the speaker, unlike {@link #KEYCODE_MUTE}.
-     * This key should normally be implemented as a toggle such that the first press
-     * mutes the speaker and the second press restores the original volume. */
+     * Mute key for speaker (unlike {@link #KEYCODE_MUTE}, which is the mute key for the
+     * microphone). This key should normally be implemented as a toggle such that the first press
+     * mutes the speaker and the second press restores the original volume.
+     */
     public static final int KEYCODE_VOLUME_MUTE     = 164;
     /** Key code constant: Info key.
      * Common on TV remotes to show additional information related to what is
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index f807da8..0c30cbb 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1554,9 +1554,14 @@
 
     void handleAppVisibility(boolean visible) {
         if (mAppVisible != visible) {
+            final boolean previousVisible = getHostVisibility() == View.VISIBLE;
             mAppVisible = visible;
-            mAppVisibilityChanged = true;
-            scheduleTraversals();
+            final boolean currentVisible = getHostVisibility() == View.VISIBLE;
+            // Root view only cares about whether it is visible or not.
+            if (previousVisible != currentVisible) {
+                mAppVisibilityChanged = true;
+                scheduleTraversals();
+            }
             if (!mAppVisible) {
                 WindowManagerGlobal.trimForeground();
             }
@@ -1846,8 +1851,13 @@
                 renderer.setStopped(mStopped);
             }
             if (!mStopped) {
-                mNewSurfaceNeeded = true;
-                scheduleTraversals();
+                // Unnecessary to traverse if the window is not yet visible.
+                if (getHostVisibility() == View.VISIBLE) {
+                    // Make sure that relayoutWindow will be called to get valid surface because
+                    // the previous surface may have been released.
+                    mAppVisibilityChanged = true;
+                    scheduleTraversals();
+                }
             } else {
                 if (renderer != null) {
                     renderer.destroyHardwareResources(mView);
@@ -2028,7 +2038,8 @@
     }
 
     int getHostVisibility() {
-        return (mAppVisible || mForceDecorViewVisibility) ? mView.getVisibility() : View.GONE;
+        return mView != null && (mAppVisible || mForceDecorViewVisibility)
+                ? mView.getVisibility() : View.GONE;
     }
 
     /**
@@ -9729,14 +9740,6 @@
             }
         }
 
-        @Override
-        public void windowFocusChanged(boolean hasFocus) {
-            final ViewRootImpl viewAncestor = mViewAncestor.get();
-            if (viewAncestor != null) {
-                viewAncestor.windowFocusChanged(hasFocus);
-            }
-        }
-
         private static int checkCallingPermission(String permission) {
             try {
                 return ActivityManager.getService().checkPermission(
diff --git a/core/java/android/view/ViewRootInsetsControllerHost.java b/core/java/android/view/ViewRootInsetsControllerHost.java
index efffa2b..9793f8c 100644
--- a/core/java/android/view/ViewRootInsetsControllerHost.java
+++ b/core/java/android/view/ViewRootInsetsControllerHost.java
@@ -133,7 +133,7 @@
             //  frame instead.
             final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
             mApplier.applyParams(t, params);
-            mApplier.applyTransaction(t, -1);
+            t.apply();
         }
     }
 
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 3b4fcc0..7fe810a 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -129,17 +129,15 @@
 
 /**
  * The interface that apps use to talk to the window manager.
- * </p><p>
- * Each window manager instance is bound to a particular {@link Display}.
- * To obtain a {@link WindowManager} for a different display, use
- * {@link Context#createDisplayContext} to obtain a {@link Context} for that
- * display, then use <code>Context.getSystemService(Context.WINDOW_SERVICE)</code>
- * to get the WindowManager.
- * </p><p>
- * The simplest way to show a window on another display is to create a
- * {@link Presentation}.  The presentation will automatically obtain a
- * {@link WindowManager} and {@link Context} for that display.
- * </p>
+ * <p>
+ * Each window manager instance is bound to a {@link Display}. To obtain the
+ * <code>WindowManager</code> associated with a display,
+ * call {@link Context#createWindowContext(Display, int, Bundle)} to get the display's UI context,
+ * then call {@link Context#getSystemService(String)} or {@link Context#getSystemService(Class)} on
+ * the UI context.
+ * <p>
+ * The simplest way to show a window on a particular display is to create a {@link Presentation},
+ * which automatically obtains a <code>WindowManager</code> and context for the display.
  */
 @SystemService(Context.WINDOW_SERVICE)
 public interface WindowManager extends ViewManager {
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 4730eaa..7680aa6 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -3957,8 +3957,10 @@
         }
 
         if (isBitSet(nonDefaultFields, fieldIndex++)) {
+            parcel.writeString(mCollectionItemInfo.getRowTitle());
             parcel.writeInt(mCollectionItemInfo.getRowIndex());
             parcel.writeInt(mCollectionItemInfo.getRowSpan());
+            parcel.writeString(mCollectionItemInfo.getColumnTitle());
             parcel.writeInt(mCollectionItemInfo.getColumnIndex());
             parcel.writeInt(mCollectionItemInfo.getColumnSpan());
             parcel.writeInt(mCollectionItemInfo.isHeading() ? 1 : 0);
@@ -4100,8 +4102,9 @@
                                      ci.mHierarchical, ci.mSelectionMode);
         CollectionItemInfo cii = other.mCollectionItemInfo;
         mCollectionItemInfo = (cii == null)  ? null
-                : new CollectionItemInfo(cii.mRowIndex, cii.mRowSpan, cii.mColumnIndex,
-                                         cii.mColumnSpan, cii.mHeading, cii.mSelected);
+                : new CollectionItemInfo(cii.mRowTitle, cii.mRowIndex, cii.mRowSpan,
+                        cii.mColumnTitle, cii.mColumnIndex, cii.mColumnSpan,
+                        cii.mHeading, cii.mSelected);
         ExtraRenderingInfo ti = other.mExtraRenderingInfo;
         mExtraRenderingInfo = (ti == null) ? null
                 : new ExtraRenderingInfo(ti);
@@ -4221,8 +4224,10 @@
         if (mCollectionItemInfo != null) mCollectionItemInfo.recycle();
         mCollectionItemInfo = isBitSet(nonDefaultFields, fieldIndex++)
                 ? CollectionItemInfo.obtain(
+                        parcel.readString(),
                         parcel.readInt(),
                         parcel.readInt(),
+                        parcel.readString(),
                         parcel.readInt(),
                         parcel.readInt(),
                         parcel.readInt() == 1,
@@ -5570,8 +5575,9 @@
          * @hide
          */
         public static CollectionItemInfo obtain(CollectionItemInfo other) {
-            return CollectionItemInfo.obtain(other.mRowIndex, other.mRowSpan, other.mColumnIndex,
-                    other.mColumnSpan, other.mHeading, other.mSelected);
+            return CollectionItemInfo.obtain(other.mRowTitle, other.mRowIndex, other.mRowSpan,
+                    other.mColumnTitle, other.mColumnIndex, other.mColumnSpan, other.mHeading,
+                    other.mSelected);
         }
 
         /**
@@ -5612,10 +5618,36 @@
          */
         public static CollectionItemInfo obtain(int rowIndex, int rowSpan,
                 int columnIndex, int columnSpan, boolean heading, boolean selected) {
+            return obtain(null, rowIndex, rowSpan, null, columnIndex,
+                    columnSpan, heading, selected);
+        }
+
+        /**
+         * Obtains a pooled instance.
+         *
+         * <p>In most situations object pooling is not beneficial. Creates a new instance using the
+         * constructor {@link
+         * AccessibilityNodeInfo.CollectionItemInfo#CollectionItemInfo(int,
+         * int, int, int, boolean, boolean)} instead.
+         *
+         * @param rowTitle The row title at which the item is located.
+         * @param rowIndex The row index at which the item is located.
+         * @param rowSpan The number of rows the item spans.
+         * @param columnTitle The column title at which the item is located.
+         * @param columnIndex The column index at which the item is located.
+         * @param columnSpan The number of columns the item spans.
+         * @param heading Whether the item is a heading. (Prefer
+         *                {@link AccessibilityNodeInfo#setHeading(boolean)})
+         * @param selected Whether the item is selected.
+         */
+        @NonNull
+        public static CollectionItemInfo obtain(@Nullable String rowTitle, int rowIndex,
+                int rowSpan, @Nullable String columnTitle, int columnIndex, int columnSpan,
+                boolean heading, boolean selected) {
             final CollectionItemInfo info = sPool.acquire();
             if (info == null) {
-                return new CollectionItemInfo(
-                        rowIndex, rowSpan, columnIndex, columnSpan, heading, selected);
+                return new CollectionItemInfo(rowTitle, rowIndex, rowSpan, columnTitle,
+                        columnIndex, columnSpan, heading, selected);
             }
 
             info.mRowIndex = rowIndex;
@@ -5624,6 +5656,8 @@
             info.mColumnSpan = columnSpan;
             info.mHeading = heading;
             info.mSelected = selected;
+            info.mRowTitle = rowTitle;
+            info.mColumnTitle = columnTitle;
             return info;
         }
 
@@ -5633,6 +5667,8 @@
         private int mColumnSpan;
         private int mRowSpan;
         private boolean mSelected;
+        private String mRowTitle;
+        private String mColumnTitle;
 
         /**
          * Creates a new instance.
@@ -5660,12 +5696,33 @@
          */
         public CollectionItemInfo(int rowIndex, int rowSpan, int columnIndex, int columnSpan,
                 boolean heading, boolean selected) {
+            this(null, rowIndex, rowSpan, null, columnIndex, columnSpan,
+                    heading, selected);
+        }
+
+        /**
+         * Creates a new instance.
+         *
+         * @param rowTitle The row title at which the item is located.
+         * @param rowIndex The row index at which the item is located.
+         * @param rowSpan The number of rows the item spans.
+         * @param columnTitle The column title at which the item is located.
+         * @param columnIndex The column index at which the item is located.
+         * @param columnSpan The number of columns the item spans.
+         * @param heading Whether the item is a heading.
+         * @param selected Whether the item is selected.
+         */
+        public CollectionItemInfo(@Nullable String rowTitle, int rowIndex, int rowSpan,
+                @Nullable String columnTitle, int columnIndex, int columnSpan, boolean heading,
+                boolean selected) {
             mRowIndex = rowIndex;
             mRowSpan = rowSpan;
             mColumnIndex = columnIndex;
             mColumnSpan = columnSpan;
             mHeading = heading;
             mSelected = selected;
+            mRowTitle = rowTitle;
+            mColumnTitle = columnTitle;
         }
 
         /**
@@ -5725,6 +5782,26 @@
         }
 
         /**
+         * Gets the row title at which the item is located.
+         *
+         * @return The row title.
+         */
+        @Nullable
+        public String getRowTitle() {
+            return mRowTitle;
+        }
+
+        /**
+         * Gets the column title at which the item is located.
+         *
+         * @return The column title.
+         */
+        @Nullable
+        public String getColumnTitle() {
+            return mColumnTitle;
+        }
+
+        /**
          * Recycles this instance.
          *
          * <p>In most situations object pooling is not beneficial, and recycling is not necessary.
@@ -5741,6 +5818,8 @@
             mRowSpan = 0;
             mHeading = false;
             mSelected = false;
+            mRowTitle = null;
+            mColumnTitle = null;
         }
     }
 
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index f724285..3d4d9ec 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -338,7 +338,10 @@
      * Maps bitmaps to unique indicies to avoid Bitmap duplication.
      */
     @UnsupportedAppUsage
-    private BitmapCache mBitmapCache;
+    private BitmapCache mBitmapCache = new BitmapCache();
+
+    /** Cache of ApplicationInfos used by collection items. */
+    private ApplicationInfoCache mApplicationInfoCache = new ApplicationInfoCache();
 
     /**
      * Indicates whether or not this RemoteViews object is contained as a child of any other
@@ -576,7 +579,7 @@
             return 0;
         }
 
-        public void setBitmapCache(BitmapCache bitmapCache) {
+        public void setHierarchyRootData(HierarchyRootData root) {
             // Do nothing
         }
 
@@ -605,14 +608,6 @@
             return false;
         }
 
-        /**
-         * Overridden by subclasses which have (or inherit) an ApplicationInfo instance
-         * as member variable
-         */
-        public boolean hasSameAppInfo(ApplicationInfo parentInfo) {
-            return true;
-        }
-
         public void visitUris(@NonNull Consumer<Uri> visitor) {
             // Nothing to visit by default
         }
@@ -690,9 +685,8 @@
             }
         }
 
-        // Because pruning can remove the need for bitmaps, we reconstruct the bitmap cache
-        mBitmapCache = new BitmapCache();
-        setBitmapCache(mBitmapCache);
+        // Because pruning can remove the need for bitmaps, we reconstruct the caches.
+        reconstructCaches();
     }
 
     /**
@@ -938,23 +932,70 @@
         ArrayList<RemoteViews> list;
     }
 
-    private static class SetRemoteCollectionItemListAdapterAction extends Action {
+    /**
+     * Cache of {@link ApplicationInfo}s that can be used to ensure that the same
+     * {@link ApplicationInfo} instance is used throughout the RemoteViews.
+     */
+    private static class ApplicationInfoCache {
+        private final Map<Pair<String, Integer>, ApplicationInfo> mPackageUserToApplicationInfo;
+
+        ApplicationInfoCache() {
+            mPackageUserToApplicationInfo = new ArrayMap<>();
+        }
+
+        /**
+         * Adds the {@link ApplicationInfo} to the cache if it's not present. Returns either the
+         * provided {@code applicationInfo} or a previously added value with the same package name
+         * and uid.
+         */
+        @Nullable
+        ApplicationInfo getOrPut(@Nullable ApplicationInfo applicationInfo) {
+            Pair<String, Integer> key = getPackageUserKey(applicationInfo);
+            if (key == null) return null;
+            return mPackageUserToApplicationInfo.computeIfAbsent(key, ignored -> applicationInfo);
+        }
+
+        /** Puts the {@link ApplicationInfo} in the cache, replacing any previously stored value. */
+        void put(@Nullable ApplicationInfo applicationInfo) {
+            Pair<String, Integer> key = getPackageUserKey(applicationInfo);
+            if (key == null) return;
+            mPackageUserToApplicationInfo.put(key, applicationInfo);
+        }
+
+        /**
+         * Returns the currently stored {@link ApplicationInfo} from the cache matching
+         * {@code  applicationInfo}, or null if there wasn't any.
+         */
+        @Nullable ApplicationInfo get(@Nullable ApplicationInfo applicationInfo) {
+            Pair<String, Integer> key = getPackageUserKey(applicationInfo);
+            if (key == null) return null;
+            return mPackageUserToApplicationInfo.get(key);
+        }
+    }
+
+    private class SetRemoteCollectionItemListAdapterAction extends Action {
         private final RemoteCollectionItems mItems;
 
         SetRemoteCollectionItemListAdapterAction(@IdRes int id, RemoteCollectionItems items) {
             viewId = id;
             mItems = items;
+            mItems.setHierarchyRootData(getHierarchyRootData());
         }
 
         SetRemoteCollectionItemListAdapterAction(Parcel parcel) {
             viewId = parcel.readInt();
-            mItems = parcel.readTypedObject(RemoteCollectionItems.CREATOR);
+            mItems = new RemoteCollectionItems(parcel, getHierarchyRootData());
+        }
+
+        @Override
+        public void setHierarchyRootData(HierarchyRootData rootData) {
+            mItems.setHierarchyRootData(rootData);
         }
 
         @Override
         public void writeToParcel(Parcel dest, int flags) {
             dest.writeInt(viewId);
-            dest.writeTypedObject(mItems, flags);
+            mItems.writeToParcel(dest, flags, /* attached= */ true);
         }
 
         @Override
@@ -1602,8 +1643,8 @@
         }
 
         @Override
-        public void setBitmapCache(BitmapCache bitmapCache) {
-            bitmapId = bitmapCache.getBitmapId(bitmap);
+        public void setHierarchyRootData(HierarchyRootData rootData) {
+            bitmapId = rootData.mBitmapCache.getBitmapId(bitmap);
         }
 
         @Override
@@ -2220,15 +2261,6 @@
         }
     }
 
-    private void configureRemoteViewsAsChild(RemoteViews rv) {
-        rv.setBitmapCache(mBitmapCache);
-        rv.setNotRoot();
-    }
-
-    void setNotRoot() {
-        mIsRoot = false;
-    }
-
     private static boolean hasStableId(View view) {
         Object tag = view.getTag(com.android.internal.R.id.remote_views_stable_id);
         return tag != null;
@@ -2302,17 +2334,14 @@
             mNestedViews = nestedViews;
             mIndex = index;
             mStableId = stableId;
-            if (nestedViews != null) {
-                configureRemoteViewsAsChild(nestedViews);
-            }
+            nestedViews.configureAsChild(getHierarchyRootData());
         }
 
-        ViewGroupActionAdd(Parcel parcel, BitmapCache bitmapCache, ApplicationInfo info,
-                int depth, Map<Class, Object> classCookies) {
+        ViewGroupActionAdd(Parcel parcel, ApplicationInfo info, int depth) {
             viewId = parcel.readInt();
             mIndex = parcel.readInt();
             mStableId = parcel.readInt();
-            mNestedViews = new RemoteViews(parcel, bitmapCache, info, depth, classCookies);
+            mNestedViews = new RemoteViews(parcel, getHierarchyRootData(), info, depth);
             mNestedViews.addFlags(mApplyFlags);
         }
 
@@ -2324,8 +2353,8 @@
         }
 
         @Override
-        public boolean hasSameAppInfo(ApplicationInfo parentInfo) {
-            return mNestedViews.hasSameAppInfo(parentInfo);
+        public void setHierarchyRootData(HierarchyRootData root) {
+            mNestedViews.configureAsChild(root);
         }
 
         private int findViewIndexToRecycle(ViewGroup target, RemoteViews newContent) {
@@ -2494,11 +2523,6 @@
         }
 
         @Override
-        public void setBitmapCache(BitmapCache bitmapCache) {
-            mNestedViews.setBitmapCache(bitmapCache);
-        }
-
-        @Override
         public int mergeBehavior() {
             return MERGE_APPEND;
         }
@@ -3505,8 +3529,7 @@
     protected RemoteViews(ApplicationInfo application, @LayoutRes int layoutId) {
         mApplication = application;
         mLayoutId = layoutId;
-        mBitmapCache = new BitmapCache();
-        mClassCookies = null;
+        mApplicationInfoCache.put(application);
     }
 
     private boolean hasMultipleLayouts() {
@@ -3562,12 +3585,10 @@
         mLandscape = landscape;
         mPortrait = portrait;
 
-        mBitmapCache = new BitmapCache();
-        configureRemoteViewsAsChild(landscape);
-        configureRemoteViewsAsChild(portrait);
-
         mClassCookies = (portrait.mClassCookies != null)
                 ? portrait.mClassCookies : landscape.mClassCookies;
+
+        configureDescendantsAsChildren();
     }
 
     /**
@@ -3593,10 +3614,12 @@
             throw new IllegalArgumentException("Too many RemoteViews in constructor");
         }
         if (remoteViews.size() == 1) {
-            initializeFrom(remoteViews.values().iterator().next());
+            // If the map only contains a single mapping, treat this as if that RemoteViews was
+            // passed as the top-level RemoteViews.
+            RemoteViews single = remoteViews.values().iterator().next();
+            initializeFrom(single, /* hierarchyRoot= */ single);
             return;
         }
-        mBitmapCache = new BitmapCache();
         mClassCookies = initializeSizedRemoteViews(
                 remoteViews.entrySet().stream().map(
                         entry -> {
@@ -3611,6 +3634,8 @@
         mLayoutId = smallestView.mLayoutId;
         mViewId = smallestView.mViewId;
         mLightBackgroundLayoutId = smallestView.mLightBackgroundLayoutId;
+
+        configureDescendantsAsChildren();
     }
 
     // Initialize mSizedRemoteViews and return the class cookies.
@@ -3639,7 +3664,6 @@
             } else {
                 sizedRemoteViews.add(view);
             }
-            configureRemoteViewsAsChild(view);
             view.setIdealSize(size);
             if (classCookies == null) {
                 classCookies = view.mClassCookies;
@@ -3654,13 +3678,38 @@
      * Creates a copy of another RemoteViews.
      */
     public RemoteViews(RemoteViews src) {
-        initializeFrom(src);
+        initializeFrom(src, /* hierarchyRoot= */ null);
     }
 
-    private void initializeFrom(RemoteViews src) {
-        mBitmapCache = src.mBitmapCache;
+    /**
+     * No-arg constructor for use with {@link #initializeFrom(RemoteViews, RemoteViews)}. A
+     * constructor taking two RemoteViews parameters would clash with the landscape/portrait
+     * constructor.
+     */
+    private RemoteViews() {}
+
+    private static RemoteViews createInitializedFrom(@NonNull RemoteViews src,
+            @Nullable RemoteViews hierarchyRoot) {
+        RemoteViews child = new RemoteViews();
+        child.initializeFrom(src, hierarchyRoot);
+        return child;
+    }
+
+    private void initializeFrom(@NonNull RemoteViews src, @Nullable RemoteViews hierarchyRoot) {
+        if (hierarchyRoot == null || src.mIsRoot) {
+            // If there's no provided root, or if src was itself a root, then this RemoteViews is
+            // the root of the new hierarchy.
+            mIsRoot = true;
+            mBitmapCache = new BitmapCache();
+            mApplicationInfoCache = new ApplicationInfoCache();
+            hierarchyRoot = this;
+        } else {
+            // Otherwise, we're a descendant in the hierarchy.
+            mIsRoot = false;
+            mBitmapCache = hierarchyRoot.mBitmapCache;
+            mApplicationInfoCache = hierarchyRoot.mApplicationInfoCache;
+        }
         mApplication = src.mApplication;
-        mIsRoot = src.mIsRoot;
         mLayoutId = src.mLayoutId;
         mLightBackgroundLayoutId = src.mLightBackgroundLayoutId;
         mApplyFlags = src.mApplyFlags;
@@ -3669,21 +3718,21 @@
         mProviderInstanceId = src.mProviderInstanceId;
 
         if (src.hasLandscapeAndPortraitLayouts()) {
-            mLandscape = new RemoteViews(src.mLandscape);
-            mPortrait = new RemoteViews(src.mPortrait);
+            mLandscape = createInitializedFrom(src.mLandscape, hierarchyRoot);
+            mPortrait = createInitializedFrom(src.mPortrait, hierarchyRoot);
         }
 
         if (src.hasSizedRemoteViews()) {
             mSizedRemoteViews = new ArrayList<>(src.mSizedRemoteViews.size());
             for (RemoteViews srcView : src.mSizedRemoteViews) {
-                mSizedRemoteViews.add(new RemoteViews(srcView));
+                mSizedRemoteViews.add(createInitializedFrom(srcView, hierarchyRoot));
             }
         }
 
         if (src.mActions != null) {
             Parcel p = Parcel.obtain();
             p.putClassCookies(mClassCookies);
-            src.writeActionsToParcel(p);
+            src.writeActionsToParcel(p, /* flags= */ 0);
             p.setDataPosition(0);
             // Since src is already in memory, we do not care about stack overflow as it has
             // already been read once.
@@ -3691,9 +3740,11 @@
             p.recycle();
         }
 
-        // Now that everything is initialized and duplicated, setting a new BitmapCache will
-        // re-initialize the cache.
-        setBitmapCache(new BitmapCache());
+        // Now that everything is initialized and duplicated, create new caches for this
+        // RemoteViews and recursively set up all descendants.
+        if (mIsRoot) {
+            reconstructCaches();
+        }
     }
 
     /**
@@ -3702,11 +3753,11 @@
      * @param parcel
      */
     public RemoteViews(Parcel parcel) {
-        this(parcel, null, null, 0, null);
+        this(parcel, /* rootParent= */ null, /* info= */ null, /* depth= */ 0);
     }
 
-    private RemoteViews(Parcel parcel, BitmapCache bitmapCache, ApplicationInfo info, int depth,
-            Map<Class, Object> classCookies) {
+    private RemoteViews(@NonNull Parcel parcel, @Nullable HierarchyRootData rootData,
+            @Nullable ApplicationInfo info, int depth) {
         if (depth > MAX_NESTED_VIEWS
                 && (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID)) {
             throw new IllegalArgumentException("Too many nested views.");
@@ -3715,20 +3766,17 @@
 
         int mode = parcel.readInt();
 
-        // We only store a bitmap cache in the root of the RemoteViews.
-        if (bitmapCache == null) {
+        if (rootData == null) {
+            // We only store a bitmap cache in the root of the RemoteViews.
             mBitmapCache = new BitmapCache(parcel);
             // Store the class cookies such that they are available when we clone this RemoteView.
             mClassCookies = parcel.copyClassCookies();
         } else {
-            setBitmapCache(bitmapCache);
-            mClassCookies = classCookies;
-            setNotRoot();
+            configureAsChild(rootData);
         }
 
         if (mode == MODE_NORMAL) {
-            mApplication = parcel.readInt() == 0 ? info :
-                    ApplicationInfo.CREATOR.createFromParcel(parcel);
+            mApplication = ApplicationInfo.CREATOR.createFromParcel(parcel);
             mIdealSize = parcel.readInt() == 0 ? null : SizeF.CREATOR.createFromParcel(parcel);
             mLayoutId = parcel.readInt();
             mViewId = parcel.readInt();
@@ -3743,8 +3791,7 @@
             }
             List<RemoteViews> remoteViews = new ArrayList<>(numViews);
             for (int i = 0; i < numViews; i++) {
-                RemoteViews view = new RemoteViews(parcel, mBitmapCache, info, depth,
-                        mClassCookies);
+                RemoteViews view = new RemoteViews(parcel, getHierarchyRootData(), info, depth);
                 info = view.mApplication;
                 remoteViews.add(view);
             }
@@ -3756,9 +3803,9 @@
             mLightBackgroundLayoutId = smallestView.mLightBackgroundLayoutId;
         } else {
             // MODE_HAS_LANDSCAPE_AND_PORTRAIT
-            mLandscape = new RemoteViews(parcel, mBitmapCache, info, depth, mClassCookies);
-            mPortrait = new RemoteViews(parcel, mBitmapCache, mLandscape.mApplication, depth,
-                    mClassCookies);
+            mLandscape = new RemoteViews(parcel, getHierarchyRootData(), info, depth);
+            mPortrait =
+                    new RemoteViews(parcel, getHierarchyRootData(), mLandscape.mApplication, depth);
             mApplication = mPortrait.mApplication;
             mLayoutId = mPortrait.mLayoutId;
             mViewId = mPortrait.mViewId;
@@ -3766,6 +3813,11 @@
         }
         mApplyFlags = parcel.readInt();
         mProviderInstanceId = parcel.readLong();
+
+        // Ensure that all descendants have their caches set up recursively.
+        if (mIsRoot) {
+            configureDescendantsAsChildren();
+        }
     }
 
     private void readActionsFromParcel(Parcel parcel, int depth) {
@@ -3788,8 +3840,7 @@
             case REFLECTION_ACTION_TAG:
                 return new ReflectionAction(parcel);
             case VIEW_GROUP_ACTION_ADD_TAG:
-                return new ViewGroupActionAdd(parcel, mBitmapCache, mApplication, depth,
-                        mClassCookies);
+                return new ViewGroupActionAdd(parcel, mApplication, depth);
             case VIEW_GROUP_ACTION_REMOVE_TAG:
                 return new ViewGroupActionRemove(parcel);
             case VIEW_CONTENT_NAVIGATION_TAG:
@@ -3879,28 +3930,56 @@
     }
 
     /**
-     * Recursively sets BitmapCache in the hierarchy and update the bitmap ids.
+     * Sets the root of the hierarchy and then recursively traverses the tree to update the root
+     * and populate caches for all descendants.
      */
-    private void setBitmapCache(BitmapCache bitmapCache) {
-        mBitmapCache = bitmapCache;
+    private void configureAsChild(@NonNull HierarchyRootData rootData) {
+        mIsRoot = false;
+        mBitmapCache = rootData.mBitmapCache;
+        mApplicationInfoCache = rootData.mApplicationInfoCache;
+        mClassCookies = rootData.mClassCookies;
+        configureDescendantsAsChildren();
+    }
+
+    /**
+     * Recursively traverses the tree to update the root and populate caches for all descendants.
+     */
+    private void configureDescendantsAsChildren() {
+        // Before propagating down the tree, replace our application from the root application info
+        // cache, to ensure the same instance is present throughout the hierarchy to allow for
+        // squashing.
+        mApplication = mApplicationInfoCache.getOrPut(mApplication);
+
+        HierarchyRootData rootData = getHierarchyRootData();
         if (hasSizedRemoteViews()) {
             for (RemoteViews remoteView : mSizedRemoteViews) {
-                remoteView.setBitmapCache(bitmapCache);
+                remoteView.configureAsChild(rootData);
             }
         } else if (hasLandscapeAndPortraitLayouts()) {
-            mLandscape.setBitmapCache(bitmapCache);
-            mPortrait.setBitmapCache(bitmapCache);
+            mLandscape.configureAsChild(rootData);
+            mPortrait.configureAsChild(rootData);
         } else {
             if (mActions != null) {
-                final int count = mActions.size();
-                for (int i = 0; i < count; ++i) {
-                    mActions.get(i).setBitmapCache(bitmapCache);
+                for (Action action : mActions) {
+                    action.setHierarchyRootData(rootData);
                 }
             }
         }
     }
 
     /**
+     * Recreates caches at the root level of the hierarchy, then recursively populates the caches
+     * down the hierarchy.
+     */
+    private void reconstructCaches() {
+        if (!mIsRoot) return;
+        mBitmapCache = new BitmapCache();
+        mApplicationInfoCache = new ApplicationInfoCache();
+        mApplication = mApplicationInfoCache.getOrPut(mApplication);
+        configureDescendantsAsChildren();
+    }
+
+    /**
      * Returns an estimate of the bitmap heap memory usage for this RemoteViews.
      */
     /** @hide */
@@ -5848,21 +5927,18 @@
 
     /** @hide */
     public void updateAppInfo(@NonNull ApplicationInfo info) {
-        if (mApplication != null && mApplication.sourceDir.equals(info.sourceDir)) {
+        ApplicationInfo existing = mApplicationInfoCache.get(info);
+        if (existing != null && !existing.sourceDir.equals(info.sourceDir)) {
             // Overlay paths are generated against a particular version of an application.
             // The overlays paths of a newly upgraded application are incompatible with the
             // old version of the application.
-            mApplication = info;
+            return;
         }
-        if (hasSizedRemoteViews()) {
-            for (RemoteViews layout : mSizedRemoteViews) {
-                layout.updateAppInfo(info);
-            }
-        }
-        if (hasLandscapeAndPortraitLayouts()) {
-            mLandscape.updateAppInfo(info);
-            mPortrait.updateAppInfo(info);
-        }
+
+        // If we can update to the new AppInfo, put it in the cache and propagate the change
+        // throughout the hierarchy.
+        mApplicationInfoCache.put(info);
+        configureDescendantsAsChildren();
     }
 
     private Context getContextForResourcesEnsuringCorrectCachedApkPaths(Context context) {
@@ -6028,6 +6104,8 @@
     }
 
     public void writeToParcel(Parcel dest, int flags) {
+        boolean prevSquashingAllowed = dest.allowSquashing();
+
         if (!hasMultipleLayouts()) {
             dest.writeInt(MODE_NORMAL);
             // We only write the bitmap cache if we are the root RemoteViews, as this cache
@@ -6035,12 +6113,7 @@
             if (mIsRoot) {
                 mBitmapCache.writeBitmapsToParcel(dest, flags);
             }
-            if (!mIsRoot && (flags & PARCELABLE_ELIDE_DUPLICATES) != 0) {
-                dest.writeInt(0);
-            } else {
-                dest.writeInt(1);
-                mApplication.writeToParcel(dest, flags);
-            }
+            mApplication.writeToParcel(dest, flags);
             if (mIsRoot || mIdealSize == null) {
                 dest.writeInt(0);
             } else {
@@ -6050,17 +6123,15 @@
             dest.writeInt(mLayoutId);
             dest.writeInt(mViewId);
             dest.writeInt(mLightBackgroundLayoutId);
-            writeActionsToParcel(dest);
+            writeActionsToParcel(dest, flags);
         } else if (hasSizedRemoteViews()) {
             dest.writeInt(MODE_HAS_SIZED_REMOTEVIEWS);
             if (mIsRoot) {
                 mBitmapCache.writeBitmapsToParcel(dest, flags);
             }
-            int childFlags = flags;
             dest.writeInt(mSizedRemoteViews.size());
             for (RemoteViews view : mSizedRemoteViews) {
-                view.writeToParcel(dest, childFlags);
-                childFlags |= PARCELABLE_ELIDE_DUPLICATES;
+                view.writeToParcel(dest, flags);
             }
         } else {
             dest.writeInt(MODE_HAS_LANDSCAPE_AND_PORTRAIT);
@@ -6071,13 +6142,15 @@
             }
             mLandscape.writeToParcel(dest, flags);
             // Both RemoteViews already share the same package and user
-            mPortrait.writeToParcel(dest, flags | PARCELABLE_ELIDE_DUPLICATES);
+            mPortrait.writeToParcel(dest, flags);
         }
         dest.writeInt(mApplyFlags);
         dest.writeLong(mProviderInstanceId);
+
+        dest.restoreAllowSquashing(prevSquashingAllowed);
     }
 
-    private void writeActionsToParcel(Parcel parcel) {
+    private void writeActionsToParcel(Parcel parcel, int flags) {
         int count;
         if (mActions != null) {
             count = mActions.size();
@@ -6088,8 +6161,7 @@
         for (int i = 0; i < count; i++) {
             Action a = mActions.get(i);
             parcel.writeInt(a.getActionTag());
-            a.writeToParcel(parcel, a.hasSameAppInfo(mApplication)
-                    ? PARCELABLE_ELIDE_DUPLICATES : 0);
+            a.writeToParcel(parcel, flags);
         }
     }
 
@@ -6568,6 +6640,8 @@
         private final boolean mHasStableIds;
         private final int mViewTypeCount;
 
+        private HierarchyRootData mHierarchyRootData;
+
         RemoteCollectionItems(
                 long[] ids, RemoteViews[] views, boolean hasStableIds, int viewTypeCount) {
             mIds = ids;
@@ -6590,16 +6664,53 @@
                         "View type count is set to " + viewTypeCount + ", but the collection "
                                 + "contains " + layoutIdCount + " different layout ids");
             }
+
+            // Until the collection items are attached to a parent, we configure the first item
+            // to be the root of the others to share caches and save space during serialization.
+            if (views.length > 0) {
+                setHierarchyRootData(views[0].getHierarchyRootData());
+                views[0].mIsRoot = true;
+            }
         }
 
-        RemoteCollectionItems(Parcel in) {
+        RemoteCollectionItems(@NonNull Parcel in, @Nullable HierarchyRootData hierarchyRootData) {
+            mHasStableIds = in.readBoolean();
+            mViewTypeCount = in.readInt();
             int length = in.readInt();
             mIds = new long[length];
             in.readLongArray(mIds);
+
+            boolean attached = in.readBoolean();
             mViews = new RemoteViews[length];
-            in.readTypedArray(mViews, RemoteViews.CREATOR);
-            mHasStableIds = in.readBoolean();
-            mViewTypeCount = in.readInt();
+            int firstChildIndex;
+            if (attached) {
+                if (hierarchyRootData == null) {
+                    throw new IllegalStateException("Cannot unparcel a RemoteCollectionItems that "
+                            + "was parceled as attached without providing data for a root "
+                            + "RemoteViews");
+                }
+                mHierarchyRootData = hierarchyRootData;
+                firstChildIndex = 0;
+            } else {
+                mViews[0] = new RemoteViews(in);
+                mHierarchyRootData = mViews[0].getHierarchyRootData();
+                firstChildIndex = 1;
+            }
+
+            for (int i = firstChildIndex; i < length; i++) {
+                mViews[i] = new RemoteViews(
+                        in,
+                        mHierarchyRootData,
+                        /* info= */ null,
+                        /* depth= */ 0);
+            }
+        }
+
+        void setHierarchyRootData(@NonNull HierarchyRootData rootData) {
+            mHierarchyRootData = rootData;
+            for (RemoteViews view : mViews) {
+                view.configureAsChild(rootData);
+            }
         }
 
         @Override
@@ -6609,11 +6720,39 @@
 
         @Override
         public void writeToParcel(@NonNull Parcel dest, int flags) {
-            dest.writeInt(mIds.length);
-            dest.writeLongArray(mIds);
-            dest.writeTypedArray(mViews, flags);
+            writeToParcel(dest, flags, /* attached= */ false);
+        }
+
+        private void writeToParcel(@NonNull Parcel dest, int flags, boolean attached) {
+            boolean prevAllowSquashing = dest.allowSquashing();
+
             dest.writeBoolean(mHasStableIds);
             dest.writeInt(mViewTypeCount);
+            dest.writeInt(mIds.length);
+            dest.writeLongArray(mIds);
+
+            if (attached && mHierarchyRootData == null) {
+                throw new IllegalStateException("Cannot call writeToParcelAttached for a "
+                        + "RemoteCollectionItems without first calling setHierarchyRootData()");
+            }
+
+            // Write whether we parceled as attached or not. This allows cleaner validation and
+            // proper error messaging when unparceling later.
+            dest.writeBoolean(attached);
+            boolean restoreRoot = false;
+            if (!attached && mViews.length > 0 && !mViews[0].mIsRoot) {
+                // If we're writing unattached, temporarily set the first item as the root so that
+                // the bitmap cache is written to the parcel.
+                restoreRoot = true;
+                mViews[0].mIsRoot = true;
+            }
+
+            for (RemoteViews view : mViews) {
+                view.writeToParcel(dest, flags);
+            }
+
+            if (restoreRoot) mViews[0].mIsRoot = false;
+            dest.restoreAllowSquashing(prevAllowSquashing);
         }
 
         /**
@@ -6671,7 +6810,7 @@
             @NonNull
             @Override
             public RemoteCollectionItems createFromParcel(@NonNull Parcel source) {
-                return new RemoteCollectionItems(source);
+                return new RemoteCollectionItems(source, /* hierarchyRoot= */ null);
             }
 
             @NonNull
@@ -6846,4 +6985,29 @@
         viewId |= childId;
         return viewId;
     }
+
+    @Nullable
+    private static Pair<String, Integer> getPackageUserKey(@Nullable ApplicationInfo info) {
+        if (info == null || info.packageName ==  null) return null;
+        return Pair.create(info.packageName, info.uid);
+    }
+
+    private HierarchyRootData getHierarchyRootData() {
+        return new HierarchyRootData(mBitmapCache, mApplicationInfoCache, mClassCookies);
+    }
+
+    private static final class HierarchyRootData {
+        final BitmapCache mBitmapCache;
+        final ApplicationInfoCache mApplicationInfoCache;
+        final Map<Class, Object> mClassCookies;
+
+        HierarchyRootData(
+                BitmapCache bitmapCache,
+                ApplicationInfoCache applicationInfoCache,
+                Map<Class, Object> classCookies) {
+            mBitmapCache = bitmapCache;
+            mApplicationInfoCache = applicationInfoCache;
+            mClassCookies = classCookies;
+        }
+    }
 }
diff --git a/core/java/android/widget/SpellChecker.java b/core/java/android/widget/SpellChecker.java
index 6b3a698..c532557 100644
--- a/core/java/android/widget/SpellChecker.java
+++ b/core/java/android/widget/SpellChecker.java
@@ -20,6 +20,7 @@
 import android.text.Editable;
 import android.text.Selection;
 import android.text.Spanned;
+import android.text.SpannedString;
 import android.text.method.WordIterator;
 import android.text.style.SpellCheckSpan;
 import android.text.style.SuggestionSpan;
@@ -416,7 +417,15 @@
                     }
                     if (spellCheckSpanStart >= 0 && spellCheckSpanEnd > spellCheckSpanStart
                             && end > start) {
-                        removeErrorSuggestionSpan(editable, start, end, RemoveReason.OBSOLETE);
+                        boolean visibleToAccessibility = mTextView.isVisibleToAccessibility();
+                        CharSequence beforeText =
+                                visibleToAccessibility ? new SpannedString(editable) : null;
+                        boolean spanRemoved = removeErrorSuggestionSpan(
+                                editable, start, end, RemoveReason.OBSOLETE);
+                        if (visibleToAccessibility && spanRemoved) {
+                            mTextView.sendAccessibilityEventTypeViewTextChanged(
+                                    beforeText, start, end);
+                        }
                     }
                 }
                 return spellCheckSpan;
@@ -437,8 +446,9 @@
         OBSOLETE,
     }
 
-    private static void removeErrorSuggestionSpan(
+    private static boolean removeErrorSuggestionSpan(
             Editable editable, int start, int end, RemoveReason reason) {
+        boolean spanRemoved = false;
         SuggestionSpan[] spans = editable.getSpans(start, end, SuggestionSpan.class);
         for (SuggestionSpan span : spans) {
             if (editable.getSpanStart(span) == start
@@ -450,8 +460,10 @@
                             + editable.subSequence(start, end) + ", reason: " + reason);
                 }
                 editable.removeSpan(span);
+                spanRemoved = true;
             }
         }
+        return spanRemoved;
     }
 
     @Override
@@ -568,8 +580,13 @@
         }
         SuggestionSpan suggestionSpan =
                 new SuggestionSpan(mTextView.getContext(), suggestions, flags);
-        removeErrorSuggestionSpan(editable, start, end, RemoveReason.REPLACE);
+        boolean spanRemoved = removeErrorSuggestionSpan(editable, start, end, RemoveReason.REPLACE);
+        boolean sendAccessibilityEvent = !spanRemoved && mTextView.isVisibleToAccessibility();
+        CharSequence beforeText = sendAccessibilityEvent ? new SpannedString(editable) : null;
         editable.setSpan(suggestionSpan, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+        if (sendAccessibilityEvent) {
+            mTextView.sendAccessibilityEventTypeViewTextChanged(beforeText, start, end);
+        }
 
         mTextView.invalidateRegion(start, end, false /* No cursor involved */);
     }
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 8fba583..496fa67 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -12501,6 +12501,11 @@
         return TextUtils.trimToParcelableSize(mTransformed);
     }
 
+    boolean isVisibleToAccessibility() {
+        return AccessibilityManager.getInstance(mContext).isEnabled()
+                && (isFocused() || (isSelected() && isShown()));
+    }
+
     void sendAccessibilityEventTypeViewTextChanged(CharSequence beforeText,
             int fromIndex, int removedCount, int addedCount) {
         AccessibilityEvent event =
@@ -12512,6 +12517,16 @@
         sendAccessibilityEventUnchecked(event);
     }
 
+    void sendAccessibilityEventTypeViewTextChanged(CharSequence beforeText,
+            int fromIndex, int toIndex) {
+        AccessibilityEvent event =
+                AccessibilityEvent.obtain(AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED);
+        event.setFromIndex(fromIndex);
+        event.setToIndex(toIndex);
+        event.setBeforeText(beforeText);
+        sendAccessibilityEventUnchecked(event);
+    }
+
     private InputMethodManager getInputMethodManager() {
         return getContext().getSystemService(InputMethodManager.class);
     }
@@ -13826,10 +13841,9 @@
             }
             TextView.this.handleTextChanged(buffer, start, before, after);
 
-            if (AccessibilityManager.getInstance(mContext).isEnabled()
-                    && (isFocused() || (isSelected() && isShown()))) {
+            if (isVisibleToAccessibility()) {
                 sendAccessibilityEventTypeViewTextChanged(mBeforeText, start, before, after);
-                mBeforeText = TextUtils.stringOrSpannedString(mTransformed);
+                mBeforeText = null;
             }
         }
 
@@ -13857,54 +13871,6 @@
                 Log.v(LOG_TAG, "onSpanAdded s=" + s + " e=" + e + " what=" + what + ": " + buf);
             }
             TextView.this.spanChange(buf, what, -1, s, -1, e);
-            // Note we don't update mBeforeText here. We look for SuggestionSpans added after the
-            // text content changes.
-            if (AccessibilityManager.getInstance(mContext).isEnabled()
-                    && (isFocused() || (isSelected() && isShown()))
-                    && (what instanceof SuggestionSpan)) {
-                // When the user types a new word, and SuggestionSpans on the existing words will be
-                // removed and added again. We don't need to send out events for existing
-                // SuggestionSpans. Multiple spans can be placed on the range.
-                if (mBeforeText instanceof SpannedString) {
-                    final SpannedString beforeSpannedString = (SpannedString) mBeforeText;
-                    if ((beforeSpannedString.getSpanStart(what) == s)
-                            && (beforeSpannedString.getSpanEnd(what) == e)) {
-                        // Exactly same span is found.
-                        return;
-                    }
-                    // Suggestion span couldn't be found. Try to find a suggestion span that has the
-                    // same contents.
-                    SuggestionSpan[] suggestionSpans = beforeSpannedString.getSpans(s, e,
-                            SuggestionSpan.class);
-                    for (final SuggestionSpan suggestionSpan : suggestionSpans) {
-                        final int start = beforeSpannedString.getSpanStart(suggestionSpan);
-                        if (start != s) {
-                            continue;
-                        }
-                        final int end = beforeSpannedString.getSpanEnd(suggestionSpan);
-                        if (end != e) {
-                            continue;
-                        }
-                        if (equalSuggestionSpan(suggestionSpan, (SuggestionSpan) what)) {
-                            return;
-                        }
-                    }
-                }
-                AccessibilityEvent event =
-                        AccessibilityEvent.obtain(AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED);
-                event.setFromIndex(s);
-                event.setToIndex(e);
-                event.setBeforeText(mBeforeText);
-                sendAccessibilityEventUnchecked(event);
-            }
-        }
-
-        private boolean equalSuggestionSpan(SuggestionSpan span1, SuggestionSpan span2) {
-            // We compare flags because flags will determine the underline color.
-            return Arrays.equals(span1.getSuggestions(), span2.getSuggestions())
-                    && Objects.equals(span1.getLocaleObject(), span2.getLocaleObject())
-                    && span1.getLocale().equals(span2.getLocale())
-                    && (span1.getFlags() == span2.getFlags());
         }
 
         public void onSpanRemoved(Spannable buf, Object what, int s, int e) {
diff --git a/core/java/android/window/DisplayAreaOrganizer.java b/core/java/android/window/DisplayAreaOrganizer.java
index 6758a3b..974a1dd 100644
--- a/core/java/android/window/DisplayAreaOrganizer.java
+++ b/core/java/android/window/DisplayAreaOrganizer.java
@@ -109,6 +109,18 @@
     public static final int FEATURE_ONE_HANDED_BACKGROUND_PANEL = FEATURE_SYSTEM_FIRST + 8;
 
     /**
+     * Display area hosting IME window tokens (@see ImeContainer). By default, IMEs are parented
+     * to FEATURE_IME_PLACEHOLDER but can be reparented under other RootDisplayArea.
+     *
+     * This feature can register organizers in order to disable the reparenting logic and manage
+     * the position and settings of the container manually. This is useful for foldable devices
+     * which require custom UX rules for the IME position (e.g. IME on one screen and the focused
+     * app on another screen).
+     * @hide
+     */
+    public static final int FEATURE_IME = FEATURE_SYSTEM_FIRST + 9;
+
+    /**
      * The last boundary of display area for system features
      */
     public static final int FEATURE_SYSTEM_LAST = 10_000;
diff --git a/core/java/android/window/DisplayWindowPolicyController.java b/core/java/android/window/DisplayWindowPolicyController.java
new file mode 100644
index 0000000..7677b89
--- /dev/null
+++ b/core/java/android/window/DisplayWindowPolicyController.java
@@ -0,0 +1,84 @@
+/*
+ * 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.window;
+
+import android.annotation.NonNull;
+import android.content.ComponentName;
+import android.content.pm.ActivityInfo;
+
+import java.io.PrintWriter;
+import java.util.List;
+
+/**
+ * Abstract class to control the policies of the windows that can be displayed on the virtual
+ * display.
+ *
+ * @hide
+ */
+public abstract class DisplayWindowPolicyController {
+    /**
+     * The window flags that we are interested in.
+     * @see android.view.WindowManager.LayoutParams
+     * @see #keepActivityOnWindowFlagsChanged
+     */
+    private int mWindowFlags;
+
+    /**
+     * Returns {@code true} if the given window flags contain the flags that we're interested in.
+     */
+    public final boolean isInterestedWindowFlags(int windowFlags) {
+        return (mWindowFlags & windowFlags) != 0;
+    }
+
+    /**
+     * Sets the window flags that we’re interested in and expected
+     * #keepActivityOnWindowFlagsChanged to be called if any changes.
+     */
+    public final void setInterestedWindowFlags(int windowFlags) {
+        mWindowFlags = windowFlags;
+    }
+
+    /**
+     * Returns {@code true} if the given activities can be displayed on this virtual display.
+     */
+    public abstract boolean canContainActivities(@NonNull List<ActivityInfo> activities);
+
+    /**
+     * Called when an Activity window is layouted with the new changes where contains the
+     * window flags that we’re interested in.
+     * Returns {@code false} if the Activity cannot remain on the display and the activity task will
+     * be moved back to default display.
+     */
+    public abstract boolean keepActivityOnWindowFlagsChanged(
+            ActivityInfo activityInfo, int windowFlags);
+
+    /**
+     * This is called when the top activity of the display is changed.
+     */
+    public void onTopActivityChanged(ComponentName topActivity, int uid) {}
+
+    /**
+     * This is called when the apps that contains running activities on the display has changed.
+     */
+    public void onRunningAppsChanged(int[] runningUids) {}
+
+    /** Dump debug data */
+    public void dump(String prefix, final PrintWriter pw) {
+        pw.println(prefix + "DisplayWindowPolicyController{" + super.toString() + "}");
+        pw.println(prefix + "  mWindowFlags=" + mWindowFlags);
+    }
+}
diff --git a/core/java/android/window/ITaskFragmentOrganizer.aidl b/core/java/android/window/ITaskFragmentOrganizer.aidl
index 5eb432e..cdfa206 100644
--- a/core/java/android/window/ITaskFragmentOrganizer.aidl
+++ b/core/java/android/window/ITaskFragmentOrganizer.aidl
@@ -19,12 +19,11 @@
 import android.content.res.Configuration;
 import android.os.Bundle;
 import android.os.IBinder;
-import android.window.TaskFragmentAppearedInfo;
 import android.window.TaskFragmentInfo;
 
 /** @hide */
 oneway interface ITaskFragmentOrganizer {
-    void onTaskFragmentAppeared(in TaskFragmentAppearedInfo taskFragmentAppearedInfo);
+    void onTaskFragmentAppeared(in TaskFragmentInfo taskFragmentInfo);
     void onTaskFragmentInfoChanged(in TaskFragmentInfo taskFragmentInfo);
     void onTaskFragmentVanished(in TaskFragmentInfo taskFragmentInfo);
 
diff --git a/core/java/android/window/TaskFragmentAppearedInfo.java b/core/java/android/window/TaskFragmentAppearedInfo.java
deleted file mode 100644
index 89d9a95..0000000
--- a/core/java/android/window/TaskFragmentAppearedInfo.java
+++ /dev/null
@@ -1,93 +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.window;
-
-import android.annotation.NonNull;
-import android.annotation.TestApi;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.view.SurfaceControl;
-
-/**
- * Data object for the TaskFragment info provided when a TaskFragment is presented to an organizer.
- * @hide
- */
-@TestApi
-public final class TaskFragmentAppearedInfo implements Parcelable {
-
-    @NonNull
-    private final TaskFragmentInfo mTaskFragmentInfo;
-
-    @NonNull
-    private final SurfaceControl mLeash;
-
-    /** @hide */
-    public TaskFragmentAppearedInfo(
-            @NonNull TaskFragmentInfo taskFragmentInfo, @NonNull SurfaceControl leash) {
-        mTaskFragmentInfo = taskFragmentInfo;
-        mLeash = leash;
-    }
-
-    @NonNull
-    public TaskFragmentInfo getTaskFragmentInfo() {
-        return mTaskFragmentInfo;
-    }
-
-    @NonNull
-    public SurfaceControl getLeash() {
-        return mLeash;
-    }
-
-    private TaskFragmentAppearedInfo(Parcel in) {
-        mTaskFragmentInfo = in.readTypedObject(TaskFragmentInfo.CREATOR);
-        mLeash = in.readTypedObject(SurfaceControl.CREATOR);
-    }
-
-    /** @hide */
-    @Override
-    public void writeToParcel(@NonNull Parcel dest, int flags) {
-        dest.writeTypedObject(mTaskFragmentInfo, flags);
-        dest.writeTypedObject(mLeash, flags);
-    }
-
-    @NonNull
-    public static final Creator<TaskFragmentAppearedInfo> CREATOR =
-            new Creator<TaskFragmentAppearedInfo>() {
-                @Override
-                public TaskFragmentAppearedInfo createFromParcel(Parcel in) {
-                    return new TaskFragmentAppearedInfo(in);
-                }
-
-                @Override
-                public TaskFragmentAppearedInfo[] newArray(int size) {
-                    return new TaskFragmentAppearedInfo[size];
-                }
-            };
-
-    @Override
-    public String toString() {
-        return "TaskFragmentAppearedInfo{"
-                + " taskFragmentInfo=" + mTaskFragmentInfo
-                + "}";
-    }
-
-    /** @hide */
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-}
diff --git a/core/java/android/window/TaskFragmentOrganizer.java b/core/java/android/window/TaskFragmentOrganizer.java
index 337c5a1..7e7d370 100644
--- a/core/java/android/window/TaskFragmentOrganizer.java
+++ b/core/java/android/window/TaskFragmentOrganizer.java
@@ -120,8 +120,7 @@
     }
 
     /** Called when a TaskFragment is created and organized by this organizer. */
-    public void onTaskFragmentAppeared(
-            @NonNull TaskFragmentAppearedInfo taskFragmentAppearedInfo) {}
+    public void onTaskFragmentAppeared(@NonNull TaskFragmentInfo taskFragmentInfo) {}
 
     /** Called when the status of an organized TaskFragment is changed. */
     public void onTaskFragmentInfoChanged(@NonNull TaskFragmentInfo taskFragmentInfo) {}
@@ -169,7 +168,7 @@
 
     private final ITaskFragmentOrganizer mInterface = new ITaskFragmentOrganizer.Stub() {
         @Override
-        public void onTaskFragmentAppeared(@NonNull TaskFragmentAppearedInfo taskFragmentInfo) {
+        public void onTaskFragmentAppeared(@NonNull TaskFragmentInfo taskFragmentInfo) {
             mExecutor.execute(
                     () -> TaskFragmentOrganizer.this.onTaskFragmentAppeared(taskFragmentInfo));
         }
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 9b1bef06..359c382 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -28,6 +28,7 @@
 import android.annotation.Nullable;
 import android.app.Activity;
 import android.app.ActivityManager;
+import android.app.ActivityTaskManager;
 import android.app.SharedElementCallback;
 import android.app.prediction.AppPredictionContext;
 import android.app.prediction.AppPredictionManager;
@@ -70,9 +71,11 @@
 import android.os.Bundle;
 import android.os.Environment;
 import android.os.Handler;
+import android.os.IBinder;
 import android.os.Message;
 import android.os.Parcelable;
 import android.os.PatternMatcher;
+import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -151,6 +154,19 @@
         ChooserListAdapter.ChooserListCommunicator,
         SelectableTargetInfoCommunicator {
     private static final String TAG = "ChooserActivity";
+
+    /**
+     * Whether this chooser is operating in "headless springboard" mode (as determined during
+     * onCreate). In this mode, our activity sits in the background and waits for the new
+     * "unbundled" chooser to handle the Sharesheet experience; the system ChooserActivity is
+     * responsible only for providing the startActivityAsCaller permission token and keeping it
+     * valid for the life of the unbundled delegate activity.
+     *
+     * TODO: when the unbundled chooser is fully launched, the system-side "springboard" can use a
+     * simpler implementation that doesn't inherit from ResolverActivity.
+     */
+    private boolean mIsHeadlessSpringboardActivity;
+
     private AppPredictor mPersonalAppPredictor;
     private AppPredictor mWorkAppPredictor;
     private boolean mShouldDisplayLandscape;
@@ -170,6 +186,17 @@
             = "com.android.internal.app.ChooserActivity.EXTRA_PRIVATE_RETAIN_IN_ON_STOP";
 
     /**
+     * Boolean extra added to "unbundled Sharesheet" delegation intents to signal whether the app
+     * prediction service is available. Our query of the service <em>availability</em> depends on
+     * privileges that are only available in the system, even though the service itself would then
+     * be available to the unbundled component. For now, we just include the query result as part of
+     * the handover intent.
+     * TODO: investigate whether the privileged query is necessary to determine the availability.
+     */
+    protected static final String EXTRA_IS_APP_PREDICTION_SERVICE_AVAILABLE =
+            "com.android.internal.app.ChooserActivity.EXTRA_IS_APP_PREDICTION_SERVICE_AVAILABLE";
+
+    /**
      * Transition name for the first image preview.
      * To be used for shared element transition into this activity.
      * @hide
@@ -235,6 +262,11 @@
 
     private static final float DIRECT_SHARE_EXPANSION_RATE = 0.78f;
 
+    private boolean mEnableChooserDelegate =
+            DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI,
+                    SystemUiDeviceConfigFlags.USE_DELEGATE_CHOOSER,
+                    false);
+
     private static final int DEFAULT_SALT_EXPIRATION_DAYS = 7;
     private int mMaxHashSaltDays = DeviceConfig.getInt(DeviceConfig.NAMESPACE_SYSTEMUI,
             SystemUiDeviceConfigFlags.HASH_SALT_MAX_DAYS,
@@ -500,6 +532,12 @@
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
+        if (handOverToDelegateChooser()) {
+            super_onCreate(savedInstanceState);
+            mIsHeadlessSpringboardActivity = true;
+            return;
+        }
+
         final long intentReceivedTime = System.currentTimeMillis();
         getChooserActivityLogger().logSharesheetTriggered();
         // This is the only place this value is being set. Effectively final.
@@ -714,6 +752,69 @@
         postponeEnterTransition();
     }
 
+    private boolean handOverToDelegateChooser() {
+        // Check the explicit classname so that we don't interfere with the flow of any subclasses.
+        if (!this.getClass().getName().equals("com.android.internal.app.ChooserActivity")
+                || !mEnableChooserDelegate) {
+            return false;
+        }
+
+        try {
+            IBinder permissionToken = ActivityTaskManager.getService()
+                    .requestStartActivityPermissionToken(getActivityToken());
+            Intent delegationIntent = new Intent();
+            final ComponentName delegateActivity = ComponentName.unflattenFromString(
+                    Resources.getSystem().getString(R.string.config_chooserActivity));
+            delegationIntent.setComponent(delegateActivity);
+            delegationIntent.putExtra(Intent.EXTRA_INTENT, getIntent());
+            delegationIntent.putExtra(ActivityTaskManager.EXTRA_PERMISSION_TOKEN, permissionToken);
+
+            // Query prediction availability; mIsAppPredictorComponentAvailable isn't initialized.
+            delegationIntent.putExtra(
+                    EXTRA_IS_APP_PREDICTION_SERVICE_AVAILABLE, isAppPredictionServiceAvailable());
+
+            delegationIntent.addFlags(Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP);
+
+            // Don't close until the delegate finishes, or the token will be invalidated.
+            mAwaitingDelegateResponse = true;
+            startActivityForResult(delegationIntent, REQUEST_CODE_RETURN_FROM_DELEGATE_CHOOSER);
+            return true;
+        } catch (RemoteException e) {
+            Log.e(TAG, e.toString());
+        }
+        return false;
+    }
+
+    @Override
+    protected void onRestart() {
+        if (mIsHeadlessSpringboardActivity) {
+            super_onRestart();
+            return;
+        }
+
+        super.onRestart();
+    }
+
+    @Override
+    protected void onSaveInstanceState(Bundle outState) {
+        if (mIsHeadlessSpringboardActivity) {
+            super_onSaveInstanceState(outState);
+            return;
+        }
+
+        super.onSaveInstanceState(outState);
+    }
+
+    @Override
+    protected void onRestoreInstanceState(Bundle savedInstanceState) {
+        if (mIsHeadlessSpringboardActivity) {
+            super_onRestoreInstanceState(savedInstanceState);
+            return;
+        }
+
+        super.onRestoreInstanceState(savedInstanceState);
+    }
+
     @Override
     protected int appliedThemeResId() {
         return R.style.Theme_DeviceDefault_Chooser;
@@ -886,7 +987,8 @@
             return false;
         }
 
-        // Check if the app prediction component actually exists on the device.
+        // Check if the app prediction component actually exists on the device. The component is
+        // only visible when this is running in a system activity; otherwise this check will fail.
         Intent intent = new Intent();
         intent.setComponent(appPredictionComponentName);
         if (getPackageManager().resolveService(intent, PackageManager.MATCH_ALL) == null) {
@@ -998,6 +1100,11 @@
 
     @Override
     public void onConfigurationChanged(Configuration newConfig) {
+        if (mIsHeadlessSpringboardActivity) {
+            super_onConfigurationChanged(newConfig);
+            return;
+        }
+
         super.onConfigurationChanged(newConfig);
         ViewPager viewPager = findViewById(R.id.profile_pager);
         if (viewPager.isLayoutRtl()) {
@@ -1543,6 +1650,11 @@
     @Override
     protected void onDestroy() {
         super.onDestroy();
+
+        if (mIsHeadlessSpringboardActivity) {
+            return;
+        }
+
         if (mRefinementResultReceiver != null) {
             mRefinementResultReceiver.destroy();
             mRefinementResultReceiver = null;
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 9af4f91..fd8637a 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -152,7 +152,7 @@
     /** See {@link #setRetainInOnStop}. */
     private boolean mRetainInOnStop;
 
-    private static final int REQUEST_CODE_RETURN_FROM_DELEGATE_CHOOSER = 20;
+    protected static final int REQUEST_CODE_RETURN_FROM_DELEGATE_CHOOSER = 20;
 
     private static final String EXTRA_SHOW_FRAGMENT_ARGS = ":settings:show_fragment_args";
     private static final String EXTRA_FRAGMENT_ARG_KEY = ":settings:fragment_args_key";
@@ -323,6 +323,86 @@
         super.onCreate(savedInstanceState);
     }
 
+    /**
+     * Pass-through API to support {@link ChooserActivity} running in "headless springboard" mode
+     * where we hand over to the unbundled chooser (while violating many of the invariants of a
+     * typical ResolverActivity implementation). Subclasses running in this mode need to be able
+     * to opt-out of the normal ResolverActivity behavior.
+     *
+     * TODO: this should be removed later on in the unbundling migration, when the springboard
+     * activity no longer needs to derive from ResolverActivity. The hold-over design here is
+     * <em>not</em> good practice (e.g. there could be other events that weren't anticipated as
+     * requiring this kind of "pass-through" override, and so might fall back on ResolverActivity
+     * implementations that depend on the invariants that are violated in the headless mode). If
+     * necessary, we could instead consider using a springboard-only activity on the system side
+     * immediately, which would delegate either to the unbundled chooser, or to a
+     * (properly-inheriting) system ChooserActivity. This would have performance implications even
+     * when the unbundling experiment is disabled.
+     */
+    protected void super_onRestart() {
+        super.onRestart();
+    }
+
+    /**
+     * Pass-through API to support {@link ChooserActivity} running in "headless springboard" mode
+     * where we hand over to the unbundled chooser (while violating many of the invariants of a
+     * typical ResolverActivity implementation). Subclasses running in this mode need to be able
+     * to opt-out of the normal ResolverActivity behavior.
+     *
+     * TODO: this should be removed later on in the unbundling migration, when the springboard
+     * activity no longer needs to derive from ResolverActivity. The hold-over design here is
+     * <em>not</em> good practice (e.g. there could be other events that weren't anticipated as
+     * requiring this kind of "pass-through" override, and so might fall back on ResolverActivity
+     * implementations that depend on the invariants that are violated in the headless mode). If
+     * necessary, we could instead consider using a springboard-only activity on the system side
+     * immediately, which would delegate either to the unbundled chooser, or to a
+     * (properly-inheriting) system ChooserActivity. This would have performance implications even
+     * when the unbundling experiment is disabled.
+     */
+    protected void super_onSaveInstanceState(Bundle outState) {
+        super.onSaveInstanceState(outState);
+    }
+
+    /**
+     * Pass-through API to support {@link ChooserActivity} running in "headless springboard" mode
+     * where we hand over to the unbundled chooser (while violating many of the invariants of a
+     * typical ResolverActivity implementation). Subclasses running in this mode need to be able
+     * to opt-out of the normal ResolverActivity behavior.
+     *
+     * TODO: this should be removed later on in the unbundling migration, when the springboard
+     * activity no longer needs to derive from ResolverActivity. The hold-over design here is
+     * <em>not</em> good practice (e.g. there could be other events that weren't anticipated as
+     * requiring this kind of "pass-through" override, and so might fall back on ResolverActivity
+     * implementations that depend on the invariants that are violated in the headless mode). If
+     * necessary, we could instead consider using a springboard-only activity on the system side
+     * immediately, which would delegate either to the unbundled chooser, or to a
+     * (properly-inheriting) system ChooserActivity. This would have performance implications even
+     * when the unbundling experiment is disabled.
+     */
+    protected void super_onRestoreInstanceState(Bundle savedInstanceState) {
+        super.onRestoreInstanceState(savedInstanceState);
+    }
+
+    /**
+     * Pass-through API to support {@link ChooserActivity} running in "headless springboard" mode
+     * where we hand over to the unbundled chooser (while violating many of the invariants of a
+     * typical ResolverActivity implementation). Subclasses running in this mode need to be able
+     * to opt-out of the normal ResolverActivity behavior.
+     *
+     * TODO: this should be removed later on in the unbundling migration, when the springboard
+     * activity no longer needs to derive from ResolverActivity. The hold-over design here is
+     * <em>not</em> good practice (e.g. there could be other events that weren't anticipated as
+     * requiring this kind of "pass-through" override, and so might fall back on ResolverActivity
+     * implementations that depend on the invariants that are violated in the headless mode). If
+     * necessary, we could instead consider using a springboard-only activity on the system side
+     * immediately, which would delegate either to the unbundled chooser, or to a
+     * (properly-inheriting) system ChooserActivity. This would have performance implications even
+     * when the unbundling experiment is disabled.
+     */
+    public void super_onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+    }
+
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         // Use a specialized prompt when we're handling the 'Home' app startActivity()
@@ -877,7 +957,7 @@
         }
         final Intent intent = getIntent();
         if ((intent.getFlags() & FLAG_ACTIVITY_NEW_TASK) != 0 && !isVoiceInteraction()
-                && !mResolvingHome && !mRetainInOnStop) {
+                && !mResolvingHome && !mRetainInOnStop && !mAwaitingDelegateResponse) {
             // This resolver is in the unusual situation where it has been
             // launched at the top of a new task.  We don't let it be added
             // to the recent tasks shown to the user, and we need to make sure
diff --git a/core/java/com/android/internal/net/OWNERS b/core/java/com/android/internal/net/OWNERS
index 050cb5c..71f997b 100644
--- a/core/java/com/android/internal/net/OWNERS
+++ b/core/java/com/android/internal/net/OWNERS
@@ -1,9 +1,4 @@
 set noparent
+file:platform/packages/modules/Connectivity:master:/OWNERS_core_networking
 
-codewiz@google.com
-ek@google.com
-jchalard@google.com
 jsharkey@android.com
-lorenzo@google.com
-reminv@google.com
-satk@google.com
diff --git a/core/java/com/android/internal/os/ClassLoaderFactory.java b/core/java/com/android/internal/os/ClassLoaderFactory.java
index 8b0411d..8f5e97d 100644
--- a/core/java/com/android/internal/os/ClassLoaderFactory.java
+++ b/core/java/com/android/internal/os/ClassLoaderFactory.java
@@ -24,6 +24,7 @@
 import dalvik.system.DexClassLoader;
 import dalvik.system.PathClassLoader;
 
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -100,14 +101,25 @@
     }
 
     /**
-     * Same as {@code createClassLoader} below, but passes a null list of shared
-     * libraries.
+     * Same as {@code createClassLoader} below, but passes a null list of shared libraries. This
+     * method is used only to load platform classes (i.e. those in framework.jar or services.jar),
+     * and MUST NOT be used for loading untrusted classes, especially the app classes. For the
+     * latter case, use the below method which accepts list of shared libraries so that the classes
+     * don't have unlimited access to all shared libraries.
      */
     public static ClassLoader createClassLoader(String dexPath,
             String librarySearchPath, String libraryPermittedPath, ClassLoader parent,
             int targetSdkVersion, boolean isNamespaceShared, String classLoaderName) {
+        // b/205164833: allow framework classes to have access to all public vendor libraries.
+        // This is because those classes are part of the platform and don't have an app manifest
+        // where required libraries can be specified using the <uses-native-library> tag.
+        // Note that this still does not give access to "private" vendor libraries.
+        List<String> nativeSharedLibraries = new ArrayList<>();
+        nativeSharedLibraries.add("ALL");
+
         return createClassLoader(dexPath, librarySearchPath, libraryPermittedPath,
-            parent, targetSdkVersion, isNamespaceShared, classLoaderName, null, null, null);
+            parent, targetSdkVersion, isNamespaceShared, classLoaderName, null,
+            nativeSharedLibraries, null);
     }
 
     /**
diff --git a/core/java/com/android/internal/protolog/ProtoLogGroup.java b/core/java/com/android/internal/protolog/ProtoLogGroup.java
index 954204f..5ac4936 100644
--- a/core/java/com/android/internal/protolog/ProtoLogGroup.java
+++ b/core/java/com/android/internal/protolog/ProtoLogGroup.java
@@ -84,7 +84,7 @@
             Consts.TAG_WM),
     WM_DEBUG_LAYER_MIRRORING(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, true,
             Consts.TAG_WM),
-    WM_DEBUG_WALLPAPER(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, true, Consts.TAG_WM),
+    WM_DEBUG_WALLPAPER(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false, Consts.TAG_WM),
     TEST_GROUP(true, true, false, "WindowManagerProtoLogTest");
 
     private final boolean mEnabled;
diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java
index f93e32f..6673f67 100644
--- a/core/java/com/android/internal/view/BaseIWindow.java
+++ b/core/java/com/android/internal/view/BaseIWindow.java
@@ -90,10 +90,6 @@
     }
 
     @Override
-    public void windowFocusChanged(boolean hasFocus) {
-    }
-
-    @Override
     public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {
         if (out != null) {
             try {
diff --git a/core/java/com/android/server/net/OWNERS b/core/java/com/android/server/net/OWNERS
index d3836d4..62c5737 100644
--- a/core/java/com/android/server/net/OWNERS
+++ b/core/java/com/android/server/net/OWNERS
@@ -1,8 +1,2 @@
 set noparent
-
-codewiz@google.com
-jchalard@google.com
-junyulai@google.com
-lorenzo@google.com
-reminv@google.com
-satk@google.com
+file:platform/packages/modules/Connectivity:master:/OWNERS_core_networking
diff --git a/core/jni/android_graphics_BLASTBufferQueue.cpp b/core/jni/android_graphics_BLASTBufferQueue.cpp
index cdfd089..e7b3fba 100644
--- a/core/jni/android_graphics_BLASTBufferQueue.cpp
+++ b/core/jni/android_graphics_BLASTBufferQueue.cpp
@@ -79,7 +79,7 @@
                                            jlong framenumber) {
     sp<BLASTBufferQueue> queue = reinterpret_cast<BLASTBufferQueue*>(ptr);
     auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionPtr);
-    queue->mergeWithNextTransaction(transaction, framenumber);
+    queue->mergeWithNextTransaction(transaction, CC_UNLIKELY(framenumber < 0) ? 0 : framenumber);
 }
 
 static jlong nativeGetLastAcquiredFrameNum(JNIEnv* env, jclass clazz, jlong ptr) {
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 5781b1e..601280a 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1751,6 +1751,13 @@
     <permission android:name="android.permission.ACCESS_MOCK_LOCATION"
         android:protectionLevel="signature" />
 
+    <!-- @SystemApi @hide Allows automotive applications to control location
+         suspend state for power management use cases.
+         <p>Not for use by third-party applications.
+    -->
+    <permission android:name="android.permission.AUTOMOTIVE_GNSS_CONTROLS"
+        android:protectionLevel="signature|privileged" />
+
     <!-- ======================================= -->
     <!-- Permissions for accessing networks -->
     <!-- ======================================= -->
@@ -6388,6 +6395,10 @@
                  android:permission="android.permission.BIND_JOB_SERVICE">
         </service>
 
+        <service android:name="com.android.server.compos.IsolatedCompilationJobService"
+                 android:permission="android.permission.BIND_JOB_SERVICE">
+        </service>
+
         <service android:name="com.android.server.PruneInstantAppsJobService"
                  android:permission="android.permission.BIND_JOB_SERVICE" >
         </service>
diff --git a/core/res/res/anim/task_fragment_close_enter.xml b/core/res/res/anim/task_fragment_close_enter.xml
new file mode 100644
index 0000000..c940552
--- /dev/null
+++ b/core/res/res/anim/task_fragment_close_enter.xml
@@ -0,0 +1,32 @@
+<?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.
+   -->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shareInterpolator="false">
+    <scale
+        android:fromXScale="1.1"
+        android:toXScale="1"
+        android:fromYScale="1.1"
+        android:toYScale="1"
+        android:pivotX="50%"
+        android:pivotY="50%"
+        android:fillEnabled="true"
+        android:fillBefore="true"
+        android:fillAfter="true"
+        android:interpolator="@interpolator/fast_out_extra_slow_in"
+        android:duration="400"/>
+</set>
\ No newline at end of file
diff --git a/core/res/res/anim/task_fragment_close_exit.xml b/core/res/res/anim/task_fragment_close_exit.xml
new file mode 100644
index 0000000..8998f76
--- /dev/null
+++ b/core/res/res/anim/task_fragment_close_exit.xml
@@ -0,0 +1,42 @@
+<?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.
+   -->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shareInterpolator="false"
+    android:zAdjustment="top">
+    <alpha
+        android:fromAlpha="1"
+        android:toAlpha="0.0"
+        android:fillEnabled="true"
+        android:fillBefore="true"
+        android:fillAfter="true"
+        android:interpolator="@interpolator/linear"
+        android:startOffset="33"
+        android:duration="50"/>
+    <scale
+        android:fromXScale="1"
+        android:toXScale="0.9"
+        android:fromYScale="1"
+        android:toYScale="0.9"
+        android:pivotX="50%"
+        android:pivotY="50%"
+        android:fillEnabled="true"
+        android:fillBefore="true"
+        android:fillAfter="true"
+        android:interpolator="@interpolator/fast_out_extra_slow_in"
+        android:duration="400"/>
+</set>
diff --git a/core/res/res/anim/task_fragment_open_enter.xml b/core/res/res/anim/task_fragment_open_enter.xml
new file mode 100644
index 0000000..6bc47de
--- /dev/null
+++ b/core/res/res/anim/task_fragment_open_enter.xml
@@ -0,0 +1,41 @@
+<?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.
+   -->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shareInterpolator="false">
+    <alpha
+        android:fromAlpha="0"
+        android:toAlpha="1.0"
+        android:fillEnabled="true"
+        android:fillBefore="true"
+        android:fillAfter="true"
+        android:interpolator="@interpolator/linear"
+        android:startOffset="50"
+        android:duration="50"/>
+    <scale
+        android:fromXScale="0.85"
+        android:toXScale="1"
+        android:fromYScale="0.85"
+        android:toYScale="1"
+        android:pivotX="50%"
+        android:pivotY="50%"
+        android:fillEnabled="true"
+        android:fillBefore="true"
+        android:fillAfter="true"
+        android:interpolator="@interpolator/fast_out_extra_slow_in"
+        android:duration="400"/>
+</set>
diff --git a/core/res/res/anim/task_fragment_open_exit.xml b/core/res/res/anim/task_fragment_open_exit.xml
new file mode 100644
index 0000000..160eb84
--- /dev/null
+++ b/core/res/res/anim/task_fragment_open_exit.xml
@@ -0,0 +1,32 @@
+<?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.
+   -->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shareInterpolator="false">
+    <scale
+        android:fromXScale="1"
+        android:toXScale="1.05"
+        android:fromYScale="1"
+        android:toYScale="1.05"
+        android:pivotX="50%"
+        android:pivotY="50%"
+        android:fillEnabled="true"
+        android:fillBefore="true"
+        android:fillAfter="true"
+        android:interpolator="@interpolator/fast_out_extra_slow_in"
+        android:duration="400"/>
+</set>
\ No newline at end of file
diff --git a/core/res/res/drawable-watch/global_actions_item_red_background_shape.xml b/core/res/res/drawable-watch/global_actions_item_red_background_shape.xml
index b556a1b..4f23700 100644
--- a/core/res/res/drawable-watch/global_actions_item_red_background_shape.xml
+++ b/core/res/res/drawable-watch/global_actions_item_red_background_shape.xml
@@ -18,5 +18,5 @@
 <shape xmlns:android="http://schemas.android.com/apk/res/android"
        android:shape="rectangle">
     <corners android:radius="26dp"/>
-    <solid android:color="@color/wear_material_red_400"/>
+    <solid android:color="@color/wear_material_red_mid"/>
 </shape>
\ No newline at end of file
diff --git a/core/res/res/drawable/ic_qs_one_handed_mode.xml b/core/res/res/drawable/ic_qs_one_handed_mode.xml
new file mode 100644
index 0000000..18e5618
--- /dev/null
+++ b/core/res/res/drawable/ic_qs_one_handed_mode.xml
@@ -0,0 +1,26 @@
+<?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.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="18dp"
+        android:height="18dp"
+        android:viewportWidth="24"
+        android:viewportHeight="24">
+
+    <path android:fillColor="@android:color/white"
+          android:pathData="M4.64169 3C3.88567 3 3.27271 3.61296 3.27271 4.36898V18.4011C3.27271 19.154 3.88875 19.7701 4.64169 19.7701H12.5339C12.5339 19.7701 12.5425 18.0588 11.2324 18.0588H6.01067C5.44597 18.0588 4.98393 17.5968 4.98393 17.0321V5.73797C4.98393 5.17326 5.44597 4.71123 6.01067 4.71123H15.9358C16.5005 4.71123 16.9625 5.17326 16.9625 5.73797V9.84492C16.9625 10.9651 16.4899 12.5952 15.5936 13.2674L9.77538 9.16043C8.58505 10.425 8.88177 11.705 10.1176 12.9251L13.1978 16.0053C13.1978 16.0053 13.3231 17.4572 13.5401 18.0588C14.2034 19.8984 16.2781 20.7968 16.2781 20.7968H19.231H19.2967C20.0835 20.7968 20.7273 20.153 20.7273 19.3662V12.2543L18.9441 4.06781C18.7662 3.23718 18.4068 3 17.8729 3H4.64169Z"/>
+</vector>
\ No newline at end of file
diff --git a/core/res/res/mipmap-watch-anydpi/sym_def_app_icon_foreground.xml b/core/res/res/mipmap-watch-anydpi/sym_def_app_icon_foreground.xml
index 69c241c..68ccb3d 100644
--- a/core/res/res/mipmap-watch-anydpi/sym_def_app_icon_foreground.xml
+++ b/core/res/res/mipmap-watch-anydpi/sym_def_app_icon_foreground.xml
@@ -1,10 +1,10 @@
 <?xml version="1.0" encoding="utf-8"?>
 <inset
     xmlns:android="http://schemas.android.com/apk/res/android"
-    android:insetLeft="24dp"
-    android:insetRight="24dp"
-    android:insetTop="24dp"
-    android:insetBottom="24dp">
+    android:insetLeft="22.22%"
+    android:insetRight="22.22%"
+    android:insetTop="22.22%"
+    android:insetBottom="22.22%">
     <vector
         android:width="60dp"
         android:height="60dp"
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index b06dbd9..0f47465 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -2180,7 +2180,7 @@
     <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Апавяшчэнне з інфармацыяй пра ўсталяваны рэжым"</string>
     <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Акумулятар можа разрадзіцца хутчэй, чым прыйдзе час звычайнай зарадкі"</string>
     <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Каб павялічыць тэрмін работы акумулятара, уключаны рэжым эканоміі зараду"</string>
-    <string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Эканомія зараду"</string>
+    <string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Рэжым энергазберажэння"</string>
     <string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Рэжым эканоміі зараду выключаны"</string>
     <string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"У тэлефона дастатковы ўзровень зараду. Функцыі больш не абмежаваны."</string>
     <string name="battery_saver_charged_notification_summary" product="tablet" msgid="4426317048139996888">"У планшэта дастатковы ўзровень зараду. Функцыі больш не абмежаваны."</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index e0a5363..88d6cd3 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -1732,7 +1732,7 @@
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Réduction supplémentaire de la luminosité"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Touches de volume maintenues enfoncées. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> activé."</string>
     <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Touches de volume maintenues enfoncées. Service <xliff:g id="SERVICE_NAME">%1$s</xliff:g> désactivé."</string>
-    <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Maintenez enfoncées les deux touches de volume pendant trois secondes pour utiliser <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Maintenez les deux touches de volume enfoncées pendant trois secondes pour utiliser <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_button_prompt_text" msgid="8343213623338605305">"Choisissez une fonctionnalité à utiliser lorsque vous touchez le bouton d\'accessibilité :"</string>
     <string name="accessibility_gesture_prompt_text" msgid="8742535972130563952">"Choisissez une fonctionnalité à utiliser lorsque vous utilisez le geste d\'accessibilité (balayer l\'écran de bas en haut avec deux doigts) :"</string>
     <string name="accessibility_gesture_3finger_prompt_text" msgid="5211827854510660203">"Choisissez une fonctionnalité à utiliser lorsque vous utilisez le geste d\'accessibilité (balayer l\'écran de bas en haut avec trois doigts) :"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 3dfbd06..3387fa0 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -35,7 +35,7 @@
     <string name="mmiError" msgid="2862759606579822246">"Problem s vezom ili nevažeći MMI kôd."</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"Operacija je ograničena samo na brojeve s fiksnim biranjem."</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"Nije moguće promijeniti postavke preusmjeravanja poziva na telefonu dok ste u roamingu."</string>
-    <string name="serviceEnabled" msgid="7549025003394765639">"Usluga nije omogućena."</string>
+    <string name="serviceEnabled" msgid="7549025003394765639">"Usluga je omogućena."</string>
     <string name="serviceEnabledFor" msgid="1463104778656711613">"Usluga je omogućena za korisnika:"</string>
     <string name="serviceDisabled" msgid="641878791205871379">"Usluga je onemogućena."</string>
     <string name="serviceRegistered" msgid="3856192211729577482">"Registracija je uspješna."</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 71cda82..548d4ad2 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -51,8 +51,8 @@
     <string name="needPuk2" msgid="7032612093451537186">"Digita il PUK2 per sbloccare la SIM."</string>
     <string name="enablePin" msgid="2543771964137091212">"Operazione non riuscita; attiva blocco SIM/RUIM."</string>
     <plurals name="pinpuk_attempts" formatted="false" msgid="1619867269012213584">
+      <item quantity="one">You have <xliff:g id="NUMBER_1">%d</xliff:g> remaining attempts before SIM is locked.</item>
       <item quantity="other">Hai ancora <xliff:g id="NUMBER_1">%d</xliff:g> tentativi a disposizione prima che la SIM venga bloccata.</item>
-      <item quantity="one">Hai ancora <xliff:g id="NUMBER_0">%d</xliff:g> tentativo a disposizione prima che la SIM venga bloccata.</item>
     </plurals>
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
@@ -181,8 +181,8 @@
     <string name="low_memory" product="tv" msgid="6663680413790323318">"Lo spazio di archiviazione del dispositivo Android TV è pieno. Elimina alcuni file per liberare spazio."</string>
     <string name="low_memory" product="default" msgid="2539532364144025569">"Spazio di archiviazione del telefono esaurito. Elimina alcuni file per liberare spazio."</string>
     <plurals name="ssl_ca_cert_warning" formatted="false" msgid="2288194355006173029">
+      <item quantity="one">Certificate authorities installed</item>
       <item quantity="other">Autorità di certificazione installate</item>
-      <item quantity="one">Autorità di certificazione installata</item>
     </plurals>
     <string name="ssl_ca_cert_noti_by_unknown" msgid="4961102218216815242">"Da una terza parte sconosciuta"</string>
     <string name="ssl_ca_cert_noti_by_administrator" msgid="4564941950768783879">"Dall\'amministratore del tuo profilo di lavoro"</string>
@@ -257,8 +257,8 @@
     <string name="bugreport_option_full_title" msgid="7681035745950045690">"Report completo"</string>
     <string name="bugreport_option_full_summary" msgid="1975130009258435885">"Utilizza questa opzione per ridurre al minimo l\'interferenza di sistema quando il dispositivo non risponde, è troppo lento oppure quando ti servono tutte le sezioni della segnalazione. Non puoi inserire altri dettagli o acquisire altri screenshot."</string>
     <plurals name="bugreport_countdown" formatted="false" msgid="3906120379260059206">
+      <item quantity="one">Taking screenshot for bug report in <xliff:g id="NUMBER_1">%d</xliff:g> seconds.</item>
       <item quantity="other">Lo screenshot per la segnalazione di bug verrà acquisito tra <xliff:g id="NUMBER_1">%d</xliff:g> secondi.</item>
-      <item quantity="one">Lo screenshot per la segnalazione di bug verrà acquisito tra <xliff:g id="NUMBER_0">%d</xliff:g> secondo.</item>
     </plurals>
     <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Screenshot con segnalazione di bug effettuato correttamente"</string>
     <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Impossibile acquisire screenshot con segnalazione di bug"</string>
@@ -1061,8 +1061,8 @@
     <string name="oneMonthDurationPast" msgid="4538030857114635777">"1 mese fa"</string>
     <string name="beforeOneMonthDurationPast" msgid="8315149541372065392">"Oltre 1 mese fa"</string>
     <plurals name="last_num_days" formatted="false" msgid="687443109145393632">
+      <item quantity="one">Last <xliff:g id="COUNT_1">%d</xliff:g> days</item>
       <item quantity="other">Ultimi <xliff:g id="COUNT_1">%d</xliff:g> giorni</item>
-      <item quantity="one">Ultimo giorno (<xliff:g id="COUNT_0">%d</xliff:g>)</item>
     </plurals>
     <string name="last_month" msgid="1528906781083518683">"Ultimo mese"</string>
     <string name="older" msgid="1645159827884647400">"Precedente"</string>
@@ -1083,68 +1083,68 @@
     <string name="years" msgid="5797714729103773425">"anni"</string>
     <string name="now_string_shortest" msgid="3684914126941650330">"ora"</string>
     <plurals name="duration_minutes_shortest" formatted="false" msgid="7519574894537185135">
+      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g>m</item>
       <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> m</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> m</item>
     </plurals>
     <plurals name="duration_hours_shortest" formatted="false" msgid="2838655994500499651">
+      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g>h</item>
       <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> h</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> h</item>
     </plurals>
     <plurals name="duration_days_shortest" formatted="false" msgid="3686058472983158496">
+      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g>d</item>
       <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> g</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> g</item>
     </plurals>
     <plurals name="duration_years_shortest" formatted="false" msgid="8299112348723640338">
+      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g>y</item>
       <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> a</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> a</item>
     </plurals>
     <plurals name="duration_minutes_shortest_future" formatted="false" msgid="849196137176399440">
+      <item quantity="one">in <xliff:g id="COUNT_1">%d</xliff:g>m</item>
       <item quantity="other">tra <xliff:g id="COUNT_1">%d</xliff:g> m</item>
-      <item quantity="one">tra <xliff:g id="COUNT_0">%d</xliff:g> m</item>
     </plurals>
     <plurals name="duration_hours_shortest_future" formatted="false" msgid="5386373597343170388">
+      <item quantity="one">in <xliff:g id="COUNT_1">%d</xliff:g>h</item>
       <item quantity="other">tra <xliff:g id="COUNT_1">%d</xliff:g> h</item>
-      <item quantity="one">tra <xliff:g id="COUNT_0">%d</xliff:g> h</item>
     </plurals>
     <plurals name="duration_days_shortest_future" formatted="false" msgid="814754627092787227">
+      <item quantity="one">in <xliff:g id="COUNT_1">%d</xliff:g>d</item>
       <item quantity="other">tra <xliff:g id="COUNT_1">%d</xliff:g> g</item>
-      <item quantity="one">tra <xliff:g id="COUNT_0">%d</xliff:g> g</item>
     </plurals>
     <plurals name="duration_years_shortest_future" formatted="false" msgid="7683731800140202145">
+      <item quantity="one">in <xliff:g id="COUNT_1">%d</xliff:g>y</item>
       <item quantity="other">tra <xliff:g id="COUNT_1">%d</xliff:g> a</item>
-      <item quantity="one">tra <xliff:g id="COUNT_0">%d</xliff:g> a</item>
     </plurals>
     <plurals name="duration_minutes_relative" formatted="false" msgid="6569851308583028344">
+      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> minutes ago</item>
       <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> minuti fa</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> minuto fa</item>
     </plurals>
     <plurals name="duration_hours_relative" formatted="false" msgid="420434788589102019">
+      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> hours ago</item>
       <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> ore fa</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> ora fa</item>
     </plurals>
     <plurals name="duration_days_relative" formatted="false" msgid="6056425878237482431">
+      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> days ago</item>
       <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> giorni fa</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> giorno fa</item>
     </plurals>
     <plurals name="duration_years_relative" formatted="false" msgid="2179998228861172159">
+      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> years ago</item>
       <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> anni fa</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> anno fa</item>
     </plurals>
     <plurals name="duration_minutes_relative_future" formatted="false" msgid="5759885720917567723">
+      <item quantity="one">in <xliff:g id="COUNT_1">%d</xliff:g> minutes</item>
       <item quantity="other">tra <xliff:g id="COUNT_1">%d</xliff:g> minuti</item>
-      <item quantity="one">tra <xliff:g id="COUNT_0">%d</xliff:g> minuto</item>
     </plurals>
     <plurals name="duration_hours_relative_future" formatted="false" msgid="8963511608507707959">
+      <item quantity="one">in <xliff:g id="COUNT_1">%d</xliff:g> hours</item>
       <item quantity="other">tra <xliff:g id="COUNT_1">%d</xliff:g> ore</item>
-      <item quantity="one">tra <xliff:g id="COUNT_0">%d</xliff:g> ora</item>
     </plurals>
     <plurals name="duration_days_relative_future" formatted="false" msgid="1964709470979250702">
+      <item quantity="one">in <xliff:g id="COUNT_1">%d</xliff:g> days</item>
       <item quantity="other">tra <xliff:g id="COUNT_1">%d</xliff:g> giorni</item>
-      <item quantity="one">tra <xliff:g id="COUNT_0">%d</xliff:g> giorno</item>
     </plurals>
     <plurals name="duration_years_relative_future" formatted="false" msgid="3985129025134896371">
+      <item quantity="one">in <xliff:g id="COUNT_1">%d</xliff:g> years</item>
       <item quantity="other">tra <xliff:g id="COUNT_1">%d</xliff:g> anni</item>
-      <item quantity="one">tra <xliff:g id="COUNT_0">%d</xliff:g> anno</item>
     </plurals>
     <string name="VideoView_error_title" msgid="5750686717225068016">"Problemi video"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3782449246085134720">"Questo video non è valido per lo streaming su questo dispositivo."</string>
@@ -1526,8 +1526,8 @@
     <string name="no_matches" msgid="6472699895759164599">"Nessuna corrispondenza"</string>
     <string name="find_on_page" msgid="5400537367077438198">"Trova nella pagina"</string>
     <plurals name="matches_found" formatted="false" msgid="1101758718194295554">
+      <item quantity="one"><xliff:g id="INDEX">%d</xliff:g> of <xliff:g id="TOTAL">%d</xliff:g></item>
       <item quantity="other"><xliff:g id="INDEX">%d</xliff:g> di <xliff:g id="TOTAL">%d</xliff:g></item>
-      <item quantity="one">1 partita</item>
     </plurals>
     <string name="action_mode_done" msgid="2536182504764803222">"Fine"</string>
     <string name="progress_erasing" msgid="6891435992721028004">"Cancellazione archivio condiviso…"</string>
@@ -1659,8 +1659,8 @@
     <string name="kg_wrong_password" msgid="2384677900494439426">"Password sbagliata"</string>
     <string name="kg_wrong_pin" msgid="3680925703673166482">"PIN errato"</string>
     <plurals name="kg_too_many_failed_attempts_countdown" formatted="false" msgid="236717428673283568">
+      <item quantity="one">Try again in <xliff:g id="NUMBER">%d</xliff:g> seconds.</item>
       <item quantity="other">Riprova fra <xliff:g id="NUMBER">%d</xliff:g> secondi.</item>
-      <item quantity="one">Riprova fra 1 secondo.</item>
     </plurals>
     <string name="kg_pattern_instructions" msgid="8366024510502517748">"Inserisci la sequenza"</string>
     <string name="kg_sim_pin_instructions" msgid="6479401489471690359">"Inserisci il PIN della SIM"</string>
@@ -1859,8 +1859,8 @@
     <string name="restr_pin_error_doesnt_match" msgid="7063392698489280556">"I PIN non corrispondono. Riprova."</string>
     <string name="restr_pin_error_too_short" msgid="1547007808237941065">"Il PIN è troppo corto. Deve avere almeno quattro cifre."</string>
     <plurals name="restr_pin_countdown" formatted="false" msgid="4427486903285216153">
+      <item quantity="one">Try again in <xliff:g id="COUNT">%d</xliff:g> seconds</item>
       <item quantity="other">Riprova tra <xliff:g id="COUNT">%d</xliff:g> secondi</item>
-      <item quantity="one">Riprova tra 1 secondo</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="5897719962541636727">"Riprova più tardi"</string>
     <string name="immersive_cling_title" msgid="2307034298721541791">"Visualizzazione a schermo intero"</string>
@@ -1890,36 +1890,36 @@
     <string name="data_saver_enable_title" msgid="7080620065745260137">"Attivare Risparmio dati?"</string>
     <string name="data_saver_enable_button" msgid="4399405762586419726">"Attiva"</string>
     <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="2877101784123058273">
+      <item quantity="one">For %1$d minutes (until <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
       <item quantity="other">Per %1$d minuti (fino alle ore <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
-      <item quantity="one">Per un minuto (fino alle ore <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
     </plurals>
     <plurals name="zen_mode_duration_minutes_summary_short" formatted="false" msgid="4230730310318858312">
+      <item quantity="one">For %1$d min (until <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
       <item quantity="other">Per %1$d minuti (fino alle ore <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
-      <item quantity="one">Per 1 minuto (fino alle ore <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
     </plurals>
     <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="7725354244196466758">
+      <item quantity="one">For %1$d hours (until <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
       <item quantity="other">Per %1$d ore (fino alle ore <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
-      <item quantity="one">Per 1 ora (fino alle ore <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
     </plurals>
     <plurals name="zen_mode_duration_hours_summary_short" formatted="false" msgid="588719069121765642">
+      <item quantity="one">For %1$d hr (until <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
       <item quantity="other">Per %1$d ore (fino alle ore <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
-      <item quantity="one">Per 1 ora (fino alle ore <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
     </plurals>
     <plurals name="zen_mode_duration_minutes" formatted="false" msgid="1148568456958944998">
+      <item quantity="one">For %d minutes</item>
       <item quantity="other">Per %d minuti</item>
-      <item quantity="one">Per un minuto</item>
     </plurals>
     <plurals name="zen_mode_duration_minutes_short" formatted="false" msgid="2742377799995454859">
+      <item quantity="one">For %d min</item>
       <item quantity="other">Per %d minuti</item>
-      <item quantity="one">Per 1 minuto</item>
     </plurals>
     <plurals name="zen_mode_duration_hours" formatted="false" msgid="525401855645490022">
+      <item quantity="one">For %d hours</item>
       <item quantity="other">Per %d ore</item>
-      <item quantity="one">Per 1 ora</item>
     </plurals>
     <plurals name="zen_mode_duration_hours_short" formatted="false" msgid="7644653189680911640">
+      <item quantity="one">For %d hr</item>
       <item quantity="other">Per %d ore</item>
-      <item quantity="one">Per 1 ora</item>
     </plurals>
     <string name="zen_mode_until_next_day" msgid="1403042784161725038">"Fino a: <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"Fino a <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
@@ -1968,8 +1968,8 @@
     <string name="call_notification_ongoing_text" msgid="3880832933933020875">"Chiamata in corso"</string>
     <string name="call_notification_screening_text" msgid="8396931408268940208">"Applicazione filtro a chiamata in arrivo"</string>
     <plurals name="selected_count" formatted="false" msgid="3946212171128200491">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> selected</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> file selezionati</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> file selezionato</item>
     </plurals>
     <string name="default_notification_channel_label" msgid="3697928973567217330">"Senza categoria"</string>
     <string name="importance_from_user" msgid="2782756722448800447">"Stabilisci tu l\'importanza di queste notifiche."</string>
@@ -2036,8 +2036,8 @@
     <string name="autofill_error_cannot_autofill" msgid="6528827648643138596">"Impossibile compilare automaticamente i contenuti"</string>
     <string name="autofill_picker_no_suggestions" msgid="1076022650427481509">"Nessun suggerimento di Compilazione automatica"</string>
     <plurals name="autofill_picker_some_suggestions" formatted="false" msgid="6651883186966959978">
+      <item quantity="one"><xliff:g id="COUNT">%1$s</xliff:g> autofill suggestions</item>
       <item quantity="other"><xliff:g id="COUNT">%1$s</xliff:g> suggerimenti di Compilazione automatica</item>
-      <item quantity="one">Un suggerimento di Compilazione automatica</item>
     </plurals>
     <string name="autofill_save_title" msgid="7719802414283739775">"Vuoi salvare su "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"?"</string>
     <string name="autofill_save_title_with_type" msgid="3002460014579799605">"Vuoi salvare la <xliff:g id="TYPE">%1$s</xliff:g> su "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"?"</string>
@@ -2140,8 +2140,8 @@
     <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"Il Bluetooth rimane attivo durante l\'uso della modalità aereo"</string>
     <string name="car_loading_profile" msgid="8219978381196748070">"Caricamento"</string>
     <plurals name="file_count" formatted="false" msgid="7063513834724389247">
+      <item quantity="one"><xliff:g id="FILE_NAME_2">%s</xliff:g> + <xliff:g id="COUNT_3">%d</xliff:g> file</item>
       <item quantity="other"><xliff:g id="FILE_NAME_2">%s</xliff:g> + <xliff:g id="COUNT_3">%d</xliff:g> file</item>
-      <item quantity="one"><xliff:g id="FILE_NAME_0">%s</xliff:g> + <xliff:g id="COUNT_1">%d</xliff:g> file</item>
     </plurals>
     <string name="chooser_no_direct_share_targets" msgid="1511722103987329028">"Nessuna persona consigliata per la condivisione"</string>
     <string name="chooser_all_apps_button_label" msgid="3230427756238666328">"Elenco di app"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index d5b92b7..a4e0123 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -219,7 +219,7 @@
     <string name="turn_on_radio" msgid="2961717788170634233">"უსადენო კავშირის ჩართვა"</string>
     <string name="turn_off_radio" msgid="7222573978109933360">"უსადენო ინტერნეტის გამორთვა"</string>
     <string name="screen_lock" msgid="2072642720826409809">"ეკრანის დაბლოკვა"</string>
-    <string name="power_off" msgid="4111692782492232778">"გამორთვ."</string>
+    <string name="power_off" msgid="4111692782492232778">"გამორთვა"</string>
     <string name="silent_mode_silent" msgid="5079789070221150912">"მრეკავი გათიშულია"</string>
     <string name="silent_mode_vibrate" msgid="8821830448369552678">"ვიბრაციის რეჟიმი"</string>
     <string name="silent_mode_ring" msgid="6039011004781526678">"ზარი ჩართულია"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 7006273..98ac85e 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -51,8 +51,8 @@
     <string name="needPuk2" msgid="7032612093451537186">"Introduza o PUK2 para desbloquear o cartão SIM."</string>
     <string name="enablePin" msgid="2543771964137091212">"Ação sem êxito. Ative o bloqueio do SIM/RUIM."</string>
     <plurals name="pinpuk_attempts" formatted="false" msgid="1619867269012213584">
-      <item quantity="other">Tem mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas antes de o cartão SIM ficar bloqueado.</item>
       <item quantity="one">Tem mais <xliff:g id="NUMBER_0">%d</xliff:g> tentativa antes de o cartão SIM ficar bloqueado.</item>
+      <item quantity="other">Tem mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas antes de o cartão SIM ficar bloqueado.</item>
     </plurals>
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
@@ -181,8 +181,8 @@
     <string name="low_memory" product="tv" msgid="6663680413790323318">"O armazenamento do dispositivo Android TV está cheio. Elimine alguns ficheiros para libertar espaço."</string>
     <string name="low_memory" product="default" msgid="2539532364144025569">"O armazenamento do telemóvel está cheio. Elimine alguns ficheiros para libertar espaço."</string>
     <plurals name="ssl_ca_cert_warning" formatted="false" msgid="2288194355006173029">
-      <item quantity="other">Autoridades de certificação instaladas</item>
       <item quantity="one">Autoridade de certificação instalada</item>
+      <item quantity="other">Autoridades de certificação instaladas</item>
     </plurals>
     <string name="ssl_ca_cert_noti_by_unknown" msgid="4961102218216815242">"Por um terceiro desconhecido"</string>
     <string name="ssl_ca_cert_noti_by_administrator" msgid="4564941950768783879">"Pelo gestor do seu perfil de trabalho"</string>
@@ -257,8 +257,8 @@
     <string name="bugreport_option_full_title" msgid="7681035745950045690">"Relatório completo"</string>
     <string name="bugreport_option_full_summary" msgid="1975130009258435885">"Utilize esta opção para uma interferência mínima do sistema quando o dispositivo não responder ou estiver demasiado lento, ou quando precisar de todas as secções de relatório. Não permite introduzir mais detalhes ou tirar capturas de ecrã adicionais."</string>
     <plurals name="bugreport_countdown" formatted="false" msgid="3906120379260059206">
-      <item quantity="other">A tirar uma captura de ecrã do relatório de erro dentro de <xliff:g id="NUMBER_1">%d</xliff:g> segundos.</item>
       <item quantity="one">A tirar uma captura de ecrã do relatório de erro dentro de <xliff:g id="NUMBER_0">%d</xliff:g> segundo…</item>
+      <item quantity="other">A tirar uma captura de ecrã do relatório de erro dentro de <xliff:g id="NUMBER_1">%d</xliff:g> segundos.</item>
     </plurals>
     <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Captura de ecrã tirada com o relatório de erro."</string>
     <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Falha ao fazer captura de ecrã com o relatório de erro."</string>
@@ -1061,8 +1061,8 @@
     <string name="oneMonthDurationPast" msgid="4538030857114635777">"Há 1 mês"</string>
     <string name="beforeOneMonthDurationPast" msgid="8315149541372065392">"Há mais de 1 mês"</string>
     <plurals name="last_num_days" formatted="false" msgid="687443109145393632">
-      <item quantity="other">Últimos <xliff:g id="COUNT_1">%d</xliff:g> dias</item>
       <item quantity="one">Último <xliff:g id="COUNT_0">%d</xliff:g> dia</item>
+      <item quantity="other">Últimos <xliff:g id="COUNT_1">%d</xliff:g> dias</item>
     </plurals>
     <string name="last_month" msgid="1528906781083518683">"Último mês"</string>
     <string name="older" msgid="1645159827884647400">"Mais antiga"</string>
@@ -1083,68 +1083,68 @@
     <string name="years" msgid="5797714729103773425">"anos"</string>
     <string name="now_string_shortest" msgid="3684914126941650330">"agora"</string>
     <plurals name="duration_minutes_shortest" formatted="false" msgid="7519574894537185135">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> m</item>
       <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> m</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> m</item>
     </plurals>
     <plurals name="duration_hours_shortest" formatted="false" msgid="2838655994500499651">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> h</item>
       <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> h</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> h</item>
     </plurals>
     <plurals name="duration_days_shortest" formatted="false" msgid="3686058472983158496">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> d</item>
       <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> d</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> d</item>
     </plurals>
     <plurals name="duration_years_shortest" formatted="false" msgid="8299112348723640338">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> a</item>
       <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> a</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> a</item>
     </plurals>
     <plurals name="duration_minutes_shortest_future" formatted="false" msgid="849196137176399440">
-      <item quantity="other">dentro de <xliff:g id="COUNT_1">%d</xliff:g> min</item>
       <item quantity="one">dentro de <xliff:g id="COUNT_0">%d</xliff:g> min</item>
+      <item quantity="other">dentro de <xliff:g id="COUNT_1">%d</xliff:g> min</item>
     </plurals>
     <plurals name="duration_hours_shortest_future" formatted="false" msgid="5386373597343170388">
-      <item quantity="other">dentro de <xliff:g id="COUNT_1">%d</xliff:g> h</item>
       <item quantity="one">dentro de <xliff:g id="COUNT_0">%d</xliff:g> h</item>
+      <item quantity="other">dentro de <xliff:g id="COUNT_1">%d</xliff:g> h</item>
     </plurals>
     <plurals name="duration_days_shortest_future" formatted="false" msgid="814754627092787227">
-      <item quantity="other">dentro de <xliff:g id="COUNT_1">%d</xliff:g> d</item>
       <item quantity="one">dentro de <xliff:g id="COUNT_0">%d</xliff:g> d</item>
+      <item quantity="other">dentro de <xliff:g id="COUNT_1">%d</xliff:g> d</item>
     </plurals>
     <plurals name="duration_years_shortest_future" formatted="false" msgid="7683731800140202145">
-      <item quantity="other">dentro de <xliff:g id="COUNT_1">%d</xliff:g> a</item>
       <item quantity="one">dentro de <xliff:g id="COUNT_0">%d</xliff:g> a</item>
+      <item quantity="other">dentro de <xliff:g id="COUNT_1">%d</xliff:g> a</item>
     </plurals>
     <plurals name="duration_minutes_relative" formatted="false" msgid="6569851308583028344">
-      <item quantity="other">há <xliff:g id="COUNT_1">%d</xliff:g> minutos</item>
       <item quantity="one">há <xliff:g id="COUNT_0">%d</xliff:g> minuto</item>
+      <item quantity="other">há <xliff:g id="COUNT_1">%d</xliff:g> minutos</item>
     </plurals>
     <plurals name="duration_hours_relative" formatted="false" msgid="420434788589102019">
-      <item quantity="other">há <xliff:g id="COUNT_1">%d</xliff:g> horas</item>
       <item quantity="one">há <xliff:g id="COUNT_0">%d</xliff:g> hora</item>
+      <item quantity="other">há <xliff:g id="COUNT_1">%d</xliff:g> horas</item>
     </plurals>
     <plurals name="duration_days_relative" formatted="false" msgid="6056425878237482431">
-      <item quantity="other">há <xliff:g id="COUNT_1">%d</xliff:g> dias</item>
       <item quantity="one">há <xliff:g id="COUNT_0">%d</xliff:g> dia</item>
+      <item quantity="other">há <xliff:g id="COUNT_1">%d</xliff:g> dias</item>
     </plurals>
     <plurals name="duration_years_relative" formatted="false" msgid="2179998228861172159">
-      <item quantity="other">há <xliff:g id="COUNT_1">%d</xliff:g> anos</item>
       <item quantity="one">há <xliff:g id="COUNT_0">%d</xliff:g> ano</item>
+      <item quantity="other">há <xliff:g id="COUNT_1">%d</xliff:g> anos</item>
     </plurals>
     <plurals name="duration_minutes_relative_future" formatted="false" msgid="5759885720917567723">
-      <item quantity="other">dentro de <xliff:g id="COUNT_1">%d</xliff:g> minutos</item>
       <item quantity="one">dentro de <xliff:g id="COUNT_0">%d</xliff:g> minuto</item>
+      <item quantity="other">dentro de <xliff:g id="COUNT_1">%d</xliff:g> minutos</item>
     </plurals>
     <plurals name="duration_hours_relative_future" formatted="false" msgid="8963511608507707959">
-      <item quantity="other">dentro de <xliff:g id="COUNT_1">%d</xliff:g> horas</item>
       <item quantity="one">dentro de <xliff:g id="COUNT_0">%d</xliff:g> hora</item>
+      <item quantity="other">dentro de <xliff:g id="COUNT_1">%d</xliff:g> horas</item>
     </plurals>
     <plurals name="duration_days_relative_future" formatted="false" msgid="1964709470979250702">
-      <item quantity="other">dentro de <xliff:g id="COUNT_1">%d</xliff:g> dias</item>
       <item quantity="one">dentro de <xliff:g id="COUNT_0">%d</xliff:g> dia</item>
+      <item quantity="other">dentro de <xliff:g id="COUNT_1">%d</xliff:g> dias</item>
     </plurals>
     <plurals name="duration_years_relative_future" formatted="false" msgid="3985129025134896371">
-      <item quantity="other">dentro de <xliff:g id="COUNT_1">%d</xliff:g> anos</item>
       <item quantity="one">dentro de <xliff:g id="COUNT_0">%d</xliff:g> ano</item>
+      <item quantity="other">dentro de <xliff:g id="COUNT_1">%d</xliff:g> anos</item>
     </plurals>
     <string name="VideoView_error_title" msgid="5750686717225068016">"Problema com o vídeo"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3782449246085134720">"Este vídeo não é válido para transmissão neste aparelho."</string>
@@ -1526,8 +1526,8 @@
     <string name="no_matches" msgid="6472699895759164599">"Sem correspondências"</string>
     <string name="find_on_page" msgid="5400537367077438198">"Localizar na página"</string>
     <plurals name="matches_found" formatted="false" msgid="1101758718194295554">
-      <item quantity="other"><xliff:g id="INDEX">%d</xliff:g> de <xliff:g id="TOTAL">%d</xliff:g></item>
       <item quantity="one">1 correspondência</item>
+      <item quantity="other"><xliff:g id="INDEX">%d</xliff:g> de <xliff:g id="TOTAL">%d</xliff:g></item>
     </plurals>
     <string name="action_mode_done" msgid="2536182504764803222">"Concluído"</string>
     <string name="progress_erasing" msgid="6891435992721028004">"A apagar o armazenamento partilhado…"</string>
@@ -1659,8 +1659,8 @@
     <string name="kg_wrong_password" msgid="2384677900494439426">"Palavra-passe Incorreta"</string>
     <string name="kg_wrong_pin" msgid="3680925703673166482">"PIN Incorreto"</string>
     <plurals name="kg_too_many_failed_attempts_countdown" formatted="false" msgid="236717428673283568">
-      <item quantity="other">Tente novamente dentro de <xliff:g id="NUMBER">%d</xliff:g> segundos.</item>
       <item quantity="one">Tente novamente dentro de 1 segundo.</item>
+      <item quantity="other">Tente novamente dentro de <xliff:g id="NUMBER">%d</xliff:g> segundos.</item>
     </plurals>
     <string name="kg_pattern_instructions" msgid="8366024510502517748">"Desenhe a sua sequência"</string>
     <string name="kg_sim_pin_instructions" msgid="6479401489471690359">"Introduzir PIN do cartão SIM"</string>
@@ -1859,8 +1859,8 @@
     <string name="restr_pin_error_doesnt_match" msgid="7063392698489280556">"Os PINs não correspondem. Tente novamente."</string>
     <string name="restr_pin_error_too_short" msgid="1547007808237941065">"O PIN é demasiado pequeno. Deve ter, no mínimo, 4 dígitos."</string>
     <plurals name="restr_pin_countdown" formatted="false" msgid="4427486903285216153">
-      <item quantity="other">Tente novamente dentro de <xliff:g id="COUNT">%d</xliff:g> segundos</item>
       <item quantity="one">Tente novamente dentro de 1 segundo</item>
+      <item quantity="other">Tente novamente dentro de <xliff:g id="COUNT">%d</xliff:g> segundos</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="5897719962541636727">"Tente novamente mais tarde"</string>
     <string name="immersive_cling_title" msgid="2307034298721541791">"Visualização de ecrã inteiro"</string>
@@ -1890,36 +1890,36 @@
     <string name="data_saver_enable_title" msgid="7080620065745260137">"Pretende ativar a Poupança de dados?"</string>
     <string name="data_saver_enable_button" msgid="4399405762586419726">"Ativar"</string>
     <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="2877101784123058273">
-      <item quantity="other">Durante %1$d minutos (até à(s) <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
       <item quantity="one">Durante um minuto (até à(s) <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+      <item quantity="other">Durante %1$d minutos (até à(s) <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
     </plurals>
     <plurals name="zen_mode_duration_minutes_summary_short" formatted="false" msgid="4230730310318858312">
-      <item quantity="other">Durante %1$d min (até à(s) <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
       <item quantity="one">Durante 1 min (até à(s) <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+      <item quantity="other">Durante %1$d min (até à(s) <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
     </plurals>
     <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="7725354244196466758">
-      <item quantity="other">Durante %1$d horas (até à(s) <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
       <item quantity="one">Durante 1 hora (até à(s) <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+      <item quantity="other">Durante %1$d horas (até à(s) <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
     </plurals>
     <plurals name="zen_mode_duration_hours_summary_short" formatted="false" msgid="588719069121765642">
-      <item quantity="other">Durante %1$d h (até à(s) <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
       <item quantity="one">Durante 1 h (até à(s) <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+      <item quantity="other">Durante %1$d h (até à(s) <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
     </plurals>
     <plurals name="zen_mode_duration_minutes" formatted="false" msgid="1148568456958944998">
-      <item quantity="other">Durante %d minutos</item>
       <item quantity="one">Durante um minuto</item>
+      <item quantity="other">Durante %d minutos</item>
     </plurals>
     <plurals name="zen_mode_duration_minutes_short" formatted="false" msgid="2742377799995454859">
-      <item quantity="other">Durante %d min</item>
       <item quantity="one">Durante 1 min</item>
+      <item quantity="other">Durante %d min</item>
     </plurals>
     <plurals name="zen_mode_duration_hours" formatted="false" msgid="525401855645490022">
-      <item quantity="other">Durante %d horas</item>
       <item quantity="one">Durante 1 hora</item>
+      <item quantity="other">Durante %d horas</item>
     </plurals>
     <plurals name="zen_mode_duration_hours_short" formatted="false" msgid="7644653189680911640">
-      <item quantity="other">Durante %d h</item>
       <item quantity="one">Durante 1 h</item>
+      <item quantity="other">Durante %d h</item>
     </plurals>
     <string name="zen_mode_until_next_day" msgid="1403042784161725038">"Até <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"Até às <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
@@ -1968,8 +1968,8 @@
     <string name="call_notification_ongoing_text" msgid="3880832933933020875">"Chamada em curso"</string>
     <string name="call_notification_screening_text" msgid="8396931408268940208">"A filtrar uma chamada recebida…"</string>
     <plurals name="selected_count" formatted="false" msgid="3946212171128200491">
-      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> selecionados</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> selecionado</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> selecionados</item>
     </plurals>
     <string name="default_notification_channel_label" msgid="3697928973567217330">"Sem categoria"</string>
     <string name="importance_from_user" msgid="2782756722448800447">"Definiu a importância destas notificações."</string>
@@ -2036,8 +2036,8 @@
     <string name="autofill_error_cannot_autofill" msgid="6528827648643138596">"Não é possível preencher automaticamente o conteúdo"</string>
     <string name="autofill_picker_no_suggestions" msgid="1076022650427481509">"Sem sugestões do preenchimento automático"</string>
     <plurals name="autofill_picker_some_suggestions" formatted="false" msgid="6651883186966959978">
-      <item quantity="other"><xliff:g id="COUNT">%1$s</xliff:g> sugestões do preenchimento automático</item>
       <item quantity="one">Uma sugestão do preenchimento automático</item>
+      <item quantity="other"><xliff:g id="COUNT">%1$s</xliff:g> sugestões do preenchimento automático</item>
     </plurals>
     <string name="autofill_save_title" msgid="7719802414283739775">"Pretende guardar em "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"?"</string>
     <string name="autofill_save_title_with_type" msgid="3002460014579799605">"Pretende guardar <xliff:g id="TYPE">%1$s</xliff:g> em "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"?"</string>
@@ -2140,8 +2140,8 @@
     <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"O Bluetooth continuará ativado durante o modo de avião."</string>
     <string name="car_loading_profile" msgid="8219978381196748070">"A carregar…"</string>
     <plurals name="file_count" formatted="false" msgid="7063513834724389247">
-      <item quantity="other"><xliff:g id="FILE_NAME_2">%s</xliff:g> + <xliff:g id="COUNT_3">%d</xliff:g> ficheiros</item>
       <item quantity="one"><xliff:g id="FILE_NAME_0">%s</xliff:g> + <xliff:g id="COUNT_1">%d</xliff:g> ficheiro</item>
+      <item quantity="other"><xliff:g id="FILE_NAME_2">%s</xliff:g> + <xliff:g id="COUNT_3">%d</xliff:g> ficheiros</item>
     </plurals>
     <string name="chooser_no_direct_share_targets" msgid="1511722103987329028">"Não existem pessoas recomendadas com quem partilhar"</string>
     <string name="chooser_all_apps_button_label" msgid="3230427756238666328">"Lista de aplicações"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index a6f8257..c14dd45 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -223,7 +223,7 @@
     <string name="turn_on_radio" msgid="2961717788170634233">"Vklopi brezžično omrežje"</string>
     <string name="turn_off_radio" msgid="7222573978109933360">"Izklopi brezžično omrežje"</string>
     <string name="screen_lock" msgid="2072642720826409809">"Zaklep zaslona"</string>
-    <string name="power_off" msgid="4111692782492232778">"Izklopi"</string>
+    <string name="power_off" msgid="4111692782492232778">"Izklop"</string>
     <string name="silent_mode_silent" msgid="5079789070221150912">"Izklopi zvonjenje"</string>
     <string name="silent_mode_vibrate" msgid="8821830448369552678">"Zvonjenje z vibriranjem"</string>
     <string name="silent_mode_ring" msgid="6039011004781526678">"Vklopi zvonjenje"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index c3e5a66..e8dbf3c 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -90,12 +90,12 @@
     <string name="notification_channel_network_alert" msgid="4788053066033851841">"అలర్ట్‌లు"</string>
     <string name="notification_channel_call_forward" msgid="8230490317314272406">"కాల్ ఫార్వార్డింగ్"</string>
     <string name="notification_channel_emergency_callback" msgid="54074839059123159">"అత్యవసర కాల్‌బ్యాక్ మోడ్"</string>
-    <string name="notification_channel_mobile_data_status" msgid="1941911162076442474">"మొబైల్ డేటా స్థితి"</string>
+    <string name="notification_channel_mobile_data_status" msgid="1941911162076442474">"మొబైల్ డేటా స్టేటస్‌"</string>
     <string name="notification_channel_sms" msgid="1243384981025535724">"SMS మెసేజ్‌లు"</string>
     <string name="notification_channel_voice_mail" msgid="8457433203106654172">"వాయిస్ మెయిల్ మెసేజ్‌లు"</string>
     <string name="notification_channel_wfc" msgid="9048240466765169038">"Wi-Fi కాలింగ్"</string>
     <string name="notification_channel_sim" msgid="5098802350325677490">"SIM స్టేటస్"</string>
-    <string name="notification_channel_sim_high_prio" msgid="642361929452850928">"అధిక ప్రాధాన్యత గల SIM స్థితి"</string>
+    <string name="notification_channel_sim_high_prio" msgid="642361929452850928">"అధిక ప్రాధాన్యత గల SIM స్టేటస్‌"</string>
     <string name="peerTtyModeFull" msgid="337553730440832160">"అవతలి వారు FULL TTY మోడ్‌ని అభ్యర్థించారు"</string>
     <string name="peerTtyModeHco" msgid="5626377160840915617">"అవతలి వారు HCO TTY మోడ్‌ని అభ్యర్థించారు"</string>
     <string name="peerTtyModeVco" msgid="572208600818270944">"అవతలి వారు VCO TTY మోడ్‌ని అభ్యర్థించారు"</string>
@@ -278,14 +278,14 @@
     <string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"భౌతిక కీబోర్డ్"</string>
     <string name="notification_channel_security" msgid="8516754650348238057">"సెక్యూరిటీ"</string>
     <string name="notification_channel_car_mode" msgid="2123919247040988436">"కార్‌ మోడ్"</string>
-    <string name="notification_channel_account" msgid="6436294521740148173">"ఖాతా స్థితి"</string>
+    <string name="notification_channel_account" msgid="6436294521740148173">"ఖాతా స్టేటస్‌"</string>
     <string name="notification_channel_developer" msgid="1691059964407549150">"డెవలపర్ మెసేజ్‌లు"</string>
     <string name="notification_channel_developer_important" msgid="7197281908918789589">"ముఖ్యమైన డెవలపర్ మెసేజ్‌లు"</string>
     <string name="notification_channel_updates" msgid="7907863984825495278">"అప్‌డేట్‌లు"</string>
-    <string name="notification_channel_network_status" msgid="2127687368725272809">"నెట్‌వర్క్ స్థితి"</string>
+    <string name="notification_channel_network_status" msgid="2127687368725272809">"నెట్‌వర్క్ స్టేటస్‌"</string>
     <string name="notification_channel_network_alerts" msgid="6312366315654526528">"నెట్‌వర్క్ హెచ్చరికలు"</string>
     <string name="notification_channel_network_available" msgid="6083697929214165169">"నెట్‌వర్క్ అందుబాటులో ఉంది"</string>
-    <string name="notification_channel_vpn" msgid="1628529026203808999">"VPN స్థితి"</string>
+    <string name="notification_channel_vpn" msgid="1628529026203808999">"VPN స్టేటస్‌"</string>
     <string name="notification_channel_device_admin" msgid="6384932669406095506">"మీ IT నిర్వాహకుల నుండి వచ్చే హెచ్చరికలు"</string>
     <string name="notification_channel_alerts" msgid="5070241039583668427">"అలర్ట్‌లు"</string>
     <string name="notification_channel_retail_mode" msgid="3732239154256431213">"రిటైల్ డెమో"</string>
@@ -342,12 +342,12 @@
     <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"పరికర వేలిముద్ర సెన్సార్‌లో ఉపయోగించిన సంజ్ఞలను క్యాప్చర్ చేయవచ్చు."</string>
     <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"స్క్రీన్‌షాట్‌ను తీయండి"</string>
     <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"డిస్‌ప్లే యొక్క స్క్రీన్‌షాట్ తీసుకోవచ్చు."</string>
-    <string name="permlab_statusBar" msgid="8798267849526214017">"స్థితి బార్‌ను నిలిపివేయడం లేదా సవరించడం"</string>
-    <string name="permdesc_statusBar" msgid="5809162768651019642">"స్థితి బార్‌ను నిలిపివేయడానికి లేదా సిస్టమ్ చిహ్నాలను జోడించడానికి మరియు తీసివేయడానికి యాప్‌ను అనుమతిస్తుంది."</string>
-    <string name="permlab_statusBarService" msgid="2523421018081437981">"స్థితి పట్టీగా ఉండటం"</string>
-    <string name="permdesc_statusBarService" msgid="6652917399085712557">"స్థితి బార్‌ ఉండేలా చేయడానికి యాప్‌ను అనుమతిస్తుంది."</string>
-    <string name="permlab_expandStatusBar" msgid="1184232794782141698">"స్థితి పట్టీని విస్తరింపజేయడం/కుదించడం"</string>
-    <string name="permdesc_expandStatusBar" msgid="7180756900448498536">"స్థితి బార్‌ను విస్తరింపజేయడానికి లేదా కుదించడానికి యాప్‌ను అనుమతిస్తుంది."</string>
+    <string name="permlab_statusBar" msgid="8798267849526214017">"స్టేటస్‌ బార్‌ను డిజేబుల్ చేయడం లేదా మార్చడం"</string>
+    <string name="permdesc_statusBar" msgid="5809162768651019642">"స్టేటస్‌ బార్‌ను డిజేబుల్ చేయడానికి లేదా సిస్టమ్ చిహ్నాలను జోడించడానికి మరియు తీసివేయడానికి యాప్‌ను అనుమతిస్తుంది."</string>
+    <string name="permlab_statusBarService" msgid="2523421018081437981">"స్టేటస్‌ పట్టీగా ఉండటం"</string>
+    <string name="permdesc_statusBarService" msgid="6652917399085712557">"స్టేటస్‌ బార్‌ ఉండేలా చేయడానికి యాప్‌ను అనుమతిస్తుంది."</string>
+    <string name="permlab_expandStatusBar" msgid="1184232794782141698">"స్టేటస్‌ పట్టీని విస్తరింపజేయడం/కుదించడం"</string>
+    <string name="permdesc_expandStatusBar" msgid="7180756900448498536">"స్టేటస్‌ బార్‌ను విస్తరింపజేయడానికి లేదా కుదించడానికి యాప్‌ను అనుమతిస్తుంది."</string>
     <string name="permlab_fullScreenIntent" msgid="4310888199502509104">"లాక్ చేసి ఉన్న పరికరంలో నోటిఫికేషన్‌లను ఫుల్ స్క్రీన్ యాక్టివిటీలుగా డిస్‌ప్లే చేస్తుంది"</string>
     <string name="permdesc_fullScreenIntent" msgid="1100721419406643997">"లాక్ చేసి ఉన్న పరికరంలో నోటిఫికేషన్‌లను ఫుల్ స్క్రీన్ యాక్టివిటీలుగా డిస్‌ప్లే చేయడానికి యాప్‌ను అనుమతిస్తుంది"</string>
     <string name="permlab_install_shortcut" msgid="7451554307502256221">"షార్ట్‌కట్‌లను ఇన్‌స్టాల్ చేయడం"</string>
@@ -469,7 +469,7 @@
     <string name="permdesc_callPhone" msgid="5439809516131609109">"మీ ప్రమేయం లేకుండా ఫోన్ నంబర్‌లకు కాల్ చేయడానికి యాప్‌ను అనుమతిస్తుంది. దీని వలన అనుకోని ఛార్జీలు విధించబడవచ్చు లేదా కాల్స్‌ రావచ్చు. ఇది అత్యవసర నంబర్‌లకు కాల్ చేయడానికి యాప్‌ను అనుమతించదని గుర్తుంచుకోండి. హానికరమైన యాప్‌లు మీ నిర్ధారణ లేకుండానే కాల్స్‌ చేయడం ద్వారా మీకు డబ్బు ఖర్చయ్యేలా చేయవచ్చు."</string>
     <string name="permlab_accessImsCallService" msgid="442192920714863782">"IMS కాల్ సేవ యాక్సెస్ అనుమతి"</string>
     <string name="permdesc_accessImsCallService" msgid="6328551241649687162">"మీ ప్రమేయం లేకుండా కాల్స్‌ చేయడం కోసం IMS సేవను ఉపయోగించడానికి యాప్‌ను అనుమతిస్తుంది."</string>
-    <string name="permlab_readPhoneState" msgid="8138526903259297969">"ఫోన్ స్థితి మరియు గుర్తింపుని చదవడం"</string>
+    <string name="permlab_readPhoneState" msgid="8138526903259297969">"ఫోన్ స్టేటస్‌ మరియు గుర్తింపుని చదవడం"</string>
     <string name="permdesc_readPhoneState" msgid="7229063553502788058">"పరికరం యొక్క ఫోన్ ఫీచర్‌లను యాక్సెస్ చేయడానికి యాప్‌ను అనుమతిస్తుంది. ఈ అనుమతి ఫోన్ నంబర్ మరియు పరికరం IDలను, కాల్ సక్రియంగా ఉందా లేదా అనే విషయాన్ని మరియు కాల్ ద్వారా కనెక్ట్ చేయబడిన రిమోట్ నంబర్‌ను కనుగొనడానికి యాప్‌ను అనుమతిస్తుంది."</string>
     <string name="permlab_manageOwnCalls" msgid="9033349060307561370">"కాల్స్‌ను సిస్టమ్ ద్వారా వెళ్లేలా చేయి"</string>
     <string name="permdesc_manageOwnCalls" msgid="4431178362202142574">"కాలింగ్ అనుభవాన్ని మెరుగుపరచడం కోసం తన కాల్స్‌ను సిస్టమ్ ద్వారా వెళ్లేలా చేయడానికి యాప్‌ను అనుమతిస్తుంది."</string>
@@ -716,7 +716,7 @@
     <string name="permdesc_setInputCalibration" msgid="2937872391426631726">"టచ్ స్క్రీన్ యొక్క క్రమాంకన పరామితులను సవరించడానికి యాప్‌ను అనుమతిస్తుంది. సాధారణ యాప్‌లకు ఎప్పటికీ అవసరం ఉండదు."</string>
     <string name="permlab_accessDrmCertificates" msgid="6473765454472436597">"DRM ప్రమాణపత్రాలను యాక్సెస్ చేయడం"</string>
     <string name="permdesc_accessDrmCertificates" msgid="6983139753493781941">"DRM ప్రమాణపత్రాలను కేటాయించడానికి మరియు ఉపయోగించడానికి యాప్‌ను అనుమతిస్తుంది. సాధారణ యాప్‌లకు ఎప్పటికీ అవసరం ఉండదు."</string>
-    <string name="permlab_handoverStatus" msgid="7620438488137057281">"Android Beam బదిలీ స్థితిని స్వీకరించడం"</string>
+    <string name="permlab_handoverStatus" msgid="7620438488137057281">"Android Beam బదిలీ స్టేటస్‌ని స్వీకరించడం"</string>
     <string name="permdesc_handoverStatus" msgid="3842269451732571070">"ప్రస్తుత Android Beam బదిలీలకు సంబంధించిన సమాచారాన్ని స్వీకరించడానికి ఈ యాప్‌ను అనుమతిస్తుంది"</string>
     <string name="permlab_removeDrmCertificates" msgid="710576248717404416">"DRM ప్రమాణపత్రాలను తీసివేయడం"</string>
     <string name="permdesc_removeDrmCertificates" msgid="4068445390318355716">"DRM ప్రమాణపత్రాలను తీసివేయడానికి యాప్‌ను అనుమతిస్తుంది. సాధారణ యాప్‌లకు ఎప్పటికీ అవసరం ఉండదు."</string>
@@ -959,7 +959,7 @@
     <string name="keyguard_accessibility_unlock_area_collapsed" msgid="4729922043778400434">"అన్‌లాక్ ప్రాంతం కుదించబడింది."</string>
     <string name="keyguard_accessibility_widget" msgid="6776892679715699875">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> విడ్జెట్."</string>
     <string name="keyguard_accessibility_user_selector" msgid="1466067610235696600">"వినియోగదారు ఎంపికకర్త"</string>
-    <string name="keyguard_accessibility_status" msgid="6792745049712397237">"స్థితి"</string>
+    <string name="keyguard_accessibility_status" msgid="6792745049712397237">"స్టేటస్‌"</string>
     <string name="keyguard_accessibility_camera" msgid="7862557559464986528">"కెమెరా"</string>
     <string name="keygaurd_accessibility_media_controls" msgid="2267379779900620614">"మీడియా నియంత్రణలు"</string>
     <string name="keyguard_accessibility_widget_reorder_start" msgid="7066213328912939191">"విడ్జెట్ పునఃక్రమం ప్రారంభించబడింది."</string>
@@ -1204,9 +1204,9 @@
     <string name="whichOpenLinksWithApp" msgid="6917864367861910086">"<xliff:g id="APPLICATION">%1$s</xliff:g>తో లింక్‌లను తెరవండి"</string>
     <string name="whichOpenHostLinksWithApp" msgid="2401668560768463004">"<xliff:g id="HOST">%1$s</xliff:g> లింక్‌లను <xliff:g id="APPLICATION">%2$s</xliff:g>తో తెరవండి"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="7805857277166106236">"యాక్సెస్ ఇవ్వండి"</string>
-    <string name="whichEditApplication" msgid="6191568491456092812">"దీనితో సవరించు"</string>
-    <string name="whichEditApplicationNamed" msgid="8096494987978521514">"%1$sతో సవరించు"</string>
-    <string name="whichEditApplicationLabel" msgid="1463288652070140285">"సవరించు"</string>
+    <string name="whichEditApplication" msgid="6191568491456092812">"దీనితో ఎడిట్ చేయండి"</string>
+    <string name="whichEditApplicationNamed" msgid="8096494987978521514">"%1$sతో ఎడిట్ చేయండి"</string>
+    <string name="whichEditApplicationLabel" msgid="1463288652070140285">"ఎడిట్"</string>
     <string name="whichSendApplication" msgid="4143847974460792029">"షేర్ చేయండి"</string>
     <string name="whichSendApplicationNamed" msgid="4470386782693183461">"%1$sతో షేర్ చేయండి"</string>
     <string name="whichSendApplicationLabel" msgid="7467813004769188515">"షేర్ చేయి"</string>
diff --git a/core/res/res/values-w198dp/dimens_material.xml b/core/res/res/values-w198dp/dimens_material.xml
new file mode 100644
index 0000000..a8aed25
--- /dev/null
+++ b/core/res/res/values-w198dp/dimens_material.xml
@@ -0,0 +1,20 @@
+<?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.
+-->
+<resources>
+    <dimen name="screen_percentage_05">9.9dp</dimen>
+    <dimen name="screen_percentage_10">19.8dp</dimen>
+    <dimen name="screen_percentage_15">29.7dp</dimen>
+</resources>
diff --git a/core/res/res/values-w211dp/dimens_material.xml b/core/res/res/values-w211dp/dimens_material.xml
new file mode 100644
index 0000000..bd7ca9a
--- /dev/null
+++ b/core/res/res/values-w211dp/dimens_material.xml
@@ -0,0 +1,20 @@
+<?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.
+-->
+<resources>
+    <dimen name="screen_percentage_05">10.55dp</dimen>
+    <dimen name="screen_percentage_10">21.1dp</dimen>
+    <dimen name="screen_percentage_15">31.65dp</dimen>
+</resources>
diff --git a/core/res/res/values-watch/colors.xml b/core/res/res/values-watch/colors.xml
index 854fbfd..6d908be 100644
--- a/core/res/res/values-watch/colors.xml
+++ b/core/res/res/values-watch/colors.xml
@@ -17,6 +17,6 @@
 
 <resources>
     <!-- Wear Material standard colors -->
-    <color name="wear_material_red_400">#EE675C</color>
+    <color name="wear_material_red_mid">#CC5D58</color>
     <color name="wear_material_grey_900">#202124</color>
 </resources>
\ No newline at end of file
diff --git a/core/res/res/values-watch/config.xml b/core/res/res/values-watch/config.xml
index cd809b8..cf0488b 100644
--- a/core/res/res/values-watch/config.xml
+++ b/core/res/res/values-watch/config.xml
@@ -27,10 +27,6 @@
         <item>restart</item>
     </string-array>
 
-    <!-- Base "touch slop" value used by ViewConfiguration as a
-         movement threshold where scrolling should begin. -->
-    <dimen name="config_viewConfigurationTouchSlop">4dp</dimen>
-
     <!-- Minimum velocity to initiate a fling, as measured in dips per second. -->
     <dimen name="config_viewMinFlingVelocity">500dp</dimen>
 
diff --git a/core/res/res/values-watch/donottranslate.xml b/core/res/res/values-watch/donottranslate.xml
index d247ff6..f328def 100644
--- a/core/res/res/values-watch/donottranslate.xml
+++ b/core/res/res/values-watch/donottranslate.xml
@@ -17,6 +17,6 @@
 <resources>
     <!-- DO NOT TRANSLATE Spans within this text are applied to style composing regions
     within an EditText widget. The text content is ignored and not used.
-    Note: This is @color/material_deep_teal_200, cannot use @color references here. -->
-    <string name="candidates_style" translatable="false"><font color="#80cbc4">candidates</font></string>
+    Note: This is @color/GM2_blue_300, cannot use @color references here. -->
+    <string name="candidates_style" translatable="false"><font color="#8AB4F8">candidates</font></string>
  </resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 1380165..697ec20 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -5383,6 +5383,16 @@
             <!-- Standard amount of hyphenation, useful for running text and for
             screens with limited space for text. -->
             <enum name="full" value="2" />
+
+            <!-- Same to hyphenationFrequency="normal" but using faster algorithm for measuring
+            hyphenation break points. To make text rendering faster with hyphenation, this algorithm
+             ignores some hyphen character related typographic features, e.g. kerning. -->
+            <enum name="normalFast" value="3" />
+
+            <!-- Same to hyphenationFrequency="full" but using faster algorithm for measuring
+            hyphenation break points. To make text rendering faster with hyphenation, this algorithm
+             ignores some hyphen character related typographic features, e.g. kerning. -->
+            <enum name="fullFast" value="4" />
         </attr>
         <!-- Specify the type of auto-size. Note that this feature is not supported by EditText,
         works only for TextView. -->
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 7805d46..94717b1 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1991,6 +1991,12 @@
 
         <!-- Whether attributions provided are meant to be user-visible. -->
         <attr name="attributionsAreUserVisible" format="boolean" />
+
+        <!-- Specifies whether enabled settings of components in the application should be
+             reset to {@link android.content.pm.PackageManager#COMPONENT_ENABLED_STATE_DEFAULT}
+             when the application's user data is cleared. The default value is false.
+        -->
+        <attr name="resetEnabledSettingsOnAppDataCleared" format="boolean" />
     </declare-styleable>
 
     <!-- An attribution is a logical part of an app and is identified by a tag.
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 2c60fbd8..a36785f 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -4943,9 +4943,10 @@
          the app in the letterbox mode. -->
     <item name="config_fixedOrientationLetterboxAspectRatio" format="float" type="dimen">0.0</item>
 
-    <!-- Corners radius for activity presented the letterbox mode. Values < 0 will be ignored and
-         min between device bottom corner radii will be used instead. -->
-    <integer name="config_letterboxActivityCornersRadius">-1</integer>
+    <!-- Corners radius for activity presented the letterbox mode. Values < 0 enable rounded
+         corners with radius equal to min between device bottom corner radii. Default 0 value turns
+         off rounded corners logic in LetterboxUiController. -->
+    <integer name="config_letterboxActivityCornersRadius">0</integer>
 
     <!-- Blur radius for the Option 3 in R.integer.config_letterboxBackgroundType. Values < 0 are
         ignored and 0 is used. -->
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index a2dadb9..dc548b9 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3305,6 +3305,7 @@
     <public name="splitTypes" />
     <public name="canDisplayOnRemoteDevices" />
     <public name="supportedTypes" />
+    <public name="resetEnabledSettingsOnAppDataCleared" />
   </staging-public-group>
 
   <staging-public-group type="id" first-id="0x01de0000">
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 192f5c0..f6a0e61 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2027,6 +2027,10 @@
     typed when unlocking the screen, and lock your Android TV device or erase all your Android TV device\'s
     data if too many incorrect passwords are typed.</string>
     <!-- Description of policy access to watch user login attempts -->
+    <string name="policydesc_watchLogin" product="automotive">Monitor the number of incorrect passwords
+    typed. when unlocking the screen, and lock the infotainment system or erase all the infotainment system\'s
+    data if too many incorrect passwords are typed.</string>
+    <!-- Description of policy access to watch user login attempts -->
     <string name="policydesc_watchLogin" product="default">Monitor the number of incorrect passwords
     typed. when unlocking the screen, and lock the phone or erase all the phone\'s
     data if too many incorrect passwords are typed.</string>
@@ -2036,6 +2040,9 @@
     <string name="policydesc_watchLogin_secondaryUser" product="tv">Monitor the number of incorrect passwords
     typed when unlocking the screen, and lock your Android TV device or erase all this user\'s data
     if too many incorrect passwords are typed.</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="automotive">Monitor the number of incorrect passwords
+    typed when unlocking the screen, and lock the infotainment system or erase all this profile\'s data
+    if too many incorrect passwords are typed.</string>
     <string name="policydesc_watchLogin_secondaryUser" product="default">Monitor the number of incorrect passwords
     typed when unlocking the screen, and lock the phone or erase all this user\'s data
     if too many incorrect passwords are typed.</string>
@@ -2054,14 +2061,20 @@
     <!-- Description of policy access to wipe the user's data -->
     <string name="policydesc_wipeData" product="tv">Erase your Android TV device\'s data without warning by performing a factory data reset.</string>
     <!-- Description of policy access to wipe the user's data -->
+    <string name="policydesc_wipeData" product="automotive">Erase the infotainment system\'s data without warning by performing a factory data reset.</string>
+    <!-- Description of policy access to wipe the user's data -->
     <string name="policydesc_wipeData" product="default">Erase the phone\'s data without warning by performing a factory data reset.</string>
     <!-- Title of policy access to wipe secondary user's data -->
-    <string name="policylab_wipeData_secondaryUser">Erase user data</string>
+    <string name="policylab_wipeData_secondaryUser" product="automotive">Erase profile data</string>
+    <!-- Title of policy access to wipe secondary user's data -->
+    <string name="policylab_wipeData_secondaryUser" product="default">Erase user data</string>
     <!-- Description of policy access to wipe the user's data -->
     <string name="policydesc_wipeData_secondaryUser" product="tablet">Erase this user\'s data on this tablet without warning.</string>
     <!-- Description of policy access to wipe the user's data -->
     <string name="policydesc_wipeData_secondaryUser" product="tv">Erase this user\'s data on this Android TV device without warning.</string>
     <!-- Description of policy access to wipe the user's data -->
+    <string name="policydesc_wipeData_secondaryUser" product="automotive">Erase this profile\'s data on this infotainment system without warning.</string>
+    <!-- Description of policy access to wipe the user's data -->
     <string name="policydesc_wipeData_secondaryUser" product="default">Erase this user\'s data on this phone without warning.</string>
     <!-- Title of policy access to set global proxy -->
     <string name="policylab_setGlobalProxy">Set the device global proxy</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 12b1842..faa9902 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1438,6 +1438,7 @@
   <java-symbol type="drawable" name="ic_qs_flashlight" />
   <java-symbol type="drawable" name="ic_qs_auto_rotate" />
   <java-symbol type="drawable" name="ic_qs_dnd" />
+  <java-symbol type="drawable" name="ic_qs_one_handed_mode" />
 
   <java-symbol type="drawable" name="sim_light_blue" />
   <java-symbol type="drawable" name="sim_light_green" />
@@ -1700,6 +1701,10 @@
   <java-symbol type="anim" name="activity_translucent_close_exit" />
   <java-symbol type="anim" name="activity_open_enter" />
   <java-symbol type="anim" name="activity_close_exit" />
+  <java-symbol type="anim" name="task_fragment_close_enter" />
+  <java-symbol type="anim" name="task_fragment_close_exit" />
+  <java-symbol type="anim" name="task_fragment_open_enter" />
+  <java-symbol type="anim" name="task_fragment_open_exit" />
 
   <java-symbol type="array" name="config_autoRotationTiltTolerance" />
   <java-symbol type="array" name="config_longPressVibePattern" />
@@ -4591,7 +4596,6 @@
   <java-symbol type="fraction" name="global_actions_vertical_padding_percentage" />
   <java-symbol type="fraction" name="global_actions_horizontal_padding_percentage" />
   <java-symbol type="drawable" name="global_actions_item_red_background" />
-  <java-symbol type="color" name="wear_material_grey_900" />
 
   <java-symbol type="string" name="config_wearSysUiPackage"/>
   <java-symbol type="string" name="config_wearSysUiMainActivity"/>
diff --git a/core/tests/coretests/src/android/app/NotificationTest.java b/core/tests/coretests/src/android/app/NotificationTest.java
index 34c1763..37cf514 100644
--- a/core/tests/coretests/src/android/app/NotificationTest.java
+++ b/core/tests/coretests/src/android/app/NotificationTest.java
@@ -43,6 +43,7 @@
 import android.graphics.Color;
 import android.graphics.drawable.Icon;
 import android.os.Build;
+import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.Spannable;
@@ -545,6 +546,29 @@
         validateColorizedPaletteForColor(Color.BLACK);
     }
 
+    @Test
+    public void testIsMediaNotification_nullSession_returnsFalse() {
+        // Null media session
+        Notification.MediaStyle mediaStyle = new Notification.MediaStyle();
+        Notification notification = new Notification.Builder(mContext, "test id")
+                .setStyle(mediaStyle)
+                .build();
+        assertFalse(notification.isMediaNotification());
+    }
+
+    @Test
+    public void testIsMediaNotification_invalidSession_returnsFalse() {
+        // Extra was set manually to an invalid type
+        Bundle extras = new Bundle();
+        extras.putParcelable(Notification.EXTRA_MEDIA_SESSION, new Intent());
+        Notification.MediaStyle mediaStyle = new Notification.MediaStyle();
+        Notification notification = new Notification.Builder(mContext, "test id")
+                .setStyle(mediaStyle)
+                .addExtras(extras)
+                .build();
+        assertFalse(notification.isMediaNotification());
+    }
+
     public void validateColorizedPaletteForColor(int rawColor) {
         Notification.Colors cDay = new Notification.Colors();
         Notification.Colors cNight = new Notification.Colors();
diff --git a/core/tests/coretests/src/android/os/VibratorTest.java b/core/tests/coretests/src/android/os/VibratorTest.java
index 0ece793..0ac8f08 100644
--- a/core/tests/coretests/src/android/os/VibratorTest.java
+++ b/core/tests/coretests/src/android/os/VibratorTest.java
@@ -209,6 +209,17 @@
     }
 
     @Test
+    public void vibrate_withVibrationAttributes_usesGivenAttributes() {
+        VibrationEffect effect = VibrationEffect.get(VibrationEffect.EFFECT_CLICK);
+        VibrationAttributes attributes = new VibrationAttributes.Builder().setUsage(
+                VibrationAttributes.USAGE_TOUCH).build();
+
+        mVibratorSpy.vibrate(effect, attributes);
+
+        verify(mVibratorSpy).vibrate(anyInt(), anyString(), eq(effect), isNull(), eq(attributes));
+    }
+
+    @Test
     public void vibrate_withAudioAttributes_createsVibrationAttributesWithSameUsage() {
         VibrationEffect effect = VibrationEffect.get(VibrationEffect.EFFECT_CLICK);
         AudioAttributes audioAttributes = new AudioAttributes.Builder().setUsage(
@@ -229,27 +240,7 @@
     }
 
     @Test
-    public void vibrate_withUnknownAudioAttributes_hasTouchUsageFromEffect() {
-        VibrationEffect effect = VibrationEffect.get(VibrationEffect.EFFECT_CLICK);
-        AudioAttributes audioAttributes = new AudioAttributes.Builder().setUsage(
-                AudioAttributes.USAGE_UNKNOWN).build();
-
-        mVibratorSpy.vibrate(effect, audioAttributes);
-
-        ArgumentCaptor<VibrationAttributes> captor = ArgumentCaptor.forClass(
-                VibrationAttributes.class);
-        verify(mVibratorSpy).vibrate(anyInt(), anyString(), eq(effect), isNull(), captor.capture());
-
-        VibrationAttributes vibrationAttributes = captor.getValue();
-        assertEquals(VibrationAttributes.USAGE_TOUCH,
-                vibrationAttributes.getUsage());
-        // Sets AudioAttributes usage based on effect.
-        assertEquals(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION,
-                vibrationAttributes.getAudioUsage());
-    }
-
-    @Test
-    public void vibrate_withoutAudioAttributes_hasTouchUsageFromEffect() {
+    public void vibrate_withoutAudioAttributes_passesOnDefaultAttributes() {
         mVibratorSpy.vibrate(VibrationEffect.get(VibrationEffect.EFFECT_CLICK));
 
         ArgumentCaptor<VibrationAttributes> captor = ArgumentCaptor.forClass(
@@ -257,10 +248,7 @@
         verify(mVibratorSpy).vibrate(anyInt(), anyString(), any(), isNull(), captor.capture());
 
         VibrationAttributes vibrationAttributes = captor.getValue();
-        assertEquals(VibrationAttributes.USAGE_TOUCH, vibrationAttributes.getUsage());
-        // Sets AudioAttributes usage based on effect.
-        assertEquals(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION,
-                vibrationAttributes.getAudioUsage());
+        assertEquals(new VibrationAttributes.Builder().build(), vibrationAttributes);
     }
 
     @Test
diff --git a/core/tests/coretests/src/android/text/MeasuredParagraphTest.java b/core/tests/coretests/src/android/text/MeasuredParagraphTest.java
index 57bb434..d6a7682 100644
--- a/core/tests/coretests/src/android/text/MeasuredParagraphTest.java
+++ b/core/tests/coretests/src/android/text/MeasuredParagraphTest.java
@@ -23,6 +23,7 @@
 
 import android.content.Context;
 import android.graphics.Typeface;
+import android.graphics.text.MeasuredText;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
@@ -135,7 +136,8 @@
         MeasuredParagraph mt = null;
 
         mt = MeasuredParagraph.buildForStaticLayout(
-                PAINT, "XXX", 0, 3, LTR, false, false, null /* no hint */, null);
+                PAINT, "XXX", 0, 3, LTR, MeasuredText.Builder.HYPHENATION_MODE_NONE, false,
+                null /* no hint */, null);
         assertNotNull(mt);
         assertNotNull(mt.getChars());
         assertEquals("XXX", charsToString(mt.getChars()));
@@ -150,7 +152,8 @@
 
         // Recycle it
         MeasuredParagraph mt2 = MeasuredParagraph.buildForStaticLayout(
-                PAINT, "_VVV_", 1, 4, RTL, false, false, null /* no hint */, mt);
+                PAINT, "_VVV_", 1, 4, RTL, MeasuredText.Builder.HYPHENATION_MODE_NONE, false,
+                null /* no hint */, mt);
         assertEquals(mt2, mt);
         assertNotNull(mt2.getChars());
         assertEquals("VVV", charsToString(mt.getChars()));
diff --git a/data/etc/com.android.intentresolver.xml b/data/etc/com.android.intentresolver.xml
index 0f1c467..f4e94ad 100644
--- a/data/etc/com.android.intentresolver.xml
+++ b/data/etc/com.android.intentresolver.xml
@@ -18,5 +18,6 @@
     <privapp-permissions package="com.android.intentresolver">
         <permission name="android.permission.INTERACT_ACROSS_USERS"/>
         <permission name="android.permission.MANAGE_USERS"/>
+        <permission name="android.permission.PACKAGE_USAGE_STATS"/>
     </privapp-permissions>
 </permissions>
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 6983aa4..103b836 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -225,6 +225,8 @@
         <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
         <permission name="android.permission.UPDATE_APP_OPS_STATS"/>
         <permission name="android.permission.USE_RESERVED_DISK"/>
+        <permission name="android.permission.READ_COMPAT_CHANGE_CONFIG" />
+        <permission name="android.permission.LOG_COMPAT_CHANGE" />
     </privapp-permissions>
 
     <privapp-permissions package="com.android.providers.downloads">
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index 8b37805..8ccf02ca 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -961,6 +961,12 @@
       "group": "WM_DEBUG_ORIENTATION",
       "at": "com\/android\/server\/wm\/RootWindowContainer.java"
     },
+    "-1101551167": {
+      "message": "Auto-PIP allowed, entering PIP mode directly: %s, didAutoPip: %b",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
     "-1089874824": {
       "message": "SURFACE SHOW (performLayout): %s",
       "level": "INFO",
@@ -2629,12 +2635,6 @@
       "group": "WM_ERROR",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
-    "660908897": {
-      "message": "Auto-PIP allowed, entering PIP mode directly: %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/TaskFragment.java"
-    },
     "662572728": {
       "message": "Attempted to add a toast window with bad token %s.  Aborting.",
       "level": "WARN",
diff --git a/graphics/java/android/graphics/text/MeasuredText.java b/graphics/java/android/graphics/text/MeasuredText.java
index 31c3d09..df5b3f5 100644
--- a/graphics/java/android/graphics/text/MeasuredText.java
+++ b/graphics/java/android/graphics/text/MeasuredText.java
@@ -17,12 +17,14 @@
 package android.graphics.text;
 
 import android.annotation.FloatRange;
+import android.annotation.IntDef;
 import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.Px;
 import android.graphics.Paint;
 import android.graphics.Rect;
+import android.util.Log;
 
 import com.android.internal.util.Preconditions;
 
@@ -30,6 +32,9 @@
 
 import libcore.util.NativeAllocationRegistry;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 /**
  * Result of text shaping of the single paragraph string.
  *
@@ -49,6 +54,8 @@
  * </p>
  */
 public class MeasuredText {
+    private static final String TAG = "MeasuredText";
+
     private long mNativePtr;
     private boolean mComputeHyphenation;
     private boolean mComputeLayout;
@@ -179,6 +186,7 @@
         private final @NonNull char[] mText;
         private boolean mComputeHyphenation = false;
         private boolean mComputeLayout = true;
+        private boolean mFastHyphenation = false;
         private int mCurrentOffset = 0;
         private @Nullable MeasuredText mHintMt = null;
 
@@ -275,10 +283,78 @@
          * Even if you pass false to this method, you can still enable automatic hyphenation of
          * LineBreaker but line break computation becomes slower.
          *
+         * @deprecated use setComputeHyphenation(int) instead.
+         *
          * @param computeHyphenation true if you want to use automatic hyphenations.
          */
         public @NonNull Builder setComputeHyphenation(boolean computeHyphenation) {
-            mComputeHyphenation = computeHyphenation;
+            setComputeHyphenation(
+                    computeHyphenation ? HYPHENATION_MODE_NORMAL : HYPHENATION_MODE_NONE);
+            return this;
+        }
+
+        /** @hide */
+        @IntDef(prefix = { "HYPHENATION_MODE_" }, value = {
+                HYPHENATION_MODE_NONE,
+                HYPHENATION_MODE_NORMAL,
+                HYPHENATION_MODE_FAST
+        })
+        @Retention(RetentionPolicy.SOURCE)
+        public @interface HyphenationMode {}
+
+        /**
+         * A value for hyphenation calculation mode.
+         *
+         * This value indicates that no hyphenation points are calculated.
+         */
+        public static final int HYPHENATION_MODE_NONE = 0;
+
+        /**
+         * A value for hyphenation calculation mode.
+         *
+         * This value indicates that hyphenation points are calculated.
+         */
+        public static final int HYPHENATION_MODE_NORMAL = 1;
+
+        /**
+         * A value for hyphenation calculation mode.
+         *
+         * This value indicates that hyphenation points are calculated with faster algorithm. This
+         * algorithm measures text width with ignoring the context of hyphen character shaping, e.g.
+         * kerning.
+         */
+        public static final int HYPHENATION_MODE_FAST = 2;
+
+        /**
+         * By passing true to this method, the build method will calculate hyphenation break
+         * points faster with ignoring some typographic features, e.g. kerning.
+         *
+         * {@link #HYPHENATION_MODE_NONE} is by default.
+         *
+         * @see #setComputeHyphenation(boolean)
+         *
+         * @param mode a hyphenation mode.
+         */
+        public @NonNull Builder setComputeHyphenation(@HyphenationMode int mode) {
+            switch (mode) {
+                case HYPHENATION_MODE_NONE:
+                    mComputeHyphenation = false;
+                    mFastHyphenation = false;
+                    break;
+                case HYPHENATION_MODE_NORMAL:
+                    mComputeHyphenation = true;
+                    mFastHyphenation = false;
+                    break;
+                case HYPHENATION_MODE_FAST:
+                    mComputeHyphenation = true;
+                    mFastHyphenation = true;
+                    break;
+                default:
+                    Log.e(TAG, "Unknown hyphenation mode: " + mode);
+                    mComputeHyphenation = false;
+                    mFastHyphenation = false;
+                    break;
+            }
             return this;
         }
 
@@ -319,7 +395,7 @@
             try {
                 long hintPtr = (mHintMt == null) ? 0 : mHintMt.getNativePtr();
                 long ptr = nBuildMeasuredText(mNativePtr, hintPtr, mText, mComputeHyphenation,
-                        mComputeLayout);
+                        mComputeLayout, mFastHyphenation);
                 final MeasuredText res = new MeasuredText(ptr, mText, mComputeHyphenation,
                         mComputeLayout);
                 sRegistry.registerNativeAllocation(res, ptr);
@@ -378,7 +454,8 @@
                 long hintMtPtr,
                 @NonNull char[] text,
                 boolean computeHyphenation,
-                boolean computeLayout);
+                boolean computeLayout,
+                boolean fastHyphenationMode);
 
         private static native void nFreeBuilder(/* Non Zero */ long nativeBuilderPtr);
     }
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java
index 85ef270..df751fc 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java
@@ -27,8 +27,6 @@
 import android.os.Bundle;
 import android.os.IBinder;
 import android.util.ArrayMap;
-import android.view.SurfaceControl;
-import android.window.TaskFragmentAppearedInfo;
 import android.window.TaskFragmentCreationParams;
 import android.window.TaskFragmentInfo;
 import android.window.TaskFragmentOrganizer;
@@ -51,9 +49,6 @@
     /** Mapping from the client assigned unique token to the {@link TaskFragmentInfo}. */
     private final Map<IBinder, TaskFragmentInfo> mFragmentInfos = new ArrayMap<>();
 
-    /** Mapping from the client assigned unique token to the TaskFragment {@link SurfaceControl}. */
-    private final Map<IBinder, SurfaceControl> mFragmentLeashes = new ArrayMap<>();
-
     /**
      * Mapping from the client assigned unique token to the TaskFragment parent
      * {@link Configuration}.
@@ -67,7 +62,7 @@
      * Callback that notifies the controller about changes to task fragments.
      */
     interface TaskFragmentCallback {
-        void onTaskFragmentAppeared(@NonNull TaskFragmentAppearedInfo taskFragmentAppearedInfo);
+        void onTaskFragmentAppeared(@NonNull TaskFragmentInfo taskFragmentInfo);
         void onTaskFragmentInfoChanged(@NonNull TaskFragmentInfo taskFragmentInfo);
         void onTaskFragmentVanished(@NonNull TaskFragmentInfo taskFragmentInfo);
         void onTaskFragmentParentInfoChanged(@NonNull IBinder fragmentToken,
@@ -259,15 +254,12 @@
     }
 
     @Override
-    public void onTaskFragmentAppeared(@NonNull TaskFragmentAppearedInfo taskFragmentAppearedInfo) {
-        final TaskFragmentInfo info = taskFragmentAppearedInfo.getTaskFragmentInfo();
-        final IBinder fragmentToken = info.getFragmentToken();
-        final SurfaceControl leash = taskFragmentAppearedInfo.getLeash();
-        mFragmentInfos.put(fragmentToken, info);
-        mFragmentLeashes.put(fragmentToken, leash);
+    public void onTaskFragmentAppeared(@NonNull TaskFragmentInfo taskFragmentInfo) {
+        final IBinder fragmentToken = taskFragmentInfo.getFragmentToken();
+        mFragmentInfos.put(fragmentToken, taskFragmentInfo);
 
         if (mCallback != null) {
-            mCallback.onTaskFragmentAppeared(taskFragmentAppearedInfo);
+            mCallback.onTaskFragmentAppeared(taskFragmentInfo);
         }
     }
 
@@ -284,7 +276,6 @@
     @Override
     public void onTaskFragmentVanished(@NonNull TaskFragmentInfo taskFragmentInfo) {
         mFragmentInfos.remove(taskFragmentInfo.getFragmentToken());
-        mFragmentLeashes.remove(taskFragmentInfo.getFragmentToken());
         mFragmentParentConfigs.remove(taskFragmentInfo.getFragmentToken());
 
         if (mCallback != null) {
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
index 68c1904..fe6c7ba 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
@@ -37,7 +37,6 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
-import android.window.TaskFragmentAppearedInfo;
 import android.window.TaskFragmentInfo;
 import android.window.WindowContainerTransaction;
 
@@ -110,14 +109,13 @@
     }
 
     @Override
-    public void onTaskFragmentAppeared(@NonNull TaskFragmentAppearedInfo taskFragmentAppearedInfo) {
-        TaskFragmentContainer container = getContainer(
-                taskFragmentAppearedInfo.getTaskFragmentInfo().getFragmentToken());
+    public void onTaskFragmentAppeared(@NonNull TaskFragmentInfo taskFragmentInfo) {
+        TaskFragmentContainer container = getContainer(taskFragmentInfo.getFragmentToken());
         if (container == null) {
             return;
         }
 
-        container.setInfo(taskFragmentAppearedInfo.getTaskFragmentInfo());
+        container.setInfo(taskFragmentInfo);
         if (container.isFinished()) {
             mPresenter.cleanupContainer(container, false /* shouldFinishDependent */);
         }
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationController.java
index 535dac1..3c7d2de 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationController.java
@@ -16,9 +16,13 @@
 
 package androidx.window.extensions.embedding;
 
+import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_CLOSE;
+import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_OPEN;
+import static android.view.WindowManager.TRANSIT_OLD_TASK_CLOSE;
 import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CHANGE;
 import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CLOSE;
 import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_OPEN;
+import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN;
 
 import android.util.Log;
 import android.view.RemoteAnimationAdapter;
@@ -45,8 +49,12 @@
         final RemoteAnimationDefinition definition = new RemoteAnimationDefinition();
         final RemoteAnimationAdapter animationAdapter =
                 new RemoteAnimationAdapter(mRemoteRunner, 0, 0, true /* changeNeedsSnapshot */);
+        definition.addRemoteAnimation(TRANSIT_OLD_ACTIVITY_OPEN, animationAdapter);
         definition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_OPEN, animationAdapter);
+        definition.addRemoteAnimation(TRANSIT_OLD_TASK_OPEN, animationAdapter);
+        definition.addRemoteAnimation(TRANSIT_OLD_ACTIVITY_CLOSE, animationAdapter);
         definition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_CLOSE, animationAdapter);
+        definition.addRemoteAnimation(TRANSIT_OLD_TASK_CLOSE, animationAdapter);
         definition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_CHANGE, animationAdapter);
         mOrganizer.registerRemoteAnimations(definition);
     }
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java
index 412559e..8c8ef92 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java
@@ -17,9 +17,13 @@
 package androidx.window.extensions.embedding;
 
 import static android.view.RemoteAnimationTarget.MODE_CLOSING;
+import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_CLOSE;
+import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_OPEN;
+import static android.view.WindowManager.TRANSIT_OLD_TASK_CLOSE;
 import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CHANGE;
 import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CLOSE;
 import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_OPEN;
+import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN;
 
 import android.animation.Animator;
 import android.animation.ValueAnimator;
@@ -155,9 +159,13 @@
             @WindowManager.TransitionOldType int transit,
             @NonNull RemoteAnimationTarget[] targets) {
         switch (transit) {
+            case TRANSIT_OLD_ACTIVITY_OPEN:
             case TRANSIT_OLD_TASK_FRAGMENT_OPEN:
+            case TRANSIT_OLD_TASK_OPEN:
                 return createOpenAnimationAdapters(targets);
+            case TRANSIT_OLD_ACTIVITY_CLOSE:
             case TRANSIT_OLD_TASK_FRAGMENT_CLOSE:
+            case TRANSIT_OLD_TASK_CLOSE:
                 return createCloseAnimationAdapters(targets);
             case TRANSIT_OLD_TASK_FRAGMENT_CHANGE:
                 return createChangeAnimationAdapters(targets);
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationSpec.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationSpec.java
index c0908a5..586ac1f 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationSpec.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationSpec.java
@@ -43,6 +43,7 @@
 import com.android.internal.policy.TransitionAnimation;
 
 /** Animation spec for TaskFragment transition. */
+// TODO(b/206557124): provide an easier way to customize animation
 class TaskFragmentAnimationSpec {
 
     private static final String TAG = "TaskFragAnimationSpec";
@@ -179,9 +180,9 @@
     Animation loadOpenAnimation(@NonNull RemoteAnimationTarget target,
             @NonNull Rect wholeAnimationBounds) {
         final boolean isEnter = target.mode != MODE_CLOSING;
-        final Animation animation = mTransitionAnimation.loadDefaultAnimationAttr(isEnter
-                ? R.styleable.WindowAnimation_activityOpenEnterAnimation
-                : R.styleable.WindowAnimation_activityOpenExitAnimation);
+        final Animation animation = mTransitionAnimation.loadDefaultAnimationRes(isEnter
+                ? com.android.internal.R.anim.task_fragment_open_enter
+                : com.android.internal.R.anim.task_fragment_open_exit);
         animation.initialize(target.localBounds.width(), target.localBounds.height(),
                 wholeAnimationBounds.width(), wholeAnimationBounds.height());
         animation.scaleCurrentDuration(mTransitionAnimationScaleSetting);
@@ -191,9 +192,9 @@
     Animation loadCloseAnimation(@NonNull RemoteAnimationTarget target,
             @NonNull Rect wholeAnimationBounds) {
         final boolean isEnter = target.mode != MODE_CLOSING;
-        final Animation animation = mTransitionAnimation.loadDefaultAnimationAttr(isEnter
-                ? R.styleable.WindowAnimation_activityCloseEnterAnimation
-                : R.styleable.WindowAnimation_activityCloseExitAnimation);
+        final Animation animation = mTransitionAnimation.loadDefaultAnimationRes(isEnter
+                ? com.android.internal.R.anim.task_fragment_close_enter
+                : com.android.internal.R.anim.task_fragment_close_exit);
         animation.initialize(target.localBounds.width(), target.localBounds.height(),
                 wholeAnimationBounds.width(), wholeAnimationBounds.height());
         animation.scaleCurrentDuration(mTransitionAnimationScaleSetting);
diff --git a/packages/SystemUI/res/color/prv_text_color_on_accent.xml b/libs/WindowManager/Shell/res/color/size_compat_background_ripple.xml
similarity index 76%
rename from packages/SystemUI/res/color/prv_text_color_on_accent.xml
rename to libs/WindowManager/Shell/res/color/size_compat_background_ripple.xml
index 9f44aca..329e5b9 100644
--- a/packages/SystemUI/res/color/prv_text_color_on_accent.xml
+++ b/libs/WindowManager/Shell/res/color/size_compat_background_ripple.xml
@@ -14,7 +14,6 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-<selector xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
-          xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="?androidprv:attr/textColorOnAccent" />
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="@android:color/system_neutral1_500" android:lStar="35" />
 </selector>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/drawable/size_compat_hint_bubble.xml b/libs/WindowManager/Shell/res/drawable/size_compat_hint_bubble.xml
index 94165a1..22cd384 100644
--- a/libs/WindowManager/Shell/res/drawable/size_compat_hint_bubble.xml
+++ b/libs/WindowManager/Shell/res/drawable/size_compat_hint_bubble.xml
@@ -16,6 +16,6 @@
   -->
 <shape xmlns:android="http://schemas.android.com/apk/res/android"
        android:shape="rectangle">
-    <solid android:color="@color/size_compat_hint_bubble"/>
+    <solid android:color="@color/size_compat_background"/>
     <corners android:radius="@dimen/size_compat_hint_corner_radius"/>
 </shape>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/drawable/size_compat_hint_point.xml b/libs/WindowManager/Shell/res/drawable/size_compat_hint_point.xml
index a8f0f76..af9063a 100644
--- a/libs/WindowManager/Shell/res/drawable/size_compat_hint_point.xml
+++ b/libs/WindowManager/Shell/res/drawable/size_compat_hint_point.xml
@@ -20,6 +20,6 @@
         android:viewportWidth="10"
         android:viewportHeight="8">
     <path
-        android:fillColor="@color/size_compat_hint_bubble"
+        android:fillColor="@color/size_compat_background"
         android:pathData="M10,0 l-4.1875,6.6875 a1,1 0 0,1 -1.625,0 l-4.1875,-6.6875z"/>
 </vector>
diff --git a/libs/WindowManager/Shell/res/drawable/size_compat_restart_button.xml b/libs/WindowManager/Shell/res/drawable/size_compat_restart_button.xml
index 3e486df..18caa35 100644
--- a/libs/WindowManager/Shell/res/drawable/size_compat_restart_button.xml
+++ b/libs/WindowManager/Shell/res/drawable/size_compat_restart_button.xml
@@ -20,16 +20,16 @@
         android:viewportWidth="48"
         android:viewportHeight="48">
     <path
-        android:fillColor="#53534D"
+        android:fillColor="@color/size_compat_background"
         android:pathData="M0,24 a24,24 0 1,0 48,0 a24,24 0 1,0 -48,0" />
     <group
         android:translateX="12"
         android:translateY="12">
         <path
-            android:fillColor="#E4E3DA"
+            android:fillColor="@color/size_compat_text"
             android:pathData="M6,13c0,-1.65 0.67,-3.15 1.76,-4.24L6.34,7.34C4.9,8.79 4,10.79 4,13c0,4.08 3.05,7.44 7,7.93v-2.02C8.17,18.43 6,15.97 6,13z"/>
         <path
-            android:fillColor="#E4E3DA"
+            android:fillColor="@color/size_compat_text"
             android:pathData="M20,13c0,-4.42 -3.58,-8 -8,-8c-0.06,0 -0.12,0.01 -0.18,0.01v0l1.09,-1.09L11.5,2.5L8,6l3.5,3.5l1.41,-1.41l-1.08,-1.08C11.89,7.01 11.95,7 12,7c3.31,0 6,2.69 6,6c0,2.97 -2.17,5.43 -5,5.91v2.02C16.95,20.44 20,17.08 20,13z"/>
     </group>
 </vector>
diff --git a/packages/SystemUI/res/color/prv_text_color_on_accent.xml b/libs/WindowManager/Shell/res/drawable/size_compat_restart_button_ripple.xml
similarity index 74%
copy from packages/SystemUI/res/color/prv_text_color_on_accent.xml
copy to libs/WindowManager/Shell/res/drawable/size_compat_restart_button_ripple.xml
index 9f44aca..95decff 100644
--- a/packages/SystemUI/res/color/prv_text_color_on_accent.xml
+++ b/libs/WindowManager/Shell/res/drawable/size_compat_restart_button_ripple.xml
@@ -14,7 +14,7 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-<selector xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
-          xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="?androidprv:attr/textColorOnAccent" />
-</selector>
\ No newline at end of file
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+        android:color="@color/size_compat_background_ripple">
+    <item android:drawable="@drawable/size_compat_restart_button"/>
+</ripple>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/layout/size_compat_mode_hint.xml b/libs/WindowManager/Shell/res/layout/size_compat_mode_hint.xml
index 17347f6..d0e7c42 100644
--- a/libs/WindowManager/Shell/res/layout/size_compat_mode_hint.xml
+++ b/libs/WindowManager/Shell/res/layout/size_compat_mode_hint.xml
@@ -40,7 +40,7 @@
                 android:padding="16dp"
                 android:text="@string/restart_button_description"
                 android:textAlignment="viewStart"
-                android:textColor="#E4E3DA"
+                android:textColor="@color/size_compat_text"
                 android:textSize="14sp"/>
 
             <ImageView
diff --git a/libs/WindowManager/Shell/res/layout/size_compat_ui.xml b/libs/WindowManager/Shell/res/layout/size_compat_ui.xml
index 47e76f0..82ebee2 100644
--- a/libs/WindowManager/Shell/res/layout/size_compat_ui.xml
+++ b/libs/WindowManager/Shell/res/layout/size_compat_ui.xml
@@ -30,7 +30,7 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_gravity="center"
-            android:src="@drawable/size_compat_restart_button"
+            android:src="@drawable/size_compat_restart_button_ripple"
             android:background="@android:color/transparent"
             android:contentDescription="@string/restart_button_description"/>
 
diff --git a/libs/WindowManager/Shell/res/values-af/strings.xml b/libs/WindowManager/Shell/res/values-af/strings.xml
index 34b2667..107da81 100644
--- a/libs/WindowManager/Shell/res/values-af/strings.xml
+++ b/libs/WindowManager/Shell/res/values-af/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"Maak toe"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"Vou uit"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"Instellings"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"Gaan by verdeelde skerm in"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"Kieslys"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> is in beeld-in-beeld"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"As jy nie wil hê dat <xliff:g id="NAME">%s</xliff:g> hierdie kenmerk moet gebruik nie, tik om instellings oop te maak en skakel dit af."</string>
diff --git a/libs/WindowManager/Shell/res/values-am/strings.xml b/libs/WindowManager/Shell/res/values-am/strings.xml
index 73c3cc8..d724372 100644
--- a/libs/WindowManager/Shell/res/values-am/strings.xml
+++ b/libs/WindowManager/Shell/res/values-am/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"ዝጋ"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"ዘርጋ"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"ቅንብሮች"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"የተከፈለ ማያ ገጽን አስገባ"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"ምናሌ"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> በስዕል-ላይ-ስዕል ውስጥ ነው"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"<xliff:g id="NAME">%s</xliff:g> ይህን ባህሪ እንዲጠቀም ካልፈለጉ ቅንብሮችን ለመክፈት መታ ያድርጉና ያጥፉት።"</string>
diff --git a/libs/WindowManager/Shell/res/values-ar/strings.xml b/libs/WindowManager/Shell/res/values-ar/strings.xml
index 25bad80..7dd1f81 100644
--- a/libs/WindowManager/Shell/res/values-ar/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ar/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"إغلاق"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"توسيع"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"الإعدادات"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"الدخول في وضع تقسيم الشاشة"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"القائمة"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> يظهر في صورة داخل صورة"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"إذا كنت لا تريد أن يستخدم <xliff:g id="NAME">%s</xliff:g> هذه الميزة، فانقر لفتح الإعدادات، ثم أوقِف تفعيل هذه الميزة."</string>
diff --git a/libs/WindowManager/Shell/res/values-as/strings.xml b/libs/WindowManager/Shell/res/values-as/strings.xml
index 69113da..190f7ca 100644
--- a/libs/WindowManager/Shell/res/values-as/strings.xml
+++ b/libs/WindowManager/Shell/res/values-as/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"বন্ধ কৰক"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"বিস্তাৰ কৰক"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"ছেটিং"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"বিভাজিত স্ক্ৰীন ম’ডলৈ যাওক"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"মেনু"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> চিত্ৰৰ ভিতৰৰ চিত্ৰত আছে"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"আপুনি যদি <xliff:g id="NAME">%s</xliff:g> সুবিধাটো ব্যৱহাৰ কৰিব নোখোজে, তেন্তে ছেটিং খুলিবলৈ টিপক আৰু তালৈ গৈ ইয়াক অফ কৰক।"</string>
diff --git a/libs/WindowManager/Shell/res/values-az/strings.xml b/libs/WindowManager/Shell/res/values-az/strings.xml
index 2551063..e33a35f 100644
--- a/libs/WindowManager/Shell/res/values-az/strings.xml
+++ b/libs/WindowManager/Shell/res/values-az/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"Bağlayın"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"Genişləndirin"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"Ayarlar"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"Bölünmüş ekrana daxil olun"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"Menyu"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> şəkil içində şəkildədir"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"<xliff:g id="NAME">%s</xliff:g> tətbiqinin bu funksiyadan istifadə etməyini istəmirsinizsə, ayarları açmaq və deaktiv etmək üçün klikləyin."</string>
diff --git a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml
index 9c18e73..f59e932 100644
--- a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"Zatvori"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"Proširi"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"Podešavanja"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"Uđi na podeljeni ekran"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"Meni"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> je slika u slici"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"Ako ne želite da <xliff:g id="NAME">%s</xliff:g> koristi ovu funkciju, dodirnite da biste otvorili podešavanja i isključili je."</string>
diff --git a/libs/WindowManager/Shell/res/values-be/strings.xml b/libs/WindowManager/Shell/res/values-be/strings.xml
index 66d2a8c..3b478f2 100644
--- a/libs/WindowManager/Shell/res/values-be/strings.xml
+++ b/libs/WindowManager/Shell/res/values-be/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"Закрыць"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"Разгарнуць"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"Налады"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"Падзяліць экран"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"Меню"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> з’яўляецца відарысам у відарысе"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"Калі вы не хочаце, каб праграма <xliff:g id="NAME">%s</xliff:g> выкарыстоўвала гэту функцыю, дакраніцеся, каб адкрыць налады і адключыць яе."</string>
diff --git a/libs/WindowManager/Shell/res/values-bg/strings.xml b/libs/WindowManager/Shell/res/values-bg/strings.xml
index 6df231c..3a77a1c 100644
--- a/libs/WindowManager/Shell/res/values-bg/strings.xml
+++ b/libs/WindowManager/Shell/res/values-bg/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"Затваряне"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"Разгъване"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"Настройки"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"Преминаване към разделен екран"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"Меню"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> е в режима „Картина в картината“"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"Ако не искате <xliff:g id="NAME">%s</xliff:g> да използва тази функция, докоснете, за да отворите настройките, и я изключете."</string>
diff --git a/libs/WindowManager/Shell/res/values-bn/strings.xml b/libs/WindowManager/Shell/res/values-bn/strings.xml
index ce87f21..8bfd775 100644
--- a/libs/WindowManager/Shell/res/values-bn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-bn/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"বন্ধ করুন"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"বড় করুন"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"সেটিংস"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"\'স্প্লিট স্ক্রিন\' মোড চালু করুন"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"মেনু"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"ছবির-মধ্যে-ছবি তে <xliff:g id="NAME">%s</xliff:g> আছেন"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"<xliff:g id="NAME">%s</xliff:g> কে এই বৈশিষ্ট্যটি ব্যবহার করতে দিতে না চাইলে ট্যাপ করে সেটিংসে গিয়ে সেটি বন্ধ করে দিন।"</string>
diff --git a/libs/WindowManager/Shell/res/values-bs/strings.xml b/libs/WindowManager/Shell/res/values-bs/strings.xml
index 5b454c5..d23cc61 100644
--- a/libs/WindowManager/Shell/res/values-bs/strings.xml
+++ b/libs/WindowManager/Shell/res/values-bs/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"Zatvori"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"Proširi"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"Postavke"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"Otvori podijeljeni ekran"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"Meni"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> je u načinu priakza Slika u slici"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"Ako ne želite da <xliff:g id="NAME">%s</xliff:g> koristi ovu funkciju, dodirnite da otvorite postavke i isključite je."</string>
diff --git a/libs/WindowManager/Shell/res/values-ca/strings.xml b/libs/WindowManager/Shell/res/values-ca/strings.xml
index 0b3d8bc..6434e31 100644
--- a/libs/WindowManager/Shell/res/values-ca/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ca/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"Tanca"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"Desplega"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"Configuració"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"Entra al mode de pantalla dividida"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"Menú"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> està en pantalla en pantalla"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"Si no vols que <xliff:g id="NAME">%s</xliff:g> utilitzi aquesta funció, toca per obrir la configuració i desactiva-la."</string>
diff --git a/libs/WindowManager/Shell/res/values-cs/strings.xml b/libs/WindowManager/Shell/res/values-cs/strings.xml
index d474b7b..3530a7c 100644
--- a/libs/WindowManager/Shell/res/values-cs/strings.xml
+++ b/libs/WindowManager/Shell/res/values-cs/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"Zavřít"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"Rozbalit"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"Nastavení"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"Aktivovat rozdělenou obrazovku"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"Nabídka"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"Aplikace <xliff:g id="NAME">%s</xliff:g> je v režimu obraz v obraze"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"Pokud nechcete, aby aplikace <xliff:g id="NAME">%s</xliff:g> tuto funkci používala, klepnutím otevřete nastavení a funkci vypněte."</string>
diff --git a/libs/WindowManager/Shell/res/values-da/strings.xml b/libs/WindowManager/Shell/res/values-da/strings.xml
index 80043b5..89b66e5 100644
--- a/libs/WindowManager/Shell/res/values-da/strings.xml
+++ b/libs/WindowManager/Shell/res/values-da/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"Luk"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"Udvid"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"Indstillinger"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"Åbn opdelt skærm"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"Menu"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> vises som integreret billede"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"Hvis du ikke ønsker, at <xliff:g id="NAME">%s</xliff:g> skal benytte denne funktion, kan du åbne indstillingerne og deaktivere den."</string>
diff --git a/libs/WindowManager/Shell/res/values-de/strings.xml b/libs/WindowManager/Shell/res/values-de/strings.xml
index a5dd189..b49b446 100644
--- a/libs/WindowManager/Shell/res/values-de/strings.xml
+++ b/libs/WindowManager/Shell/res/values-de/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"Schließen"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"Maximieren"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"Einstellungen"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"„Bildschirm teilen“ aktivieren"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"Menü"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> ist in Bild im Bild"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"Wenn du nicht möchtest, dass <xliff:g id="NAME">%s</xliff:g> diese Funktion verwendet, tippe, um die Einstellungen zu öffnen und die Funktion zu deaktivieren."</string>
diff --git a/libs/WindowManager/Shell/res/values-el/strings.xml b/libs/WindowManager/Shell/res/values-el/strings.xml
index 76cdb28..ed1d913 100644
--- a/libs/WindowManager/Shell/res/values-el/strings.xml
+++ b/libs/WindowManager/Shell/res/values-el/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"Κλείσιμο"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"Ανάπτυξη"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"Ρυθμίσεις"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"Μετάβαση σε διαχωρισμό οθόνης"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"Μενού"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"Η λειτουργία picture-in-picture είναι ενεργή σε <xliff:g id="NAME">%s</xliff:g>."</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"Εάν δεν θέλετε να χρησιμοποιείται αυτή η λειτουργία από την εφαρμογή <xliff:g id="NAME">%s</xliff:g>, πατήστε για να ανοίξετε τις ρυθμίσεις και απενεργοποιήστε την."</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rAU/strings.xml b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
index 8973c2c..067e998 100644
--- a/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"Close"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"Expand"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"Settings"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"Enter split screen"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"Menu"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> is in picture-in-picture"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"If you don\'t want <xliff:g id="NAME">%s</xliff:g> to use this feature, tap to open settings and turn it off."</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rCA/strings.xml b/libs/WindowManager/Shell/res/values-en-rCA/strings.xml
index 8973c2c..067e998 100644
--- a/libs/WindowManager/Shell/res/values-en-rCA/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rCA/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"Close"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"Expand"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"Settings"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"Enter split screen"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"Menu"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> is in picture-in-picture"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"If you don\'t want <xliff:g id="NAME">%s</xliff:g> to use this feature, tap to open settings and turn it off."</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rGB/strings.xml b/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
index 8973c2c..067e998 100644
--- a/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"Close"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"Expand"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"Settings"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"Enter split screen"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"Menu"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> is in picture-in-picture"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"If you don\'t want <xliff:g id="NAME">%s</xliff:g> to use this feature, tap to open settings and turn it off."</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rIN/strings.xml b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
index 8973c2c..067e998 100644
--- a/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"Close"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"Expand"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"Settings"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"Enter split screen"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"Menu"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> is in picture-in-picture"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"If you don\'t want <xliff:g id="NAME">%s</xliff:g> to use this feature, tap to open settings and turn it off."</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rXC/strings.xml b/libs/WindowManager/Shell/res/values-en-rXC/strings.xml
index 68e0600..95c0d01 100644
--- a/libs/WindowManager/Shell/res/values-en-rXC/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rXC/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‎‎‎‏‎‎‎‏‎‎‎‎‎‎‎‏‎‎‎‏‏‎‎‎‎‏‎‏‎‎‎‏‎‎‏‎‏‎‎‎‏‎‏‎‏‏‎‎‎‏‏‎‏‎‏‏‎‏‎Close‎‏‎‎‏‎"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‏‏‏‏‎‎‏‎‏‏‎‏‏‏‏‏‎‏‎‎‏‏‏‎‏‎‏‏‏‎‎‎‏‎‏‏‏‎‏‎‎‏‏‏‎‎‎‏‏‎‎‎‎‏‎‎‎‎‎Expand‎‏‎‎‏‎"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‏‏‏‏‎‎‏‎‏‏‎‏‏‏‏‏‎‏‏‎‎‏‏‏‎‏‎‎‎‎‏‏‏‎‎‎‏‏‎‎‏‏‏‎‏‎‎‎‏‎‎‎‎‏‏‏‎‎Settings‎‏‎‎‏‎"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‎‏‏‎‏‏‏‏‎‏‎‏‎‏‎‎‏‏‏‎‎‎‏‏‏‎‏‎‎‎‎‏‏‎‎‏‎‎‎‏‏‏‏‏‎‏‏‏‎‏‎‏‏‏‎‏‏‏‎Enter split screen‎‏‎‎‏‎"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‎‏‏‎‏‏‎‎‏‏‏‏‏‏‏‎‎‎‎‏‏‎‎‏‎‎‏‏‎‎‏‎‎‎‎‏‎‏‎‎‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎‎‎‎Menu‎‏‎‎‏‎"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‎‏‎‏‏‎‎‎‏‏‏‏‎‎‎‎‎‏‎‎‏‏‏‎‎‏‏‎‎‏‏‏‎‎‏‎‎‏‏‏‏‏‏‏‎‏‏‎‎‏‏‏‎‏‏‎‏‎‎‏‎‎‏‏‎<xliff:g id="NAME">%s</xliff:g>‎‏‎‎‏‏‏‎ is in picture-in-picture‎‏‎‎‏‎"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‏‎‏‏‏‏‏‏‏‏‎‏‎‎‏‎‏‎‎‏‏‎‏‏‎‎‎‏‎‏‏‏‏‎‎‎‎‏‏‏‏‎‎‏‎‏‏‎‎‎‏‏‏‎‎‎If you don\'t want ‎‏‎‎‏‏‎<xliff:g id="NAME">%s</xliff:g>‎‏‎‎‏‏‏‎ to use this feature, tap to open settings and turn it off.‎‏‎‎‏‎"</string>
diff --git a/libs/WindowManager/Shell/res/values-es-rUS/strings.xml b/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
index ca5312e..6e5347d 100644
--- a/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
+++ b/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"Cerrar"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"Expandir"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"Configuración"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"Introducir pantalla dividida"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"Menú"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> está en modo de Pantalla en pantalla"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"Si no quieres que <xliff:g id="NAME">%s</xliff:g> use esta función, presiona para abrir la configuración y desactivarla."</string>
diff --git a/libs/WindowManager/Shell/res/values-es/strings.xml b/libs/WindowManager/Shell/res/values-es/strings.xml
index 8ea06c6..4820a0f 100644
--- a/libs/WindowManager/Shell/res/values-es/strings.xml
+++ b/libs/WindowManager/Shell/res/values-es/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"Cerrar"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"Mostrar"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"Ajustes"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"Introducir pantalla dividida"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"Menú"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> está en imagen en imagen"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"Si no quieres que <xliff:g id="NAME">%s</xliff:g> utilice esta función, toca la notificación para abrir los ajustes y desactivarla."</string>
diff --git a/libs/WindowManager/Shell/res/values-et/strings.xml b/libs/WindowManager/Shell/res/values-et/strings.xml
index 4e7013a..4c94694 100644
--- a/libs/WindowManager/Shell/res/values-et/strings.xml
+++ b/libs/WindowManager/Shell/res/values-et/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"Sule"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"Laiendamine"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"Seaded"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"Ava jagatud ekraanikuva"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"Menüü"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> on režiimis Pilt pildis"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"Kui te ei soovi, et rakendus <xliff:g id="NAME">%s</xliff:g> seda funktsiooni kasutaks, puudutage seadete avamiseks ja lülitage see välja."</string>
diff --git a/libs/WindowManager/Shell/res/values-eu/strings.xml b/libs/WindowManager/Shell/res/values-eu/strings.xml
index 810d113..afc4292 100644
--- a/libs/WindowManager/Shell/res/values-eu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-eu/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"Itxi"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"Zabaldu"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"Ezarpenak"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"Sartu pantaila zatituan"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"Menua"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"Pantaila txiki gainjarrian dago <xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"Ez baduzu nahi <xliff:g id="NAME">%s</xliff:g> zerbitzuak eginbide hori erabiltzea, sakatu hau ezarpenak ireki eta aukera desaktibatzeko."</string>
diff --git a/libs/WindowManager/Shell/res/values-fa/strings.xml b/libs/WindowManager/Shell/res/values-fa/strings.xml
index cd9aaf1..e8a0682 100644
--- a/libs/WindowManager/Shell/res/values-fa/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fa/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"بستن"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"بزرگ کردن"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"تنظیمات"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"ورود به حالت «صفحهٔ دونیمه»"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"منو"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> درحالت تصویر در تصویر است"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"اگر نمی‌خواهید <xliff:g id="NAME">%s</xliff:g> از این قابلیت استفاده کند، با ضربه زدن، تنظیمات را باز کنید و آن را خاموش کنید."</string>
diff --git a/libs/WindowManager/Shell/res/values-fi/strings.xml b/libs/WindowManager/Shell/res/values-fi/strings.xml
index 1ce0c86..f671105 100644
--- a/libs/WindowManager/Shell/res/values-fi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fi/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"Sulje"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"Laajenna"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"Asetukset"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"Avaa jaettu näyttö"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"Valikko"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> on kuva kuvassa ‑tilassa"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"Jos et halua, että <xliff:g id="NAME">%s</xliff:g> voi käyttää tätä ominaisuutta, avaa asetukset napauttamalla ja poista se käytöstä."</string>
diff --git a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
index 7565b7a..0d0b718 100644
--- a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"Fermer"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"Développer"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"Paramètres"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"Entrer dans l\'écran partagé"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"Menu"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> est en mode d\'incrustation d\'image"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"Si vous ne voulez pas que <xliff:g id="NAME">%s</xliff:g> utilise cette fonctionnalité, touchez l\'écran pour ouvrir les paramètres, puis désactivez-la."</string>
diff --git a/libs/WindowManager/Shell/res/values-fr/strings.xml b/libs/WindowManager/Shell/res/values-fr/strings.xml
index c69f2a1..5652d7e 100644
--- a/libs/WindowManager/Shell/res/values-fr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fr/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"Fermer"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"Développer"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"Paramètres"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"Accéder à l\'écran partagé"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"Menu"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> est en mode Picture-in-picture"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"Si vous ne voulez pas que l\'application <xliff:g id="NAME">%s</xliff:g> utilise cette fonctionnalité, appuyez ici pour ouvrir les paramètres et la désactiver."</string>
diff --git a/libs/WindowManager/Shell/res/values-gl/strings.xml b/libs/WindowManager/Shell/res/values-gl/strings.xml
index 0357300..81bd916 100644
--- a/libs/WindowManager/Shell/res/values-gl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-gl/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"Pechar"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"Despregar"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"Configuración"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"Inserir pantalla dividida"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"Menú"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> está na pantalla superposta"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"Se non queres que <xliff:g id="NAME">%s</xliff:g> utilice esta función, toca a configuración para abrir as opcións e desactivar a función."</string>
diff --git a/libs/WindowManager/Shell/res/values-gu/strings.xml b/libs/WindowManager/Shell/res/values-gu/strings.xml
index a55a52b..3d408cf2 100644
--- a/libs/WindowManager/Shell/res/values-gu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-gu/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"બંધ કરો"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"વિસ્તૃત કરો"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"સેટિંગ"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"વિભાજિત સ્ક્રીન મોડમાં દાખલ થાઓ"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"મેનૂ"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> ચિત્રમાં-ચિત્રની અંદર છે"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"જો તમે નથી ઇચ્છતા કે <xliff:g id="NAME">%s</xliff:g> આ સુવિધાનો ઉપયોગ કરે, તો સેટિંગ ખોલવા માટે ટૅપ કરો અને તેને બંધ કરો."</string>
diff --git a/libs/WindowManager/Shell/res/values-hi/strings.xml b/libs/WindowManager/Shell/res/values-hi/strings.xml
index 1352695..8c93e0a 100644
--- a/libs/WindowManager/Shell/res/values-hi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hi/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"बंद करें"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"विस्तार करें"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"सेटिंग"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"स्प्लिट स्क्रीन मोड में जाएं"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"मेन्यू"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> \"पिक्चर में पिक्चर\" के अंदर है"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"अगर आप नहीं चाहते कि <xliff:g id="NAME">%s</xliff:g> इस सुविधा का उपयोग करे, तो सेटिंग खोलने के लिए टैप करें और उसे बंद करें ."</string>
diff --git a/libs/WindowManager/Shell/res/values-hr/strings.xml b/libs/WindowManager/Shell/res/values-hr/strings.xml
index 1660dc2..1f8f982 100644
--- a/libs/WindowManager/Shell/res/values-hr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hr/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"Zatvori"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"Proširivanje"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"Postavke"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"Otvorite podijeljeni zaslon"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"Izbornik"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> jest na slici u slici"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"Ako ne želite da aplikacija <xliff:g id="NAME">%s</xliff:g> upotrebljava tu značajku, dodirnite da biste otvorili postavke i isključili je."</string>
diff --git a/libs/WindowManager/Shell/res/values-hu/strings.xml b/libs/WindowManager/Shell/res/values-hu/strings.xml
index a0eeceb7..ebd02e5 100644
--- a/libs/WindowManager/Shell/res/values-hu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hu/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"Bezárás"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"Kibontás"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"Beállítások"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"Váltás osztott képernyőre"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"Menü"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"A(z) <xliff:g id="NAME">%s</xliff:g> kép a képben funkciót használ"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"Ha nem szeretné, hogy a(z) <xliff:g id="NAME">%s</xliff:g> használja ezt a funkciót, koppintson a beállítások megnyitásához, és kapcsolja ki."</string>
diff --git a/libs/WindowManager/Shell/res/values-hy/strings.xml b/libs/WindowManager/Shell/res/values-hy/strings.xml
index 3dce9f7..29b2052 100644
--- a/libs/WindowManager/Shell/res/values-hy/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hy/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"Փակել"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"Ընդարձակել"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"Կարգավորումներ"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"Մտնել տրոհված էկրանի ռեժիմ"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"Ընտրացանկ"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g>-ը «Նկար նկարի մեջ» ռեժիմում է"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"Եթե չեք ցանկանում, որ <xliff:g id="NAME">%s</xliff:g>-ն օգտագործի այս գործառույթը, հպեք՝ կարգավորումները բացելու և այն անջատելու համար։"</string>
diff --git a/libs/WindowManager/Shell/res/values-in/strings.xml b/libs/WindowManager/Shell/res/values-in/strings.xml
index b1924c4..e488855 100644
--- a/libs/WindowManager/Shell/res/values-in/strings.xml
+++ b/libs/WindowManager/Shell/res/values-in/strings.xml
@@ -20,6 +20,8 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"Tutup"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"Luaskan"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"Setelan"</string>
+    <!-- no translation found for pip_phone_enter_split (7042877263880641911) -->
+    <skip />
     <string name="pip_menu_title" msgid="5393619322111827096">"Menu"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> adalah picture-in-picture"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"Jika Anda tidak ingin <xliff:g id="NAME">%s</xliff:g> menggunakan fitur ini, ketuk untuk membuka setelan dan menonaktifkannya."</string>
diff --git a/libs/WindowManager/Shell/res/values-is/strings.xml b/libs/WindowManager/Shell/res/values-is/strings.xml
index 4c1b653..126d1f1 100644
--- a/libs/WindowManager/Shell/res/values-is/strings.xml
+++ b/libs/WindowManager/Shell/res/values-is/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"Loka"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"Stækka"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"Stillingar"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"Opna skjáskiptingu"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"Valmynd"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> er með mynd í mynd"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"Ef þú vilt ekki að <xliff:g id="NAME">%s</xliff:g> noti þennan eiginleika skaltu ýta til að opna stillingarnar og slökkva á því."</string>
diff --git a/libs/WindowManager/Shell/res/values-it/strings.xml b/libs/WindowManager/Shell/res/values-it/strings.xml
index 8321d83..ec221b1 100644
--- a/libs/WindowManager/Shell/res/values-it/strings.xml
+++ b/libs/WindowManager/Shell/res/values-it/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"Chiudi"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"Espandi"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"Impostazioni"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"Accedi a schermo diviso"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"Menu"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> è in Picture in picture"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"Se non desideri che l\'app <xliff:g id="NAME">%s</xliff:g> utilizzi questa funzione, tocca per aprire le impostazioni e disattivarla."</string>
diff --git a/libs/WindowManager/Shell/res/values-iw/strings.xml b/libs/WindowManager/Shell/res/values-iw/strings.xml
index 721b222..b87d10c 100644
--- a/libs/WindowManager/Shell/res/values-iw/strings.xml
+++ b/libs/WindowManager/Shell/res/values-iw/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"סגירה"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"הרחבה"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"הגדרות"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"כניסה למסך המפוצל"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"תפריט"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> במצב תמונה בתוך תמונה"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"אם אינך רוצה שהתכונה הזו תשמש את <xliff:g id="NAME">%s</xliff:g>, יש להקיש כדי לפתוח את ההגדרות ולהשבית את התכונה."</string>
diff --git a/libs/WindowManager/Shell/res/values-ja/strings.xml b/libs/WindowManager/Shell/res/values-ja/strings.xml
index 80c54f7..51ffca6 100644
--- a/libs/WindowManager/Shell/res/values-ja/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ja/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"閉じる"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"展開"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"設定"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"分割画面に切り替え"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"メニュー"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g>はピクチャー イン ピクチャーで表示中です"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"<xliff:g id="NAME">%s</xliff:g>でこの機能を使用しない場合は、タップして設定を開いて OFF にしてください。"</string>
diff --git a/libs/WindowManager/Shell/res/values-ka/strings.xml b/libs/WindowManager/Shell/res/values-ka/strings.xml
index c7b3b68..fc91d72 100644
--- a/libs/WindowManager/Shell/res/values-ka/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ka/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"დახურვა"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"გაშლა"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"პარამეტრები"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"გაყოფილ ეკრანში შესვლა"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"მენიუ"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> იყენებს რეჟიმს „ეკრანი ეკრანში“"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"თუ არ გსურთ, რომ <xliff:g id="NAME">%s</xliff:g> ამ ფუნქციას იყენებდეს, აქ შეხებით შეგიძლიათ გახსნათ პარამეტრები და გამორთოთ ის."</string>
diff --git a/libs/WindowManager/Shell/res/values-kk/strings.xml b/libs/WindowManager/Shell/res/values-kk/strings.xml
index ca9bffc..05a905d 100644
--- a/libs/WindowManager/Shell/res/values-kk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-kk/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"Жабу"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"Жаю"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"Параметрлер"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"Бөлінген экранға кіру"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"Mәзір"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> \"суреттегі сурет\" режимінде"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"<xliff:g id="NAME">%s</xliff:g> деген пайдаланушының бұл мүмкіндікті пайдалануын қаламасаңыз, параметрлерді түртіп ашыңыз да, оларды өшіріңіз."</string>
diff --git a/libs/WindowManager/Shell/res/values-km/strings.xml b/libs/WindowManager/Shell/res/values-km/strings.xml
index 55d4e46..6a1cb2b 100644
--- a/libs/WindowManager/Shell/res/values-km/strings.xml
+++ b/libs/WindowManager/Shell/res/values-km/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"បិទ"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"ពង្រីក"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"ការកំណត់"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"ចូលមុខងារ​បំបែកអេក្រង់"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"ម៉ឺនុយ"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> ស្ថិតក្នុងមុខងាររូបក្នុងរូប"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"ប្រសិនបើ​អ្នក​មិន​ចង់​ឲ្យ <xliff:g id="NAME">%s</xliff:g> ប្រើ​មុខងារ​នេះ​ សូមចុច​​បើក​ការកំណត់ រួច​បិទ​វា។"</string>
diff --git a/libs/WindowManager/Shell/res/values-kn/strings.xml b/libs/WindowManager/Shell/res/values-kn/strings.xml
index 86c128e..aecb54b 100644
--- a/libs/WindowManager/Shell/res/values-kn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-kn/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"ಮುಚ್ಚಿ"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"ವಿಸ್ತೃತಗೊಳಿಸು"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"ಸ್ಪ್ಲಿಟ್‌-ಸ್ಕ್ರೀನ್‌ಗೆ ಪ್ರವೇಶಿಸಿ"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"ಮೆನು"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> ಚಿತ್ರದಲ್ಲಿ ಚಿತ್ರವಾಗಿದೆ"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"<xliff:g id="NAME">%s</xliff:g> ಈ ವೈಶಿಷ್ಟ್ಯ ಬಳಸುವುದನ್ನು ನೀವು ಬಯಸದಿದ್ದರೆ, ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ತೆರೆಯಲು ಮತ್ತು ಅದನ್ನು ಆಫ್ ಮಾಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
diff --git a/libs/WindowManager/Shell/res/values-ko/strings.xml b/libs/WindowManager/Shell/res/values-ko/strings.xml
index ae360e1..5af9ca2a 100644
--- a/libs/WindowManager/Shell/res/values-ko/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ko/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"닫기"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"펼치기"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"설정"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"화면 분할 모드로 전환"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"메뉴"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g>에서 PIP 사용 중"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"<xliff:g id="NAME">%s</xliff:g>에서 이 기능이 사용되는 것을 원하지 않는 경우 탭하여 설정을 열고 기능을 사용 중지하세요."</string>
diff --git a/libs/WindowManager/Shell/res/values-ky/strings.xml b/libs/WindowManager/Shell/res/values-ky/strings.xml
index 7e56359..76f192e 100644
--- a/libs/WindowManager/Shell/res/values-ky/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ky/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"Жабуу"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"Жайып көрсөтүү"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"Жөндөөлөр"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"Экранды бөлүү режимине өтүү"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"Меню"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> – сүрөт ичиндеги сүрөт"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"Эгер <xliff:g id="NAME">%s</xliff:g> колдонмосу бул функцияны пайдаланбасын десеңиз, жөндөөлөрдү ачып туруп, аны өчүрүп коюңуз."</string>
diff --git a/libs/WindowManager/Shell/res/values-lo/strings.xml b/libs/WindowManager/Shell/res/values-lo/strings.xml
index e64dc3a..4ec6313 100644
--- a/libs/WindowManager/Shell/res/values-lo/strings.xml
+++ b/libs/WindowManager/Shell/res/values-lo/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"ປິດ"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"ຂະຫຍາຍ"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"ການຕັ້ງຄ່າ"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"ເຂົ້າການແບ່ງໜ້າຈໍ"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"ເມນູ"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> ແມ່ນເປັນການສະແດງຜົນຫຼາຍຢ່າງພ້ອມກັນ"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"ຫາກທ່ານບໍ່ຕ້ອງການ <xliff:g id="NAME">%s</xliff:g> ໃຫ້ໃຊ້ຄຸນສົມບັດນີ້, ໃຫ້ແຕະເພື່ອເປີດການຕັ້ງຄ່າ ແລ້ວປິດມັນໄວ້."</string>
diff --git a/libs/WindowManager/Shell/res/values-lt/strings.xml b/libs/WindowManager/Shell/res/values-lt/strings.xml
index b80ed48..8630e91 100644
--- a/libs/WindowManager/Shell/res/values-lt/strings.xml
+++ b/libs/WindowManager/Shell/res/values-lt/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"Uždaryti"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"Išskleisti"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"Nustatymai"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"Įjungti išskaidyto ekrano režimą"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"Meniu"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> rodom. vaizdo vaizde"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"Jei nenorite, kad „<xliff:g id="NAME">%s</xliff:g>“ naudotų šią funkciją, palietę atidarykite nustatymus ir išjunkite ją."</string>
diff --git a/libs/WindowManager/Shell/res/values-lv/strings.xml b/libs/WindowManager/Shell/res/values-lv/strings.xml
index fb260b9..b095b88 100644
--- a/libs/WindowManager/Shell/res/values-lv/strings.xml
+++ b/libs/WindowManager/Shell/res/values-lv/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"Aizvērt"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"Izvērst"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"Iestatījumi"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"Piekļūt ekrāna sadalīšanas režīmam"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"Izvēlne"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> ir attēlā attēlā"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"Ja nevēlaties lietotnē <xliff:g id="NAME">%s</xliff:g> izmantot šo funkciju, pieskarieties, lai atvērtu iestatījumus un izslēgtu funkciju."</string>
diff --git a/libs/WindowManager/Shell/res/values-mk/strings.xml b/libs/WindowManager/Shell/res/values-mk/strings.xml
index 944d5c7..184fe9d 100644
--- a/libs/WindowManager/Shell/res/values-mk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-mk/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"Затвори"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"Проширете"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"Поставки"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"Влези во поделен екран"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"Мени"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> е во слика во слика"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"Ако не сакате <xliff:g id="NAME">%s</xliff:g> да ја користи функцијава, допрете за да ги отворите поставките и да ја исклучите."</string>
diff --git a/libs/WindowManager/Shell/res/values-ml/strings.xml b/libs/WindowManager/Shell/res/values-ml/strings.xml
index 63b47a8..f1bfe9a 100644
--- a/libs/WindowManager/Shell/res/values-ml/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ml/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"അവസാനിപ്പിക്കുക"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"വികസിപ്പിക്കുക"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"ക്രമീകരണം"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"സ്ക്രീൻ വിഭജന മോഡിൽ പ്രവേശിക്കുക"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"മെനു"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> ചിത്രത്തിനുള്ളിൽ ചിത്രം രീതിയിലാണ്"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"<xliff:g id="NAME">%s</xliff:g> ഈ ഫീച്ചർ ഉപയോഗിക്കേണ്ടെങ്കിൽ, ടാപ്പ് ചെയ്‌ത് ക്രമീകരണം തുറന്ന് അത് ഓഫാക്കുക."</string>
diff --git a/libs/WindowManager/Shell/res/values-mn/strings.xml b/libs/WindowManager/Shell/res/values-mn/strings.xml
index 2de7b50..afe8584 100644
--- a/libs/WindowManager/Shell/res/values-mn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-mn/strings.xml
@@ -20,6 +20,8 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"Хаах"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"Дэлгэх"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"Тохиргоо"</string>
+    <!-- no translation found for pip_phone_enter_split (7042877263880641911) -->
+    <skip />
     <string name="pip_menu_title" msgid="5393619322111827096">"Цэс"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> дэлгэцэн доторх дэлгэцэд байна"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"Та <xliff:g id="NAME">%s</xliff:g>-д энэ онцлогийг ашиглуулахыг хүсэхгүй байвал тохиргоог нээгээд, үүнийг унтраана уу."</string>
diff --git a/libs/WindowManager/Shell/res/values-mr/strings.xml b/libs/WindowManager/Shell/res/values-mr/strings.xml
index 12506d8..c11af7b 100644
--- a/libs/WindowManager/Shell/res/values-mr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-mr/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"बंद करा"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"विस्तृत करा"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"सेटिंग्ज"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"स्प्लिट स्क्रीन एंटर करा"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"मेनू"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> चित्रामध्ये चित्र मध्ये आहे"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"<xliff:g id="NAME">%s</xliff:g>ने हे वैशिष्ट्य वापरू नये असे तुम्हाला वाटत असल्यास, सेटिंग्ज उघडण्यासाठी टॅप करा आणि ते बंद करा."</string>
diff --git a/libs/WindowManager/Shell/res/values-ms/strings.xml b/libs/WindowManager/Shell/res/values-ms/strings.xml
index 5cd1ca5..b495fef 100644
--- a/libs/WindowManager/Shell/res/values-ms/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ms/strings.xml
@@ -20,6 +20,8 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"Tutup"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"Kembangkan"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"Tetapan"</string>
+    <!-- no translation found for pip_phone_enter_split (7042877263880641911) -->
+    <skip />
     <string name="pip_menu_title" msgid="5393619322111827096">"Menu"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> terdapat dalam gambar dalam gambar"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"Jika anda tidak mahu <xliff:g id="NAME">%s</xliff:g> menggunakan ciri ini, ketik untuk membuka tetapan dan matikan ciri."</string>
diff --git a/libs/WindowManager/Shell/res/values-my/strings.xml b/libs/WindowManager/Shell/res/values-my/strings.xml
index 4b3334d..2849137 100644
--- a/libs/WindowManager/Shell/res/values-my/strings.xml
+++ b/libs/WindowManager/Shell/res/values-my/strings.xml
@@ -20,6 +20,8 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"ပိတ်ရန်"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"ချဲ့ရန်"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"ဆက်တင်များ"</string>
+    <!-- no translation found for pip_phone_enter_split (7042877263880641911) -->
+    <skip />
     <string name="pip_menu_title" msgid="5393619322111827096">"မီနူး"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> သည် နှစ်ခုထပ်၍ကြည့်ခြင်း ဖွင့်ထားသည်"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"<xliff:g id="NAME">%s</xliff:g> အား ဤဝန်ဆောင်မှုကို အသုံးမပြုစေလိုလျှင် ဆက်တင်ကိုဖွင့်ရန် တို့ပြီး ၎င်းဝန်ဆောင်မှုကို ပိတ်လိုက်ပါ။"</string>
diff --git a/libs/WindowManager/Shell/res/values-nb/strings.xml b/libs/WindowManager/Shell/res/values-nb/strings.xml
index f9cf0aa..87bc7da 100644
--- a/libs/WindowManager/Shell/res/values-nb/strings.xml
+++ b/libs/WindowManager/Shell/res/values-nb/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"Lukk"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"Vis"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"Innstillinger"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"Aktivér delt skjerm"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"Meny"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> er i bilde-i-bilde"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"Hvis du ikke vil at <xliff:g id="NAME">%s</xliff:g> skal bruke denne funksjonen, kan du trykke for å åpne innstillingene og slå den av."</string>
diff --git a/libs/WindowManager/Shell/res/values-ne/strings.xml b/libs/WindowManager/Shell/res/values-ne/strings.xml
index 803f4c4..12df158 100644
--- a/libs/WindowManager/Shell/res/values-ne/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ne/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"बन्द गर्नुहोस्"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"विस्तृत गर्नुहोस्"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"सेटिङहरू"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"स्प्लिट स्क्रिन मोड प्रयोग गर्नुहोस्"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"मेनु"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> Picture-in-picture मा छ"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"तपाईं <xliff:g id="NAME">%s</xliff:g> ले सुविधा प्रयोग नगरोस् भन्ने चाहनुहुन्छ भने ट्याप गरेर सेटिङहरू खोल्नुहोस् र यसलाई निष्क्रिय पार्नुहोस्।"</string>
diff --git a/libs/WindowManager/Shell/res/values-nl/strings.xml b/libs/WindowManager/Shell/res/values-nl/strings.xml
index 658cf6a..f83ad22 100644
--- a/libs/WindowManager/Shell/res/values-nl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-nl/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"Sluiten"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"Uitvouwen"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"Instellingen"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"Gesplitst scherm openen"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"Menu"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> is in scherm-in-scherm"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"Als je niet wilt dat <xliff:g id="NAME">%s</xliff:g> deze functie gebruikt, tik je om de instellingen te openen en zet je de functie uit."</string>
diff --git a/libs/WindowManager/Shell/res/values-or/strings.xml b/libs/WindowManager/Shell/res/values-or/strings.xml
index 06f53e51..14f92c8 100644
--- a/libs/WindowManager/Shell/res/values-or/strings.xml
+++ b/libs/WindowManager/Shell/res/values-or/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"ବନ୍ଦ କରନ୍ତୁ"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"ବଢ଼ାନ୍ତୁ"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"ସେଟିଂସ୍"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"ସ୍ପ୍ଲିଟ ସ୍କ୍ରିନ ମୋଡ ବ୍ୟବହାର କରନ୍ତୁ"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"ମେନୁ"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> \"ଛବି-ଭିତରେ-ଛବି\"ରେ ଅଛି"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"ଏହି ବୈଶିଷ୍ଟ୍ୟ <xliff:g id="NAME">%s</xliff:g> ବ୍ୟବହାର ନକରିବାକୁ ଯଦି ଆପଣ ଚାହାଁନ୍ତି, ସେଟିଙ୍ଗ ଖୋଲିବାକୁ ଟାପ୍‍ କରନ୍ତୁ ଏବଂ ଏହା ଅଫ୍‍ କରିଦିଅନ୍ତୁ।"</string>
diff --git a/libs/WindowManager/Shell/res/values-pa/strings.xml b/libs/WindowManager/Shell/res/values-pa/strings.xml
index 93bdfe9..e09f53adb 100644
--- a/libs/WindowManager/Shell/res/values-pa/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pa/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"ਬੰਦ ਕਰੋ"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"ਵਿਸਤਾਰ ਕਰੋ"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"ਸੈਟਿੰਗਾਂ"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"ਸਪਲਿਟ ਸਕ੍ਰੀਨ ਵਿੱਚ ਦਾਖਲ ਹੋਵੋ"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"ਮੀਨੂ"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> ਤਸਵੀਰ-ਅੰਦਰ-ਤਸਵੀਰ ਵਿੱਚ ਹੈ"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"ਜੇਕਰ ਤੁਸੀਂ ਨਹੀਂ ਚਾਹੁੰਦੇ ਕਿ <xliff:g id="NAME">%s</xliff:g> ਐਪ ਇਸ ਵਿਸ਼ੇਸ਼ਤਾ ਦੀ ਵਰਤੋਂ ਕਰੇ, ਤਾਂ ਸੈਟਿੰਗਾਂ ਖੋਲ੍ਹਣ ਲਈ ਟੈਪ ਕਰੋ ਅਤੇ ਇਸਨੂੰ ਬੰਦ ਕਰੋ।"</string>
diff --git a/libs/WindowManager/Shell/res/values-pl/strings.xml b/libs/WindowManager/Shell/res/values-pl/strings.xml
index f704b01..a2ef997 100644
--- a/libs/WindowManager/Shell/res/values-pl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pl/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"Zamknij"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"Rozwiń"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"Ustawienia"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"Włącz podzielony ekran"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"Menu"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"Aplikacja <xliff:g id="NAME">%s</xliff:g> działa w trybie obraz w obrazie"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"Jeśli nie chcesz, by aplikacja <xliff:g id="NAME">%s</xliff:g> korzystała z tej funkcji, otwórz ustawienia i wyłącz ją."</string>
diff --git a/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml b/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml
index 111d78c..1300e53 100644
--- a/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"Fechar"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"Abrir"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"Configurações"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"Dividir tela"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"Menu"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> está em picture-in-picture"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"Se você não quer que o app <xliff:g id="NAME">%s</xliff:g> use este recurso, toque para abrir as configurações e desativá-lo."</string>
diff --git a/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml b/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
index bb5d30c..f3314f8 100644
--- a/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"Fechar"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"Expandir"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"Definições"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"Aceder ao ecrã dividido"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"Menu"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"A app <xliff:g id="NAME">%s</xliff:g> está no modo de ecrã no ecrã"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"Se não pretende que a app <xliff:g id="NAME">%s</xliff:g> utilize esta funcionalidade, toque para abrir as definições e desative-a."</string>
diff --git a/libs/WindowManager/Shell/res/values-pt/strings.xml b/libs/WindowManager/Shell/res/values-pt/strings.xml
index 111d78c..1300e53 100644
--- a/libs/WindowManager/Shell/res/values-pt/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pt/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"Fechar"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"Abrir"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"Configurações"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"Dividir tela"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"Menu"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> está em picture-in-picture"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"Se você não quer que o app <xliff:g id="NAME">%s</xliff:g> use este recurso, toque para abrir as configurações e desativá-lo."</string>
diff --git a/libs/WindowManager/Shell/res/values-ro/strings.xml b/libs/WindowManager/Shell/res/values-ro/strings.xml
index d5e6284..01f96c8 100644
--- a/libs/WindowManager/Shell/res/values-ro/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ro/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"Închideți"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"Extindeți"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"Setări"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"Accesați ecranul împărțit"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"Meniu"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> este în modul picture-in-picture"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"Dacă nu doriți ca <xliff:g id="NAME">%s</xliff:g> să utilizeze această funcție, atingeți pentru a deschide setările și dezactivați-o."</string>
diff --git a/libs/WindowManager/Shell/res/values-ru/strings.xml b/libs/WindowManager/Shell/res/values-ru/strings.xml
index ec3f3c3..6a0e9c1 100644
--- a/libs/WindowManager/Shell/res/values-ru/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ru/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"Закрыть"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"Развернуть"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"Настройки"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"Включить разделение экрана"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"Меню"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> находится в режиме \"Картинка в картинке\""</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"Чтобы отключить эту функцию для приложения \"<xliff:g id="NAME">%s</xliff:g>\", перейдите в настройки."</string>
diff --git a/libs/WindowManager/Shell/res/values-si/strings.xml b/libs/WindowManager/Shell/res/values-si/strings.xml
index a2afa0d..d7ed246 100644
--- a/libs/WindowManager/Shell/res/values-si/strings.xml
+++ b/libs/WindowManager/Shell/res/values-si/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"වසන්න"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"දිග හරින්න"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"සැකසීම්"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"බෙදුම් තිරයට ඇතුළු වන්න"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"මෙනුව"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> පින්තූරය-තුළ-පින්තූරය තුළ වේ"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"ඔබට <xliff:g id="NAME">%s</xliff:g> මෙම විශේෂාංගය භාවිත කිරීමට අවශ්‍ය නැති නම්, සැකසීම් විවෘත කිරීමට තට්ටු කර එය ක්‍රියාවිරහිත කරන්න."</string>
diff --git a/libs/WindowManager/Shell/res/values-sk/strings.xml b/libs/WindowManager/Shell/res/values-sk/strings.xml
index dc16329..13fd58f 100644
--- a/libs/WindowManager/Shell/res/values-sk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sk/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"Zavrieť"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"Rozbaliť"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"Nastavenia"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"Prejsť na rozdelenú obrazovku"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"Ponuka"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> je v režime obraz v obraze"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"Ak nechcete, aby aplikácia <xliff:g id="NAME">%s</xliff:g> používala túto funkciu, klepnutím otvorte nastavenia a vypnite ju."</string>
diff --git a/libs/WindowManager/Shell/res/values-sl/strings.xml b/libs/WindowManager/Shell/res/values-sl/strings.xml
index 2feac00..6a68069 100644
--- a/libs/WindowManager/Shell/res/values-sl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sl/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"Zapri"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"Razširi"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"Nastavitve"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"Vklopi razdeljen zaslon"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"Meni"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> je v načinu slika v sliki"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"Če ne želite, da aplikacija <xliff:g id="NAME">%s</xliff:g> uporablja to funkcijo, se dotaknite, da odprete nastavitve, in funkcijo izklopite."</string>
diff --git a/libs/WindowManager/Shell/res/values-sq/strings.xml b/libs/WindowManager/Shell/res/values-sq/strings.xml
index cae9306..2b0b551 100644
--- a/libs/WindowManager/Shell/res/values-sq/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sq/strings.xml
@@ -20,6 +20,8 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"Mbyll"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"Zgjero"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"Cilësimet"</string>
+    <!-- no translation found for pip_phone_enter_split (7042877263880641911) -->
+    <skip />
     <string name="pip_menu_title" msgid="5393619322111827096">"Menyja"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> është në figurë brenda figurës"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"Nëse nuk dëshiron që <xliff:g id="NAME">%s</xliff:g> ta përdorë këtë funksion, trokit për të hapur cilësimet dhe për ta çaktivizuar."</string>
diff --git a/libs/WindowManager/Shell/res/values-sr/strings.xml b/libs/WindowManager/Shell/res/values-sr/strings.xml
index 3fe844b..c0c1e3f 100644
--- a/libs/WindowManager/Shell/res/values-sr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sr/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"Затвори"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"Прошири"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"Подешавања"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"Уђи на подељени екран"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"Мени"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> је слика у слици"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"Ако не желите да <xliff:g id="NAME">%s</xliff:g> користи ову функцију, додирните да бисте отворили подешавања и искључили је."</string>
diff --git a/libs/WindowManager/Shell/res/values-sv/strings.xml b/libs/WindowManager/Shell/res/values-sv/strings.xml
index b3b80ad..34254d9 100644
--- a/libs/WindowManager/Shell/res/values-sv/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sv/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"Stäng"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"Utöka"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"Inställningar"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"Starta delad skärm"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"Meny"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> visas i bild-i-bild"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"Om du inte vill att den här funktionen används i <xliff:g id="NAME">%s</xliff:g> öppnar du inställningarna genom att trycka. Sedan inaktiverar du funktionen."</string>
diff --git a/libs/WindowManager/Shell/res/values-sw/strings.xml b/libs/WindowManager/Shell/res/values-sw/strings.xml
index 0643669..82a9f14 100644
--- a/libs/WindowManager/Shell/res/values-sw/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sw/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"Funga"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"Panua"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"Mipangilio"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"Weka skrini iliyogawanywa"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"Menyu"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> iko katika hali ya picha ndani ya picha nyingine"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"Ikiwa hutaki <xliff:g id="NAME">%s</xliff:g> itumie kipengele hiki, gusa ili ufungue mipangilio na uizime."</string>
diff --git a/libs/WindowManager/Shell/res/values-ta/strings.xml b/libs/WindowManager/Shell/res/values-ta/strings.xml
index fa0efe6d..0ed778a 100644
--- a/libs/WindowManager/Shell/res/values-ta/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ta/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"மூடு"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"விரி"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"அமைப்புகள்"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"திரைப் பிரிப்பு பயன்முறைக்குச் செல்"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"மெனு"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> தற்போது பிக்ச்சர்-இன்-பிக்ச்சரில் உள்ளது"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"<xliff:g id="NAME">%s</xliff:g> இந்த அம்சத்தைப் பயன்படுத்த வேண்டாம் என நினைத்தால் இங்கு தட்டி அமைப்புகளைத் திறந்து இதை முடக்கவும்."</string>
diff --git a/libs/WindowManager/Shell/res/values-te/strings.xml b/libs/WindowManager/Shell/res/values-te/strings.xml
index 3d1f3c0..8fef67b 100644
--- a/libs/WindowManager/Shell/res/values-te/strings.xml
+++ b/libs/WindowManager/Shell/res/values-te/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"మూసివేయి"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"విస్తరింపజేయి"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"సెట్టింగ్‌లు"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"స్ప్లిట్ స్క్రీన్‌ను ఎంటర్ చేయండి"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"మెనూ"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> చిత్రంలో చిత్రం రూపంలో ఉంది"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"<xliff:g id="NAME">%s</xliff:g> ఈ లక్షణాన్ని ఉపయోగించకూడదు అని మీరు అనుకుంటే, సెట్టింగ్‌లను తెరవడానికి ట్యాప్ చేసి, దీన్ని ఆఫ్ చేయండి."</string>
diff --git a/libs/WindowManager/Shell/res/values-th/strings.xml b/libs/WindowManager/Shell/res/values-th/strings.xml
index 3eb40fe..563ec2f 100644
--- a/libs/WindowManager/Shell/res/values-th/strings.xml
+++ b/libs/WindowManager/Shell/res/values-th/strings.xml
@@ -20,6 +20,8 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"ปิด"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"ขยาย"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"การตั้งค่า"</string>
+    <!-- no translation found for pip_phone_enter_split (7042877263880641911) -->
+    <skip />
     <string name="pip_menu_title" msgid="5393619322111827096">"เมนู"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> ใช้การแสดงภาพซ้อนภาพ"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"หากคุณไม่ต้องการให้ <xliff:g id="NAME">%s</xliff:g> ใช้ฟีเจอร์นี้ ให้แตะเพื่อเปิดการตั้งค่าแล้วปิดฟีเจอร์"</string>
diff --git a/libs/WindowManager/Shell/res/values-tl/strings.xml b/libs/WindowManager/Shell/res/values-tl/strings.xml
index 6908cb8..a9a36bb 100644
--- a/libs/WindowManager/Shell/res/values-tl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-tl/strings.xml
@@ -20,6 +20,8 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"Isara"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"Palawakin"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"Mga Setting"</string>
+    <!-- no translation found for pip_phone_enter_split (7042877263880641911) -->
+    <skip />
     <string name="pip_menu_title" msgid="5393619322111827096">"Menu"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"Nasa picture-in-picture ang <xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"Kung ayaw mong magamit ni <xliff:g id="NAME">%s</xliff:g> ang feature na ito, i-tap upang buksan ang mga setting at i-off ito."</string>
diff --git a/libs/WindowManager/Shell/res/values-tr/strings.xml b/libs/WindowManager/Shell/res/values-tr/strings.xml
index 61deb56..971520a 100644
--- a/libs/WindowManager/Shell/res/values-tr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-tr/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"Kapat"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"Genişlet"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"Ayarlar"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"Bölünmüş ekrana geç"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"Menü"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g>, pencere içinde pencere özelliğini kullanıyor"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"<xliff:g id="NAME">%s</xliff:g> uygulamasının bu özelliği kullanmasını istemiyorsanız dokunarak ayarları açın ve söz konusu özelliği kapatın."</string>
diff --git a/libs/WindowManager/Shell/res/values-uk/strings.xml b/libs/WindowManager/Shell/res/values-uk/strings.xml
index 00f5dd1..3014735 100644
--- a/libs/WindowManager/Shell/res/values-uk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-uk/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"Закрити"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"Розгорнути"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"Налаштування"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"Розділити екран"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"Меню"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"У додатку <xliff:g id="NAME">%s</xliff:g> є функція \"Картинка в картинці\""</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"Щоб додаток <xliff:g id="NAME">%s</xliff:g> не використовував цю функцію, вимкніть її в налаштуваннях."</string>
diff --git a/libs/WindowManager/Shell/res/values-ur/strings.xml b/libs/WindowManager/Shell/res/values-ur/strings.xml
index 7a12c91..07319ef 100644
--- a/libs/WindowManager/Shell/res/values-ur/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ur/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"بند کریں"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"پھیلائیں"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"ترتیبات"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"اسپلٹ اسکرین تک رسائی"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"مینو"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> تصویر میں تصویر میں ہے"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"اگر آپ نہیں چاہتے ہیں کہ <xliff:g id="NAME">%s</xliff:g> اس خصوصیت کا استعمال کرے تو ترتیبات کھولنے کے لیے تھپتھپا کر اسے آف کرے۔"</string>
diff --git a/libs/WindowManager/Shell/res/values-uz/strings.xml b/libs/WindowManager/Shell/res/values-uz/strings.xml
index c640744..4c79d64 100644
--- a/libs/WindowManager/Shell/res/values-uz/strings.xml
+++ b/libs/WindowManager/Shell/res/values-uz/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"Yopish"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"Yoyish"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"Sozlamalar"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"Ajratilgan ekranga kirish"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"Menyu"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> tasvir ustida tasvir rejimida"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"<xliff:g id="NAME">%s</xliff:g> ilovasi uchun bu funksiyani sozlamalar orqali faolsizlantirish mumkin."</string>
diff --git a/libs/WindowManager/Shell/res/values-vi/strings.xml b/libs/WindowManager/Shell/res/values-vi/strings.xml
index ebf0bf6..b9f23cd 100644
--- a/libs/WindowManager/Shell/res/values-vi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-vi/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"Đóng"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"Mở rộng"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"Cài đặt"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"Truy cập chế độ chia đôi màn hình"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"Menu"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> đang ở chế độ ảnh trong ảnh"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"Nếu bạn không muốn <xliff:g id="NAME">%s</xliff:g> sử dụng tính năng này, hãy nhấn để mở cài đặt và tắt tính năng này."</string>
diff --git a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
index f134e2e..c007258 100644
--- a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"关闭"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"展开"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"设置"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"进入分屏模式"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"菜单"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g>目前位于“画中画”中"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"如果您不想让“<xliff:g id="NAME">%s</xliff:g>”使用此功能,请点按以打开设置,然后关闭此功能。"</string>
diff --git a/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
index 01b861d..5e33677 100644
--- a/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"關閉"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"展開"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"設定"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"進入分割螢幕"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"選單"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"「<xliff:g id="NAME">%s</xliff:g>」目前在畫中畫模式"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"如果您不想「<xliff:g id="NAME">%s</xliff:g>」使用此功能,請輕按以開啟設定,然後停用此功能。"</string>
diff --git a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
index bd7ec93..2439a97 100644
--- a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"關閉"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"展開"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"設定"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"進入分割畫面"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"選單"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"「<xliff:g id="NAME">%s</xliff:g>」目前在子母畫面中"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"如果你不想讓「<xliff:g id="NAME">%s</xliff:g>」使用這項功能,請輕觸開啟設定頁面,然後停用此功能。"</string>
diff --git a/libs/WindowManager/Shell/res/values-zu/strings.xml b/libs/WindowManager/Shell/res/values-zu/strings.xml
index 6d0858c..20128f6 100644
--- a/libs/WindowManager/Shell/res/values-zu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zu/strings.xml
@@ -20,6 +20,7 @@
     <string name="pip_phone_close" msgid="5783752637260411309">"Vala"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"Nweba"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"Izilungiselelo"</string>
+    <string name="pip_phone_enter_split" msgid="7042877263880641911">"Faka ukuhlukanisa isikrini"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"Imenyu"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"U-<xliff:g id="NAME">%s</xliff:g> ungaphakathi kwesithombe esiphakathi kwesithombe"</string>
     <string name="pip_notification_message" msgid="8854051911700302620">"Uma ungafuni i-<xliff:g id="NAME">%s</xliff:g> ukuthi isebenzise lesi sici, thepha ukuze uvule izilungiselelo uphinde uyivale."</string>
diff --git a/libs/WindowManager/Shell/res/values/colors.xml b/libs/WindowManager/Shell/res/values/colors.xml
index b25a218..23a2172 100644
--- a/libs/WindowManager/Shell/res/values/colors.xml
+++ b/libs/WindowManager/Shell/res/values/colors.xml
@@ -29,7 +29,10 @@
     <color name="bubbles_light">#FFFFFF</color>
     <color name="bubbles_dark">@color/GM2_grey_800</color>
     <color name="bubbles_icon_tint">@color/GM2_grey_700</color>
-    <color name="size_compat_hint_bubble">#30312B</color>
+
+    <!-- Size Compat Restart Button -->
+    <color name="size_compat_background">@android:color/system_neutral1_800</color>
+    <color name="size_compat_text">@android:color/system_neutral1_50</color>
 
     <!-- GM2 colors -->
     <color name="GM2_grey_200">#E8EAED</color>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java
index 7784665..6f4e22f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java
@@ -93,6 +93,19 @@
     private boolean mReverseDefaultRotation = false;
     private InsetsState mInsetsState = new InsetsState();
 
+    /**
+     * Different from {@link #equals(Object)}, this method compares the basic geometry properties
+     * of two {@link DisplayLayout} objects including width, height, rotation, density and cutout.
+     * @return {@code true} if the given {@link DisplayLayout} is identical geometry wise.
+     */
+    public boolean isSameGeometry(@NonNull DisplayLayout other) {
+        return mWidth == other.mWidth
+                && mHeight == other.mHeight
+                && mRotation == other.mRotation
+                && mDensityDpi == other.mDensityDpi
+                && Objects.equals(mCutout, other.mCutout);
+    }
+
     @Override
     public boolean equals(Object o) {
         if (this == o) return true;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
index c5713b4..1039e2a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
@@ -356,9 +356,6 @@
         public void dispatchGetNewSurface() {}
 
         @Override
-        public void windowFocusChanged(boolean hasFocus) {}
-
-        @Override
         public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {}
 
         @Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
index 625bcee..d07fff3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
@@ -34,6 +34,7 @@
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ValueAnimator;
 import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.app.ActivityManager;
 import android.content.Context;
 import android.content.res.Configuration;
@@ -61,6 +62,8 @@
 import com.android.wm.shell.common.DisplayImeController;
 import com.android.wm.shell.common.DisplayInsetsController;
 
+import java.io.PrintWriter;
+
 /**
  * Records and handles layout of splits. Helps to calculate proper bounds when configuration or
  * divide position changes.
@@ -415,6 +418,19 @@
         return bounds.width() > bounds.height();
     }
 
+    /** Reverse the split position. */
+    @SplitPosition
+    public static int reversePosition(@SplitPosition int position) {
+        switch (position) {
+            case SPLIT_POSITION_TOP_OR_LEFT:
+                return SPLIT_POSITION_BOTTOM_OR_RIGHT;
+            case SPLIT_POSITION_BOTTOM_OR_RIGHT:
+                return SPLIT_POSITION_TOP_OR_LEFT;
+            default:
+                return SPLIT_POSITION_UNDEFINED;
+        }
+    }
+
     /**
      * Return if this layout is landscape.
      */
@@ -502,6 +518,13 @@
         }
     }
 
+    /** Dumps the current split bounds recorded in this layout. */
+    public void dump(@NonNull PrintWriter pw, String prefix) {
+        pw.println(prefix + "bounds1=" + mBounds1.toShortString());
+        pw.println(prefix + "dividerBounds=" + mDividerBounds.toShortString());
+        pw.println(prefix + "bounds2=" + mBounds2.toShortString());
+    }
+
     /** Handles layout change event. */
     public interface SplitLayoutHandler {
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
index 3f5b70b..9ceed24 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
@@ -74,6 +74,7 @@
 import com.android.wm.shell.pip.phone.PipTouchHandler;
 import com.android.wm.shell.recents.RecentTasks;
 import com.android.wm.shell.recents.RecentTasksController;
+import com.android.wm.shell.sizecompatui.SizeCompatUI;
 import com.android.wm.shell.sizecompatui.SizeCompatUIController;
 import com.android.wm.shell.splitscreen.SplitScreen;
 import com.android.wm.shell.splitscreen.SplitScreenController;
@@ -171,11 +172,18 @@
 
     @WMSingleton
     @Provides
+    static SizeCompatUI provideSizeCompatUI(SizeCompatUIController sizeCompatUIController) {
+        return sizeCompatUIController.asSizeCompatUI();
+    }
+
+    @WMSingleton
+    @Provides
     static SizeCompatUIController provideSizeCompatUIController(Context context,
             DisplayController displayController, DisplayInsetsController displayInsetsController,
-            DisplayImeController imeController, SyncTransactionQueue syncQueue) {
+            DisplayImeController imeController, SyncTransactionQueue syncQueue,
+            @ShellMainThread ShellExecutor mainExecutor) {
         return new SizeCompatUIController(context, displayController, displayInsetsController,
-                imeController, syncQueue);
+                imeController, syncQueue, mainExecutor);
     }
 
     @WMSingleton
@@ -236,15 +244,24 @@
     // Fullscreen
     //
 
+    // Workaround for dynamic overriding with a default implementation, see {@link DynamicOverride}
+    @BindsOptionalOf
+    @DynamicOverride
+    abstract FullscreenTaskListener optionalFullscreenTaskListener();
+
     @WMSingleton
     @Provides
     static FullscreenTaskListener provideFullscreenTaskListener(
+            @DynamicOverride Optional<FullscreenTaskListener> fullscreenTaskListener,
             SyncTransactionQueue syncQueue,
             Optional<FullscreenUnfoldController> optionalFullscreenUnfoldController,
-            Optional<RecentTasksController> recentTasksOptional
-    ) {
-        return new FullscreenTaskListener(syncQueue, optionalFullscreenUnfoldController,
-                recentTasksOptional);
+            Optional<RecentTasksController> recentTasksOptional) {
+        if (fullscreenTaskListener.isPresent()) {
+            return fullscreenTaskListener.get();
+        } else {
+            return new FullscreenTaskListener(syncQueue, optionalFullscreenUnfoldController,
+                    recentTasksOptional);
+        }
     }
 
     //
@@ -329,7 +346,7 @@
     @Provides
     static Optional<OneHandedController> providesOneHandedController(
             @DynamicOverride Optional<OneHandedController> oneHandedController) {
-        if (!SystemProperties.getBoolean(SUPPORT_ONE_HANDED_MODE, false)) {
+        if (SystemProperties.getBoolean(SUPPORT_ONE_HANDED_MODE, false)) {
             return oneHandedController;
         }
         return Optional.empty();
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 3253bb0..b00182f 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
@@ -17,6 +17,7 @@
 package com.android.wm.shell.onehanded;
 
 import android.content.res.Configuration;
+import android.os.SystemProperties;
 
 import com.android.wm.shell.common.annotations.ExternalThread;
 
@@ -26,6 +27,9 @@
 @ExternalThread
 public interface OneHanded {
 
+    boolean sIsSupportOneHandedMode =  SystemProperties.getBoolean(
+            OneHandedController.SUPPORT_ONE_HANDED_MODE, false);
+
     /**
      * Returns a binder that can be passed to an external process to manipulate OneHanded.
      */
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 e068614..72bb655 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
@@ -16,7 +16,6 @@
 
 package com.android.wm.shell.onehanded;
 
-import static android.os.UserHandle.USER_CURRENT;
 import static android.os.UserHandle.myUserId;
 import static android.view.Display.DEFAULT_DISPLAY;
 
@@ -30,12 +29,10 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.om.IOverlayManager;
-import android.content.om.OverlayInfo;
 import android.content.res.Configuration;
 import android.database.ContentObserver;
 import android.graphics.Rect;
 import android.os.Handler;
-import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemProperties;
 import android.provider.Settings;
@@ -70,9 +67,6 @@
 
     private static final String ONE_HANDED_MODE_OFFSET_PERCENTAGE =
             "persist.debug.one_handed_offset_percentage";
-    private static final String ONE_HANDED_MODE_GESTURAL_OVERLAY =
-            "com.android.internal.systemui.onehanded.gestural";
-    private static final int OVERLAY_ENABLED_DELAY_MS = 250;
     private static final int DISPLAY_AREA_READY_RETRY_MS = 10;
 
     public static final String SUPPORT_ONE_HANDED_MODE = "ro.support_one_handed_mode";
@@ -282,7 +276,6 @@
         setupCallback();
         registerSettingObservers(mUserId);
         setupTimeoutListener();
-        setupGesturalOverlay();
         updateSettings();
 
         mAccessibilityManager = AccessibilityManager.getInstance(context);
@@ -517,11 +510,6 @@
                 : OneHandedUiEventLogger.EVENT_ONE_HANDED_SETTINGS_ENABLED_OFF);
 
         setOneHandedEnabled(enabled);
-
-        // Also checks swipe to notification settings since they all need gesture overlay.
-        setEnabledGesturalOverlay(
-                enabled || mOneHandedSettingsUtil.getSettingsSwipeToNotificationEnabled(
-                        mContext.getContentResolver(), mUserId), true /* DelayExecute */);
     }
 
     @VisibleForTesting
@@ -602,40 +590,6 @@
         }
     }
 
-    private void setupGesturalOverlay() {
-        if (!mOneHandedSettingsUtil.getSettingsOneHandedModeEnabled(
-                mContext.getContentResolver(), mUserId)) {
-            return;
-        }
-
-        OverlayInfo info = null;
-        try {
-            mOverlayManager.setHighestPriority(ONE_HANDED_MODE_GESTURAL_OVERLAY, USER_CURRENT);
-            info = mOverlayManager.getOverlayInfo(ONE_HANDED_MODE_GESTURAL_OVERLAY, USER_CURRENT);
-        } catch (RemoteException e) { /* Do nothing */ }
-
-        if (info != null && !info.isEnabled()) {
-            // Enable the default gestural one handed overlay.
-            setEnabledGesturalOverlay(true /* enabled */, false /* delayExecute */);
-        }
-    }
-
-    @VisibleForTesting
-    private void setEnabledGesturalOverlay(boolean enabled, boolean delayExecute) {
-        if (mState.isTransitioning() || delayExecute) {
-            // Enabled overlay package may affect the current animation(e.g:Settings switch),
-            // so we delay 250ms to enabled overlay after switch animation finish, only delay once.
-            mMainExecutor.executeDelayed(() -> setEnabledGesturalOverlay(enabled, false),
-                    OVERLAY_ENABLED_DELAY_MS);
-            return;
-        }
-        try {
-            mOverlayManager.setEnabled(ONE_HANDED_MODE_GESTURAL_OVERLAY, enabled, USER_CURRENT);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
     @VisibleForTesting
     void setLockedDisabled(boolean locked, boolean enabled) {
         final boolean isFeatureEnabled = mIsOneHandedEnabled || mIsSwipeToNotificationEnabled;
@@ -714,19 +668,6 @@
         }
 
         mOneHandedSettingsUtil.dump(pw, innerPrefix, mContext.getContentResolver(), mUserId);
-
-        if (mOverlayManager != null) {
-            OverlayInfo info = null;
-            try {
-                info = mOverlayManager.getOverlayInfo(ONE_HANDED_MODE_GESTURAL_OVERLAY,
-                        USER_CURRENT);
-            } catch (RemoteException e) { /* Do nothing */ }
-
-            if (info != null && !info.isEnabled()) {
-                pw.print(innerPrefix + "OverlayInfo=");
-                pw.println(info);
-            }
-        }
     }
 
     /**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
index 05111a3..9575b0a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
@@ -594,10 +594,10 @@
                         getSurfaceTransactionHelper().scaleAndCrop(tx, leash,
                                 initialSourceValue, bounds, insets);
                         if (shouldApplyCornerRadius()) {
-                            final Rect destinationBounds = new Rect(bounds);
-                            destinationBounds.inset(insets);
+                            final Rect sourceBounds = new Rect(initialContainerRect);
+                            sourceBounds.inset(insets);
                             getSurfaceTransactionHelper().round(tx, leash,
-                                    initialContainerRect, destinationBounds);
+                                    sourceBounds, bounds);
                         }
                     }
                     if (!handlePipTransaction(leash, tx, bounds)) {
@@ -641,11 +641,13 @@
                             y = fraction * (end.bottom - start.top) + start.top;
                         }
                     }
+                    final Rect sourceBounds = new Rect(initialContainerRect);
+                    sourceBounds.inset(insets);
                     getSurfaceTransactionHelper()
                             .rotateAndScaleWithCrop(tx, leash, initialContainerRect, bounds,
                                     insets, degree, x, y, isOutPipDirection,
                                     rotationDelta == ROTATION_270 /* clockwise */)
-                            .round(tx, leash, initialContainerRect, bounds);
+                            .round(tx, leash, sourceBounds, bounds);
                     tx.apply();
                 }
 
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 f25cff7..79e3444 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
@@ -88,7 +88,6 @@
 import com.android.wm.shell.transition.Transitions;
 
 import java.io.PrintWriter;
-import java.util.Objects;
 import java.util.Optional;
 import java.util.function.Consumer;
 
@@ -469,7 +468,7 @@
     }
 
     private void onDisplayChanged(DisplayLayout layout, boolean saveRestoreSnapFraction) {
-        if (Objects.equals(layout, mPipBoundsState.getDisplayLayout())) {
+        if (mPipBoundsState.getDisplayLayout().isSameGeometry(layout)) {
             return;
         }
         Runnable updateDisplayLayout = () -> {
@@ -491,25 +490,12 @@
         if (mPipTaskOrganizer.isInPip() && saveRestoreSnapFraction) {
             // Calculate the snap fraction of the current stack along the old movement bounds
             final PipSnapAlgorithm pipSnapAlgorithm = mPipBoundsAlgorithm.getSnapAlgorithm();
-            final float snapFraction = pipSnapAlgorithm.getSnapFraction(mPipBoundsState.getBounds(),
-                    mPipBoundsAlgorithm.getMovementBounds(mPipBoundsState.getBounds()),
+            final Rect postChangeStackBounds = new Rect(mPipBoundsState.getBounds());
+            final float snapFraction = pipSnapAlgorithm.getSnapFraction(postChangeStackBounds,
+                    mPipBoundsAlgorithm.getMovementBounds(postChangeStackBounds),
                     mPipBoundsState.getStashedState());
 
             updateDisplayLayout.run();
-            final Rect postChangeStackBounds;
-            if (mPipBoundsState.getBounds() != null
-                    && (mPipBoundsState.getBounds().width() > mPipBoundsState.getMaxSize().x
-                    || mPipBoundsState.getBounds().height() > mPipBoundsState.getMaxSize().y)) {
-                postChangeStackBounds = new Rect(0, 0, mPipBoundsState.getMaxSize().x,
-                        mPipBoundsState.getMaxSize().y);
-            } else if (mPipBoundsState.getBounds() != null
-                    && (mPipBoundsState.getBounds().width() < mPipBoundsState.getMinSize().x
-                    || mPipBoundsState.getBounds().height() < mPipBoundsState.getMinSize().y)) {
-                postChangeStackBounds = new Rect(0, 0, mPipBoundsState.getMinSize().x,
-                        mPipBoundsState.getMinSize().y);
-            } else {
-                postChangeStackBounds = new Rect(mPipBoundsState.getBounds());
-            }
 
             // Calculate the stack bounds in the new orientation based on same fraction along the
             // rotated movement bounds.
@@ -521,7 +507,7 @@
                     mPipBoundsState.getDisplayBounds(),
                     mPipBoundsState.getDisplayLayout().stableInsets());
 
-            mTouchHandler.getMotionHelper().animateResizedBounds(postChangeStackBounds);
+            mTouchHandler.getMotionHelper().movePip(postChangeStackBounds);
         } else {
             updateDisplayLayout.run();
         }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java
index c634b7f..96fd59f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java
@@ -69,7 +69,6 @@
     private static final int UNSTASH_DURATION = 250;
     private static final int LEAVE_PIP_DURATION = 300;
     private static final int SHIFT_DURATION = 300;
-    private static final int ANIMATE_PIP_RESIZE_ANIMATION = 250;
 
     /** Friction to use for PIP when it moves via physics fling animations. */
     private static final float DEFAULT_FRICTION = 1.9f;
@@ -549,14 +548,6 @@
     }
 
     /**
-     * Animates the PiP from an old bound to a new bound. This is mostly used when display
-     * has changed and PiP bounds needs to be changed.
-     */
-    void animateResizedBounds(Rect newBounds) {
-        resizeAndAnimatePipUnchecked(newBounds, ANIMATE_PIP_RESIZE_ANIMATION);
-    }
-
-    /**
      * Animates the PiP to offset it from the IME or shelf.
      */
     void animateToOffset(Rect originalBounds, int offset) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java
index 00083d9..83390a5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java
@@ -57,7 +57,7 @@
 public class TvPipController implements PipTransitionController.PipTransitionCallback,
         TvPipMenuController.Delegate, TvPipNotificationController.Delegate {
     private static final String TAG = "TvPipController";
-    static final boolean DEBUG = true;
+    static final boolean DEBUG = false;
 
     private static final int NONEXISTENT_TASK_ID = -1;
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
index 7cf3baf..a006f30 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
@@ -111,6 +111,11 @@
         if (taskId1 == taskId2) {
             return;
         }
+        if (mSplitTasks.get(taskId1, INVALID_TASK_ID) == taskId2
+                && mTaskSplitBoundsMap.get(taskId1).equals(splitBounds)) {
+            // If the two tasks are already paired and the bounds are the same, then skip updating
+            return;
+        }
         // Remove any previous pairs
         removeSplitPair(taskId1);
         removeSplitPair(taskId2);
@@ -121,6 +126,7 @@
         mSplitTasks.put(taskId2, taskId1);
         mTaskSplitBoundsMap.put(taskId1, splitBounds);
         mTaskSplitBoundsMap.put(taskId2, splitBounds);
+        notifyRecentTasksChanged();
     }
 
     /**
@@ -133,6 +139,7 @@
             mSplitTasks.delete(pairedTaskId);
             mTaskSplitBoundsMap.remove(taskId);
             mTaskSplitBoundsMap.remove(pairedTaskId);
+            notifyRecentTasksChanged();
         }
     }
 
@@ -217,7 +224,7 @@
             }
 
             final int pairedTaskId = mSplitTasks.get(taskInfo.taskId);
-            if (pairedTaskId != INVALID_TASK_ID) {
+            if (pairedTaskId != INVALID_TASK_ID && rawMapping.contains(pairedTaskId)) {
                 final ActivityManager.RecentTaskInfo pairedTaskInfo = rawMapping.get(pairedTaskId);
                 rawMapping.remove(pairedTaskId);
                 recentTasks.add(new GroupedRecentTaskInfo(taskInfo, pairedTaskInfo,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUI.java b/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUI.java
new file mode 100644
index 0000000..a703114
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUI.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.wm.shell.sizecompatui;
+
+import com.android.wm.shell.common.annotations.ExternalThread;
+
+/**
+ * Interface to engage size compat UI.
+ */
+@ExternalThread
+public interface SizeCompatUI {
+    /**
+     * Called when the keyguard occluded state changes. Removes all size compat UIs if the
+     * keyguard is now occluded.
+     * @param occluded indicates if the keyguard is now occluded.
+     */
+    void onKeyguardOccludedChanged(boolean occluded);
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUIController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUIController.java
index 04d974a..e06070a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUIController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUIController.java
@@ -35,13 +35,16 @@
 import com.android.wm.shell.common.DisplayInsetsController;
 import com.android.wm.shell.common.DisplayInsetsController.OnInsetsChangedListener;
 import com.android.wm.shell.common.DisplayLayout;
+import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.SyncTransactionQueue;
+import com.android.wm.shell.common.annotations.ExternalThread;
 
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
 import java.util.function.Consumer;
+import java.util.function.Predicate;
 
 /**
  * Controls to show/update restart-activity buttons on Tasks based on whether the foreground
@@ -78,26 +81,37 @@
     private final DisplayInsetsController mDisplayInsetsController;
     private final DisplayImeController mImeController;
     private final SyncTransactionQueue mSyncQueue;
+    private final ShellExecutor mMainExecutor;
+    private final SizeCompatUIImpl mImpl = new SizeCompatUIImpl();
 
     private SizeCompatUICallback mCallback;
 
     /** Only show once automatically in the process life. */
     private boolean mHasShownHint;
+    /** Indicates if the keyguard is currently occluded, in which case size compat UIs shouldn't
+     * be shown. */
+    private boolean mKeyguardOccluded;
 
     public SizeCompatUIController(Context context,
             DisplayController displayController,
             DisplayInsetsController displayInsetsController,
             DisplayImeController imeController,
-            SyncTransactionQueue syncQueue) {
+            SyncTransactionQueue syncQueue,
+            ShellExecutor mainExecutor) {
         mContext = context;
         mDisplayController = displayController;
         mDisplayInsetsController = displayInsetsController;
         mImeController = imeController;
         mSyncQueue = syncQueue;
+        mMainExecutor = mainExecutor;
         mDisplayController.addDisplayWindowListener(this);
         mImeController.addPositionProcessor(this);
     }
 
+    public SizeCompatUI asSizeCompatUI() {
+        return mImpl;
+    }
+
     /** Sets the callback for UI interactions. */
     public void setSizeCompatUICallback(SizeCompatUICallback callback) {
         mCallback = callback;
@@ -106,6 +120,7 @@
     /**
      * Called when the Task info changed. Creates and updates the size compat UI if there is an
      * activity in size compat, or removes the UI if there is no size compat activity.
+     *
      * @param displayId display the task and activity are in.
      * @param taskId task the activity is in.
      * @param taskConfig task config to place the size compat UI with.
@@ -180,7 +195,19 @@
         }
 
         // Hide the size compat UIs when input method is showing.
-        forAllLayoutsOnDisplay(displayId, layout -> layout.updateImeVisibility(isShowing));
+        forAllLayoutsOnDisplay(displayId,
+                layout -> layout.updateVisibility(showOnDisplay(displayId)));
+    }
+
+    @VisibleForTesting
+    void onKeyguardOccludedChanged(boolean occluded) {
+        mKeyguardOccluded = occluded;
+        // Hide the size compat UIs when keyguard is occluded.
+        forAllLayouts(layout -> layout.updateVisibility(showOnDisplay(layout.getDisplayId())));
+    }
+
+    private boolean showOnDisplay(int displayId) {
+        return !mKeyguardOccluded && !isImeShowingOnDisplay(displayId);
     }
 
     private boolean isImeShowingOnDisplay(int displayId) {
@@ -198,7 +225,7 @@
         final SizeCompatUILayout layout = createLayout(context, displayId, taskId, taskConfig,
                 taskListener);
         mActiveLayouts.put(taskId, layout);
-        layout.createSizeCompatButton(isImeShowingOnDisplay(displayId));
+        layout.createSizeCompatButton(showOnDisplay(displayId));
     }
 
     @VisibleForTesting
@@ -218,8 +245,7 @@
         if (layout == null) {
             return;
         }
-        layout.updateSizeCompatInfo(taskConfig, taskListener,
-                isImeShowingOnDisplay(layout.getDisplayId()));
+        layout.updateSizeCompatInfo(taskConfig, taskListener, showOnDisplay(layout.getDisplayId()));
     }
 
     private void removeLayout(int taskId) {
@@ -250,15 +276,37 @@
     }
 
     private void forAllLayoutsOnDisplay(int displayId, Consumer<SizeCompatUILayout> callback) {
+        forAllLayouts(layout -> layout.getDisplayId() == displayId, callback);
+    }
+
+    private void forAllLayouts(Consumer<SizeCompatUILayout> callback) {
+        forAllLayouts(layout -> true, callback);
+    }
+
+    private void forAllLayouts(Predicate<SizeCompatUILayout> condition,
+            Consumer<SizeCompatUILayout> callback) {
         for (int i = 0; i < mActiveLayouts.size(); i++) {
             final int taskId = mActiveLayouts.keyAt(i);
             final SizeCompatUILayout layout = mActiveLayouts.get(taskId);
-            if (layout != null && layout.getDisplayId() == displayId) {
+            if (layout != null && condition.test(layout)) {
                 callback.accept(layout);
             }
         }
     }
 
+    /**
+     * The interface for calls from outside the Shell, within the host process.
+     */
+    @ExternalThread
+    private class SizeCompatUIImpl implements SizeCompatUI {
+        @Override
+        public void onKeyguardOccludedChanged(boolean occluded) {
+            mMainExecutor.execute(() -> {
+                SizeCompatUIController.this.onKeyguardOccludedChanged(occluded);
+            });
+        }
+    }
+
     /** An implementation of {@link OnInsetsChangedListener} for a given display id. */
     private class PerDisplayOnInsetsChangedListener implements OnInsetsChangedListener {
         final int mDisplayId;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUILayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUILayout.java
index 1a2c94f..c35b89a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUILayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUILayout.java
@@ -103,9 +103,9 @@
     }
 
     /** Creates the activity restart button window. */
-    void createSizeCompatButton(boolean isImeShowing) {
-        if (isImeShowing || mButton != null) {
-            // When ime is showing, wait until ime is dismiss to create UI.
+    void createSizeCompatButton(boolean show) {
+        if (!show || mButton != null) {
+            // Wait until button should be visible.
             return;
         }
         mButton = mButtonWindowManager.createSizeCompatButton();
@@ -154,7 +154,7 @@
 
     /** Called when size compat info changed. */
     void updateSizeCompatInfo(Configuration taskConfig,
-            ShellTaskOrganizer.TaskListener taskListener, boolean isImeShowing) {
+            ShellTaskOrganizer.TaskListener taskListener, boolean show) {
         final Configuration prevTaskConfig = mTaskConfig;
         final ShellTaskOrganizer.TaskListener prevTaskListener = mTaskListener;
         mTaskConfig = taskConfig;
@@ -170,7 +170,7 @@
         if (mButton == null || prevTaskListener != taskListener) {
             // TaskListener changed, recreate the button for new surface parent.
             release();
-            createSizeCompatButton(isImeShowing);
+            createSizeCompatButton(show);
             return;
         }
 
@@ -204,16 +204,16 @@
         }
     }
 
-    /** Called when IME visibility changed. */
-    void updateImeVisibility(boolean isImeShowing) {
+    /** Called when the visibility of the UI should change. */
+    void updateVisibility(boolean show) {
         if (mButton == null) {
-            // Button may not be created because ime is previous showing.
-            createSizeCompatButton(isImeShowing);
+            // Button may not have been created because it was hidden previously.
+            createSizeCompatButton(show);
             return;
         }
 
         // Hide size compat UIs when IME is showing.
-        final int newVisibility = isImeShowing ? View.GONE : View.VISIBLE;
+        final int newVisibility = show ? View.VISIBLE : View.GONE;
         if (mButton.getVisibility() != newVisibility) {
             mButton.setVisibility(newVisibility);
         }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java
index f8c0304..1ba1d22 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java
@@ -50,10 +50,6 @@
         wct.setBounds(rootToken, rootBounds).reorder(rootToken, true /* onTop */);
     }
 
-    void addTask(ActivityManager.RunningTaskInfo task, WindowContainerTransaction wct) {
-        wct.reparent(task.token, mRootTaskInfo.token, true /* onTop*/);
-    }
-
     boolean removeAllTasks(WindowContainerTransaction wct, boolean toTop) {
         // No matter if the root task is empty or not, moving the root to bottom because it no
         // longer preserves visible child task.
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 e86462f..02edaa0 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
@@ -87,6 +87,12 @@
      */
     void onKeyguardVisibilityChanged(boolean showing);
 
+    /** Called when device waking up finished. */
+    void onFinishedWakingUp();
+
+    /** Called when device going to sleep finished. */
+    void onFinishedGoingToSleep();
+
     /** Get a string representation of a stage type */
     static String stageTypeToString(@StageType int stage) {
         switch (stage) {
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 8af72a8..6b42ed7 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
@@ -24,6 +24,8 @@
 import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
 import static com.android.wm.shell.common.split.SplitLayout.SPLIT_POSITION_BOTTOM_OR_RIGHT;
 import static com.android.wm.shell.common.split.SplitLayout.SPLIT_POSITION_TOP_OR_LEFT;
+import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_SIDE;
+import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_UNDEFINED;
 
 import android.app.ActivityManager;
 import android.app.ActivityTaskManager;
@@ -182,30 +184,17 @@
     }
 
     public boolean moveToSideStage(int taskId, @SplitPosition int sideStagePosition) {
+        return moveToStage(taskId, STAGE_TYPE_SIDE, sideStagePosition,
+                new WindowContainerTransaction());
+    }
+
+    private boolean moveToStage(int taskId, @SplitScreen.StageType int stageType,
+            @SplitPosition int stagePosition, WindowContainerTransaction wct) {
         final ActivityManager.RunningTaskInfo task = mTaskOrganizer.getRunningTaskInfo(taskId);
         if (task == null) {
             throw new IllegalArgumentException("Unknown taskId" + taskId);
         }
-        return moveToSideStage(task, sideStagePosition);
-    }
-
-    public boolean moveToSideStage(int taskId, @SplitPosition int sideStagePosition,
-            WindowContainerTransaction wct) {
-        final ActivityManager.RunningTaskInfo task = mTaskOrganizer.getRunningTaskInfo(taskId);
-        if (task == null) {
-            throw new IllegalArgumentException("Unknown taskId" + taskId);
-        }
-        return moveToSideStage(task, sideStagePosition, wct);
-    }
-
-    public boolean moveToSideStage(ActivityManager.RunningTaskInfo task,
-            @SplitPosition int sideStagePosition) {
-        return mStageCoordinator.moveToSideStage(task, sideStagePosition);
-    }
-
-    public boolean moveToSideStage(ActivityManager.RunningTaskInfo task,
-            @SplitPosition int sideStagePosition, WindowContainerTransaction wct) {
-        return mStageCoordinator.moveToSideStage(task, sideStagePosition, wct);
+        return mStageCoordinator.moveToStage(task, stageType, stagePosition, wct);
     }
 
     public boolean removeFromSideStage(int taskId) {
@@ -221,13 +210,14 @@
     }
 
     public void enterSplitScreen(int taskId, boolean leftOrTop) {
-        moveToSideStage(taskId,
-                leftOrTop ? SPLIT_POSITION_TOP_OR_LEFT : SPLIT_POSITION_BOTTOM_OR_RIGHT);
+        enterSplitScreen(taskId, leftOrTop, new WindowContainerTransaction());
     }
 
     public void enterSplitScreen(int taskId, boolean leftOrTop, WindowContainerTransaction wct) {
-        moveToSideStage(taskId,
-                leftOrTop ? SPLIT_POSITION_TOP_OR_LEFT : SPLIT_POSITION_BOTTOM_OR_RIGHT, wct);
+        final int stageType = isSplitScreenVisible() ? STAGE_TYPE_UNDEFINED : STAGE_TYPE_SIDE;
+        final int stagePosition =
+                leftOrTop ? SPLIT_POSITION_TOP_OR_LEFT : SPLIT_POSITION_BOTTOM_OR_RIGHT;
+        moveToStage(taskId, stageType, stagePosition, wct);
     }
 
     public void exitSplitScreen(int toTopTaskId, @ExitReason int exitReason) {
@@ -242,6 +232,14 @@
         mStageCoordinator.onKeyguardVisibilityChanged(showing);
     }
 
+    public void onFinishedWakingUp() {
+        mStageCoordinator.onFinishedWakingUp();
+    }
+
+    public void onFinishedGoingToSleep() {
+        mStageCoordinator.onFinishedGoingToSleep();
+    }
+
     public void exitSplitScreenOnHide(boolean exitSplitScreenOnHide) {
         mStageCoordinator.exitSplitScreenOnHide(exitSplitScreenOnHide);
     }
@@ -501,6 +499,20 @@
                 SplitScreenController.this.onKeyguardVisibilityChanged(showing);
             });
         }
+
+        @Override
+        public void onFinishedWakingUp() {
+            mMainExecutor.execute(() -> {
+                SplitScreenController.this.onFinishedWakingUp();
+            });
+        }
+
+        @Override
+        public void onFinishedGoingToSleep() {
+            mMainExecutor.execute(() -> {
+                SplitScreenController.this.onFinishedGoingToSleep();
+            });
+        }
     }
 
     /**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index d494191..a3726d4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -155,6 +155,7 @@
     private boolean mShouldUpdateRecents;
     private boolean mExitSplitScreenOnHide;
     private boolean mKeyguardOccluded;
+    private boolean mDeviceSleep;
 
     @SplitScreen.StageType
     private int mDismissTop = NO_DISMISS;
@@ -273,18 +274,31 @@
         return mSideStageListener.mVisible && mMainStageListener.mVisible;
     }
 
-    boolean moveToSideStage(ActivityManager.RunningTaskInfo task,
-            @SplitPosition int sideStagePosition) {
-        final WindowContainerTransaction wct = new WindowContainerTransaction();
-        return moveToSideStage(task, sideStagePosition, wct);
-    }
+    boolean moveToStage(ActivityManager.RunningTaskInfo task, @SplitScreen.StageType int stageType,
+            @SplitPosition int stagePosition, WindowContainerTransaction wct) {
+        StageTaskListener targetStage;
+        int sideStagePosition;
+        if (stageType == STAGE_TYPE_MAIN) {
+            targetStage = mMainStage;
+            sideStagePosition = SplitLayout.reversePosition(stagePosition);
+        } else if (stageType == STAGE_TYPE_SIDE) {
+            targetStage = mSideStage;
+            sideStagePosition = stagePosition;
+        } else {
+            if (mMainStage.isActive()) {
+                // If the split screen is activated, retrieves target stage based on position.
+                targetStage = stagePosition == mSideStagePosition ? mSideStage : mMainStage;
+                sideStagePosition = mSideStagePosition;
+            } else {
+                targetStage = mSideStage;
+                sideStagePosition = stagePosition;
+            }
+        }
 
-    boolean moveToSideStage(ActivityManager.RunningTaskInfo task,
-            @SplitPosition int sideStagePosition, WindowContainerTransaction wct) {
-        final WindowContainerTransaction evictWct = new WindowContainerTransaction();
         setSideStagePosition(sideStagePosition, wct);
-        mSideStage.evictAllChildren(evictWct);
-        mSideStage.addTask(task, wct);
+        final WindowContainerTransaction evictWct = new WindowContainerTransaction();
+        targetStage.evictAllChildren(evictWct);
+        targetStage.addTask(task, wct);
         if (!evictWct.isEmpty()) {
             wct.merge(evictWct, true /* transfer */);
         }
@@ -463,9 +477,7 @@
             case STAGE_TYPE_MAIN: {
                 if (position != SPLIT_POSITION_UNDEFINED) {
                     // Set the side stage opposite of what we want to the main stage.
-                    final int sideStagePosition = position == SPLIT_POSITION_TOP_OR_LEFT
-                            ? SPLIT_POSITION_BOTTOM_OR_RIGHT : SPLIT_POSITION_TOP_OR_LEFT;
-                    setSideStagePosition(sideStagePosition, wct);
+                    setSideStagePosition(SplitLayout.reversePosition(position), wct);
                 } else {
                     position = getMainStagePosition();
                 }
@@ -489,8 +501,7 @@
 
     @SplitLayout.SplitPosition
     int getMainStagePosition() {
-        return mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT
-                ? SPLIT_POSITION_BOTTOM_OR_RIGHT : SPLIT_POSITION_TOP_OR_LEFT;
+        return SplitLayout.reversePosition(mSideStagePosition);
     }
 
     void setSideStagePosition(@SplitPosition int sideStagePosition,
@@ -537,6 +548,17 @@
         }
     }
 
+    void onFinishedWakingUp() {
+        if (mMainStage.isActive()) {
+            exitSplitScreenIfKeyguardOccluded();
+        }
+        mDeviceSleep = false;
+    }
+
+    void onFinishedGoingToSleep() {
+        mDeviceSleep = true;
+    }
+
     void exitSplitScreenOnHide(boolean exitSplitScreenOnHide) {
         mExitSplitScreenOnHide = exitSplitScreenOnHide;
     }
@@ -565,6 +587,19 @@
         applyExitSplitScreen(childrenToTop, wct, exitReason);
     }
 
+    private void exitSplitScreenIfKeyguardOccluded() {
+        final boolean mainStageVisible = mMainStageListener.mVisible;
+        final boolean oneStageVisible = mainStageVisible ^ mSideStageListener.mVisible;
+        if (mDeviceSleep && mKeyguardOccluded && oneStageVisible) {
+            // Only the stages include show-when-locked activity is visible while keyguard occluded.
+            // Dismiss split because there's show-when-locked activity showing on top of keyguard.
+            // Also make sure the task contains show-when-locked activity remains on top after split
+            // dismissed.
+            final StageTaskListener toTop = mainStageVisible ? mMainStage : mSideStage;
+            exitSplitScreen(toTop, EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP);
+        }
+    }
+
     private void applyExitSplitScreen(StageTaskListener childrenToTop,
             WindowContainerTransaction wct, @ExitReason int exitReason) {
         mRecentTasks.ifPresent(recentTasks -> {
@@ -780,14 +815,8 @@
             // like the cases keyguard showing or screen off.
                 exitSplitScreen(null /* childrenToTop */, EXIT_REASON_RETURN_HOME);
             }
-        } else if (mKeyguardOccluded) {
-            // At least one of the stages is visible while keyguard occluded. Dismiss split because
-            // there's show-when-locked activity showing on top of keyguard. Also make sure the
-            // task contains show-when-locked activity remains on top after split dismissed.
-            final StageTaskListener toTop =
-                    mainStageVisible ? mMainStage : (sideStageVisible ? mSideStage : null);
-            exitSplitScreen(toTop, EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP);
         }
+        exitSplitScreenIfKeyguardOccluded();
 
         mSyncQueue.runInSync(t -> {
             // Same above, we only set root tasks and divider leash visibility when both stage
@@ -870,8 +899,7 @@
 
     @Override
     public void onDoubleTappedDivider() {
-        setSideStagePosition(mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT
-                ? SPLIT_POSITION_BOTTOM_OR_RIGHT : SPLIT_POSITION_TOP_OR_LEFT, null /* wct */);
+        setSideStagePosition(SplitLayout.reversePosition(mSideStagePosition), null /* wct */);
         mLogger.logSwap(getMainStagePosition(), mMainStage.getTopChildTaskUid(),
                 getSideStagePosition(), mSideStage.getTopChildTaskUid(),
                 mSplitLayout.isLandscape());
@@ -1296,11 +1324,16 @@
         pw.println(prefix + TAG + " mDisplayId=" + mDisplayId);
         pw.println(innerPrefix + "mDividerVisible=" + mDividerVisible);
         pw.println(innerPrefix + "MainStage");
+        pw.println(childPrefix + "stagePosition=" + getMainStagePosition());
         pw.println(childPrefix + "isActive=" + mMainStage.isActive());
         mMainStageListener.dump(pw, childPrefix);
         pw.println(innerPrefix + "SideStage");
+        pw.println(childPrefix + "stagePosition=" + getSideStagePosition());
         mSideStageListener.dump(pw, childPrefix);
-        pw.println(innerPrefix + "mSplitLayout=" + mSplitLayout);
+        if (mMainStage.isActive()) {
+            pw.println(innerPrefix + "SplitLayout");
+            mSplitLayout.dump(pw, childPrefix);
+        }
     }
 
     /**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
index 62b8638..5b08245 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
@@ -293,6 +293,10 @@
         }
     }
 
+    void addTask(ActivityManager.RunningTaskInfo task, WindowContainerTransaction wct) {
+        wct.reparent(task.token, mRootTaskInfo.token, true /* onTop*/);
+    }
+
     void setBounds(Rect bounds, WindowContainerTransaction wct) {
         wct.setBounds(mRootTaskInfo.token, bounds);
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/util/StagedSplitBounds.java b/libs/WindowManager/Shell/src/com/android/wm/shell/util/StagedSplitBounds.java
index aadf792..a0c84cc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/util/StagedSplitBounds.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/util/StagedSplitBounds.java
@@ -19,6 +19,8 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import java.util.Objects;
+
 /**
  * Container of various information needed to display split screen
  * tasks/leashes/etc in Launcher
@@ -93,6 +95,24 @@
     }
 
     @Override
+    public boolean equals(Object obj) {
+        if (!(obj instanceof StagedSplitBounds)) {
+            return false;
+        }
+        // Only need to check the base fields (the other fields are derived from these)
+        final StagedSplitBounds other = (StagedSplitBounds) obj;
+        return Objects.equals(leftTopBounds, other.leftTopBounds)
+                && Objects.equals(rightBottomBounds, other.rightBottomBounds)
+                && leftTopTaskId == other.leftTopTaskId
+                && rightBottomTaskId == other.rightBottomTaskId;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(leftTopBounds, rightBottomBounds, leftTopTaskId, rightBottomTaskId);
+    }
+
+    @Override
     public String toString() {
         return "LeftTop: " + leftTopBounds + ", taskId: " + leftTopTaskId + "\n"
                 + "RightBottom: " + rightBottomBounds + ", taskId: " + rightBottomTaskId +  "\n"
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 c439922..c706428 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
@@ -27,8 +28,10 @@
 import com.android.server.wm.flicker.annotation.Group3
 import com.android.server.wm.flicker.dsl.FlickerBuilder
 import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
+import com.android.server.wm.flicker.rules.WMFlickerServiceRuleForTestSpec
 import org.junit.Assume.assumeFalse
 import org.junit.FixMethodOrder
+import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.MethodSorters
@@ -57,6 +60,9 @@
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
 @Group3
 class EnterPipTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
+    @get:Rule
+    val flickerRule = WMFlickerServiceRuleForTestSpec(testSpec)
+
     /**
      * Defines the transition used to run the test
      */
@@ -67,6 +73,24 @@
             }
         }
 
+    @Postsubmit
+    @Test
+    fun runPresubmitAssertion() {
+        flickerRule.checkPresubmitAssertions()
+    }
+
+    @Postsubmit
+    @Test
+    fun runPostsubmitAssertion() {
+        flickerRule.checkPostsubmitAssertions()
+    }
+
+    @FlakyTest
+    @Test
+    fun runFlakyAssertion() {
+        flickerRule.checkFlakyAssertions()
+    }
+
     /** {@inheritDoc}  */
     @Presubmit
     @Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
index c2f58b8..935f669 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
@@ -191,7 +191,7 @@
         mPipController.mDisplaysChangedListener.onDisplayConfigurationChanged(
                 displayId, new Configuration());
 
-        verify(mMockPipMotionHelper).animateResizedBounds(any(Rect.class));
+        verify(mMockPipMotionHelper).movePip(any(Rect.class));
     }
 
     @Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
index 19a5417..50f6bd7 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
@@ -28,6 +28,7 @@
 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 java.lang.Integer.MAX_VALUE;
@@ -83,6 +84,36 @@
     }
 
     @Test
+    public void testAddRemoveSplitNotifyChange() {
+        ActivityManager.RecentTaskInfo t1 = makeTaskInfo(1);
+        ActivityManager.RecentTaskInfo t2 = makeTaskInfo(2);
+        setRawList(t1, t2);
+
+        mRecentTasksController.addSplitPair(t1.taskId, t2.taskId, mock(StagedSplitBounds.class));
+        verify(mRecentTasksController).notifyRecentTasksChanged();
+
+        reset(mRecentTasksController);
+        mRecentTasksController.removeSplitPair(t1.taskId);
+        verify(mRecentTasksController).notifyRecentTasksChanged();
+    }
+
+    @Test
+    public void testAddSameSplitBoundsInfoSkipNotifyChange() {
+        ActivityManager.RecentTaskInfo t1 = makeTaskInfo(1);
+        ActivityManager.RecentTaskInfo t2 = makeTaskInfo(2);
+        setRawList(t1, t2);
+
+        // Verify only one update if the split info is the same
+        StagedSplitBounds bounds1 = new StagedSplitBounds(new Rect(0, 0, 50, 50),
+                new Rect(50, 50, 100, 100), t1.taskId, t2.taskId);
+        mRecentTasksController.addSplitPair(t1.taskId, t2.taskId, bounds1);
+        StagedSplitBounds bounds2 = new StagedSplitBounds(new Rect(0, 0, 50, 50),
+                new Rect(50, 50, 100, 100), t1.taskId, t2.taskId);
+        mRecentTasksController.addSplitPair(t1.taskId, t2.taskId, bounds2);
+        verify(mRecentTasksController, times(1)).notifyRecentTasksChanged();
+    }
+
+    @Test
     public void testGetRecentTasks() {
         ActivityManager.RecentTaskInfo t1 = makeTaskInfo(1);
         ActivityManager.RecentTaskInfo t2 = makeTaskInfo(2);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatUIControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatUIControllerTest.java
index d12cf5c..877b192 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatUIControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatUIControllerTest.java
@@ -26,6 +26,7 @@
 import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
 import android.content.Context;
@@ -43,6 +44,7 @@
 import com.android.wm.shell.common.DisplayInsetsController;
 import com.android.wm.shell.common.DisplayInsetsController.OnInsetsChangedListener;
 import com.android.wm.shell.common.DisplayLayout;
+import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.SyncTransactionQueue;
 
 import org.junit.Before;
@@ -72,6 +74,7 @@
     private @Mock DisplayImeController mMockImeController;
     private @Mock ShellTaskOrganizer.TaskListener mMockTaskListener;
     private @Mock SyncTransactionQueue mMockSyncQueue;
+    private @Mock ShellExecutor mMockExecutor;
     private @Mock SizeCompatUILayout mMockLayout;
 
     @Captor
@@ -85,7 +88,7 @@
         doReturn(DISPLAY_ID).when(mMockLayout).getDisplayId();
         doReturn(TASK_ID).when(mMockLayout).getTaskId();
         mController = new SizeCompatUIController(mContext, mMockDisplayController,
-                mMockDisplayInsetsController, mMockImeController, mMockSyncQueue) {
+                mMockDisplayInsetsController, mMockImeController, mMockSyncQueue, mMockExecutor) {
             @Override
             SizeCompatUILayout createLayout(Context context, int displayId, int taskId,
                     Configuration taskConfig, ShellTaskOrganizer.TaskListener taskListener) {
@@ -106,19 +109,17 @@
         final Configuration taskConfig = new Configuration();
 
         // Verify that the restart button is added with non-null size compat info.
-        mController.onSizeCompatInfoChanged(DISPLAY_ID, TASK_ID, taskConfig,
-                mMockTaskListener);
+        mController.onSizeCompatInfoChanged(DISPLAY_ID, TASK_ID, taskConfig, mMockTaskListener);
 
         verify(mController).createLayout(any(), eq(DISPLAY_ID), eq(TASK_ID), eq(taskConfig),
                 eq(mMockTaskListener));
 
         // Verify that the restart button is updated with non-null new size compat info.
         final Configuration newTaskConfig = new Configuration();
-        mController.onSizeCompatInfoChanged(DISPLAY_ID, TASK_ID, newTaskConfig,
-                mMockTaskListener);
+        mController.onSizeCompatInfoChanged(DISPLAY_ID, TASK_ID, newTaskConfig, mMockTaskListener);
 
         verify(mMockLayout).updateSizeCompatInfo(taskConfig, mMockTaskListener,
-                false /* isImeShowing */);
+                true /* show */);
 
         // Verify that the restart button is removed with null size compat info.
         mController.onSizeCompatInfoChanged(DISPLAY_ID, TASK_ID, null, mMockTaskListener);
@@ -196,15 +197,90 @@
     @Test
     public void testChangeButtonVisibilityOnImeShowHide() {
         final Configuration taskConfig = new Configuration();
-        mController.onSizeCompatInfoChanged(DISPLAY_ID, TASK_ID, taskConfig,
-                mMockTaskListener);
+        mController.onSizeCompatInfoChanged(DISPLAY_ID, TASK_ID, taskConfig, mMockTaskListener);
 
+        // Verify that the restart button is hidden after IME is showing.
         mController.onImeVisibilityChanged(DISPLAY_ID, true /* isShowing */);
 
-        verify(mMockLayout).updateImeVisibility(true);
+        verify(mMockLayout).updateVisibility(false);
 
+        // Verify button remains hidden while IME is showing.
+        mController.onSizeCompatInfoChanged(DISPLAY_ID, TASK_ID, taskConfig, mMockTaskListener);
+
+        verify(mMockLayout).updateSizeCompatInfo(taskConfig, mMockTaskListener,
+                false /* show */);
+
+        // Verify button is shown after IME is hidden.
         mController.onImeVisibilityChanged(DISPLAY_ID, false /* isShowing */);
 
-        verify(mMockLayout).updateImeVisibility(false);
+        verify(mMockLayout).updateVisibility(true);
+    }
+
+    @Test
+    public void testChangeButtonVisibilityOnKeyguardOccludedChanged() {
+        final Configuration taskConfig = new Configuration();
+        mController.onSizeCompatInfoChanged(DISPLAY_ID, TASK_ID, taskConfig, mMockTaskListener);
+
+        // Verify that the restart button is hidden after keyguard becomes occluded.
+        mController.onKeyguardOccludedChanged(true);
+
+        verify(mMockLayout).updateVisibility(false);
+
+        // Verify button remains hidden while keyguard is occluded.
+        mController.onSizeCompatInfoChanged(DISPLAY_ID, TASK_ID, taskConfig, mMockTaskListener);
+
+        verify(mMockLayout).updateSizeCompatInfo(taskConfig, mMockTaskListener,
+                false /* show */);
+
+        // Verify button is shown after keyguard becomes not occluded.
+        mController.onKeyguardOccludedChanged(false);
+
+        verify(mMockLayout).updateVisibility(true);
+    }
+
+    @Test
+    public void testButtonRemainsHiddenOnKeyguardOccludedFalseWhenImeIsShowing() {
+        final Configuration taskConfig = new Configuration();
+        mController.onSizeCompatInfoChanged(DISPLAY_ID, TASK_ID, taskConfig, mMockTaskListener);
+
+        mController.onImeVisibilityChanged(DISPLAY_ID, true /* isShowing */);
+        mController.onKeyguardOccludedChanged(true);
+
+        verify(mMockLayout, times(2)).updateVisibility(false);
+
+        clearInvocations(mMockLayout);
+
+        // Verify button remains hidden after keyguard becomes not occluded since IME is showing.
+        mController.onKeyguardOccludedChanged(false);
+
+        verify(mMockLayout).updateVisibility(false);
+
+        // Verify button is shown after IME is not showing.
+        mController.onImeVisibilityChanged(DISPLAY_ID, false /* isShowing */);
+
+        verify(mMockLayout).updateVisibility(true);
+    }
+
+    @Test
+    public void testButtonRemainsHiddenOnImeHideWhenKeyguardIsOccluded() {
+        final Configuration taskConfig = new Configuration();
+        mController.onSizeCompatInfoChanged(DISPLAY_ID, TASK_ID, taskConfig, mMockTaskListener);
+
+        mController.onImeVisibilityChanged(DISPLAY_ID, true /* isShowing */);
+        mController.onKeyguardOccludedChanged(true);
+
+        verify(mMockLayout, times(2)).updateVisibility(false);
+
+        clearInvocations(mMockLayout);
+
+        // Verify button remains hidden after IME is hidden since keyguard is occluded.
+        mController.onImeVisibilityChanged(DISPLAY_ID, false /* isShowing */);
+
+        verify(mMockLayout).updateVisibility(false);
+
+        // Verify button is shown after keyguard becomes not occluded.
+        mController.onKeyguardOccludedChanged(false);
+
+        verify(mMockLayout).updateVisibility(true);
     }
 }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatUILayoutTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatUILayoutTest.java
index 2ba603c..eb9305b 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatUILayoutTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatUILayoutTest.java
@@ -96,8 +96,8 @@
 
     @Test
     public void testCreateSizeCompatButton() {
-        // Not create button if IME is showing.
-        mLayout.createSizeCompatButton(true /* isImeShowing */);
+        // Not create button if show is false.
+        mLayout.createSizeCompatButton(false /* show */);
 
         verify(mLayout.mButtonWindowManager, never()).createSizeCompatButton();
         assertNull(mLayout.mButton);
@@ -106,7 +106,7 @@
 
         // Not create hint popup.
         mLayout.mShouldShowHint = false;
-        mLayout.createSizeCompatButton(false /* isImeShowing */);
+        mLayout.createSizeCompatButton(true /* show */);
 
         verify(mLayout.mButtonWindowManager).createSizeCompatButton();
         assertNotNull(mLayout.mButton);
@@ -116,7 +116,7 @@
         // Create hint popup.
         mLayout.release();
         mLayout.mShouldShowHint = true;
-        mLayout.createSizeCompatButton(false /* isImeShowing */);
+        mLayout.createSizeCompatButton(true /* show */);
 
         verify(mLayout.mButtonWindowManager, times(2)).createSizeCompatButton();
         assertNotNull(mLayout.mButton);
@@ -128,7 +128,7 @@
 
     @Test
     public void testRelease() {
-        mLayout.createSizeCompatButton(false /* isImeShowing */);
+        mLayout.createSizeCompatButton(true /* show */);
         final SizeCompatUIWindowManager hintWindowManager = mLayout.mHintWindowManager;
 
         mLayout.release();
@@ -142,12 +142,11 @@
 
     @Test
     public void testUpdateSizeCompatInfo() {
-        mLayout.createSizeCompatButton(false /* isImeShowing */);
+        mLayout.createSizeCompatButton(true /* show */);
 
         // No diff
         clearInvocations(mLayout);
-        mLayout.updateSizeCompatInfo(mTaskConfig, mTaskListener,
-                false /* isImeShowing */);
+        mLayout.updateSizeCompatInfo(mTaskConfig, mTaskListener, true /* show */);
 
         verify(mLayout, never()).updateButtonSurfacePosition();
         verify(mLayout, never()).release();
@@ -158,7 +157,7 @@
         final ShellTaskOrganizer.TaskListener newTaskListener = mock(
                 ShellTaskOrganizer.TaskListener.class);
         mLayout.updateSizeCompatInfo(mTaskConfig, newTaskListener,
-                false /* isImeShowing */);
+                true /* show */);
 
         verify(mLayout).release();
         verify(mLayout).createSizeCompatButton(anyBoolean());
@@ -168,7 +167,7 @@
         final Configuration newTaskConfiguration = new Configuration();
         newTaskConfiguration.windowConfiguration.setBounds(new Rect(0, 1000, 0, 2000));
         mLayout.updateSizeCompatInfo(newTaskConfiguration, newTaskListener,
-                false /* isImeShowing */);
+                true /* show */);
 
         verify(mLayout).updateButtonSurfacePosition();
         verify(mLayout).updateHintSurfacePosition();
@@ -220,24 +219,24 @@
     }
 
     @Test
-    public void testUpdateImeVisibility() {
+    public void testUpdateVisibility() {
         // Create button if it is not created.
         mLayout.mButton = null;
-        mLayout.updateImeVisibility(false /* isImeShowing */);
+        mLayout.updateVisibility(true /* show */);
 
-        verify(mLayout).createSizeCompatButton(false /* isImeShowing */);
+        verify(mLayout).createSizeCompatButton(true /* show */);
 
-        // Hide button if ime is shown.
+        // Hide button.
         clearInvocations(mLayout);
         doReturn(View.VISIBLE).when(mButton).getVisibility();
-        mLayout.updateImeVisibility(true /* isImeShowing */);
+        mLayout.updateVisibility(false /* show */);
 
         verify(mLayout, never()).createSizeCompatButton(anyBoolean());
         verify(mButton).setVisibility(View.GONE);
 
-        // Show button if ime is not shown.
+        // Show button.
         doReturn(View.GONE).when(mButton).getVisibility();
-        mLayout.updateImeVisibility(false /* isImeShowing */);
+        mLayout.updateVisibility(true /* show */);
 
         verify(mLayout, never()).createSizeCompatButton(anyBoolean());
         verify(mButton).setVisibility(View.VISIBLE);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
index ad65c04..ef14d84 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
@@ -19,11 +19,14 @@
 import static android.app.ActivityTaskManager.INVALID_TASK_ID;
 import static android.view.Display.DEFAULT_DISPLAY;
 
-import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__RETURN_HOME;
 import static com.android.wm.shell.common.split.SplitLayout.SPLIT_POSITION_BOTTOM_OR_RIGHT;
 import static com.android.wm.shell.common.split.SplitLayout.SPLIT_POSITION_TOP_OR_LEFT;
+import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_MAIN;
+import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_SIDE;
+import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_UNDEFINED;
 import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_RETURN_HOME;
 
+import static org.junit.Assert.assertEquals;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.clearInvocations;
@@ -49,7 +52,6 @@
 import com.android.wm.shell.common.SyncTransactionQueue;
 import com.android.wm.shell.common.TransactionPool;
 import com.android.wm.shell.common.split.SplitLayout;
-import com.android.wm.shell.recents.RecentTasksController;
 import com.android.wm.shell.transition.Transitions;
 
 import org.junit.Before;
@@ -110,12 +112,39 @@
     }
 
     @Test
-    public void testMoveToSideStage() {
+    public void testMoveToStage() {
         final ActivityManager.RunningTaskInfo task = new TestRunningTaskInfoBuilder().build();
 
-        mStageCoordinator.moveToSideStage(task, SPLIT_POSITION_BOTTOM_OR_RIGHT);
+        mStageCoordinator.moveToStage(task, STAGE_TYPE_MAIN, SPLIT_POSITION_BOTTOM_OR_RIGHT,
+                new WindowContainerTransaction());
+        verify(mMainStage).addTask(eq(task), any(WindowContainerTransaction.class));
+        assertEquals(SPLIT_POSITION_BOTTOM_OR_RIGHT, mStageCoordinator.getMainStagePosition());
 
+        mStageCoordinator.moveToStage(task, STAGE_TYPE_SIDE, SPLIT_POSITION_BOTTOM_OR_RIGHT,
+                new WindowContainerTransaction());
         verify(mSideStage).addTask(eq(task), any(WindowContainerTransaction.class));
+        assertEquals(SPLIT_POSITION_BOTTOM_OR_RIGHT, mStageCoordinator.getSideStagePosition());
+    }
+
+    @Test
+    public void testMoveToUndefinedStage() {
+        final ActivityManager.RunningTaskInfo task = new TestRunningTaskInfoBuilder().build();
+
+        // Verify move to undefined stage while split screen not activated moves task to side stage.
+        when(mMainStage.isActive()).thenReturn(false);
+        mStageCoordinator.setSideStagePosition(SPLIT_POSITION_TOP_OR_LEFT, null);
+        mStageCoordinator.moveToStage(task, STAGE_TYPE_UNDEFINED, SPLIT_POSITION_BOTTOM_OR_RIGHT,
+                new WindowContainerTransaction());
+        verify(mSideStage).addTask(eq(task), any(WindowContainerTransaction.class));
+        assertEquals(SPLIT_POSITION_BOTTOM_OR_RIGHT, mStageCoordinator.getSideStagePosition());
+
+        // Verify move to undefined stage after split screen activated moves task based on position.
+        when(mMainStage.isActive()).thenReturn(true);
+        assertEquals(SPLIT_POSITION_TOP_OR_LEFT, mStageCoordinator.getMainStagePosition());
+        mStageCoordinator.moveToStage(task, STAGE_TYPE_UNDEFINED, SPLIT_POSITION_TOP_OR_LEFT,
+                new WindowContainerTransaction());
+        verify(mMainStage).addTask(eq(task), any(WindowContainerTransaction.class));
+        assertEquals(SPLIT_POSITION_TOP_OR_LEFT, mStageCoordinator.getMainStagePosition());
     }
 
     @Test
diff --git a/libs/hwui/WebViewFunctorManager.cpp b/libs/hwui/WebViewFunctorManager.cpp
index 5aad821..6fc251d 100644
--- a/libs/hwui/WebViewFunctorManager.cpp
+++ b/libs/hwui/WebViewFunctorManager.cpp
@@ -118,6 +118,24 @@
     }
 }
 
+bool WebViewFunctor::prepareRootSurfaceControl() {
+    if (!Properties::enableWebViewOverlays) return false;
+
+    renderthread::CanvasContext* activeContext = renderthread::CanvasContext::getActiveContext();
+    if (!activeContext) return false;
+
+    ASurfaceControl* rootSurfaceControl = activeContext->getSurfaceControl();
+    if (!rootSurfaceControl) return false;
+
+    int32_t rgid = activeContext->getSurfaceControlGenerationId();
+    if (mParentSurfaceControlGenerationId != rgid) {
+        reparentSurfaceControl(rootSurfaceControl);
+        mParentSurfaceControlGenerationId = rgid;
+    }
+
+    return true;
+}
+
 void WebViewFunctor::drawGl(const DrawGlInfo& drawInfo) {
     ATRACE_NAME("WebViewFunctor::drawGl");
     if (!mHasContext) {
@@ -131,20 +149,8 @@
             .mergeTransaction = currentFunctor.mergeTransaction,
     };
 
-    if (Properties::enableWebViewOverlays && !drawInfo.isLayer) {
-        renderthread::CanvasContext* activeContext =
-                renderthread::CanvasContext::getActiveContext();
-        if (activeContext != nullptr) {
-            ASurfaceControl* rootSurfaceControl = activeContext->getSurfaceControl();
-            if (rootSurfaceControl) {
-                overlayParams.overlaysMode = OverlaysMode::Enabled;
-                int32_t rgid = activeContext->getSurfaceControlGenerationId();
-                if (mParentSurfaceControlGenerationId != rgid) {
-                    reparentSurfaceControl(rootSurfaceControl);
-                    mParentSurfaceControlGenerationId = rgid;
-                }
-            }
-        }
+    if (!drawInfo.isLayer && prepareRootSurfaceControl()) {
+        overlayParams.overlaysMode = OverlaysMode::Enabled;
     }
 
     mCallbacks.gles.draw(mFunctor, mData, drawInfo, overlayParams);
@@ -170,7 +176,10 @@
             .mergeTransaction = currentFunctor.mergeTransaction,
     };
 
-    // TODO, enable surface control once offscreen mode figured out
+    if (!params.is_layer && prepareRootSurfaceControl()) {
+        overlayParams.overlaysMode = OverlaysMode::Enabled;
+    }
+
     mCallbacks.vk.draw(mFunctor, mData, params, overlayParams);
 }
 
diff --git a/libs/hwui/WebViewFunctorManager.h b/libs/hwui/WebViewFunctorManager.h
index f28f310..0a02f2d 100644
--- a/libs/hwui/WebViewFunctorManager.h
+++ b/libs/hwui/WebViewFunctorManager.h
@@ -88,6 +88,7 @@
     }
 
 private:
+    bool prepareRootSurfaceControl();
     void reparentSurfaceControl(ASurfaceControl* parent);
 
 private:
diff --git a/libs/hwui/jni/text/MeasuredText.cpp b/libs/hwui/jni/text/MeasuredText.cpp
index 7793746..bd9bd71 100644
--- a/libs/hwui/jni/text/MeasuredText.cpp
+++ b/libs/hwui/jni/text/MeasuredText.cpp
@@ -80,15 +80,17 @@
 }
 
 // Regular JNI
-static jlong nBuildMeasuredText(JNIEnv* env, jclass /* unused */, jlong builderPtr,
-                                jlong hintPtr, jcharArray javaText, jboolean computeHyphenation,
-                                jboolean computeLayout) {
+static jlong nBuildMeasuredText(JNIEnv* env, jclass /* unused */, jlong builderPtr, jlong hintPtr,
+                                jcharArray javaText, jboolean computeHyphenation,
+                                jboolean computeLayout, jboolean fastHyphenationMode) {
     ScopedCharArrayRO text(env, javaText);
     const minikin::U16StringPiece textBuffer(text.get(), text.size());
 
     // Pass the ownership to Java.
-    return toJLong(toBuilder(builderPtr)->build(textBuffer, computeHyphenation, computeLayout,
-                                                toMeasuredParagraph(hintPtr)).release());
+    return toJLong(toBuilder(builderPtr)
+                           ->build(textBuffer, computeHyphenation, computeLayout,
+                                   fastHyphenationMode, toMeasuredParagraph(hintPtr))
+                           .release());
 }
 
 // Regular JNI
@@ -140,12 +142,12 @@
 }
 
 static const JNINativeMethod gMTBuilderMethods[] = {
-    // MeasuredParagraphBuilder native functions.
-    {"nInitBuilder", "()J", (void*) nInitBuilder},
-    {"nAddStyleRun", "(JJIIZ)V", (void*) nAddStyleRun},
-    {"nAddReplacementRun", "(JJIIF)V", (void*) nAddReplacementRun},
-    {"nBuildMeasuredText", "(JJ[CZZ)J", (void*) nBuildMeasuredText},
-    {"nFreeBuilder", "(J)V", (void*) nFreeBuilder},
+        // MeasuredParagraphBuilder native functions.
+        {"nInitBuilder", "()J", (void*)nInitBuilder},
+        {"nAddStyleRun", "(JJIIZ)V", (void*)nAddStyleRun},
+        {"nAddReplacementRun", "(JJIIF)V", (void*)nAddReplacementRun},
+        {"nBuildMeasuredText", "(JJ[CZZZ)J", (void*)nBuildMeasuredText},
+        {"nFreeBuilder", "(J)V", (void*)nFreeBuilder},
 };
 
 static const JNINativeMethod gMTMethods[] = {
diff --git a/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp b/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp
index 8abf4534..e6ef95b 100644
--- a/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp
+++ b/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp
@@ -72,6 +72,7 @@
             .clip_top = mClip.fTop,
             .clip_right = mClip.fRight,
             .clip_bottom = mClip.fBottom,
+            .is_layer = !vulkan_info.fFromSwapchainOrAndroidWindow,
     };
     mat4.getColMajor(&params.transform[0]);
     params.secondary_command_buffer = vulkan_info.fSecondaryCommandBuffer;
diff --git a/libs/hwui/private/hwui/DrawVkInfo.h b/libs/hwui/private/hwui/DrawVkInfo.h
index 4ae0f5a..5c59657 100644
--- a/libs/hwui/private/hwui/DrawVkInfo.h
+++ b/libs/hwui/private/hwui/DrawVkInfo.h
@@ -68,6 +68,9 @@
   int clip_top;
   int clip_right;
   int clip_bottom;
+
+  // Input: Whether destination surface is offscreen surface.
+  bool is_layer;
 };
 
 }  // namespace uirenderer
diff --git a/libs/hwui/renderthread/VulkanSurface.cpp b/libs/hwui/renderthread/VulkanSurface.cpp
index fe9a30a..611a4d9 100644
--- a/libs/hwui/renderthread/VulkanSurface.cpp
+++ b/libs/hwui/renderthread/VulkanSurface.cpp
@@ -426,7 +426,7 @@
     if (bufferInfo->skSurface.get() == nullptr) {
         bufferInfo->skSurface = SkSurface::MakeFromAHardwareBuffer(
                 mGrContext, ANativeWindowBuffer_getHardwareBuffer(bufferInfo->buffer.get()),
-                kTopLeft_GrSurfaceOrigin, mWindowInfo.colorspace, nullptr);
+                kTopLeft_GrSurfaceOrigin, mWindowInfo.colorspace, nullptr, /*from_window=*/true);
         if (bufferInfo->skSurface.get() == nullptr) {
             ALOGE("SkSurface::MakeFromAHardwareBuffer failed");
             mNativeWindow->cancelBuffer(mNativeWindow.get(), buffer,
diff --git a/libs/input/PointerController.cpp b/libs/input/PointerController.cpp
index 6ea303c..f43586f 100644
--- a/libs/input/PointerController.cpp
+++ b/libs/input/PointerController.cpp
@@ -76,6 +76,10 @@
     SurfaceComposerClient::getDefault()->addWindowInfosListener(mDisplayInfoListener);
 }
 
+PointerController::~PointerController() {
+    SurfaceComposerClient::getDefault()->removeWindowInfosListener(mDisplayInfoListener);
+}
+
 bool PointerController::getBounds(float* outMinX, float* outMinY, float* outMaxX,
                                   float* outMaxY) const {
     return mCursorController.getBounds(outMinX, outMinY, outMaxX, outMaxY);
diff --git a/libs/input/PointerController.h b/libs/input/PointerController.h
index 58bb014..796077f 100644
--- a/libs/input/PointerController.h
+++ b/libs/input/PointerController.h
@@ -47,7 +47,7 @@
             const sp<PointerControllerPolicyInterface>& policy, const sp<Looper>& looper,
             const sp<SpriteController>& spriteController);
 
-    virtual ~PointerController() = default;
+    ~PointerController() override;
 
     virtual bool getBounds(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY) const;
     virtual void move(float deltaX, float deltaY);
diff --git a/libs/input/SpriteController.cpp b/libs/input/SpriteController.cpp
index da21438..2b809ea 100644
--- a/libs/input/SpriteController.cpp
+++ b/libs/input/SpriteController.cpp
@@ -70,8 +70,8 @@
 }
 
 void SpriteController::invalidateSpriteLocked(const sp<SpriteImpl>& sprite) {
-    bool wasEmpty = mLocked.invalidatedSprites.isEmpty();
-    mLocked.invalidatedSprites.push(sprite);
+    bool wasEmpty = mLocked.invalidatedSprites.empty();
+    mLocked.invalidatedSprites.push_back(sprite);
     if (wasEmpty) {
         if (mLocked.transactionNestingCount != 0) {
             mLocked.deferredSpriteUpdate = true;
@@ -82,8 +82,8 @@
 }
 
 void SpriteController::disposeSurfaceLocked(const sp<SurfaceControl>& surfaceControl) {
-    bool wasEmpty = mLocked.disposedSurfaces.isEmpty();
-    mLocked.disposedSurfaces.push(surfaceControl);
+    bool wasEmpty = mLocked.disposedSurfaces.empty();
+    mLocked.disposedSurfaces.push_back(surfaceControl);
     if (wasEmpty) {
         mLooper->sendMessage(mHandler, Message(MSG_DISPOSE_SURFACES));
     }
@@ -113,7 +113,7 @@
 
         numSprites = mLocked.invalidatedSprites.size();
         for (size_t i = 0; i < numSprites; i++) {
-            const sp<SpriteImpl>& sprite = mLocked.invalidatedSprites.itemAt(i);
+            const sp<SpriteImpl>& sprite = mLocked.invalidatedSprites[i];
 
             updates.push(SpriteUpdate(sprite, sprite->getStateLocked()));
             sprite->resetDirtyLocked();
@@ -305,7 +305,7 @@
 
 void SpriteController::doDisposeSurfaces() {
     // Collect disposed surfaces.
-    Vector<sp<SurfaceControl> > disposedSurfaces;
+    std::vector<sp<SurfaceControl>> disposedSurfaces;
     { // acquire lock
         AutoMutex _l(mLock);
 
@@ -313,6 +313,13 @@
         mLocked.disposedSurfaces.clear();
     } // release lock
 
+    // Remove the parent from all surfaces.
+    SurfaceComposerClient::Transaction t;
+    for (const sp<SurfaceControl>& sc : disposedSurfaces) {
+        t.reparent(sc, nullptr);
+    }
+    t.apply();
+
     // Release the last reference to each surface outside of the lock.
     // We don't want the surfaces to be deleted while we are holding our lock.
     disposedSurfaces.clear();
diff --git a/libs/input/SpriteController.h b/libs/input/SpriteController.h
index 2a80d95..2e9cb96 100644
--- a/libs/input/SpriteController.h
+++ b/libs/input/SpriteController.h
@@ -251,8 +251,8 @@
     sp<SurfaceComposerClient> mSurfaceComposerClient;
 
     struct Locked {
-        Vector<sp<SpriteImpl> > invalidatedSprites;
-        Vector<sp<SurfaceControl> > disposedSurfaces;
+        std::vector<sp<SpriteImpl>> invalidatedSprites;
+        std::vector<sp<SurfaceControl>> disposedSurfaces;
         uint32_t transactionNestingCount;
         bool deferredSpriteUpdate;
     } mLocked; // guarded by mLock
diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl
index 5d5c0fc..8054fd4 100644
--- a/location/java/android/location/ILocationManager.aidl
+++ b/location/java/android/location/ILocationManager.aidl
@@ -125,6 +125,9 @@
     boolean isAdasGnssLocationEnabledForUser(int userId);
     void setAdasGnssLocationEnabledForUser(boolean enabled, int userId);
 
+    boolean isAutoGnssSuspended();
+    void setAutoGnssSuspended(boolean suspended);
+
     void addTestProvider(String name, in ProviderProperties properties,
         in List<String> locationTags, String packageName, @nullable String attributionTag);
     void removeTestProvider(String provider, String packageName, @nullable String attributionTag);
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index becaca9..61caa0b 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -758,6 +758,51 @@
     }
 
     /**
+     * Set whether GNSS requests are suspended on the device.
+     *
+     * This method was added to help support power management use cases on automotive devices. More
+     * specifically, it is being added to fix a suspend to RAM issue where the SoC can't go into
+     * a lower power state when applications are actively requesting GNSS updates.
+     *
+     * Ideally, the issue should be fixed at a lower layer in the stack, but this API introduces a
+     * workaround in the platform layer. This API allows car specific services to halt GNSS requests
+     * based on changes to the car power policy, which will in turn enable the device to go into
+     * suspend.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.AUTOMOTIVE_GNSS_CONTROLS)
+    public void setAutoGnssSuspended(boolean suspended) {
+        try {
+            mService.setAutoGnssSuspended(suspended);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Return whether GNSS requests are suspended or not.
+     *
+     * This method was added to help support power management use cases on automotive devices. More
+     * specifically, it is being added as part of the fix for a suspend to RAM issue where the SoC
+     * can't go into a lower power state when applications are actively requesting GNSS updates.
+     *
+     * @return true if GNSS requests are suspended and false if they aren't.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.AUTOMOTIVE_GNSS_CONTROLS)
+    public boolean isAutoGnssSuspended() {
+        try {
+            return mService.isAutoGnssSuspended();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Gets the last known location from the fused provider, or null if there is no last known
      * location. The returned location may be quite old in some circumstances, so the age of the
      * location should always be checked.
diff --git a/media/Android.bp b/media/Android.bp
index 15b24b2..fcdfd72 100644
--- a/media/Android.bp
+++ b/media/Android.bp
@@ -115,6 +115,7 @@
 aidl_interface {
     name: "android.media.soundtrigger.types",
     vendor_available: true,
+    host_supported: true,
     flags: [
         "-Werror",
         "-Weverything",
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index c662223..2916b01 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -40,6 +40,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.media.AudioAttributes.AttributeSystemUsage;
+import android.media.CallbackUtil.ListenerInfo;
 import android.media.audiopolicy.AudioPolicy;
 import android.media.audiopolicy.AudioPolicy.AudioPolicyFocusListener;
 import android.media.audiopolicy.AudioProductStrategy;
@@ -2900,79 +2901,33 @@
      * List is lazy-initialized on first registration
      */
     @GuardedBy("mModeListenerLock")
-    private @Nullable ArrayList<ModeListenerInfo> mModeListeners;
+    private @Nullable ArrayList<ListenerInfo<OnModeChangedListener>> mModeListeners;
 
     @GuardedBy("mModeListenerLock")
     private ModeDispatcherStub mModeDispatcherStub;
 
-    private final class ModeDispatcherStub
-            extends IAudioModeDispatcher.Stub {
+    private final class ModeDispatcherStub extends IAudioModeDispatcher.Stub {
+
+        public void register(boolean register) {
+            try {
+                if (register) {
+                    getService().registerModeDispatcher(this);
+                } else {
+                    getService().unregisterModeDispatcher(this);
+                }
+            } catch (RemoteException e) {
+                e.rethrowFromSystemServer();
+            }
+        }
 
         @Override
+        @SuppressLint("GuardedBy") // lock applied inside callListeners method
         public void dispatchAudioModeChanged(int mode) {
-            // make a shallow copy of listeners so callback is not executed under lock
-            final ArrayList<ModeListenerInfo> modeListeners;
-            synchronized (mModeListenerLock) {
-                if (mModeListeners == null || mModeListeners.size() == 0) {
-                    return;
-                }
-                modeListeners = (ArrayList<ModeListenerInfo>) mModeListeners.clone();
-            }
-            final long ident = Binder.clearCallingIdentity();
-            try {
-                for (ModeListenerInfo info : modeListeners) {
-                    info.mExecutor.execute(() ->
-                            info.mListener.onModeChanged(mode));
-                }
-            } finally {
-                Binder.restoreCallingIdentity(ident);
-            }
+            CallbackUtil.callListeners(mModeListeners, mModeListenerLock,
+                    (listener) -> listener.onModeChanged(mode));
         }
     }
 
-    private static class ModeListenerInfo {
-        final @NonNull OnModeChangedListener mListener;
-        final @NonNull Executor mExecutor;
-
-        ModeListenerInfo(OnModeChangedListener listener, Executor exe) {
-            mListener = listener;
-            mExecutor = exe;
-        }
-    }
-
-    @GuardedBy("mModeListenerLock")
-    private boolean hasModeListener(OnModeChangedListener listener) {
-        return getModeListenerInfo(listener) != null;
-    }
-
-    @GuardedBy("mModeListenerLock")
-    private @Nullable ModeListenerInfo getModeListenerInfo(
-            OnModeChangedListener listener) {
-        if (mModeListeners == null) {
-            return null;
-        }
-        for (ModeListenerInfo info : mModeListeners) {
-            if (info.mListener == listener) {
-                return info;
-            }
-        }
-        return null;
-    }
-
-
-    @GuardedBy("mModeListenerLock")
-    /**
-     * @return true if the listener was removed from the list
-     */
-    private boolean removeModeListener(OnModeChangedListener listener) {
-        final ModeListenerInfo infoToRemove = getModeListenerInfo(listener);
-        if (infoToRemove != null) {
-            mModeListeners.remove(infoToRemove);
-            return true;
-        }
-        return false;
-    }
-
     /**
      * Adds a listener to be notified of changes to the audio mode.
      * See {@link #getMode()}
@@ -2982,30 +2937,14 @@
     public void addOnModeChangedListener(
             @NonNull @CallbackExecutor Executor executor,
             @NonNull OnModeChangedListener listener) {
-        Objects.requireNonNull(executor);
-        Objects.requireNonNull(listener);
         synchronized (mModeListenerLock) {
-            if (hasModeListener(listener)) {
-                throw new IllegalArgumentException("attempt to call addOnModeChangedListener() "
-                        + "on a previously registered listener");
-            }
-            // lazy initialization of the list of strategy-preferred device listener
-            if (mModeListeners == null) {
-                mModeListeners = new ArrayList<>();
-            }
-            final int oldCbCount = mModeListeners.size();
-            mModeListeners.add(new ModeListenerInfo(listener, executor));
-            if (oldCbCount == 0) {
-                // register binder for callbacks
-                if (mModeDispatcherStub == null) {
-                    mModeDispatcherStub = new ModeDispatcherStub();
-                }
-                try {
-                    getService().registerModeDispatcher(mModeDispatcherStub);
-                } catch (RemoteException e) {
-                    throw e.rethrowFromSystemServer();
-                }
-            }
+            final Pair<ArrayList<ListenerInfo<OnModeChangedListener>>, ModeDispatcherStub> res =
+                    CallbackUtil.addListener("addOnModeChangedListener",
+                            executor, listener, mModeListeners, mModeDispatcherStub,
+                            () -> new ModeDispatcherStub(),
+                            stub -> stub.register(true));
+            mModeListeners = res.first;
+            mModeDispatcherStub = res.second;
         }
     }
 
@@ -3015,23 +2954,13 @@
      * @param listener
      */
     public void removeOnModeChangedListener(@NonNull OnModeChangedListener listener) {
-        Objects.requireNonNull(listener);
         synchronized (mModeListenerLock) {
-            if (!removeModeListener(listener)) {
-                throw new IllegalArgumentException("attempt to call removeOnModeChangedListener() "
-                        + "on an unregistered listener");
-            }
-            if (mModeListeners.size() == 0) {
-                // unregister binder for callbacks
-                try {
-                    getService().unregisterModeDispatcher(mModeDispatcherStub);
-                } catch (RemoteException e) {
-                    throw e.rethrowFromSystemServer();
-                } finally {
-                    mModeDispatcherStub = null;
-                    mModeListeners = null;
-                }
-            }
+            final Pair<ArrayList<ListenerInfo<OnModeChangedListener>>, ModeDispatcherStub> res =
+                    CallbackUtil.removeListener("removeOnModeChangedListener",
+                            listener, mModeListeners, mModeDispatcherStub,
+                            stub -> stub.register(false));
+            mModeListeners = res.first;
+            mModeDispatcherStub = res.second;
         }
     }
 
@@ -3098,7 +3027,7 @@
     public static final int MODE_CALL_REDIRECT   = AudioSystem.MODE_CALL_REDIRECT;
 
     /**
-     * n audio/video chat or VoIP call is established and its audio is being redirected to another
+     * An audio/video chat or VoIP call is established and its audio is being redirected to another
      * device.
      */
     public static final int MODE_COMMUNICATION_REDIRECT = AudioSystem.MODE_COMMUNICATION_REDIRECT;
@@ -7646,31 +7575,15 @@
     public void addOnCommunicationDeviceChangedListener(
             @NonNull @CallbackExecutor Executor executor,
             @NonNull OnCommunicationDeviceChangedListener listener) {
-        Objects.requireNonNull(executor);
-        Objects.requireNonNull(listener);
         synchronized (mCommDevListenerLock) {
-            if (hasCommDevListener(listener)) {
-                throw new IllegalArgumentException(
-                        "attempt to call addOnCommunicationDeviceChangedListener() "
-                                + "on a previously registered listener");
-            }
-            // lazy initialization of the list of strategy-preferred device listener
-            if (mCommDevListeners == null) {
-                mCommDevListeners = new ArrayList<>();
-            }
-            final int oldCbCount = mCommDevListeners.size();
-            mCommDevListeners.add(new CommDevListenerInfo(listener, executor));
-            if (oldCbCount == 0 && mCommDevListeners.size() > 0) {
-                // register binder for callbacks
-                if (mCommDevDispatcherStub == null) {
-                    mCommDevDispatcherStub = new CommunicationDeviceDispatcherStub();
-                }
-                try {
-                    getService().registerCommunicationDeviceDispatcher(mCommDevDispatcherStub);
-                } catch (RemoteException e) {
-                    throw e.rethrowFromSystemServer();
-                }
-            }
+            final Pair<ArrayList<ListenerInfo<OnCommunicationDeviceChangedListener>>,
+                    CommunicationDeviceDispatcherStub> res =
+                    CallbackUtil.addListener("addOnCommunicationDeviceChangedListener",
+                            executor, listener, mCommDevListeners, mCommDevDispatcherStub,
+                            () -> new CommunicationDeviceDispatcherStub(),
+                            stub -> stub.register(true));
+            mCommDevListeners = res.first;
+            mCommDevDispatcherStub = res.second;
         }
     }
 
@@ -7681,25 +7594,14 @@
      */
     public void removeOnCommunicationDeviceChangedListener(
             @NonNull OnCommunicationDeviceChangedListener listener) {
-        Objects.requireNonNull(listener);
         synchronized (mCommDevListenerLock) {
-            if (!removeCommDevListener(listener)) {
-                throw new IllegalArgumentException(
-                        "attempt to call removeOnCommunicationDeviceChangedListener() "
-                                + "on an unregistered listener");
-            }
-            if (mCommDevListeners.size() == 0) {
-                // unregister binder for callbacks
-                try {
-                    getService().unregisterCommunicationDeviceDispatcher(
-                            mCommDevDispatcherStub);
-                } catch (RemoteException e) {
-                    throw e.rethrowFromSystemServer();
-                } finally {
-                    mCommDevDispatcherStub = null;
-                    mCommDevListeners = null;
-                }
-            }
+            final Pair<ArrayList<ListenerInfo<OnCommunicationDeviceChangedListener>>,
+                    CommunicationDeviceDispatcherStub> res =
+                    CallbackUtil.removeListener("removeOnCommunicationDeviceChangedListener",
+                            listener, mCommDevListeners, mCommDevDispatcherStub,
+                            stub -> stub.register(false));
+            mCommDevListeners = res.first;
+            mCommDevDispatcherStub = res.second;
         }
     }
 
@@ -7709,17 +7611,8 @@
      * List is lazy-initialized on first registration
      */
     @GuardedBy("mCommDevListenerLock")
-    private @Nullable ArrayList<CommDevListenerInfo> mCommDevListeners;
-
-    private static class CommDevListenerInfo {
-        final @NonNull OnCommunicationDeviceChangedListener mListener;
-        final @NonNull Executor mExecutor;
-
-        CommDevListenerInfo(OnCommunicationDeviceChangedListener listener, Executor exe) {
-            mListener = listener;
-            mExecutor = exe;
-        }
-    }
+    private @Nullable
+            ArrayList<ListenerInfo<OnCommunicationDeviceChangedListener>> mCommDevListeners;
 
     @GuardedBy("mCommDevListenerLock")
     private CommunicationDeviceDispatcherStub mCommDevDispatcherStub;
@@ -7727,59 +7620,25 @@
     private final class CommunicationDeviceDispatcherStub
             extends ICommunicationDeviceDispatcher.Stub {
 
-        @Override
-        public void dispatchCommunicationDeviceChanged(int portId) {
-            // make a shallow copy of listeners so callback is not executed under lock
-            final ArrayList<CommDevListenerInfo> commDevListeners;
-            synchronized (mCommDevListenerLock) {
-                if (mCommDevListeners == null || mCommDevListeners.size() == 0) {
-                    return;
-                }
-                commDevListeners = (ArrayList<CommDevListenerInfo>) mCommDevListeners.clone();
-            }
-            AudioDeviceInfo device = getDeviceForPortId(portId, GET_DEVICES_OUTPUTS);
-            final long ident = Binder.clearCallingIdentity();
+        public void register(boolean register) {
             try {
-                for (CommDevListenerInfo info : commDevListeners) {
-                    info.mExecutor.execute(() ->
-                            info.mListener.onCommunicationDeviceChanged(device));
+                if (register) {
+                    getService().registerCommunicationDeviceDispatcher(this);
+                } else {
+                    getService().unregisterCommunicationDeviceDispatcher(this);
                 }
-            } finally {
-                Binder.restoreCallingIdentity(ident);
+            } catch (RemoteException e) {
+                e.rethrowFromSystemServer();
             }
         }
-    }
 
-    @GuardedBy("mCommDevListenerLock")
-    private @Nullable CommDevListenerInfo getCommDevListenerInfo(
-            OnCommunicationDeviceChangedListener listener) {
-        if (mCommDevListeners == null) {
-            return null;
+        @Override
+        @SuppressLint("GuardedBy") // lock applied inside callListeners method
+        public void dispatchCommunicationDeviceChanged(int portId) {
+            AudioDeviceInfo device = getDeviceForPortId(portId, GET_DEVICES_OUTPUTS);
+            CallbackUtil.callListeners(mCommDevListeners, mCommDevListenerLock,
+                    (listener) -> listener.onCommunicationDeviceChanged(device));
         }
-        for (CommDevListenerInfo info : mCommDevListeners) {
-            if (info.mListener == listener) {
-                return info;
-            }
-        }
-        return null;
-    }
-
-    @GuardedBy("mCommDevListenerLock")
-    private boolean hasCommDevListener(OnCommunicationDeviceChangedListener listener) {
-        return getCommDevListenerInfo(listener) != null;
-    }
-
-    @GuardedBy("mCommDevListenerLock")
-    /**
-     * @return true if the listener was removed from the list
-     */
-    private boolean removeCommDevListener(OnCommunicationDeviceChangedListener listener) {
-        final CommDevListenerInfo infoToRemove = getCommDevListenerInfo(listener);
-        if (infoToRemove != null) {
-            mCommDevListeners.remove(infoToRemove);
-            return true;
-        }
-        return false;
     }
 
     //---------------------------------------------------------
@@ -7838,4 +7697,4 @@
             return mHandler;
         }
     }
-}
+}
\ No newline at end of file
diff --git a/media/java/android/media/CallbackUtil.java b/media/java/android/media/CallbackUtil.java
new file mode 100644
index 0000000..ac39317
--- /dev/null
+++ b/media/java/android/media/CallbackUtil.java
@@ -0,0 +1,224 @@
+/*
+ * 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.media;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.media.permission.ClearCallingIdentityContext;
+import android.media.permission.SafeCloseable;
+import android.util.Log;
+import android.util.Pair;
+
+import java.util.ArrayList;
+import java.util.Objects;
+import java.util.concurrent.Executor;
+
+/**
+ * @hide
+ * A utility class to implement callback listeners and their management.
+ * This is meant to be used for lazily-initialized listener lists and stubs for event reception,
+ * typically received from server (e.g. AudioService).
+ */
+
+/*package*/ class CallbackUtil {
+
+    private static final String TAG = "CallbackUtil";
+
+    /**
+     * Container class to store a listener and associated Executor
+     * @param <T> the type of the listener
+     */
+    static class ListenerInfo<T> {
+        final @NonNull T mListener;
+        final @NonNull Executor mExecutor;
+
+        ListenerInfo(@NonNull T listener, @NonNull Executor exe) {
+            mListener = listener;
+            mExecutor = exe;
+        }
+    }
+
+    /**
+     * Finds the listener information (listener + Executor) in a given list of listeners
+     * @param listener the listener to find
+     * @param listeners the list of listener informations, can be null if not instantiated yet
+     * @param <T> the type of the listeners
+     * @return null if the listener is not in the given list of listener informations
+     */
+    static <T> @Nullable ListenerInfo<T> getListenerInfo(
+            @NonNull T listener, @Nullable ArrayList<ListenerInfo<T>> listeners) {
+        if (listeners == null) {
+            return null;
+        }
+        for (ListenerInfo<T> info : listeners) {
+            if (info.mListener == listener) {
+                return info;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Returns true if the given listener is present in the list of listener informations
+     * @param listener the listener to find
+     * @param listeners the list of listener informations, can be null if not instantiated yet
+     * @param <T> the type of the listeners
+     * @return true if the listener is in the list
+     */
+    static <T> boolean hasListener(@NonNull T listener,
+            @Nullable ArrayList<ListenerInfo<T>> listeners) {
+        return getListenerInfo(listener, listeners) != null;
+    }
+
+    /**
+     * Removes the given listener from the list of listener informations
+     * @param listener the listener to remove
+     * @param listeners the list of listener informations, can be null if not instantiated yet
+     * @param <T> the type of the listeners
+     * @return true if the listener was found and removed from the list, false otherwise
+     */
+    static <T> boolean removeListener(@NonNull T listener,
+            @Nullable ArrayList<ListenerInfo<T>> listeners) {
+        final ListenerInfo<T> infoToRemove = getListenerInfo(listener, listeners);
+        if (infoToRemove != null) {
+            listeners.remove(infoToRemove);
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Adds a listener and associated Executor in the list of listeners.
+     * This method handles the lazy initialization of both the list of listeners and the stub
+     * used to receive the events that will be forwarded to the listener, see the returned pair
+     * for the updated references.
+     * @param methodName the name of the method calling this, for inclusion in the
+     *                   string in case of IllegalArgumentException
+     * @param executor the Executor for the listener
+     * @param listener the listener to add
+     * @param listeners the list of listener informations, can be null if not instantiated yet
+     * @param dispatchStub the stub that receives the events to be forwarded to the listeners,
+     *                    can be null if not instantiated yet
+     * @param newStub the function to create a new stub if needed
+     * @param registerStub the function for the stub registration if needed
+     * @param <T> the type of the listener interface
+     * @param <S> the type of the event receiver stub
+     * @return a pair of the listener list and the event receiver stub which may have been
+     *         initialized if needed (e.g. on the first ever addition of a listener)
+     */
+    static <T, S> Pair<ArrayList<ListenerInfo<T>>, S> addListener(String methodName,
+            @NonNull Executor executor,
+            @NonNull T listener,
+            @Nullable ArrayList<ListenerInfo<T>> listeners,
+            @Nullable S dispatchStub,
+            @NonNull java.util.function.Supplier<S> newStub,
+            @NonNull java.util.function.Consumer<S> registerStub) {
+        Objects.requireNonNull(executor);
+        Objects.requireNonNull(listener);
+
+        if (hasListener(listener, listeners)) {
+            throw new IllegalArgumentException("attempt to call " + methodName
+                    + "on a previously registered listener");
+        }
+        // lazy initialization of the list of strategy-preferred device listener
+        if (listeners == null) {
+            listeners = new ArrayList<>();
+        }
+        if (listeners.size() == 0) {
+            // register binder for callbacks
+            if (dispatchStub == null) {
+                try {
+                    dispatchStub = newStub.get();
+                } catch (Exception e) {
+                    Log.e(TAG, "Exception while creating stub in " + methodName, e);
+                    return new Pair<>(null, null);
+                }
+            }
+            registerStub.accept(dispatchStub);
+        }
+        listeners.add(new ListenerInfo<T>(listener, executor));
+        return new Pair(listeners, dispatchStub);
+    }
+
+    /**
+     * Removes a listener from the list of listeners.
+     * This method handles the freeing of both the list of listeners and the stub
+     * used to receive the events that will be forwarded to the listener,see the returned pair
+     * for the updated references.
+     * @param methodName the name of the method calling this, for inclusion in the
+     *                   string in case of IllegalArgumentException
+     * @param listener the listener to remove
+     * @param listeners the list of listener informations, can be null if not instantiated yet
+     * @param dispatchStub the stub that receives the events to be forwarded to the listeners,
+     *                    can be null if not instantiated yet
+     * @param unregisterStub the function to unregister the stub if needed
+     * @param <T> the type of the listener interface
+     * @param <S> the type of the event receiver stub
+     * @return a pair of the listener list and the event receiver stub which may have been
+     *         changed if needed (e.g. on the removal of the last listener)
+     */
+    static <T, S> Pair<ArrayList<ListenerInfo<T>>, S> removeListener(String methodName,
+            @NonNull T listener,
+            @Nullable ArrayList<ListenerInfo<T>> listeners,
+            @Nullable S dispatchStub,
+            @NonNull java.util.function.Consumer<S> unregisterStub) {
+        Objects.requireNonNull(listener);
+
+        if (!removeListener(listener, listeners)) {
+            throw new IllegalArgumentException("attempt to call " + methodName
+                    + "on an unregistered listener");
+        }
+        if (listeners.size() == 0) {
+            unregisterStub.accept(dispatchStub);
+            return new Pair<>(null, null);
+        } else {
+            return new Pair<>(listeners, dispatchStub);
+        }
+    }
+
+    interface CallbackMethod<T> {
+        void callbackMethod(T listener);
+    }
+
+    /**
+     * Exercise the callback of the listeners
+     * @param listeners the list of listeners
+     * @param listenerLock the lock guarding the list of listeners
+     * @param callback the function to call for each listener
+     * @param <T>  the type of the listener interface
+     */
+    static <T> void callListeners(
+            @Nullable ArrayList<ListenerInfo<T>> listeners,
+            @NonNull Object listenerLock,
+            @NonNull CallbackMethod<T> callback) {
+        Objects.requireNonNull(listenerLock);
+        // make a shallow copy of listeners so callback is not executed under lock
+        final ArrayList<ListenerInfo<T>> listenersShallowCopy;
+        synchronized (listenerLock) {
+            if (listeners == null || listeners.size() == 0) {
+                return;
+            }
+            listenersShallowCopy = (ArrayList<ListenerInfo<T>>) listeners.clone();
+        }
+        try (SafeCloseable ignored = ClearCallingIdentityContext.create()) {
+            for (ListenerInfo<T> info : listenersShallowCopy) {
+                info.mExecutor.execute(() -> callback.callbackMethod(info.mListener));
+            }
+        }
+
+    }
+}
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index 374cc75..3c152fb 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -426,6 +426,12 @@
         /** @deprecated Use {@link #COLOR_Format32bitABGR8888}. */
         public static final int COLOR_Format24BitABGR6666           = 43;
 
+        /** @hide
+         * P010 is a 4:2:0 YCbCr semiplanar format comprised of a WxH Y plane
+         * followed by a Wx(H/2) CbCr plane. Each sample is represented by a 16-bit
+         * little-endian value, with the lower 6 bits set to zero. */
+        public static final int COLOR_FormatYUVP010                 = 54;
+
         /** @deprecated Use {@link #COLOR_FormatYUV420Flexible}. */
         public static final int COLOR_TI_FormatYUV420PackedSemiPlanar = 0x7f000100;
         // COLOR_FormatSurface indicates that the data will be a GraphicBuffer metadata reference.
diff --git a/media/java/android/media/Spatializer.java b/media/java/android/media/Spatializer.java
index e6fff39..c0793ec 100644
--- a/media/java/android/media/Spatializer.java
+++ b/media/java/android/media/Spatializer.java
@@ -22,11 +22,14 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
+import android.media.CallbackUtil.ListenerInfo;
 import android.media.permission.ClearCallingIdentityContext;
 import android.media.permission.SafeCloseable;
 import android.os.RemoteException;
 import android.util.Log;
+import android.util.Pair;
 
 import com.android.internal.annotations.GuardedBy;
 
@@ -373,32 +376,15 @@
     public void addOnSpatializerStateChangedListener(
             @NonNull @CallbackExecutor Executor executor,
             @NonNull OnSpatializerStateChangedListener listener) {
-        Objects.requireNonNull(executor);
-        Objects.requireNonNull(listener);
         synchronized (mStateListenerLock) {
-            if (hasSpatializerStateListener(listener)) {
-                throw new IllegalArgumentException(
-                        "Called addOnSpatializerStateChangedListener() "
-                        + "on a previously registered listener");
-            }
-            // lazy initialization of the list of strategy-preferred device listener
-            if (mStateListeners == null) {
-                mStateListeners = new ArrayList<>();
-            }
-            mStateListeners.add(new StateListenerInfo(listener, executor));
-            if (mStateListeners.size() == 1) {
-                // register binder for callbacks
-                if (mInfoDispatcherStub == null) {
-                    mInfoDispatcherStub =
-                            new SpatializerInfoDispatcherStub();
-                }
-                try {
-                    mAm.getService().registerSpatializerCallback(
-                            mInfoDispatcherStub);
-                } catch (RemoteException e) {
-                    throw e.rethrowFromSystemServer();
-                }
-            }
+            final Pair<ArrayList<ListenerInfo<OnSpatializerStateChangedListener>>,
+                    SpatializerInfoDispatcherStub> res =
+                    CallbackUtil.addListener("addOnSpatializerStateChangedListener",
+                            executor, listener, mStateListeners, mInfoDispatcherStub,
+                            () -> new SpatializerInfoDispatcherStub(),
+                            stub -> stub.register(true));
+            mStateListeners = res.first;
+            mInfoDispatcherStub = res.second;
         }
     }
 
@@ -410,24 +396,14 @@
      */
     public void removeOnSpatializerStateChangedListener(
             @NonNull OnSpatializerStateChangedListener listener) {
-        Objects.requireNonNull(listener);
         synchronized (mStateListenerLock) {
-            if (!removeStateListener(listener)) {
-                throw new IllegalArgumentException(
-                        "Called removeOnSpatializerStateChangedListener() "
-                        + "on an unregistered listener");
-            }
-            if (mStateListeners.size() == 0) {
-                // unregister binder for callbacks
-                try {
-                    mAm.getService().unregisterSpatializerCallback(mInfoDispatcherStub);
-                } catch (RemoteException e) {
-                    throw e.rethrowFromSystemServer();
-                } finally {
-                    mInfoDispatcherStub = null;
-                    mStateListeners = null;
-                }
-            }
+            final Pair<ArrayList<ListenerInfo<OnSpatializerStateChangedListener>>,
+                    SpatializerInfoDispatcherStub> res =
+                    CallbackUtil.removeListener("removeOnSpatializerStateChangedListener",
+                            listener, mStateListeners, mInfoDispatcherStub,
+                            stub -> stub.register(false));
+            mStateListeners = res.first;
+            mInfoDispatcherStub = res.second;
         }
     }
 
@@ -489,93 +465,41 @@
      * List is lazy-initialized on first registration
      */
     @GuardedBy("mStateListenerLock")
-    private @Nullable ArrayList<StateListenerInfo> mStateListeners;
+    private @Nullable ArrayList<ListenerInfo<OnSpatializerStateChangedListener>> mStateListeners;
 
     @GuardedBy("mStateListenerLock")
     private @Nullable SpatializerInfoDispatcherStub mInfoDispatcherStub;
 
     private final class SpatializerInfoDispatcherStub extends ISpatializerCallback.Stub {
+        public void register(boolean register) {
+            try {
+                if (register) {
+                    mAm.getService().registerSpatializerCallback(this);
+                } else {
+                    mAm.getService().unregisterSpatializerCallback(this);
+                }
+            } catch (RemoteException e) {
+                e.rethrowFromSystemServer();
+            }
+        }
+
         @Override
+        @SuppressLint("GuardedBy") // lock applied inside callListeners method
         public void dispatchSpatializerEnabledChanged(boolean enabled) {
-            // make a shallow copy of listeners so callback is not executed under lock
-            final ArrayList<StateListenerInfo> stateListeners;
-            synchronized (mStateListenerLock) {
-                if (mStateListeners == null || mStateListeners.size() == 0) {
-                    return;
-                }
-                stateListeners = (ArrayList<StateListenerInfo>) mStateListeners.clone();
-            }
-            try (SafeCloseable ignored = ClearCallingIdentityContext.create()) {
-                for (StateListenerInfo info : stateListeners) {
-                    info.mExecutor.execute(() ->
-                            info.mListener.onSpatializerEnabledChanged(Spatializer.this, enabled));
-                }
-            }
+            CallbackUtil.callListeners(mStateListeners, mStateListenerLock,
+                    (listener) -> listener.onSpatializerEnabledChanged(
+                            Spatializer.this, enabled));
         }
 
         @Override
+        @SuppressLint("GuardedBy") // lock applied inside callListeners method
         public void dispatchSpatializerAvailableChanged(boolean available) {
-            // make a shallow copy of listeners so callback is not executed under lock
-            final ArrayList<StateListenerInfo> stateListeners;
-            synchronized (mStateListenerLock) {
-                if (mStateListeners == null || mStateListeners.size() == 0) {
-                    return;
-                }
-                stateListeners = (ArrayList<StateListenerInfo>) mStateListeners.clone();
-            }
-            try (SafeCloseable ignored = ClearCallingIdentityContext.create()) {
-                for (StateListenerInfo info : stateListeners) {
-                    info.mExecutor.execute(() ->
-                            info.mListener.onSpatializerAvailableChanged(
-                                    Spatializer.this, available));
-                }
-            }
+            CallbackUtil.callListeners(mStateListeners, mStateListenerLock,
+                    (listener) -> listener.onSpatializerAvailableChanged(
+                            Spatializer.this, available));
         }
     }
 
-    private static class StateListenerInfo {
-        final @NonNull OnSpatializerStateChangedListener mListener;
-        final @NonNull Executor mExecutor;
-
-        StateListenerInfo(@NonNull OnSpatializerStateChangedListener listener,
-                @NonNull Executor exe) {
-            mListener = listener;
-            mExecutor = exe;
-        }
-    }
-
-    @GuardedBy("mStateListenerLock")
-    private boolean hasSpatializerStateListener(OnSpatializerStateChangedListener listener) {
-        return getStateListenerInfo(listener) != null;
-    }
-
-    @GuardedBy("mStateListenerLock")
-    private @Nullable StateListenerInfo getStateListenerInfo(
-            OnSpatializerStateChangedListener listener) {
-        if (mStateListeners == null) {
-            return null;
-        }
-        for (StateListenerInfo info : mStateListeners) {
-            if (info.mListener == listener) {
-                return info;
-            }
-        }
-        return null;
-    }
-
-    @GuardedBy("mStateListenerLock")
-    /**
-     * @return true if the listener was removed from the list
-     */
-    private boolean removeStateListener(OnSpatializerStateChangedListener listener) {
-        final StateListenerInfo infoToRemove = getStateListenerInfo(listener);
-        if (infoToRemove != null) {
-            mStateListeners.remove(infoToRemove);
-            return true;
-        }
-        return false;
-    }
-
 
     /**
      * @hide
@@ -688,33 +612,15 @@
     public void addOnHeadTrackingModeChangedListener(
             @NonNull @CallbackExecutor Executor executor,
             @NonNull OnHeadTrackingModeChangedListener listener) {
-        Objects.requireNonNull(executor);
-        Objects.requireNonNull(listener);
         synchronized (mHeadTrackingListenerLock) {
-            if (hasListener(listener, mHeadTrackingListeners)) {
-                throw new IllegalArgumentException(
-                        "Called addOnHeadTrackingModeChangedListener() "
-                                + "on a previously registered listener");
-            }
-            // lazy initialization of the list of strategy-preferred device listener
-            if (mHeadTrackingListeners == null) {
-                mHeadTrackingListeners = new ArrayList<>();
-            }
-            mHeadTrackingListeners.add(
-                    new ListenerInfo<OnHeadTrackingModeChangedListener>(listener, executor));
-            if (mHeadTrackingListeners.size() == 1) {
-                // register binder for callbacks
-                if (mHeadTrackingDispatcherStub == null) {
-                    mHeadTrackingDispatcherStub =
-                            new SpatializerHeadTrackingDispatcherStub();
-                }
-                try {
-                    mAm.getService().registerSpatializerHeadTrackingCallback(
-                            mHeadTrackingDispatcherStub);
-                } catch (RemoteException e) {
-                    throw e.rethrowFromSystemServer();
-                }
-            }
+            final Pair<ArrayList<ListenerInfo<OnHeadTrackingModeChangedListener>>,
+                    SpatializerHeadTrackingDispatcherStub> res = CallbackUtil.addListener(
+                        "addOnHeadTrackingModeChangedListener", executor, listener,
+                        mHeadTrackingListeners, mHeadTrackingDispatcherStub,
+                        () -> new SpatializerHeadTrackingDispatcherStub(),
+                        stub -> stub.register(true));
+            mHeadTrackingListeners = res.first;
+            mHeadTrackingDispatcherStub = res.second;
         }
     }
 
@@ -728,25 +634,14 @@
     @RequiresPermission(android.Manifest.permission.MODIFY_DEFAULT_AUDIO_EFFECTS)
     public void removeOnHeadTrackingModeChangedListener(
             @NonNull OnHeadTrackingModeChangedListener listener) {
-        Objects.requireNonNull(listener);
         synchronized (mHeadTrackingListenerLock) {
-            if (!removeListener(listener, mHeadTrackingListeners)) {
-                throw new IllegalArgumentException(
-                        "Called removeOnHeadTrackingModeChangedListener() "
-                                + "on an unregistered listener");
-            }
-            if (mHeadTrackingListeners.size() == 0) {
-                // unregister binder for callbacks
-                try {
-                    mAm.getService().unregisterSpatializerHeadTrackingCallback(
-                            mHeadTrackingDispatcherStub);
-                } catch (RemoteException e) {
-                    throw e.rethrowFromSystemServer();
-                } finally {
-                    mHeadTrackingDispatcherStub = null;
-                    mHeadTrackingListeners = null;
-                }
-            }
+            final Pair<ArrayList<ListenerInfo<OnHeadTrackingModeChangedListener>>,
+                    SpatializerHeadTrackingDispatcherStub> res = CallbackUtil.removeListener(
+                        "removeOnHeadTrackingModeChangedListener", listener,
+                        mHeadTrackingListeners, mHeadTrackingDispatcherStub,
+                        stub -> stub.register(false));
+            mHeadTrackingListeners = res.first;
+            mHeadTrackingDispatcherStub = res.second;
         }
     }
 
@@ -931,45 +826,6 @@
     }
 
     //-----------------------------------------------------------------------------
-    // callback helper definitions
-
-    private static class ListenerInfo<T> {
-        final @NonNull T mListener;
-        final @NonNull Executor mExecutor;
-
-        ListenerInfo(T listener, Executor exe) {
-            mListener = listener;
-            mExecutor = exe;
-        }
-    }
-
-    private static <T> ListenerInfo<T> getListenerInfo(
-            T listener, ArrayList<ListenerInfo<T>> listeners) {
-        if (listeners == null) {
-            return null;
-        }
-        for (ListenerInfo<T> info : listeners) {
-            if (info.mListener == listener) {
-                return info;
-            }
-        }
-        return null;
-    }
-
-    private static <T> boolean hasListener(T listener, ArrayList<ListenerInfo<T>> listeners) {
-        return getListenerInfo(listener, listeners) != null;
-    }
-
-    private static <T> boolean removeListener(T listener, ArrayList<ListenerInfo<T>> listeners) {
-        final ListenerInfo<T> infoToRemove = getListenerInfo(listener, listeners);
-        if (infoToRemove != null) {
-            listeners.remove(infoToRemove);
-            return true;
-        }
-        return false;
-    }
-
-    //-----------------------------------------------------------------------------
     // head tracking callback management and stub
 
     private final Object mHeadTrackingListenerLock = new Object();
@@ -986,42 +842,31 @@
 
     private final class SpatializerHeadTrackingDispatcherStub
             extends ISpatializerHeadTrackingModeCallback.Stub {
-        @Override
-        public void dispatchSpatializerActualHeadTrackingModeChanged(int mode) {
-            // make a shallow copy of listeners so callback is not executed under lock
-            final ArrayList<ListenerInfo<OnHeadTrackingModeChangedListener>> headTrackingListeners;
-            synchronized (mHeadTrackingListenerLock) {
-                if (mHeadTrackingListeners == null || mHeadTrackingListeners.size() == 0) {
-                    return;
+        public void register(boolean register) {
+            try {
+                if (register) {
+                    mAm.getService().registerSpatializerHeadTrackingCallback(this);
+                } else {
+                    mAm.getService().unregisterSpatializerHeadTrackingCallback(this);
                 }
-                headTrackingListeners = (ArrayList<ListenerInfo<OnHeadTrackingModeChangedListener>>)
-                        mHeadTrackingListeners.clone();
-            }
-            try (SafeCloseable ignored = ClearCallingIdentityContext.create()) {
-                for (ListenerInfo<OnHeadTrackingModeChangedListener> info : headTrackingListeners) {
-                    info.mExecutor.execute(() -> info.mListener
-                            .onHeadTrackingModeChanged(Spatializer.this, mode));
-                }
+            } catch (RemoteException e) {
+                e.rethrowFromSystemServer();
             }
         }
 
         @Override
+        @SuppressLint("GuardedBy") // lock applied inside callListeners method
+        public void dispatchSpatializerActualHeadTrackingModeChanged(int mode) {
+            CallbackUtil.callListeners(mHeadTrackingListeners, mHeadTrackingListenerLock,
+                    (listener) -> listener.onHeadTrackingModeChanged(Spatializer.this, mode));
+        }
+
+        @Override
+        @SuppressLint("GuardedBy") // lock applied inside callListeners method
         public void dispatchSpatializerDesiredHeadTrackingModeChanged(int mode) {
-            // make a shallow copy of listeners so callback is not executed under lock
-            final ArrayList<ListenerInfo<OnHeadTrackingModeChangedListener>> headTrackingListeners;
-            synchronized (mHeadTrackingListenerLock) {
-                if (mHeadTrackingListeners == null || mHeadTrackingListeners.size() == 0) {
-                    return;
-                }
-                headTrackingListeners = (ArrayList<ListenerInfo<OnHeadTrackingModeChangedListener>>)
-                        mHeadTrackingListeners.clone();
-            }
-            try (SafeCloseable ignored = ClearCallingIdentityContext.create()) {
-                for (ListenerInfo<OnHeadTrackingModeChangedListener> info : headTrackingListeners) {
-                    info.mExecutor.execute(() -> info.mListener
-                            .onDesiredHeadTrackingModeChanged(Spatializer.this, mode));
-                }
-            }
+            CallbackUtil.callListeners(mHeadTrackingListeners, mHeadTrackingListenerLock,
+                    (listener) -> listener.onDesiredHeadTrackingModeChanged(
+                            Spatializer.this, mode));
         }
     }
 
diff --git a/media/java/android/media/tv/interactive/ITvIAppManager.aidl b/media/java/android/media/tv/interactive/ITvIAppManager.aidl
index c7b08d5..104efe6 100644
--- a/media/java/android/media/tv/interactive/ITvIAppManager.aidl
+++ b/media/java/android/media/tv/interactive/ITvIAppManager.aidl
@@ -17,6 +17,8 @@
 package android.media.tv.interactive;
 
 import android.media.tv.interactive.ITvIAppClient;
+import android.media.tv.interactive.ITvIAppManagerCallback;
+import android.media.tv.interactive.TvIAppInfo;
 import android.view.Surface;
 
 /**
@@ -24,6 +26,7 @@
  * @hide
  */
 interface ITvIAppManager {
+    List<TvIAppInfo> getTvIAppServiceList(int userId);
     void startIApp(in IBinder sessionToken, int userId);
     void createSession(
             in ITvIAppClient client, in String iAppServiceId, int type, int seq, int userId);
@@ -31,4 +34,7 @@
     void setSurface(in IBinder sessionToken, in Surface surface, int userId);
     void dispatchSurfaceChanged(in IBinder sessionToken, int format, int width, int height,
             int userId);
+
+    void registerCallback(in ITvIAppManagerCallback callback, int userId);
+    void unregisterCallback(in ITvIAppManagerCallback callback, int userId);
 }
\ No newline at end of file
diff --git a/media/java/android/media/tv/interactive/ITvIAppManagerCallback.aidl b/media/java/android/media/tv/interactive/ITvIAppManagerCallback.aidl
new file mode 100644
index 0000000..77a09b7
--- /dev/null
+++ b/media/java/android/media/tv/interactive/ITvIAppManagerCallback.aidl
@@ -0,0 +1,30 @@
+/*
+ * 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.media.tv.interactive;
+
+import android.media.tv.interactive.TvIAppInfo;
+
+/**
+ * Interface to receive callbacks from ITvIAppManager regardless of sessions.
+ * @hide
+ */
+interface ITvIAppManagerCallback {
+    void onIAppServiceAdded(in String iAppServiceId);
+    void onIAppServiceRemoved(in String iAppServiceId);
+    void onIAppServiceUpdated(in String iAppServiceId);
+    void onTvIAppInfoUpdated(in TvIAppInfo tvIAppInfo);
+}
\ No newline at end of file
diff --git a/media/java/android/media/tv/interactive/ITvIAppService.aidl b/media/java/android/media/tv/interactive/ITvIAppService.aidl
index c4f82eb..2f165f0 100644
--- a/media/java/android/media/tv/interactive/ITvIAppService.aidl
+++ b/media/java/android/media/tv/interactive/ITvIAppService.aidl
@@ -16,6 +16,7 @@
 
 package android.media.tv.interactive;
 
+import android.media.tv.interactive.ITvIAppServiceCallback;
 import android.media.tv.interactive.ITvIAppSessionCallback;
 
 /**
@@ -24,5 +25,7 @@
  * @hide
  */
 oneway interface ITvIAppService {
+    void registerCallback(in ITvIAppServiceCallback callback);
+    void unregisterCallback(in ITvIAppServiceCallback callback);
     void createSession(in ITvIAppSessionCallback callback, in String iAppServiceId, int type);
 }
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FlagWriter.kt b/media/java/android/media/tv/interactive/TvIAppInfo.aidl
similarity index 84%
rename from packages/SystemUI/src/com/android/systemui/flags/FlagWriter.kt
rename to media/java/android/media/tv/interactive/TvIAppInfo.aidl
index bacc66b..6041460 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FlagWriter.kt
+++ b/media/java/android/media/tv/interactive/TvIAppInfo.aidl
@@ -14,8 +14,6 @@
  * limitations under the License.
  */
 
-package com.android.systemui.flags
+package android.media.tv.interactive;
 
-interface FlagWriter {
-    fun setEnabled(key: Int, value: Boolean) {}
-}
\ No newline at end of file
+parcelable TvIAppInfo;
\ No newline at end of file
diff --git a/media/java/android/media/tv/interactive/TvIAppInfo.java b/media/java/android/media/tv/interactive/TvIAppInfo.java
index b3b5aee..de3a47e 100644
--- a/media/java/android/media/tv/interactive/TvIAppInfo.java
+++ b/media/java/android/media/tv/interactive/TvIAppInfo.java
@@ -90,6 +90,14 @@
     }
 
     /**
+     * Returns the component of the TV IApp service.
+     * @hide
+     */
+    public ComponentName getComponent() {
+        return new ComponentName(mService.serviceInfo.packageName, mService.serviceInfo.name);
+    }
+
+    /**
      * Returns the information of the service that implements this TV IApp service.
      */
     public ServiceInfo getServiceInfo() {
diff --git a/media/java/android/media/tv/interactive/TvIAppManager.java b/media/java/android/media/tv/interactive/TvIAppManager.java
index 94534cd..093e1be 100644
--- a/media/java/android/media/tv/interactive/TvIAppManager.java
+++ b/media/java/android/media/tv/interactive/TvIAppManager.java
@@ -30,6 +30,10 @@
 
 import com.android.internal.util.Preconditions;
 
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
 /**
  * Central system API to the overall TV interactive application framework (TIAF) architecture, which
  * arbitrates interaction between applications and interactive apps.
@@ -46,10 +50,15 @@
     private final SparseArray<SessionCallbackRecord> mSessionCallbackRecordMap =
             new SparseArray<>();
 
+    // @GuardedBy("mLock")
+    private final List<TvIAppCallbackRecord> mCallbackRecords = new LinkedList<>();
+
     // A sequence number for the next session to be created. Should be protected by a lock
     // {@code mSessionCallbackRecordMap}.
     private int mNextSeq;
 
+    private final Object mLock = new Object();
+
     private final ITvIAppClient mClient;
 
     /** @hide */
@@ -103,6 +112,154 @@
                 }
             }
         };
+        ITvIAppManagerCallback managerCallback = new ITvIAppManagerCallback.Stub() {
+            // TODO: handle IApp service state changes
+            @Override
+            public void onIAppServiceAdded(String iAppServiceId) {
+                synchronized (mLock) {
+                    for (TvIAppCallbackRecord record : mCallbackRecords) {
+                        record.postIAppServiceAdded(iAppServiceId);
+                    }
+                }
+            }
+
+            @Override
+            public void onIAppServiceRemoved(String iAppServiceId) {
+                synchronized (mLock) {
+                    for (TvIAppCallbackRecord record : mCallbackRecords) {
+                        record.postIAppServiceRemoved(iAppServiceId);
+                    }
+                }
+            }
+
+            @Override
+            public void onIAppServiceUpdated(String iAppServiceId) {
+                synchronized (mLock) {
+                    for (TvIAppCallbackRecord record : mCallbackRecords) {
+                        record.postIAppServiceUpdated(iAppServiceId);
+                    }
+                }
+            }
+
+            @Override
+            public void onTvIAppInfoUpdated(TvIAppInfo iAppInfo) {
+                // TODO: add public API updateIAppInfo()
+                synchronized (mLock) {
+                    for (TvIAppCallbackRecord record : mCallbackRecords) {
+                        record.postTvIAppInfoUpdated(iAppInfo);
+                    }
+                }
+            }
+        };
+        try {
+            if (mService != null) {
+                mService.registerCallback(managerCallback, mUserId);
+            }
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Callback used to monitor status of the TV IApp.
+     * @hide
+     */
+    public abstract static class TvIAppCallback {
+        /**
+         * This is called when a TV IApp service is added to the system.
+         *
+         * <p>Normally it happens when the user installs a new TV IApp service package that
+         * implements {@link TvIAppService} interface.
+         *
+         * @param iAppServiceId The ID of the TV IApp service.
+         */
+        public void onIAppServiceAdded(String iAppServiceId) {
+        }
+
+        /**
+         * This is called when a TV IApp service is removed from the system.
+         *
+         * <p>Normally it happens when the user uninstalls the previously installed TV IApp service
+         * package.
+         *
+         * @param iAppServiceId The ID of the TV IApp service.
+         */
+        public void onIAppServiceRemoved(String iAppServiceId) {
+        }
+
+        /**
+         * This is called when a TV IApp service is updated on the system.
+         *
+         * <p>Normally it happens when a previously installed TV IApp service package is
+         * re-installed or a newer version of the package exists becomes available/unavailable.
+         *
+         * @param iAppServiceId The ID of the TV IApp service.
+         */
+        public void onIAppServiceUpdated(String iAppServiceId) {
+        }
+
+        /**
+         * This is called when the information about an existing TV IApp service has been updated.
+         *
+         * <p>Because the system automatically creates a <code>TvIAppInfo</code> object for each TV
+         * IApp service based on the information collected from the
+         * <code>AndroidManifest.xml</code>, this method is only called back when such information
+         * has changed dynamically.
+         *
+         * @param iAppInfo The <code>TvIAppInfo</code> object that contains new information.
+         */
+        public void onTvIAppInfoUpdated(TvIAppInfo iAppInfo) {
+        }
+    }
+
+    private static final class TvIAppCallbackRecord {
+        private final TvIAppCallback mCallback;
+        private final Handler mHandler;
+
+        TvIAppCallbackRecord(TvIAppCallback callback, Handler handler) {
+            mCallback = callback;
+            mHandler = handler;
+        }
+
+        public TvIAppCallback getCallback() {
+            return mCallback;
+        }
+
+        public void postIAppServiceAdded(final String iAppServiceId) {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    mCallback.onIAppServiceAdded(iAppServiceId);
+                }
+            });
+        }
+
+        public void postIAppServiceRemoved(final String iAppServiceId) {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    mCallback.onIAppServiceRemoved(iAppServiceId);
+                }
+            });
+        }
+
+        public void postIAppServiceUpdated(final String iAppServiceId) {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    mCallback.onIAppServiceUpdated(iAppServiceId);
+                }
+            });
+        }
+
+        public void postTvIAppInfoUpdated(final TvIAppInfo iAppInfo) {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    mCallback.onTvIAppInfoUpdated(iAppInfo);
+                }
+            });
+        }
     }
 
     /**
@@ -140,6 +297,56 @@
     }
 
     /**
+     * Returns the complete list of TV IApp service on the system.
+     *
+     * @return List of {@link TvIAppInfo} for each TV IApp service that describes its meta
+     *         information.
+     * @hide
+     */
+    public List<TvIAppInfo> getTvIAppServiceList() {
+        try {
+            return mService.getTvIAppServiceList(mUserId);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Registers a {@link TvIAppManager.TvIAppCallback}.
+     *
+     * @param callback A callback used to monitor status of the TV IApp services.
+     * @param handler A {@link Handler} that the status change will be delivered to.
+     * @hide
+     */
+    public void registerCallback(@NonNull TvIAppCallback callback, @NonNull Handler handler) {
+        Preconditions.checkNotNull(callback);
+        Preconditions.checkNotNull(handler);
+        synchronized (mLock) {
+            mCallbackRecords.add(new TvIAppCallbackRecord(callback, handler));
+        }
+    }
+
+    /**
+     * Unregisters the existing {@link TvIAppManager.TvIAppCallback}.
+     *
+     * @param callback The existing callback to remove.
+     * @hide
+     */
+    public void unregisterCallback(@NonNull final TvIAppCallback callback) {
+        Preconditions.checkNotNull(callback);
+        synchronized (mLock) {
+            for (Iterator<TvIAppCallbackRecord> it = mCallbackRecords.iterator();
+                    it.hasNext(); ) {
+                TvIAppCallbackRecord record = it.next();
+                if (record.getCallback() == callback) {
+                    it.remove();
+                    break;
+                }
+            }
+        }
+    }
+
+    /**
      * The Session provides the per-session functionality of interactive app.
      * @hide
      */
diff --git a/media/java/android/media/tv/interactive/TvIAppService.java b/media/java/android/media/tv/interactive/TvIAppService.java
index 8863729..78b8173 100644
--- a/media/java/android/media/tv/interactive/TvIAppService.java
+++ b/media/java/android/media/tv/interactive/TvIAppService.java
@@ -26,6 +26,7 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Message;
+import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.util.Log;
 import android.view.KeyEvent;
@@ -62,11 +63,26 @@
     public static final String SERVICE_META_DATA = "android.media.tv.interactive.app";
 
     private final Handler mServiceHandler = new ServiceHandler();
+    private final RemoteCallbackList<ITvIAppServiceCallback> mCallbacks =
+            new RemoteCallbackList<>();
 
     /** @hide */
     @Override
     public final IBinder onBind(Intent intent) {
         ITvIAppService.Stub tvIAppServiceBinder = new ITvIAppService.Stub() {
+            @Override
+            public void registerCallback(ITvIAppServiceCallback cb) {
+                if (cb != null) {
+                    mCallbacks.register(cb);
+                }
+            }
+
+            @Override
+            public void unregisterCallback(ITvIAppServiceCallback cb) {
+                if (cb != null) {
+                    mCallbacks.unregister(cb);
+                }
+            }
 
             @Override
             public void createSession(ITvIAppSessionCallback cb, String iAppServiceId, int type) {
@@ -137,7 +153,7 @@
          * Called when the application sets the surface.
          *
          * <p>The TV IApp service should render interactive app UI onto the given surface. When
-         * called with {@code null}, the input service should immediately free any references to the
+         * called with {@code null}, the IApp service should immediately free any references to the
          * currently set surface and stop using it.
          *
          * @param surface The surface to be used for interactive app UI rendering. Can be
diff --git a/media/java/android/media/tv/tuner/filter/Filter.java b/media/java/android/media/tv/tuner/filter/Filter.java
index ae271120..f0f576e 100644
--- a/media/java/android/media/tv/tuner/filter/Filter.java
+++ b/media/java/android/media/tv/tuner/filter/Filter.java
@@ -251,8 +251,8 @@
     private native int nativeFlushFilter();
     private native int nativeRead(byte[] buffer, long offset, long size);
     private native int nativeClose();
-    private native String nativeCreateSharedFilter();
-    private native void nativeReleaseSharedFilter(String token);
+    private native String nativeAcquireSharedFilterToken();
+    private native void nativeFreeSharedFilterToken(String token);
 
     // Called by JNI
     private Filter(long id) {
@@ -562,20 +562,20 @@
     }
 
     /**
-     * Creates a shared filter.
+     * Acquires a shared filter token.
      *
      * @return a string shared filter token.
      */
     @Nullable
-    public String createSharedFilter() {
+    public String acquireSharedFilterToken() {
         synchronized (mLock) {
             TunerUtils.checkResourceState(TAG, mIsClosed);
             if (mIsStarted || mIsShared) {
-                Log.d(TAG, "Create shared filter in a wrong state, started: " +
+                Log.d(TAG, "Acquire shared filter in a wrong state, started: " +
                      mIsStarted + "shared: " + mIsShared);
                 return null;
             }
-            String token = nativeCreateSharedFilter();
+            String token = nativeAcquireSharedFilterToken();
             if (token != null) {
                 mIsShared = true;
             }
@@ -584,17 +584,17 @@
     }
 
     /**
-     * Releases a shared filter.
+     * Frees a shared filter token.
      *
      * @param filterToken the token of the shared filter being released.
      */
-    public void releaseSharedFilter(@NonNull String filterToken) {
+    public void freeSharedFilterToken(@NonNull String filterToken) {
         synchronized (mLock) {
             TunerUtils.checkResourceState(TAG, mIsClosed);
             if (!mIsShared) {
                 return;
             }
-            nativeReleaseSharedFilter(filterToken);
+            nativeFreeSharedFilterToken(filterToken);
             mIsShared = false;
         }
     }
diff --git a/media/java/android/media/tv/tuner/filter/SharedFilter.java b/media/java/android/media/tv/tuner/filter/SharedFilter.java
index f86ad11..056c5d5 100644
--- a/media/java/android/media/tv/tuner/filter/SharedFilter.java
+++ b/media/java/android/media/tv/tuner/filter/SharedFilter.java
@@ -145,7 +145,7 @@
     }
 
     /**
-     * Flushes the filter.
+     * Flushes the shared filter.
      *
      * <p>The data which is already produced by filter but not consumed yet will
      * be cleared.
@@ -162,7 +162,7 @@
     }
 
     /**
-     * Copies filtered data from filter output to the given byte array.
+     * Copies filtered data from shared filter output to the given byte array.
      *
      * @param buffer the buffer to store the filtered data.
      * @param offset the index of the first byte in {@code buffer} to write.
@@ -179,7 +179,7 @@
     }
 
     /**
-     * Stops filtering data and releases the Filter instance.
+     * Stops filtering data and releases the shared filter instance.
      */
     @Override
     public void close() {
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index c4dfee4..9526c52 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -3890,22 +3890,22 @@
     return (jint)r;
 }
 
-static jstring android_media_tv_Tuner_create_shared_filter(JNIEnv *env, jobject filter) {
+static jstring android_media_tv_Tuner_acquire_shared_filter_token(JNIEnv *env, jobject filter) {
     sp<FilterClient> filterClient = getFilterClient(env, filter);
     if (filterClient == nullptr) {
         jniThrowException(env, "java/lang/IllegalStateException",
-                          "Failed to create shared filter: filter client not found");
+                          "Failed to acquire shared filter token: filter client not found");
         return nullptr;
     }
 
-    string token = filterClient->createSharedFilter();
+    string token = filterClient->acquireSharedFilterToken();
     if (token.empty()) {
         return nullptr;
     }
     return env->NewStringUTF(token.data());
 }
 
-static void android_media_tv_Tuner_release_shared_filter(
+static void android_media_tv_Tuner_free_shared_filter_token(
         JNIEnv *env, jobject filter, jstring token) {
     sp<FilterClient> filterClient = getFilterClient(env, filter);
     if (filterClient == nullptr) {
@@ -3915,7 +3915,7 @@
     }
 
     std::string filterToken(env->GetStringUTFChars(token, nullptr));
-    filterClient->releaseSharedFilter(filterToken);
+    filterClient->freeSharedFilterToken(filterToken);
 }
 
 static sp<TimeFilterClient> getTimeFilterClient(JNIEnv *env, jobject filter) {
@@ -4408,10 +4408,10 @@
     { "nativeFlushFilter", "()I", (void *)android_media_tv_Tuner_flush_filter },
     { "nativeRead", "([BJJ)I", (void *)android_media_tv_Tuner_read_filter_fmq },
     { "nativeClose", "()I", (void *)android_media_tv_Tuner_close_filter },
-    {"nativeCreateSharedFilter", "()Ljava/lang/String;",
-            (void *)android_media_tv_Tuner_create_shared_filter},
-    {"nativeReleaseSharedFilter", "(Ljava/lang/String;)V",
-            (void *)android_media_tv_Tuner_release_shared_filter},
+    {"nativeAcquireSharedFilterToken", "()Ljava/lang/String;",
+            (void *)android_media_tv_Tuner_acquire_shared_filter_token},
+    {"nativeFreeSharedFilterToken", "(Ljava/lang/String;)V",
+            (void *)android_media_tv_Tuner_free_shared_filter_token},
 };
 
 static const JNINativeMethod gSharedFilterMethods[] = {
diff --git a/media/jni/tuner/FilterClient.cpp b/media/jni/tuner/FilterClient.cpp
index e8b3de8..bd283dc 100644
--- a/media/jni/tuner/FilterClient.cpp
+++ b/media/jni/tuner/FilterClient.cpp
@@ -196,10 +196,10 @@
     return Result::INVALID_STATE;
 }
 
-string FilterClient::createSharedFilter() {
+string FilterClient::acquireSharedFilterToken() {
     if (mTunerFilter != nullptr) {
         string filterToken;
-        if (mTunerFilter->createSharedFilter(&filterToken).isOk()) {
+        if (mTunerFilter->acquireSharedFilterToken(&filterToken).isOk()) {
             return filterToken;
         }
     }
@@ -207,9 +207,9 @@
     return "";
 }
 
-Result FilterClient::releaseSharedFilter(const string& filterToken) {
+Result FilterClient::freeSharedFilterToken(const string& filterToken) {
     if (mTunerFilter != nullptr) {
-        Status s = mTunerFilter->releaseSharedFilter(filterToken);
+        Status s = mTunerFilter->freeSharedFilterToken(filterToken);
         return ClientHelper::getServiceSpecificErrorCode(s);
     }
 
diff --git a/media/jni/tuner/FilterClient.h b/media/jni/tuner/FilterClient.h
index c031b2a..7ebe7bc7 100644
--- a/media/jni/tuner/FilterClient.h
+++ b/media/jni/tuner/FilterClient.h
@@ -143,14 +143,14 @@
     Result close();
 
     /**
-     * Create a new SharedFiler.
+     * Accquire a new SharedFiler token.
      */
-    string createSharedFilter();
+    string acquireSharedFilterToken();
 
     /**
-     * Release SharedFiler.
+     * Release SharedFiler token.
      */
-    Result releaseSharedFilter(const string& filterToken);
+    Result freeSharedFilterToken(const string& filterToken);
 
 private:
     Result getFilterMq();
diff --git a/omapi/aidl/Android.bp b/omapi/aidl/Android.bp
new file mode 100644
index 0000000..2b81200
--- /dev/null
+++ b/omapi/aidl/Android.bp
@@ -0,0 +1,35 @@
+// Copyright 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 {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+aidl_interface {
+    name: "android.se.omapi",
+    vendor_available: true,
+    srcs: ["android/se/omapi/*.aidl"],
+    stability: "vintf",
+    backend: {
+        java: {
+            sdk_version: "module_current",
+        },
+        rust: {
+            enabled: true,
+        },
+        ndk: {
+            separate_platform_variant: false,
+        },
+    },
+}
diff --git a/omapi/aidl/aidl_api/android.se.omapi/current/android/se/omapi/ISecureElementChannel.aidl b/omapi/aidl/aidl_api/android.se.omapi/current/android/se/omapi/ISecureElementChannel.aidl
new file mode 100644
index 0000000..725013a
--- /dev/null
+++ b/omapi/aidl/aidl_api/android.se.omapi/current/android/se/omapi/ISecureElementChannel.aidl
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ *//*
+ * Contributed by: Giesecke & Devrient GmbH.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.se.omapi;
+/* @hide */
+@VintfStability
+interface ISecureElementChannel {
+  void close();
+  boolean isClosed();
+  boolean isBasicChannel();
+  byte[] getSelectResponse();
+  byte[] transmit(in byte[] command);
+  boolean selectNext();
+}
diff --git a/omapi/aidl/aidl_api/android.se.omapi/current/android/se/omapi/ISecureElementListener.aidl b/omapi/aidl/aidl_api/android.se.omapi/current/android/se/omapi/ISecureElementListener.aidl
new file mode 100644
index 0000000..77e1c53f
--- /dev/null
+++ b/omapi/aidl/aidl_api/android.se.omapi/current/android/se/omapi/ISecureElementListener.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *//*
+ * Contributed by: Giesecke & Devrient GmbH.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.se.omapi;
+/* @hide */
+@VintfStability
+interface ISecureElementListener {
+}
diff --git a/omapi/aidl/aidl_api/android.se.omapi/current/android/se/omapi/ISecureElementReader.aidl b/omapi/aidl/aidl_api/android.se.omapi/current/android/se/omapi/ISecureElementReader.aidl
new file mode 100644
index 0000000..2b10c47
--- /dev/null
+++ b/omapi/aidl/aidl_api/android.se.omapi/current/android/se/omapi/ISecureElementReader.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *//*
+ * Contributed by: Giesecke & Devrient GmbH.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.se.omapi;
+/* @hide */
+@VintfStability
+interface ISecureElementReader {
+  boolean isSecureElementPresent();
+  android.se.omapi.ISecureElementSession openSession();
+  void closeSessions();
+  boolean reset();
+}
diff --git a/omapi/aidl/aidl_api/android.se.omapi/current/android/se/omapi/ISecureElementService.aidl b/omapi/aidl/aidl_api/android.se.omapi/current/android/se/omapi/ISecureElementService.aidl
new file mode 100644
index 0000000..ae63462
--- /dev/null
+++ b/omapi/aidl/aidl_api/android.se.omapi/current/android/se/omapi/ISecureElementService.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *//*
+ * Copyright (c) 2015-2017, The Linux Foundation.
+ *//*
+ * Contributed by: Giesecke & Devrient GmbH.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.se.omapi;
+/* @hide */
+@VintfStability
+interface ISecureElementService {
+  String[] getReaders();
+  android.se.omapi.ISecureElementReader getReader(in String reader);
+  boolean[] isNFCEventAllowed(in String reader, in byte[] aid, in String[] packageNames);
+}
diff --git a/omapi/aidl/aidl_api/android.se.omapi/current/android/se/omapi/ISecureElementSession.aidl b/omapi/aidl/aidl_api/android.se.omapi/current/android/se/omapi/ISecureElementSession.aidl
new file mode 100644
index 0000000..06287c5
--- /dev/null
+++ b/omapi/aidl/aidl_api/android.se.omapi/current/android/se/omapi/ISecureElementSession.aidl
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *//*
+ * Copyright (c) 2015-2017, The Linux Foundation.
+ *//*
+ * Contributed by: Giesecke & Devrient GmbH.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.se.omapi;
+/* @hide */
+@VintfStability
+interface ISecureElementSession {
+  byte[] getAtr();
+  void close();
+  void closeChannels();
+  boolean isClosed();
+  android.se.omapi.ISecureElementChannel openBasicChannel(in byte[] aid, in byte p2, in android.se.omapi.ISecureElementListener listener);
+  android.se.omapi.ISecureElementChannel openLogicalChannel(in byte[] aid, in byte p2, in android.se.omapi.ISecureElementListener listener);
+}
diff --git a/core/java/android/se/omapi/ISecureElementChannel.aidl b/omapi/aidl/android/se/omapi/ISecureElementChannel.aidl
similarity index 94%
rename from core/java/android/se/omapi/ISecureElementChannel.aidl
rename to omapi/aidl/android/se/omapi/ISecureElementChannel.aidl
index 4ae57ab..bbd3c14 100644
--- a/core/java/android/se/omapi/ISecureElementChannel.aidl
+++ b/omapi/aidl/android/se/omapi/ISecureElementChannel.aidl
@@ -22,6 +22,7 @@
 import android.se.omapi.ISecureElementSession;
 
 /** @hide */
+@VintfStability
 interface ISecureElementChannel {
 
     /**
@@ -58,6 +59,9 @@
      * Transmits the specified command APDU and returns the response APDU.
      * MANAGE channel commands are not supported.
      * Selection of applets is not supported in logical channels.
+     *
+     * @param command Command APDU, its structure is defined in  ISO/IEC 7816-4
+     *                in Standard byte format
      */
     byte[] transmit(in byte[] command);
 
diff --git a/core/java/android/se/omapi/ISecureElementListener.aidl b/omapi/aidl/android/se/omapi/ISecureElementListener.aidl
similarity index 97%
rename from core/java/android/se/omapi/ISecureElementListener.aidl
rename to omapi/aidl/android/se/omapi/ISecureElementListener.aidl
index e9dd181..479dcd7 100644
--- a/core/java/android/se/omapi/ISecureElementListener.aidl
+++ b/omapi/aidl/android/se/omapi/ISecureElementListener.aidl
@@ -23,5 +23,6 @@
  * Interface to receive call-backs when the service is connected.
  * @hide
  */
+@VintfStability
 interface ISecureElementListener {
 }
diff --git a/core/java/android/se/omapi/ISecureElementReader.aidl b/omapi/aidl/android/se/omapi/ISecureElementReader.aidl
similarity index 94%
rename from core/java/android/se/omapi/ISecureElementReader.aidl
rename to omapi/aidl/android/se/omapi/ISecureElementReader.aidl
index 41244ab..a6979fa 100644
--- a/core/java/android/se/omapi/ISecureElementReader.aidl
+++ b/omapi/aidl/android/se/omapi/ISecureElementReader.aidl
@@ -22,6 +22,7 @@
 import android.se.omapi.ISecureElementSession;
 
 /** @hide */
+@VintfStability
 interface ISecureElementReader {
 
     /**
@@ -34,7 +35,7 @@
      * Connects to a secure element in this reader. <br>
      * This method prepares (initialises) the Secure Element for communication
      * before the Session object is returned (e.g. powers the Secure Element by
-     * ICC ON if its not already on). There might be multiple sessions opened at
+     * ICC ON if it is not already on). There might be multiple sessions opened at
      * the same time on the same reader. The system ensures the interleaving of
      * APDUs between the respective sessions.
      *
diff --git a/core/java/android/se/omapi/ISecureElementService.aidl b/omapi/aidl/android/se/omapi/ISecureElementService.aidl
similarity index 69%
rename from core/java/android/se/omapi/ISecureElementService.aidl
rename to omapi/aidl/android/se/omapi/ISecureElementService.aidl
index 4fa799e..61ae481 100644
--- a/core/java/android/se/omapi/ISecureElementService.aidl
+++ b/omapi/aidl/android/se/omapi/ISecureElementService.aidl
@@ -28,23 +28,31 @@
  * SecureElement service interface.
  * @hide
  */
+@VintfStability
 interface ISecureElementService {
 
     /**
      * Returns the friendly names of available Secure Element readers.
+     * <ul>
+     * <li>If the reader is a SIM reader, then its name must be "SIM[Slot]".</li>
+     * <li>If the reader is a SD or micro SD reader, then its name must be "SD[Slot]"</li>
+     * <li>If the reader is a embedded SE reader, then its name must be "eSE[Slot]"</li>
+     * </ul>
+     * Slot is a decimal number without leading zeros. The Numbering must start with 1
+     * (e.g. SIM1, SIM2, ... or SD1, SD2, ... or eSE1, eSE2, ...).
      */
     String[] getReaders();
 
     /**
      * Returns SecureElement Service reader object to the given name.
      */
-    ISecureElementReader getReader(String reader);
+    ISecureElementReader getReader(in String reader);
 
     /**
      * Checks if the application defined by the package name is allowed to
      * receive NFC transaction events for the defined AID.
      */
-    boolean[] isNFCEventAllowed(String reader, in byte[] aid,
+    boolean[] isNFCEventAllowed(in String reader, in byte[] aid,
             in String[] packageNames);
 
 }
diff --git a/core/java/android/se/omapi/ISecureElementSession.aidl b/omapi/aidl/android/se/omapi/ISecureElementSession.aidl
similarity index 84%
rename from core/java/android/se/omapi/ISecureElementSession.aidl
rename to omapi/aidl/android/se/omapi/ISecureElementSession.aidl
index 8ea599f..129ecc4 100644
--- a/core/java/android/se/omapi/ISecureElementSession.aidl
+++ b/omapi/aidl/android/se/omapi/ISecureElementSession.aidl
@@ -27,6 +27,7 @@
 import android.se.omapi.ISecureElementListener;
 
 /** @hide */
+@VintfStability
 interface ISecureElementSession {
 
     /**
@@ -45,7 +46,6 @@
      */
     void closeChannels();
 
-
     /**
      * Tells if this session is closed.
      *
@@ -59,15 +59,19 @@
      * applet if aid != null.
      * Logical channels cannot be opened with this connection.
      * Use interface method openLogicalChannel() to open a logical channel.
+     * Listener is passed to secure element service and used to monitor whether
+     * the client application that uses OMAPI is still alive or not.
      */
     ISecureElementChannel openBasicChannel(in byte[] aid, in byte p2,
-            ISecureElementListener listener);
+            in ISecureElementListener listener);
 
     /**
      * Opens a connection using the next free logical channel of the card in the
      * specified reader. Selects the specified applet.
      * Selection of other applets with this connection is not supported.
+     * Listener is passed to secure element service and used to monitor whether
+     * the client application that uses OMAPI is still alive or not.
      */
     ISecureElementChannel openLogicalChannel(in byte[] aid, in byte p2,
-            ISecureElementListener listener);
+            in ISecureElementListener listener);
 }
diff --git a/omapi/aidl/vts/functional/AccessControlApp/Android.bp b/omapi/aidl/vts/functional/AccessControlApp/Android.bp
new file mode 100644
index 0000000..f03c3f6
--- /dev/null
+++ b/omapi/aidl/vts/functional/AccessControlApp/Android.bp
@@ -0,0 +1,54 @@
+//
+// 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 {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_test {
+    name: "VtsHalOmapiSeAccessControlTestCases",
+    defaults: [
+        "VtsHalTargetTestDefaults",
+        "use_libaidlvintf_gtest_helper_static",
+    ],
+    srcs: [
+        "VtsHalOmapiSeAccessControlTestCases.cpp",
+    ],
+    shared_libs: [
+        "libbase",
+        "liblog",
+        "libcutils",
+        "libhidlbase",
+        "libnativehelper",
+        "libutils",
+        "libbinder_ndk",
+    ],
+    static_libs: [
+        "VtsHalHidlTargetTestBase",
+        "android.se.omapi-V1-ndk",
+    ],
+    cflags: [
+        "-O0",
+        "-g",
+        "-Wall",
+        "-Werror",
+    ],
+    require_root: true,
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+}
diff --git a/omapi/aidl/vts/functional/AccessControlApp/VtsHalOmapiSeAccessControlTestCases.cpp b/omapi/aidl/vts/functional/AccessControlApp/VtsHalOmapiSeAccessControlTestCases.cpp
new file mode 100644
index 0000000..9ea6543
--- /dev/null
+++ b/omapi/aidl/vts/functional/AccessControlApp/VtsHalOmapiSeAccessControlTestCases.cpp
@@ -0,0 +1,428 @@
+/*
+ * 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.
+ */
+
+#include <aidl/android/se/omapi/BnSecureElementListener.h>
+#include <aidl/android/se/omapi/ISecureElementChannel.h>
+#include <aidl/android/se/omapi/ISecureElementListener.h>
+#include <aidl/android/se/omapi/ISecureElementReader.h>
+#include <aidl/android/se/omapi/ISecureElementService.h>
+#include <aidl/android/se/omapi/ISecureElementSession.h>
+
+#include <VtsCoreUtil.h>
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <binder/IServiceManager.h>
+#include <cutils/properties.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+#include <utils/String16.h>
+
+using namespace std;
+using namespace ::testing;
+using namespace android;
+
+int main(int argc, char** argv) {
+    InitGoogleTest(&argc, argv);
+    int status = RUN_ALL_TESTS();
+    return status;
+}
+
+namespace {
+
+class OMAPISEAccessControlTest : public TestWithParam<std::string> {
+   protected:
+
+    class SEListener : public ::aidl::android::se::omapi::BnSecureElementListener {};
+
+    /**
+     * Verifies TLV data
+     *
+     * @return true if the data is tlv formatted, false otherwise
+     */
+    bool verifyBerTlvData(std::vector<uint8_t> tlv) {
+        if (tlv.size() == 0) {
+            LOG(ERROR) << "Invalid tlv, null";
+            return false;
+        }
+        int i = 0;
+        if ((tlv[i++] & 0x1F) == 0x1F) {
+            // extra byte for TAG field
+            i++;
+        }
+
+        int len = tlv[i++] & 0xFF;
+        if (len > 127) {
+            // more than 1 byte for length
+            int bytesLength = len - 128;
+            len = 0;
+            for (int j = bytesLength; j > 0; j--) {
+                len += (len << 8) + (tlv[i++] & 0xFF);
+            }
+        }
+        // Additional 2 bytes for the SW
+        return (tlv.size() == (i + len + 2));
+    }
+
+    void testSelectableAid(
+            std::vector<std::vector<uint8_t>> authorizedAids) {
+        for (auto aid : authorizedAids) {
+            std::shared_ptr<aidl::android::se::omapi::ISecureElementSession> session;
+            std::shared_ptr<aidl::android::se::omapi::ISecureElementChannel> channel;
+            auto seListener = ndk::SharedRefBase::make<SEListener>();
+
+            if (mVSReaders.size() > 0) {
+                for (const auto& [name, reader] : mVSReaders) {
+                    std::vector<uint8_t> selectResponse = {};
+                    ASSERT_NE(reader, nullptr) << "reader is null";
+
+                    bool status = false;
+                    auto res = reader->isSecureElementPresent(&status);
+                    ASSERT_TRUE(res.isOk()) << res.getMessage();
+                    ASSERT_TRUE(status);
+
+                    res = reader->openSession(&session);
+                    ASSERT_TRUE(res.isOk()) << res.getMessage();
+                    ASSERT_NE(session, nullptr) << "Could not open session";
+
+                    res = session->openLogicalChannel(aid, 0x00, seListener, &channel);
+                    ASSERT_TRUE(res.isOk()) << res.getMessage();
+                    ASSERT_NE(channel, nullptr) << "Could not open channel";
+
+                    res = channel->getSelectResponse(&selectResponse);
+                    ASSERT_TRUE(res.isOk()) << "failed to get Select Response";
+                    ASSERT_GE(selectResponse.size(), 2);
+
+                    if (channel != nullptr) channel->close();
+                    if (session != nullptr) session->close();
+
+                    ASSERT_EQ((selectResponse[selectResponse.size() - 1] & 0xFF), (0x00));
+                    ASSERT_EQ((selectResponse[selectResponse.size() - 2] & 0xFF), (0x90));
+                    ASSERT_TRUE(
+                        verifyBerTlvData(selectResponse)) << "Select Response is not complete";
+                }
+            }
+        }
+    }
+
+    void testUnauthorisedAid(
+            std::vector<std::vector<uint8_t>> unAuthorizedAids) {
+        for (auto aid : unAuthorizedAids) {
+            std::shared_ptr<aidl::android::se::omapi::ISecureElementSession> session;
+            std::shared_ptr<aidl::android::se::omapi::ISecureElementChannel> channel;
+            auto seListener = ndk::SharedRefBase::make<SEListener>();
+
+            if (mVSReaders.size() > 0) {
+                for (const auto& [name, reader] : mVSReaders) {
+                    ASSERT_NE(reader, nullptr) << "reader is null";
+
+                    bool status = false;
+                    auto res = reader->isSecureElementPresent(&status);
+                    ASSERT_TRUE(res.isOk()) << res.getMessage();
+                    ASSERT_TRUE(status);
+
+                    res = reader->openSession(&session);
+                    ASSERT_TRUE(res.isOk()) << res.getMessage();
+                    ASSERT_NE(session, nullptr) << "Could not open session";
+
+                    res = session->openLogicalChannel(aid, 0x00, seListener, &channel);
+
+                    if (channel != nullptr) channel->close();
+                    if (session != nullptr) session->close();
+
+                    if (!res.isOk()) {
+                        ASSERT_EQ(res.getExceptionCode(), EX_SECURITY);
+                        ASSERT_FALSE(res.isOk()) << "expected failed status for this test";
+                    }
+                }
+            }
+        }
+    }
+
+    void testTransmitAPDU(
+            std::vector<uint8_t> aid,
+            std::vector<std::vector<uint8_t>> apdus) {
+        for (auto apdu : apdus) {
+            std::shared_ptr<aidl::android::se::omapi::ISecureElementSession> session;
+            std::shared_ptr<aidl::android::se::omapi::ISecureElementChannel> channel;
+            auto seListener = ndk::SharedRefBase::make<SEListener>();
+
+            if (mVSReaders.size() > 0) {
+                for (const auto& [name, reader] : mVSReaders) {
+                    ASSERT_NE(reader, nullptr) << "reader is null";
+                    bool status = false;
+                    std::vector<uint8_t> selectResponse = {};
+                    std::vector<uint8_t> transmitResponse = {};
+                    auto res = reader->isSecureElementPresent(&status);
+                    ASSERT_TRUE(res.isOk()) << res.getMessage();
+                    ASSERT_TRUE(status);
+
+                    res = reader->openSession(&session);
+                    ASSERT_TRUE(res.isOk()) << res.getMessage();
+                    ASSERT_NE(session, nullptr) << "Could not open session";
+
+                    res = session->openLogicalChannel(aid, 0x00, seListener, &channel);
+                    ASSERT_TRUE(res.isOk()) << res.getMessage();
+                    ASSERT_NE(channel, nullptr) << "Could not open channel";
+
+                    res = channel->getSelectResponse(&selectResponse);
+                    ASSERT_TRUE(res.isOk()) << "failed to get Select Response";
+                    ASSERT_GE(selectResponse.size(), 2);
+                    ASSERT_EQ((selectResponse[selectResponse.size() - 1] & 0xFF), (0x00));
+                    ASSERT_EQ((selectResponse[selectResponse.size() - 2] & 0xFF), (0x90));
+                    ASSERT_TRUE(
+                        verifyBerTlvData(selectResponse)) << "Select Response is not complete";
+
+                    res = channel->transmit(apdu, &transmitResponse);
+                    LOG(INFO) << "STATUS OF TRNSMIT: " << res.getExceptionCode()
+                              << " Message: " << res.getMessage();
+                    if (channel != nullptr) channel->close();
+                    if (session != nullptr) session->close();
+                    ASSERT_TRUE(res.isOk()) << "failed to transmit";
+                }
+            }
+        }
+    }
+
+    void testUnauthorisedAPDU(
+            std::vector<uint8_t> aid,
+            std::vector<std::vector<uint8_t>> apdus) {
+        for (auto apdu : apdus) {
+            std::shared_ptr<aidl::android::se::omapi::ISecureElementSession> session;
+            std::shared_ptr<aidl::android::se::omapi::ISecureElementChannel> channel;
+            auto seListener = ndk::SharedRefBase::make<SEListener>();
+
+            if (mVSReaders.size() > 0) {
+                for (const auto& [name, reader] : mVSReaders) {
+                    ASSERT_NE(reader, nullptr) << "reader is null";
+                    bool status = false;
+                    std::vector<uint8_t> selectResponse = {};
+                    std::vector<uint8_t> transmitResponse = {};
+                    auto res = reader->isSecureElementPresent(&status);
+                    ASSERT_TRUE(res.isOk()) << res.getMessage();
+                    ASSERT_TRUE(status);
+
+                    res = reader->openSession(&session);
+                    ASSERT_TRUE(res.isOk()) << res.getMessage();
+                    ASSERT_NE(session, nullptr) << "Could not open session";
+
+                    res = session->openLogicalChannel(aid, 0x00, seListener, &channel);
+                    ASSERT_TRUE(res.isOk()) << res.getMessage();
+                    ASSERT_NE(channel, nullptr) << "Could not open channel";
+
+                    res = channel->getSelectResponse(&selectResponse);
+                    ASSERT_TRUE(res.isOk()) << "failed to get Select Response";
+                    ASSERT_GE(selectResponse.size(), 2);
+                    ASSERT_EQ((selectResponse[selectResponse.size() - 1] & 0xFF), (0x00));
+                    ASSERT_EQ((selectResponse[selectResponse.size() - 2] & 0xFF), (0x90));
+                    ASSERT_TRUE(
+                        verifyBerTlvData(selectResponse)) << "Select Response is not complete";
+
+                    res = channel->transmit(apdu, &transmitResponse);
+                    LOG(INFO) << "STATUS OF TRNSMIT: " << res.getExceptionCode()
+                              << " Message: " << res.getMessage();
+
+                    if (channel != nullptr) channel->close();
+                    if (session != nullptr) session->close();
+                    if (!res.isOk()) {
+                        ASSERT_EQ(res.getExceptionCode(), EX_SECURITY);
+                        ASSERT_FALSE(res.isOk()) << "expected failed status for this test";
+                    }
+                }
+            }
+        }
+    }
+
+    bool supportOMAPIReaders() {
+        return (deviceSupportsFeature(FEATURE_SE_OMAPI_ESE.c_str()));
+    }
+
+    void getFirstApiLevel(int32_t* outApiLevel) {
+        int32_t firstApiLevel = property_get_int32(FEATURE_SE_API_LEVEL.c_str(), -1);
+        if (firstApiLevel < 0) {
+            firstApiLevel = property_get_int32(FEATURE_SE_SDK_VERSION.c_str(), -1);
+        }
+        ASSERT_GT(firstApiLevel, 0);  // first_api_level must exist
+        *outApiLevel = firstApiLevel;
+        return;
+    }
+
+    bool supportsHardware() {
+        bool lowRamDevice = property_get_bool(FEATURE_SE_LOW_RAM.c_str(), true);
+        return !lowRamDevice || deviceSupportsFeature(FEATURE_SE_HARDWARE_WATCH.c_str()) ||
+                deviceSupportsFeature(FEATURE_SE_OMAPI_SERVICE.c_str());  // android.se.omapi
+    }
+
+    void SetUp() override {
+        ASSERT_TRUE(supportsHardware());
+        int32_t apiLevel;
+        getFirstApiLevel(&apiLevel);
+        ASSERT_TRUE(apiLevel > 27);
+        ASSERT_TRUE(supportOMAPIReaders());
+        LOG(INFO) << "get OMAPI service with name:" << GetParam();
+        ::ndk::SpAIBinder ks2Binder(AServiceManager_getService(GetParam().c_str()));
+        mOmapiSeService = aidl::android::se::omapi::ISecureElementService::fromBinder(ks2Binder);
+        ASSERT_TRUE(mOmapiSeService);
+
+        std::vector<std::string> readers = {};
+
+        if (mOmapiSeService != NULL) {
+            auto status = mOmapiSeService->getReaders(&readers);
+            ASSERT_TRUE(status.isOk()) << status.getMessage();
+
+            for (auto readerName : readers) {
+                // Filter eSE readers only
+                if (readerName.find(ESE_READER_PREFIX, 0) != std::string::npos) {
+                    std::shared_ptr<::aidl::android::se::omapi::ISecureElementReader> reader;
+                    status = mOmapiSeService->getReader(readerName, &reader);
+                    ASSERT_TRUE(status.isOk()) << status.getMessage();
+
+                    mVSReaders[readerName] = reader;
+                }
+            }
+        }
+    }
+
+    void TearDown() override {
+        if (mOmapiSeService != nullptr) {
+            if (mVSReaders.size() > 0) {
+                for (const auto& [name, reader] : mVSReaders) {
+                    reader->closeSessions();
+                }
+            }
+        }
+    }
+
+    static inline std::string const ESE_READER_PREFIX = "eSE";
+    static inline std::string const FEATURE_SE_OMAPI_ESE = "android.hardware.se.omapi.ese";
+    static inline std::string const FEATURE_SE_LOW_RAM = "ro.config.low_ram";
+    static inline std::string const FEATURE_SE_HARDWARE_WATCH = "android.hardware.type.watch";
+    static inline std::string const FEATURE_SE_OMAPI_SERVICE = "com.android.se";
+    static inline std::string const FEATURE_SE_SDK_VERSION = "ro.build.version.sdk";
+    static inline std::string const FEATURE_SE_API_LEVEL = "ro.product.first_api_level";
+
+    std::vector<uint8_t> AID_40 = {0xA0, 0x00, 0x00, 0x04, 0x76, 0x41, 0x6E, 0x64,
+                                   0x72, 0x6F, 0x69, 0x64, 0x43, 0x54, 0x53, 0x40};
+    std::vector<uint8_t> AID_41 = {0xA0, 0x00, 0x00, 0x04, 0x76, 0x41, 0x6E, 0x64,
+                                   0x72, 0x6F, 0x69, 0x64, 0x43, 0x54, 0x53, 0x41};
+    std::vector<uint8_t> AID_42 = {0xA0, 0x00, 0x00, 0x04, 0x76, 0x41, 0x6E, 0x64,
+                                   0x72, 0x6F, 0x69, 0x64, 0x43, 0x54, 0x53, 0x42};
+    std::vector<uint8_t> AID_43 = {0xA0, 0x00, 0x00, 0x04, 0x76, 0x41, 0x6E, 0x64,
+                                   0x72, 0x6F, 0x69, 0x64, 0x43, 0x54, 0x53, 0x43};
+    std::vector<uint8_t> AID_44 = {0xA0, 0x00, 0x00, 0x04, 0x76, 0x41, 0x6E, 0x64,
+                                   0x72, 0x6F, 0x69, 0x64, 0x43, 0x54, 0x53, 0x44};
+    std::vector<uint8_t> AID_45 = {0xA0, 0x00, 0x00, 0x04, 0x76, 0x41, 0x6E, 0x64,
+                                   0x72, 0x6F, 0x69, 0x64, 0x43, 0x54, 0x53, 0x45};
+    std::vector<uint8_t> AID_46 = {0xA0, 0x00, 0x00, 0x04, 0x76, 0x41, 0x6E, 0x64,
+                                   0x72, 0x6F, 0x69, 0x64, 0x43, 0x54, 0x53, 0x46};
+    std::vector<uint8_t> AID_47 = {0xA0, 0x00, 0x00, 0x04, 0x76, 0x41, 0x6E, 0x64,
+                                   0x72, 0x6F, 0x69, 0x64, 0x43, 0x54, 0x53, 0x47};
+    std::vector<uint8_t> AID_48 = {0xA0, 0x00, 0x00, 0x04, 0x76, 0x41, 0x6E, 0x64,
+                                   0x72, 0x6F, 0x69, 0x64, 0x43, 0x54, 0x53, 0x48};
+    std::vector<uint8_t> AID_49 = {0xA0, 0x00, 0x00, 0x04, 0x76, 0x41, 0x6E, 0x64,
+                                   0x72, 0x6F, 0x69, 0x64, 0x43, 0x54, 0x53, 0x49};
+    std::vector<uint8_t> AID_4A = {0xA0, 0x00, 0x00, 0x04, 0x76, 0x41, 0x6E, 0x64,
+                                   0x72, 0x6F, 0x69, 0x64, 0x43, 0x54, 0x53, 0x4A};
+    std::vector<uint8_t> AID_4B = {0xA0, 0x00, 0x00, 0x04, 0x76, 0x41, 0x6E, 0x64,
+                                   0x72, 0x6F, 0x69, 0x64, 0x43, 0x54, 0x53, 0x4B};
+    std::vector<uint8_t> AID_4C = {0xA0, 0x00, 0x00, 0x04, 0x76, 0x41, 0x6E, 0x64,
+                                   0x72, 0x6F, 0x69, 0x64, 0x43, 0x54, 0x53, 0x4C};
+    std::vector<uint8_t> AID_4D = {0xA0, 0x00, 0x00, 0x04, 0x76, 0x41, 0x6E, 0x64,
+                                   0x72, 0x6F, 0x69, 0x64, 0x43, 0x54, 0x53, 0x4D};
+    std::vector<uint8_t> AID_4E = {0xA0, 0x00, 0x00, 0x04, 0x76, 0x41, 0x6E, 0x64,
+                                   0x72, 0x6F, 0x69, 0x64, 0x43, 0x54, 0x53, 0x4E};
+    std::vector<uint8_t> AID_4F = {0xA0, 0x00, 0x00, 0x04, 0x76, 0x41, 0x6E, 0x64,
+                                   0x72, 0x6F, 0x69, 0x64, 0x43, 0x54, 0x53, 0x4F};
+
+    std::vector<std::vector<uint8_t>> AUTHORIZED_AID = {AID_40, AID_41, AID_42, AID_44, AID_45,
+                                                        AID_47, AID_48, AID_49, AID_4A, AID_4B,
+                                                        AID_4C, AID_4D, AID_4E, AID_4F};
+    std::vector<std::vector<uint8_t>> UNAUTHORIZED_AID = {AID_43, AID_46};
+
+    /* Authorized APDU for AID_40 */
+    std::vector<std::vector<uint8_t>> AUTHORIZED_APDU_AID_40 = {
+        {0x00, 0x06, 0x00, 0x00},
+        {0xA0, 0x06, 0x00, 0x00},
+    };
+    /* Unauthorized APDU for AID_40 */
+    std::vector<std::vector<uint8_t>> UNAUTHORIZED_APDU_AID_40 = {
+        {0x00, 0x08, 0x00, 0x00, 0x00},
+        {0x80, 0x06, 0x00, 0x00},
+        {0xA0, 0x08, 0x00, 0x00, 0x00},
+        {0x94, 0x06, 0x00, 0x00, 0x00},
+    };
+
+    /* Authorized APDU for AID_41 */
+    std::vector<std::vector<uint8_t>> AUTHORIZED_APDU_AID_41 = {
+        {0x94, 0x06, 0x00, 0x00},
+        {0x94, 0x08, 0x00, 0x00, 0x00},
+        {0x94, 0x0C, 0x00, 0x00, 0x01, 0xAA, 0x00},
+        {0x94, 0x0A, 0x00, 0x00, 0x01, 0xAA}};
+    /* Unauthorized APDU for AID_41 */
+    std::vector<std::vector<uint8_t>> UNAUTHORIZED_APDU_AID_41 = {
+        {0x00, 0x06, 0x00, 0x00},
+        {0x80, 0x06, 0x00, 0x00},
+        {0xA0, 0x06, 0x00, 0x00},
+        {0x00, 0x08, 0x00, 0x00, 0x00},
+        {0x00, 0x0A, 0x00, 0x00, 0x01, 0xAA},
+        {0x80, 0x0A, 0x00, 0x00, 0x01, 0xAA},
+        {0xA0, 0x0A, 0x00, 0x00, 0x01, 0xAA},
+        {0x80, 0x08, 0x00, 0x00, 0x00},
+        {0xA0, 0x08, 0x00, 0x00, 0x00},
+        {0x00, 0x0C, 0x00, 0x00, 0x01, 0xAA, 0x00},
+        {0x80, 0x0C, 0x00, 0x00, 0x01, 0xAA, 0x00},
+        {0xA0, 0x0C, 0x00, 0x00, 0x01, 0xAA, 0x00},
+    };
+
+    std::shared_ptr<aidl::android::se::omapi::ISecureElementService> mOmapiSeService;
+
+    std::map<std::string, std::shared_ptr<aidl::android::se::omapi::ISecureElementReader>>
+        mVSReaders = {};
+};
+
+TEST_P(OMAPISEAccessControlTest, TestAuthorizedAID) {
+    testSelectableAid(AUTHORIZED_AID);
+}
+
+TEST_P(OMAPISEAccessControlTest, TestUnauthorizedAID) {
+    testUnauthorisedAid(UNAUTHORIZED_AID);
+}
+
+TEST_P(OMAPISEAccessControlTest, TestAuthorizedAPDUAID40) {
+    testTransmitAPDU(AID_40, AUTHORIZED_APDU_AID_40);
+}
+
+TEST_P(OMAPISEAccessControlTest, TestUnauthorisedAPDUAID40) {
+    testUnauthorisedAPDU(AID_40, UNAUTHORIZED_APDU_AID_40);
+}
+
+TEST_P(OMAPISEAccessControlTest, TestAuthorizedAPDUAID41) {
+    testTransmitAPDU(AID_41, AUTHORIZED_APDU_AID_41);
+}
+
+TEST_P(OMAPISEAccessControlTest, TestUnauthorisedAPDUAID41) {
+    testUnauthorisedAPDU(AID_41, UNAUTHORIZED_APDU_AID_41);
+}
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, OMAPISEAccessControlTest,
+                         testing::ValuesIn(::android::getAidlHalInstanceNames(
+                             aidl::android::se::omapi::ISecureElementService::descriptor)),
+                         android::hardware::PrintInstanceNameToString);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(OMAPISEAccessControlTest);
+
+}  // namespace
diff --git a/omapi/aidl/vts/functional/omapi/Android.bp b/omapi/aidl/vts/functional/omapi/Android.bp
new file mode 100644
index 0000000..c3ab8d1
--- /dev/null
+++ b/omapi/aidl/vts/functional/omapi/Android.bp
@@ -0,0 +1,54 @@
+//
+// 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 {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_test {
+    name: "VtsHalOmapiSeServiceV1_TargetTest",
+    defaults: [
+        "VtsHalTargetTestDefaults",
+        "use_libaidlvintf_gtest_helper_static",
+    ],
+    srcs: [
+        "VtsHalOmapiSeServiceV1_TargetTest.cpp",
+    ],
+    shared_libs: [
+        "libbase",
+        "liblog",
+        "libcutils",
+        "libhidlbase",
+        "libnativehelper",
+        "libutils",
+        "libbinder_ndk",
+    ],
+    static_libs: [
+        "VtsHalHidlTargetTestBase",
+        "android.se.omapi-V1-ndk",
+    ],
+    cflags: [
+        "-O0",
+        "-g",
+        "-Wall",
+        "-Werror",
+    ],
+    require_root: true,
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+}
diff --git a/omapi/aidl/vts/functional/omapi/VtsHalOmapiSeServiceV1_TargetTest.cpp b/omapi/aidl/vts/functional/omapi/VtsHalOmapiSeServiceV1_TargetTest.cpp
new file mode 100644
index 0000000..319cb7e
--- /dev/null
+++ b/omapi/aidl/vts/functional/omapi/VtsHalOmapiSeServiceV1_TargetTest.cpp
@@ -0,0 +1,609 @@
+/*
+ * 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.
+ */
+
+#include <aidl/android/se/omapi/BnSecureElementListener.h>
+#include <aidl/android/se/omapi/ISecureElementChannel.h>
+#include <aidl/android/se/omapi/ISecureElementListener.h>
+#include <aidl/android/se/omapi/ISecureElementReader.h>
+#include <aidl/android/se/omapi/ISecureElementService.h>
+#include <aidl/android/se/omapi/ISecureElementSession.h>
+
+#include <VtsCoreUtil.h>
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <binder/IServiceManager.h>
+#include <cutils/properties.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+#include <utils/String16.h>
+
+using namespace std;
+using namespace ::testing;
+using namespace android;
+
+int main(int argc, char** argv) {
+    InitGoogleTest(&argc, argv);
+    int status = RUN_ALL_TESTS();
+    return status;
+}
+
+namespace {
+
+class OMAPISEServiceHalTest : public TestWithParam<std::string> {
+   protected:
+    class SEListener : public ::aidl::android::se::omapi::BnSecureElementListener {};
+
+    void testSelectableAid(
+        std::shared_ptr<aidl::android::se::omapi::ISecureElementReader> reader,
+        std::vector<uint8_t> aid, std::vector<uint8_t>& selectResponse) {
+        std::shared_ptr<aidl::android::se::omapi::ISecureElementSession> session;
+        std::shared_ptr<aidl::android::se::omapi::ISecureElementChannel> channel;
+        auto seListener = ndk::SharedRefBase::make<::OMAPISEServiceHalTest::SEListener>();
+
+        ASSERT_NE(reader, nullptr) << "reader is null";
+
+        bool status = false;
+        auto res = reader->isSecureElementPresent(&status);
+        ASSERT_TRUE(res.isOk()) << res.getMessage();
+        ASSERT_TRUE(status);
+
+        res = reader->openSession(&session);
+        ASSERT_TRUE(res.isOk()) << res.getMessage();
+        ASSERT_NE(session, nullptr) << "Could not open session";
+
+        res = session->openLogicalChannel(aid, 0x00, seListener, &channel);
+        ASSERT_TRUE(res.isOk()) << res.getMessage();
+        ASSERT_NE(channel, nullptr) << "Could not open channel";
+
+        res = channel->getSelectResponse(&selectResponse);
+        ASSERT_TRUE(res.isOk()) << "failed to get Select Response";
+        ASSERT_GE(selectResponse.size(), 2);
+
+        if (channel != nullptr) channel->close();
+        if (session != nullptr) session->close();
+
+        ASSERT_EQ((selectResponse[selectResponse.size() - 1] & 0xFF), (0x00));
+        ASSERT_EQ((selectResponse[selectResponse.size() - 2] & 0xFF), (0x90));
+    }
+
+    void testNonSelectableAid(
+        std::shared_ptr<aidl::android::se::omapi::ISecureElementReader> reader,
+        std::vector<uint8_t> aid) {
+        std::shared_ptr<aidl::android::se::omapi::ISecureElementSession> session;
+        std::shared_ptr<aidl::android::se::omapi::ISecureElementChannel> channel;
+        auto seListener = ndk::SharedRefBase::make<::OMAPISEServiceHalTest::SEListener>();
+
+        ASSERT_NE(reader, nullptr) << "reader is null";
+
+        bool status = false;
+        auto res = reader->isSecureElementPresent(&status);
+        ASSERT_TRUE(res.isOk()) << res.getMessage();
+        ASSERT_TRUE(status);
+
+        res = reader->openSession(&session);
+        ASSERT_TRUE(res.isOk()) << res.getMessage();
+        ASSERT_NE(session, nullptr) << "Could not open session";
+
+        res = session->openLogicalChannel(aid, 0x00, seListener, &channel);
+        if (channel != nullptr) channel->close();
+        if (session != nullptr) session->close();
+
+        LOG(ERROR) << res.getMessage();
+        ASSERT_FALSE(res.isOk()) << "expected to fail to open channel for this test";
+    }
+
+    /**
+     * Verifies TLV data
+     *
+     * @return true if the data is tlv formatted, false otherwise
+     */
+    bool verifyBerTlvData(std::vector<uint8_t> tlv) {
+        if (tlv.size() == 0) {
+            LOG(ERROR) << "Invalid tlv, null";
+            return false;
+        }
+        int i = 0;
+        if ((tlv[i++] & 0x1F) == 0x1F) {
+            // extra byte for TAG field
+            i++;
+        }
+
+        int len = tlv[i++] & 0xFF;
+        if (len > 127) {
+            // more than 1 byte for length
+            int bytesLength = len - 128;
+            len = 0;
+            for (int j = bytesLength; j > 0; j--) {
+                len += (len << 8) + (tlv[i++] & 0xFF);
+            }
+        }
+        // Additional 2 bytes for the SW
+        return (tlv.size() == (i + len + 2));
+    }
+
+    void internalTransmitApdu(
+        std::shared_ptr<aidl::android::se::omapi::ISecureElementReader> reader,
+        std::vector<uint8_t> apdu, std::vector<uint8_t>& transmitResponse) {
+        std::shared_ptr<aidl::android::se::omapi::ISecureElementSession> session;
+        std::shared_ptr<aidl::android::se::omapi::ISecureElementChannel> channel;
+        auto seListener = ndk::SharedRefBase::make<::OMAPISEServiceHalTest::SEListener>();
+        std::vector<uint8_t> selectResponse = {};
+
+        ASSERT_NE(reader, nullptr) << "reader is null";
+
+        bool status = false;
+        auto res = reader->isSecureElementPresent(&status);
+        ASSERT_TRUE(res.isOk()) << res.getMessage();
+        ASSERT_TRUE(status);
+
+        res = reader->openSession(&session);
+        ASSERT_TRUE(res.isOk()) << res.getMessage();
+        ASSERT_NE(session, nullptr) << "Could not open session";
+
+        res = session->openLogicalChannel(SELECTABLE_AID, 0x00, seListener, &channel);
+        ASSERT_TRUE(res.isOk()) << res.getMessage();
+        ASSERT_NE(channel, nullptr) << "Could not open channel";
+
+        res = channel->getSelectResponse(&selectResponse);
+        ASSERT_TRUE(res.isOk()) << "failed to get Select Response";
+        ASSERT_GE(selectResponse.size(), 2);
+
+        res = channel->transmit(apdu, &transmitResponse);
+        if (channel != nullptr) channel->close();
+        if (session != nullptr) session->close();
+        LOG(INFO) << "STATUS OF TRNSMIT: " << res.getExceptionCode()
+                  << " Message: " << res.getMessage();
+        ASSERT_TRUE(res.isOk()) << "failed to transmit";
+    }
+
+    bool supportOMAPIReaders() {
+        return (deviceSupportsFeature(FEATURE_SE_OMAPI_ESE.c_str()));
+    }
+
+    void SetUp() override {
+        LOG(INFO) << "get OMAPI service with name:" << GetParam();
+        ::ndk::SpAIBinder ks2Binder(AServiceManager_getService(GetParam().c_str()));
+        mOmapiSeService = aidl::android::se::omapi::ISecureElementService::fromBinder(ks2Binder);
+        ASSERT_TRUE(mOmapiSeService);
+
+        std::vector<std::string> readers = {};
+
+        if (omapiSecureService() != NULL) {
+            auto status = omapiSecureService()->getReaders(&readers);
+            ASSERT_TRUE(status.isOk()) << status.getMessage();
+
+            for (auto readerName : readers) {
+                // Filter eSE readers only
+                if (readerName.find(ESE_READER_PREFIX, 0) != std::string::npos) {
+                    std::shared_ptr<::aidl::android::se::omapi::ISecureElementReader> reader;
+                    status = omapiSecureService()->getReader(readerName, &reader);
+                    ASSERT_TRUE(status.isOk()) << status.getMessage();
+
+                    mVSReaders[readerName] = reader;
+                }
+            }
+        }
+    }
+
+    void TearDown() override {
+        if (mOmapiSeService != nullptr) {
+            if (mVSReaders.size() > 0) {
+                for (const auto& [name, reader] : mVSReaders) {
+                    reader->closeSessions();
+                }
+            }
+        }
+    }
+
+    bool isDebuggableBuild() {
+        char value[PROPERTY_VALUE_MAX] = {0};
+        property_get("ro.system.build.type", value, "");
+        if (strcmp(value, "userdebug") == 0) {
+            return true;
+        }
+        if (strcmp(value, "eng") == 0) {
+            return true;
+        }
+        return false;
+    }
+
+    std::shared_ptr<aidl::android::se::omapi::ISecureElementService> omapiSecureService() {
+        return mOmapiSeService;
+    }
+
+    static inline std::string const ESE_READER_PREFIX = "eSE";
+    static inline std::string const FEATURE_SE_OMAPI_ESE = "android.hardware.se.omapi.ese";
+
+    std::vector<uint8_t> SELECTABLE_AID = {0xA0, 0x00, 0x00, 0x04, 0x76, 0x41, 0x6E, 0x64,
+                                           0x72, 0x6F, 0x69, 0x64, 0x43, 0x54, 0x53, 0x31};
+    std::vector<uint8_t> LONG_SELECT_RESPONSE_AID = {0xA0, 0x00, 0x00, 0x04, 0x76, 0x41,
+                                                     0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64,
+                                                     0x43, 0x54, 0x53, 0x32};
+    std::vector<uint8_t> NON_SELECTABLE_AID = {0xA0, 0x00, 0x00, 0x04, 0x76, 0x41, 0x6E, 0x64,
+                                               0x72, 0x6F, 0x69, 0x64, 0x43, 0x54, 0x53, 0xFF};
+
+    std::vector<std::vector<uint8_t>> ILLEGAL_COMMANDS_TRANSMIT = {
+        {0x00, 0x70, 0x00, 0x00},
+        {0x00, 0x70, 0x80, 0x00},
+        {0x00, 0xA4, 0x04, 0x04, 0x10, 0x4A, 0x53, 0x52, 0x31, 0x37, 0x37,
+         0x54, 0x65, 0x73, 0x74, 0x65, 0x72, 0x20, 0x31, 0x2E, 0x30}};
+
+    /* OMAPI APDU Test case 1 and 3 */
+    std::vector<std::vector<uint8_t>> NO_DATA_APDU = {{0x00, 0x06, 0x00, 0x00},
+                                                      {0x80, 0x06, 0x00, 0x00},
+                                                      {0xA0, 0x06, 0x00, 0x00},
+                                                      {0x94, 0x06, 0x00, 0x00},
+                                                      {0x00, 0x0A, 0x00, 0x00, 0x01, 0xAA},
+                                                      {0x80, 0x0A, 0x00, 0x00, 0x01, 0xAA},
+                                                      {0xA0, 0x0A, 0x00, 0x00, 0x01, 0xAA},
+                                                      {0x94, 0x0A, 0x00, 0x00, 0x01, 0xAA}};
+
+    /* OMAPI APDU Test case 2 and 4 */
+    std::vector<std::vector<uint8_t>> DATA_APDU = {{0x00, 0x08, 0x00, 0x00, 0x00},
+                                                   {0x80, 0x08, 0x00, 0x00, 0x00},
+                                                   {0xA0, 0x08, 0x00, 0x00, 0x00},
+                                                   {0x94, 0x08, 0x00, 0x00, 0x00},
+                                                   {0x00, 0x0C, 0x00, 0x00, 0x01, 0xAA, 0x00},
+                                                   {0x80, 0x0C, 0x00, 0x00, 0x01, 0xAA, 0x00},
+                                                   {0xA0, 0x0C, 0x00, 0x00, 0x01, 0xAA, 0x00},
+                                                   {0x94, 0x0C, 0x00, 0x00, 0x01, 0xAA, 0x00}};
+
+    /* Case 2 APDU command expects the P2 received in the SELECT command as 1-byte outgoing data */
+    std::vector<uint8_t> CHECK_SELECT_P2_APDU = {0x00, 0xF4, 0x00, 0x00, 0x00};
+
+    /* OMAPI APDU Test case 1 and 3 */
+    std::vector<std::vector<uint8_t>> SW_62xx_NO_DATA_APDU = {{0x00, 0xF3, 0x00, 0x06},
+                                                              {0x00, 0xF3, 0x00, 0x0A, 0x01, 0xAA}};
+
+    /* OMAPI APDU Test case 2 and 4 */
+    std::vector<uint8_t> SW_62xx_DATA_APDU = {0x00, 0xF3, 0x00, 0x08, 0x00};
+    std::vector<uint8_t> SW_62xx_VALIDATE_DATA_APDU = {0x00, 0xF3, 0x00, 0x0C, 0x01, 0xAA, 0x00};
+    std::vector<std::vector<uint8_t>> SW_62xx = {
+        {0x62, 0x00}, {0x62, 0x81}, {0x62, 0x82}, {0x62, 0x83}, {0x62, 0x85}, {0x62, 0xF1},
+        {0x62, 0xF2}, {0x63, 0xF1}, {0x63, 0xF2}, {0x63, 0xC2}, {0x62, 0x02}, {0x62, 0x80},
+        {0x62, 0x84}, {0x62, 0x86}, {0x63, 0x00}, {0x63, 0x81}};
+
+    std::vector<std::vector<uint8_t>> SEGMENTED_RESP_APDU = {
+        // Get response Case2 61FF+61XX with answer length (P1P2) of 0x0800, 2048 bytes
+        {0x00, 0xC2, 0x08, 0x00, 0x00},
+        // Get response Case4 61FF+61XX with answer length (P1P2) of 0x0800, 2048 bytes
+        {0x00, 0xC4, 0x08, 0x00, 0x02, 0x12, 0x34, 0x00},
+        // Get response Case2 6100+61XX with answer length (P1P2) of 0x0800, 2048 bytes
+        {0x00, 0xC6, 0x08, 0x00, 0x00},
+        // Get response Case4 6100+61XX with answer length (P1P2) of 0x0800, 2048 bytes
+        {0x00, 0xC8, 0x08, 0x00, 0x02, 0x12, 0x34, 0x00},
+        // Test device buffer capacity 7FFF data
+        {0x00, 0xC2, 0x7F, 0xFF, 0x00},
+        // Get response 6CFF+61XX with answer length (P1P2) of 0x0800, 2048 bytes
+        {0x00, 0xCF, 0x08, 0x00, 0x00},
+        // Get response with another CLA  with answer length (P1P2) of 0x0800, 2048 bytes
+        {0x94, 0xC2, 0x08, 0x00, 0x00}};
+    long SERVICE_CONNECTION_TIME_OUT = 3000;
+
+    std::shared_ptr<aidl::android::se::omapi::ISecureElementService> mOmapiSeService;
+
+    std::map<std::string, std::shared_ptr<aidl::android::se::omapi::ISecureElementReader>>
+        mVSReaders = {};
+};
+
+/** Tests getReaders API */
+TEST_P(OMAPISEServiceHalTest, TestGetReaders) {
+    std::vector<std::shared_ptr<aidl::android::se::omapi::ISecureElementReader>> eseReaders =
+        {};
+
+    for (const auto& [name, reader] : mVSReaders) {
+        bool status = false;
+        LOG(INFO) << "Name of the reader: " << name;
+
+        if (reader) {
+            auto res = reader->isSecureElementPresent(&status);
+            ASSERT_TRUE(res.isOk()) << res.getMessage();
+        }
+        ASSERT_TRUE(status);
+
+        if (name.find(ESE_READER_PREFIX) == std::string::npos) {
+            LOG(ERROR) << "Incorrect Reader name";
+            FAIL();
+        }
+
+        if (name.find(ESE_READER_PREFIX, 0) != std::string::npos) {
+            eseReaders.push_back(reader);
+        } else {
+            LOG(INFO) << "Reader not supported: " << name;
+            FAIL();
+        }
+    }
+
+    if (deviceSupportsFeature(FEATURE_SE_OMAPI_ESE.c_str())) {
+        ASSERT_GE(eseReaders.size(), 1);
+    } else {
+        ASSERT_TRUE(eseReaders.size() == 0);
+    }
+}
+
+/** Tests OpenBasicChannel API when aid is null */
+TEST_P(OMAPISEServiceHalTest, TestOpenBasicChannelNullAid) {
+    ASSERT_TRUE(supportOMAPIReaders() == true);
+    std::vector<uint8_t> aid = {};
+    auto seListener = ndk::SharedRefBase::make<::OMAPISEServiceHalTest::SEListener>();
+
+    if (mVSReaders.size() > 0) {
+        for (const auto& [name, reader] : mVSReaders) {
+            std::shared_ptr<aidl::android::se::omapi::ISecureElementSession> session;
+            std::shared_ptr<aidl::android::se::omapi::ISecureElementChannel> channel;
+            bool result = false;
+
+            auto status = reader->openSession(&session);
+            ASSERT_TRUE(status.isOk()) << status.getMessage();
+            if (!session) {
+                LOG(ERROR) << "Could not open session";
+                FAIL();
+            }
+
+            status = session->openBasicChannel(aid, 0x00, seListener, &channel);
+            ASSERT_TRUE(status.isOk()) << status.getMessage();
+
+            if (channel != nullptr) channel->close();
+            if (session != nullptr) session->close();
+
+            if (channel != nullptr) {
+                status = channel->isBasicChannel(&result);
+                ASSERT_TRUE(status.isOk()) << "Basic Channel cannot be opened";
+            }
+        }
+    }
+}
+
+/** Tests OpenBasicChannel API when aid is provided */
+TEST_P(OMAPISEServiceHalTest, TestOpenBasicChannelNonNullAid) {
+    ASSERT_TRUE(supportOMAPIReaders() == true);
+    auto seListener = ndk::SharedRefBase::make<::OMAPISEServiceHalTest::SEListener>();
+
+    if (mVSReaders.size() > 0) {
+        for (const auto& [name, reader] : mVSReaders) {
+            std::shared_ptr<aidl::android::se::omapi::ISecureElementSession> session;
+            std::shared_ptr<aidl::android::se::omapi::ISecureElementChannel> channel;
+            bool result = false;
+
+            auto status = reader->openSession(&session);
+            ASSERT_TRUE(status.isOk()) << status.getMessage();
+            if (!session) {
+                LOG(ERROR) << "Could not open session";
+                FAIL();
+            }
+
+            status = session->openBasicChannel(SELECTABLE_AID, 0x00, seListener, &channel);
+            ASSERT_TRUE(status.isOk()) << status.getMessage();
+
+            if (channel != nullptr) channel->close();
+            if (session != nullptr) session->close();
+
+            if (channel != nullptr) {
+                status = channel->isBasicChannel(&result);
+                ASSERT_TRUE(status.isOk()) << "Basic Channel cannot be opened";
+            }
+        }
+    }
+}
+
+/** Tests Select API */
+TEST_P(OMAPISEServiceHalTest, TestSelectableAid) {
+    ASSERT_TRUE(supportOMAPIReaders() == true);
+    if (mVSReaders.size() > 0) {
+        for (const auto& [name, reader] : mVSReaders) {
+            std::vector<uint8_t> selectResponse = {};
+            testSelectableAid(reader, SELECTABLE_AID, selectResponse);
+        }
+    }
+}
+
+/** Tests Select API */
+TEST_P(OMAPISEServiceHalTest, TestLongSelectResponse) {
+    ASSERT_TRUE(supportOMAPIReaders() == true);
+    if (mVSReaders.size() > 0) {
+        for (const auto& [name, reader] : mVSReaders) {
+            std::vector<uint8_t> selectResponse = {};
+            testSelectableAid(reader, LONG_SELECT_RESPONSE_AID, selectResponse);
+            ASSERT_TRUE(verifyBerTlvData(selectResponse)) << "Select Response is not complete";
+        }
+    }
+}
+
+/** Test to fail open channel with wrong aid */
+TEST_P(OMAPISEServiceHalTest, TestWrongAid) {
+    ASSERT_TRUE(supportOMAPIReaders() == true);
+    if (mVSReaders.size() > 0) {
+        for (const auto& [name, reader] : mVSReaders) {
+            testNonSelectableAid(reader, NON_SELECTABLE_AID);
+        }
+    }
+}
+
+/** Tests with invalid cmds in Transmit */
+TEST_P(OMAPISEServiceHalTest, TestSecurityExceptionInTransmit) {
+    ASSERT_TRUE(supportOMAPIReaders() == true);
+    if (mVSReaders.size() > 0) {
+        for (const auto& [name, reader] : mVSReaders) {
+            std::shared_ptr<aidl::android::se::omapi::ISecureElementSession> session;
+            std::shared_ptr<aidl::android::se::omapi::ISecureElementChannel> channel;
+            auto seListener = ndk::SharedRefBase::make<::OMAPISEServiceHalTest::SEListener>();
+            std::vector<uint8_t> selectResponse = {};
+
+            ASSERT_NE(reader, nullptr) << "reader is null";
+
+            bool status = false;
+            auto res = reader->isSecureElementPresent(&status);
+            ASSERT_TRUE(res.isOk()) << res.getMessage();
+            ASSERT_TRUE(status);
+
+            res = reader->openSession(&session);
+            ASSERT_TRUE(res.isOk()) << res.getMessage();
+            ASSERT_NE(session, nullptr) << "Could not open session";
+
+            res = session->openLogicalChannel(SELECTABLE_AID, 0x00, seListener, &channel);
+            ASSERT_TRUE(res.isOk()) << res.getMessage();
+            ASSERT_NE(channel, nullptr) << "Could not open channel";
+
+            res = channel->getSelectResponse(&selectResponse);
+            ASSERT_TRUE(res.isOk()) << "failed to get Select Response";
+            ASSERT_GE(selectResponse.size(), 2);
+
+            ASSERT_EQ((selectResponse[selectResponse.size() - 1] & 0xFF), (0x00));
+            ASSERT_EQ((selectResponse[selectResponse.size() - 2] & 0xFF), (0x90));
+
+            for (auto cmd : ILLEGAL_COMMANDS_TRANSMIT) {
+                std::vector<uint8_t> response = {};
+                res = channel->transmit(cmd, &response);
+                ASSERT_EQ(res.getExceptionCode(), EX_SECURITY);
+                ASSERT_FALSE(res.isOk()) << "expected failed status for this test";
+            }
+            if (channel != nullptr) channel->close();
+            if (session != nullptr) session->close();
+        }
+    }
+}
+
+/**
+ * Tests Transmit API for all readers.
+ *
+ * Checks the return status and verifies the size of the
+ * response.
+ */
+TEST_P(OMAPISEServiceHalTest, TestTransmitApdu) {
+    ASSERT_TRUE(supportOMAPIReaders() == true);
+    if (mVSReaders.size() > 0) {
+        for (const auto& [name, reader] : mVSReaders) {
+            for (auto apdu : NO_DATA_APDU) {
+                std::vector<uint8_t> response = {};
+                internalTransmitApdu(reader, apdu, response);
+                ASSERT_GE(response.size(), 2);
+                ASSERT_EQ((response[response.size() - 1] & 0xFF), (0x00));
+                ASSERT_EQ((response[response.size() - 2] & 0xFF), (0x90));
+            }
+
+            for (auto apdu : DATA_APDU) {
+                std::vector<uint8_t> response = {};
+                internalTransmitApdu(reader, apdu, response);
+                /* 256 byte data and 2 bytes of status word */
+                ASSERT_GE(response.size(), 258);
+                ASSERT_EQ((response[response.size() - 1] & 0xFF), (0x00));
+                ASSERT_EQ((response[response.size() - 2] & 0xFF), (0x90));
+            }
+        }
+    }
+}
+
+/**
+ * Tests if underlying implementations returns the correct Status Word
+ *
+ * TO verify that :
+ * - the device does not modify the APDU sent to the Secure Element
+ * - the warning code is properly received by the application layer as SW answer
+ * - the verify that the application layer can fetch the additionnal data (when present)
+ */
+TEST_P(OMAPISEServiceHalTest, testStatusWordTransmit) {
+    ASSERT_TRUE(supportOMAPIReaders() == true);
+    if (mVSReaders.size() > 0) {
+        for (const auto& [name, reader] : mVSReaders) {
+            for (auto apdu : SW_62xx_NO_DATA_APDU) {
+                for (uint8_t i = 0x00; i < SW_62xx.size(); i++) {
+                    apdu[2] = i + 1;
+                    std::vector<uint8_t> response = {};
+                    internalTransmitApdu(reader, apdu, response);
+                    std::vector<uint8_t> SW = SW_62xx[i];
+                    ASSERT_GE(response.size(), 2);
+                    ASSERT_EQ(response[response.size() - 1], SW[1]);
+                    ASSERT_EQ(response[response.size() - 2], SW[0]);
+                }
+            }
+
+            for (uint8_t i = 0x00; i < SW_62xx.size(); i++) {
+                std::vector<uint8_t> apdu = SW_62xx_DATA_APDU;
+                apdu[2] = i + 1;
+                std::vector<uint8_t> response = {};
+                internalTransmitApdu(reader, apdu, response);
+                std::vector<uint8_t> SW = SW_62xx[i];
+                ASSERT_GE(response.size(), 3);
+                ASSERT_EQ(response[response.size() - 1], SW[1]);
+                ASSERT_EQ(response[response.size() - 2], SW[0]);
+            }
+
+            for (uint8_t i = 0x00; i < SW_62xx.size(); i++) {
+                std::vector<uint8_t> apdu = SW_62xx_VALIDATE_DATA_APDU;
+                apdu[2] = i + 1;
+                std::vector<uint8_t> response = {};
+                internalTransmitApdu(reader, apdu, response);
+                ASSERT_GE(response.size(), apdu.size() + 2);
+                std::vector<uint8_t> responseSubstring((response.begin() + 0),
+                                                       (response.begin() + apdu.size()));
+                // We should not care about which channel number is actually assigned.
+                responseSubstring[0] = apdu[0];
+                ASSERT_TRUE((responseSubstring == apdu));
+                std::vector<uint8_t> SW = SW_62xx[i];
+                ASSERT_EQ(response[response.size() - 1], SW[1]);
+                ASSERT_EQ(response[response.size() - 2], SW[0]);
+            }
+        }
+    }
+}
+
+/** Test if the responses are segmented by the underlying implementation */
+TEST_P(OMAPISEServiceHalTest, TestSegmentedResponseTransmit) {
+    ASSERT_TRUE(supportOMAPIReaders() == true);
+    if (mVSReaders.size() > 0) {
+        for (const auto& [name, reader] : mVSReaders) {
+            for (auto apdu : SEGMENTED_RESP_APDU) {
+                std::vector<uint8_t> response = {};
+                internalTransmitApdu(reader, apdu, response);
+                int expectedLength = (0x00 << 24) | (0x00 << 16) | (apdu[2] << 8) | apdu[3];
+                ASSERT_EQ(response.size(), (expectedLength + 2));
+                ASSERT_EQ((response[response.size() - 1] & 0xFF), (0x00));
+                ASSERT_EQ((response[response.size() - 2] & 0xFF), (0x90));
+                ASSERT_EQ((response[response.size() - 3] & 0xFF), (0xFF));
+            }
+        }
+    }
+}
+
+/**
+ * Tests the P2 value of the select command.
+ *
+ * Verifies that the default P2 value (0x00) is not modified by the underlying implementation.
+ */
+TEST_P(OMAPISEServiceHalTest, TestP2Value) {
+    ASSERT_TRUE(supportOMAPIReaders() == true);
+    if (mVSReaders.size() > 0) {
+        for (const auto& [name, reader] : mVSReaders) {
+            std::vector<uint8_t> response = {};
+            internalTransmitApdu(reader, CHECK_SELECT_P2_APDU, response);
+            ASSERT_GE(response.size(), 3);
+            ASSERT_EQ((response[response.size() - 1] & 0xFF), (0x00));
+            ASSERT_EQ((response[response.size() - 2] & 0xFF), (0x90));
+            ASSERT_EQ((response[response.size() - 3] & 0xFF), (0x00));
+        }
+    }
+}
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, OMAPISEServiceHalTest,
+                         testing::ValuesIn(::android::getAidlHalInstanceNames(
+                             aidl::android::se::omapi::ISecureElementService::descriptor)),
+                         android::hardware::PrintInstanceNameToString);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(OMAPISEServiceHalTest);
+
+}  // namespace
diff --git a/omapi/java/Android.bp b/omapi/java/Android.bp
new file mode 100644
index 0000000..8d38da0
--- /dev/null
+++ b/omapi/java/Android.bp
@@ -0,0 +1,17 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
+filegroup {
+    name: "framework-omapi-sources",
+    srcs: [
+        "**/*.java",
+        "**/*.aidl",
+    ],
+    visibility: ["//frameworks/base"],
+}
diff --git a/core/java/android/se/OWNERS b/omapi/java/android/se/OWNERS
similarity index 100%
rename from core/java/android/se/OWNERS
rename to omapi/java/android/se/OWNERS
diff --git a/core/java/android/se/omapi/Channel.java b/omapi/java/android/se/omapi/Channel.java
similarity index 100%
rename from core/java/android/se/omapi/Channel.java
rename to omapi/java/android/se/omapi/Channel.java
diff --git a/core/java/android/se/omapi/OWNERS b/omapi/java/android/se/omapi/OWNERS
similarity index 100%
rename from core/java/android/se/omapi/OWNERS
rename to omapi/java/android/se/omapi/OWNERS
diff --git a/core/java/android/se/omapi/Reader.java b/omapi/java/android/se/omapi/Reader.java
similarity index 98%
rename from core/java/android/se/omapi/Reader.java
rename to omapi/java/android/se/omapi/Reader.java
index 90c934d..3c2135d9 100644
--- a/core/java/android/se/omapi/Reader.java
+++ b/omapi/java/android/se/omapi/Reader.java
@@ -170,7 +170,9 @@
             try {
                 closeSessions();
                 return mReader.reset();
-            } catch (RemoteException ignore) {return false;}
+            } catch (RemoteException ignore) {
+                return false;
+            }
         }
     }
 }
diff --git a/core/java/android/se/omapi/SEService.java b/omapi/java/android/se/omapi/SEService.java
similarity index 96%
rename from core/java/android/se/omapi/SEService.java
rename to omapi/java/android/se/omapi/SEService.java
index 333af91..f42ca36 100644
--- a/core/java/android/se/omapi/SEService.java
+++ b/omapi/java/android/se/omapi/SEService.java
@@ -230,20 +230,20 @@
       *         is not exist.
       * @return A Reader object for this uicc slot.
       */
-     public @NonNull Reader getUiccReader(int slotNumber) {
-         if (slotNumber < 1) {
-             throw new IllegalArgumentException("slotNumber should be larger than 0");
-         }
-         loadReaders();
+    public @NonNull Reader getUiccReader(int slotNumber) {
+        if (slotNumber < 1) {
+            throw new IllegalArgumentException("slotNumber should be larger than 0");
+        }
+        loadReaders();
 
-         String readerName = UICC_TERMINAL + slotNumber;
-         Reader reader = mReaders.get(readerName);
+        String readerName = UICC_TERMINAL + slotNumber;
+        Reader reader = mReaders.get(readerName);
 
-         if (reader == null) {
+        if (reader == null) {
             throw new IllegalArgumentException("Reader:" + readerName + " doesn't exist");
-         }
+        }
 
-         return reader;
+        return reader;
     }
 
     /**
diff --git a/core/java/android/se/omapi/Session.java b/omapi/java/android/se/omapi/Session.java
similarity index 100%
rename from core/java/android/se/omapi/Session.java
rename to omapi/java/android/se/omapi/Session.java
diff --git a/packages/PrintSpooler/jni/com_android_printspooler_util_BitmapSerializeUtils.cpp b/packages/PrintSpooler/jni/com_android_printspooler_util_BitmapSerializeUtils.cpp
index 7ff9ced..b2c82c6 100644
--- a/packages/PrintSpooler/jni/com_android_printspooler_util_BitmapSerializeUtils.cpp
+++ b/packages/PrintSpooler/jni/com_android_printspooler_util_BitmapSerializeUtils.cpp
@@ -30,11 +30,8 @@
     char* writeBuffer = static_cast<char*>(buffer);
     size_t remainingBytes = byteCount;
     while (remainingBytes > 0) {
-        ssize_t writtenByteCount = write(fd, writeBuffer, remainingBytes);
+        ssize_t writtenByteCount = TEMP_FAILURE_RETRY(write(fd, writeBuffer, remainingBytes));
         if (writtenByteCount == -1) {
-            if (errno == EINTR) {
-                continue;
-            }
             __android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
                     "Error writing to buffer: %d", errno);
             return false;
@@ -49,19 +46,17 @@
     char* readBuffer = static_cast<char*>(buffer);
     size_t remainingBytes = byteCount;
     while (remainingBytes > 0) {
-        ssize_t readByteCount = read(fd, readBuffer, remainingBytes);
+        ssize_t readByteCount = TEMP_FAILURE_RETRY(read(fd, readBuffer, remainingBytes));
+        if (readByteCount == -1) {
+            __android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
+                    "Error reading from buffer: %d", errno);
+            return false;
+        }
 
         remainingBytes -= readByteCount;
         readBuffer += readByteCount;
 
-        if (readByteCount == -1) {
-            if (errno == EINTR) {
-                continue;
-            }
-            __android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
-                    "Error reading from buffer: %d", errno);
-            return false;
-        } else if (readByteCount == 0 && remainingBytes > 0) {
+        if (readByteCount == 0 && remainingBytes > 0) {
             __android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
                     "File closed before all bytes were read. %zu/%zu remaining", remainingBytes,
                     byteCount);
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index f28d062..bd687e4 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -489,7 +489,7 @@
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Cargando"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Carga rápida"</string>
     <string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Carga lenta"</string>
-    <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Cargando sin cables"</string>
+    <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Carga inalámbrica"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"No se está cargando"</string>
     <string name="battery_info_status_not_charging" msgid="3371084153747234837">"Conectado pero sin cargar"</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"Cargada"</string>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index 73fadf7..ebaf4b1 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -266,7 +266,7 @@
     <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Veuillez vous connecter à un réseau Wi-Fi"</string>
     <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, débogage, développeur"</string>
     <string name="bugreport_in_power" msgid="8664089072534638709">"Raccourci de rapport de bogue"</string>
-    <string name="bugreport_in_power_summary" msgid="1885529649381831775">"Afficher un bouton permettant d\'établir un rapport de bogue dans le menu de démarrage"</string>
+    <string name="bugreport_in_power_summary" msgid="1885529649381831775">"Afficher un bouton permettant d\'établir un rapport de bogue dans le menu de l\'interrupteur"</string>
     <string name="keep_screen_on" msgid="1187161672348797558">"Rester activé"</string>
     <string name="keep_screen_on_summary" msgid="1510731514101925829">"L\'écran ne se met jamais en veille lors du chargement"</string>
     <string name="bt_hci_snoop_log" msgid="7291287955649081448">"Activer le journal HCI Snoop Bluetooth"</string>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index 173588b..0a96f59 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -527,8 +527,8 @@
     <string name="status_unavailable" msgid="5279036186589861608">"Non disponibile"</string>
     <string name="wifi_status_mac_randomized" msgid="466382542497832189">"Selezione casuale dell\'indirizzo MAC"</string>
     <plurals name="wifi_tether_connected_summary" formatted="false" msgid="6317236306047306139">
+      <item quantity="one">%1$d devices connected</item>
       <item quantity="other">%1$d dispositivi connessi</item>
-      <item quantity="one">%1$d dispositivo connesso</item>
     </plurals>
     <string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"Più tempo."</string>
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Meno tempo."</string>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index ebe5753..5a0ec2e 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -527,8 +527,8 @@
     <string name="status_unavailable" msgid="5279036186589861608">"Indisponível"</string>
     <string name="wifi_status_mac_randomized" msgid="466382542497832189">"O MAC é aleatório."</string>
     <plurals name="wifi_tether_connected_summary" formatted="false" msgid="6317236306047306139">
-      <item quantity="other">%1$d dispositivos ligados</item>
       <item quantity="one">%1$d dispositivo ligado</item>
+      <item quantity="other">%1$d dispositivos ligados</item>
     </plurals>
     <string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"Mais tempo."</string>
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Menos tempo."</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
index 58d2185..1df1bce 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
@@ -160,10 +160,12 @@
     private void registerIntentReceiver(BroadcastReceiver receiver, IntentFilter filter) {
         if (mUserHandle == null) {
             // If userHandle has not been provided, simply call registerReceiver.
-            mContext.registerReceiver(receiver, filter, null, mReceiverHandler);
+            mContext.registerReceiver(receiver, filter, null, mReceiverHandler,
+                    Context.RECEIVER_EXPORTED);
         } else {
             // userHandle was explicitly specified, so need to call multi-user aware API.
-            mContext.registerReceiverAsUser(receiver, mUserHandle, filter, null, mReceiverHandler);
+            mContext.registerReceiverAsUser(receiver, mUserHandle, filter, null, mReceiverHandler,
+                    Context.RECEIVER_EXPORTED);
         }
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryStatus.java b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryStatus.java
index b3205d7..b56ae38 100644
--- a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryStatus.java
+++ b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryStatus.java
@@ -109,6 +109,15 @@
     }
 
     /**
+     * Determine whether the device is plugged in wireless.
+     *
+     * @return true if the device is plugged in wireless
+     */
+    public boolean isPluggedInWireless() {
+        return plugged == BatteryManager.BATTERY_PLUGGED_WIRELESS;
+    }
+
+    /**
      * Whether or not the device is charged. Note that some devices never return 100% for
      * battery level, so this allows either battery level or status to determine if the
      * battery is charged.
diff --git a/packages/SettingsLib/src/com/android/settingslib/notification/EnableZenModeDialog.java b/packages/SettingsLib/src/com/android/settingslib/notification/EnableZenModeDialog.java
index a210e90..8b17be1 100644
--- a/packages/SettingsLib/src/com/android/settingslib/notification/EnableZenModeDialog.java
+++ b/packages/SettingsLib/src/com/android/settingslib/notification/EnableZenModeDialog.java
@@ -19,7 +19,6 @@
 import android.app.ActivityManager;
 import android.app.AlarmManager;
 import android.app.AlertDialog;
-import android.app.Dialog;
 import android.app.NotificationManager;
 import android.content.Context;
 import android.content.DialogInterface;
@@ -85,6 +84,7 @@
 
     @VisibleForTesting
     protected Context mContext;
+    private final int mThemeResId;
     @VisibleForTesting
     protected TextView mZenAlarmWarning;
     @VisibleForTesting
@@ -97,10 +97,15 @@
     protected LayoutInflater mLayoutInflater;
 
     public EnableZenModeDialog(Context context) {
-        mContext = context;
+        this(context, 0);
     }
 
-    public Dialog createDialog() {
+    public EnableZenModeDialog(Context context, int themeResId) {
+        mContext = context;
+        mThemeResId = themeResId;
+    }
+
+    public AlertDialog createDialog() {
         mNotificationManager = (NotificationManager) mContext.
                 getSystemService(Context.NOTIFICATION_SERVICE);
         mForeverId =  Condition.newId(mContext).appendPath("forever").build();
@@ -108,7 +113,7 @@
         mUserId = mContext.getUserId();
         mAttached = false;
 
-        final AlertDialog.Builder builder = new AlertDialog.Builder(mContext)
+        final AlertDialog.Builder builder = new AlertDialog.Builder(mContext, mThemeResId)
                 .setTitle(R.string.zen_mode_settings_turn_on_dialog_title)
                 .setNegativeButton(R.string.cancel, null)
                 .setPositiveButton(R.string.zen_mode_enable_dialog_turn_on,
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index 1c7c19f..4e2111c 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -193,5 +193,6 @@
         Settings.Secure.LOCKSCREEN_SHOW_CONTROLS,
         Settings.Secure.LOCKSCREEN_SHOW_WALLET,
         Settings.Secure.LOCK_SCREEN_SHOW_QR_CODE_SCANNER,
+        Settings.Secure.LOCKSCREEN_USE_DOUBLE_LINE_CLOCK,
     };
 }
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
index 0fe4efe..a944bf5 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
@@ -80,6 +80,7 @@
         Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
         Settings.System.RING_VIBRATION_INTENSITY,
         Settings.System.HAPTIC_FEEDBACK_INTENSITY,
+        Settings.System.HARDWARE_HAPTIC_FEEDBACK_INTENSITY,
         Settings.System.DISPLAY_COLOR_MODE_VENDOR_HINT, // must precede DISPLAY_COLOR_MODE
         Settings.System.DISPLAY_COLOR_MODE,
         Settings.System.ALARM_ALERT,
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
index bf62f1d..a10b819 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
@@ -262,7 +262,6 @@
         VALIDATORS.put(Global.Wearable.AMBIENT_TOUCH_TO_WAKE, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Global.Wearable.DECOMPOSABLE_WATCHFACE, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Global.Wearable.AMBIENT_FORCE_WHEN_DOCKED, BOOLEAN_VALIDATOR);
-        VALIDATORS.put(Global.Wearable.AMBIENT_GESTURE_SENSOR_ID, ANY_INTEGER_VALIDATOR);
         VALIDATORS.put(Global.Wearable.AMBIENT_LOW_BIT_ENABLED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Global.Wearable.AMBIENT_PLUGGED_TIMEOUT_MIN, ANY_INTEGER_VALIDATOR);
         VALIDATORS.put(Global.Wearable.AMBIENT_TILT_TO_BRIGHT, BOOLEAN_VALIDATOR);
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index 3a5ead3..dd1cb6b 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -154,6 +154,7 @@
         VALIDATORS.put(Secure.LOCKSCREEN_SHOW_CONTROLS, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.LOCKSCREEN_SHOW_WALLET, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.LOCK_SCREEN_SHOW_QR_CODE_SCANNER, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.LOCKSCREEN_USE_DOUBLE_LINE_CLOCK, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.DOZE_ENABLED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.DOZE_ALWAYS_ON, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.DOZE_PICK_UP_GESTURE, BOOLEAN_VALIDATOR);
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
index 462c3a5..63acffb 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
@@ -120,6 +120,7 @@
         VALIDATORS.put(System.NOTIFICATION_VIBRATION_INTENSITY, VIBRATION_INTENSITY_VALIDATOR);
         VALIDATORS.put(System.RING_VIBRATION_INTENSITY, VIBRATION_INTENSITY_VALIDATOR);
         VALIDATORS.put(System.HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_VALIDATOR);
+        VALIDATORS.put(System.HARDWARE_HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_VALIDATOR);
         VALIDATORS.put(System.RINGTONE, URI_VALIDATOR);
         VALIDATORS.put(System.NOTIFICATION_SOUND, URI_VALIDATOR);
         VALIDATORS.put(System.ALARM_ALERT, URI_VALIDATOR);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index aca70f1..ce7517f 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -5325,9 +5325,6 @@
                             Settings.Global.Wearable.AMBIENT_FORCE_WHEN_DOCKED,
                             SystemProperties.getBoolean("ro.ambient.force_when_docked", false));
                     initGlobalSettingsDefaultValForWearLocked(
-                            Settings.Global.Wearable.AMBIENT_GESTURE_SENSOR_ID,
-                            SystemProperties.getInt("ro.ambient.gesture_sensor_id", 0));
-                    initGlobalSettingsDefaultValForWearLocked(
                             Settings.Global.Wearable.AMBIENT_LOW_BIT_ENABLED,
                             SystemProperties.getBoolean("ro.ambient.low_bit_enabled", false));
                     initGlobalSettingsDefaultValForWearLocked(
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 324c05e..c9c93c4 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -640,7 +640,6 @@
                     Settings.Global.Wearable.AMBIENT_TILT_TO_BRIGHT,
                     Settings.Global.Wearable.DECOMPOSABLE_WATCHFACE,
                     Settings.Global.Wearable.AMBIENT_FORCE_WHEN_DOCKED,
-                    Settings.Global.Wearable.AMBIENT_GESTURE_SENSOR_ID,
                     Settings.Global.Wearable.AMBIENT_LOW_BIT_ENABLED,
                     Settings.Global.Wearable.AMBIENT_PLUGGED_TIMEOUT_MIN,
                     Settings.Global.Wearable.PAIRED_DEVICE_OS_TYPE,
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index f59f099..abd010d 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -589,6 +589,9 @@
     <!-- Permission required to run GtsAssistantTestCases -->
     <uses-permission android:name="android.permission.MANAGE_VOICE_KEYPHRASES" />
 
+    <!-- Permission required for CTS test - SettingsMultiPaneDeepLinkTest -->
+    <uses-permission android:name="android.permission.LAUNCH_MULTI_PANE_SETTINGS_DEEP_LINK" />
+
     <application android:label="@string/app_label"
                 android:theme="@android:style/Theme.DeviceDefault.DayNight"
                 android:defaultToDeviceProtectedStorage="true"
diff --git a/packages/SystemUI/animation/res/values/ids.xml b/packages/SystemUI/animation/res/values/ids.xml
index ef60a24..c4cb89f 100644
--- a/packages/SystemUI/animation/res/values/ids.xml
+++ b/packages/SystemUI/animation/res/values/ids.xml
@@ -16,4 +16,5 @@
 -->
 <resources>
     <item type="id" name="launch_animation_running"/>
+    <item type="id" name="dialog_content_parent" />
 </resources>
\ No newline at end of file
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt
index 413612f..9aad278 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt
@@ -40,6 +40,7 @@
 import kotlin.math.roundToInt
 
 private const val TAG = "DialogLaunchAnimator"
+private val DIALOG_CONTENT_PARENT_ID = R.id.dialog_content_parent
 
 /**
  * A class that allows dialogs to be started in a seamless way from a view that is transforming
@@ -86,10 +87,10 @@
         // If the parent of the view we are launching from is the background of some other animated
         // dialog, then this means the caller intent is to launch a dialog from another dialog. In
         // this case, we also animate the parent (which is the dialog background).
-        val dialogContentParent = openedDialogs
+        val animatedParent = openedDialogs
             .firstOrNull { it.dialogContentParent == view.parent }
-            ?.dialogContentParent
-        val animateFrom = dialogContentParent ?: view
+        val parentHostDialog = animatedParent?.hostDialog
+        val animateFrom = animatedParent?.dialogContentParent ?: view
 
         // Make sure we don't run the launch animation from the same view twice at the same time.
         if (animateFrom.getTag(TAG_LAUNCH_ANIMATION_RUNNING) != null) {
@@ -100,12 +101,18 @@
 
         animateFrom.setTag(TAG_LAUNCH_ANIMATION_RUNNING, true)
 
-        val launchAnimation = AnimatedDialog(
-            context, launchAnimator, hostDialogProvider, animateFrom,
-            onDialogDismissed = { openedDialogs.remove(it) }, originalDialog = dialog,
-            animateBackgroundBoundsChange)
-        val hostDialog = launchAnimation.hostDialog
-        openedDialogs.add(launchAnimation)
+        val animatedDialog = AnimatedDialog(
+                context,
+                launchAnimator,
+                hostDialogProvider,
+                animateFrom,
+                onDialogDismissed = { openedDialogs.remove(it) },
+                originalDialog = dialog,
+                animateBackgroundBoundsChange,
+                openedDialogs.firstOrNull { it.hostDialog == parentHostDialog }
+        )
+        val hostDialog = animatedDialog.hostDialog
+        openedDialogs.add(animatedDialog)
 
         // If the dialog is dismissed/hidden/shown, then we should actually dismiss/hide/show the
         // host dialog.
@@ -119,15 +126,15 @@
                     // If AOD is disabled the screen will directly becomes black and we won't see
                     // the animation anyways.
                     if (reason == DialogListener.DismissReason.DEVICE_LOCKED) {
-                        launchAnimation.exitAnimationDisabled = true
+                        animatedDialog.exitAnimationDisabled = true
                     }
 
                     hostDialog.dismiss()
                 }
 
                 override fun onHide() {
-                    if (launchAnimation.ignoreNextCallToHide) {
-                        launchAnimation.ignoreNextCallToHide = false
+                    if (animatedDialog.ignoreNextCallToHide) {
+                        animatedDialog.ignoreNextCallToHide = false
                         return
                     }
 
@@ -138,21 +145,44 @@
                     hostDialog.show()
 
                     // We don't actually want to show the original dialog, so hide it.
-                    launchAnimation.ignoreNextCallToHide = true
+                    animatedDialog.ignoreNextCallToHide = true
                     dialog.hide()
                 }
 
                 override fun onSizeChanged() {
-                    launchAnimation.onOriginalDialogSizeChanged()
+                    animatedDialog.onOriginalDialogSizeChanged()
+                }
+
+                override fun prepareForStackDismiss() {
+                    animatedDialog.touchSurface = animatedDialog.prepareForStackDismiss()
                 }
             })
         }
 
-        launchAnimation.start()
+        animatedDialog.start()
         return hostDialog
     }
 
     /**
+     * Launch [dialog] from a [parentHostDialog] as returned by [showFromView]. This will allow
+     * for dismissing the whole stack.
+     *
+     * This will return a new host dialog, with the same caveat as [showFromView].
+     *
+     * @see DialogListener.prepareForStackDismiss
+     */
+    fun showFromDialog(
+        dialog: Dialog,
+        parentHostDialog: Dialog,
+        animateBackgroundBoundsChange: Boolean = false
+    ): Dialog {
+        val view = parentHostDialog.findViewById<ViewGroup>(DIALOG_CONTENT_PARENT_ID)
+                ?.getChildAt(0)
+                ?: throw IllegalStateException("No dialog content parent found in host dialog")
+        return showFromView(dialog, view, animateBackgroundBoundsChange)
+    }
+
+    /**
      * Ensure that all dialogs currently shown won't animate into their touch surface when
      * dismissed.
      *
@@ -214,6 +244,12 @@
     /** Called when this dialog show() is called. */
     fun onShow()
 
+    /**
+     * Call before dismissing a stack of dialogs (dialogs launched from dialogs), so the topmost
+     * can animate directly into the original `touchSurface`.
+     */
+    fun prepareForStackDismiss()
+
     /** Called when this dialog size might have changed, e.g. because of configuration changes. */
     fun onSizeChanged()
 }
@@ -224,7 +260,7 @@
     hostDialogProvider: HostDialogProvider,
 
     /** The view that triggered the dialog after being tapped. */
-    private val touchSurface: View,
+    var touchSurface: View,
 
     /**
      * A callback that will be called with this [AnimatedDialog] after the dialog was
@@ -236,7 +272,10 @@
     private val originalDialog: Dialog,
 
     /** Whether we should animate the dialog background when its bounds change. */
-    private val animateBackgroundBoundsChange: Boolean
+    private val animateBackgroundBoundsChange: Boolean,
+
+    /** Launch animation corresponding to the parent [hostDialog]. */
+    private val parentAnimatedDialog: AnimatedDialog? = null
 ) {
     /**
      * The fullscreen dialog to which we will add the content view [originalDialogView] of
@@ -253,7 +292,9 @@
      * the same size as the original dialog window and to which we will set the original dialog
      * window background.
      */
-    val dialogContentParent = FrameLayout(context)
+    val dialogContentParent = FrameLayout(context).apply {
+        id = DIALOG_CONTENT_PARENT_ID
+    }
 
     /**
      * The background color of [originalDialogView], taking into consideration the [originalDialog]
@@ -359,9 +400,7 @@
         // Make the touch surface invisible and make sure that it stays invisible as long as the
         // dialog is shown or animating.
         touchSurface.visibility = View.INVISIBLE
-        if (touchSurface is LaunchableView) {
-            touchSurface.setShouldBlockVisibilityChanges(true)
-        }
+        (touchSurface as? LaunchableView)?.setShouldBlockVisibilityChanges(true)
 
         // Add a pre draw listener to (maybe) start the animation once the touch surface is
         // actually invisible.
@@ -576,9 +615,7 @@
             Log.i(TAG, "Skipping animation of dialog into the touch surface")
 
             // Make sure we allow the touch surface to change its visibility again.
-            if (touchSurface is LaunchableView) {
-                touchSurface.setShouldBlockVisibilityChanges(false)
-            }
+            (touchSurface as? LaunchableView)?.setShouldBlockVisibilityChanges(false)
 
             // If the view is invisible it's probably because of us, so we make it visible again.
             if (touchSurface.visibility == View.INVISIBLE) {
@@ -598,9 +635,7 @@
             },
             onLaunchAnimationEnd = {
                 // Make sure we allow the touch surface to change its visibility again.
-                if (touchSurface is LaunchableView) {
-                    touchSurface.setShouldBlockVisibilityChanges(false)
-                }
+                (touchSurface as? LaunchableView)?.setShouldBlockVisibilityChanges(false)
 
                 touchSurface.visibility = View.VISIBLE
                 dialogContentParent.visibility = View.INVISIBLE
@@ -796,4 +831,18 @@
             animator.start()
         }
     }
+
+    fun prepareForStackDismiss(): View {
+        if (parentAnimatedDialog == null) {
+            return touchSurface
+        }
+        parentAnimatedDialog.exitAnimationDisabled = true
+        parentAnimatedDialog.originalDialog.hide()
+        val view = parentAnimatedDialog.prepareForStackDismiss()
+        parentAnimatedDialog.originalDialog.dismiss()
+        // Make the touch surface invisible, so we end up animating to it when we actually
+        // dismiss the stack
+        view.visibility = View.INVISIBLE
+        return view
+    }
 }
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt
index 3ccf5e4..5fec4cc 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt
@@ -53,8 +53,12 @@
     private val ghostedView: View,
 
     /** The [InteractionJankMonitor.CujType] associated to this animation. */
-    private val cujType: Int? = null
+    private val cujType: Int? = null,
+    private var interactionJankMonitor: InteractionJankMonitor? = null
 ) : ActivityLaunchAnimator.Controller {
+
+    constructor(view: View, type: Int) : this(view, type, null)
+
     /** The container to which we will add the ghost view and expanding background. */
     override var launchContainer = ghostedView.rootView as ViewGroup
     private val launchContainerOverlay: ViewGroupOverlay
@@ -170,7 +174,7 @@
         val matrix = ghostView?.animationMatrix ?: Matrix.IDENTITY_MATRIX
         matrix.getValues(initialGhostViewMatrixValues)
 
-        cujType?.let { InteractionJankMonitor.getInstance().begin(ghostedView, it) }
+        cujType?.let { interactionJankMonitor?.begin(ghostedView, it) }
     }
 
     override fun onLaunchAnimationProgress(
@@ -251,7 +255,7 @@
             return
         }
 
-        cujType?.let { InteractionJankMonitor.getInstance().end(it) }
+        cujType?.let { interactionJankMonitor?.end(it) }
 
         backgroundDrawable?.wrapped?.alpha = startBackgroundAlpha
 
diff --git a/packages/SystemUI/res-keyguard/values-it/strings.xml b/packages/SystemUI/res-keyguard/values-it/strings.xml
index 985f952..337d433 100644
--- a/packages/SystemUI/res-keyguard/values-it/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-it/strings.xml
@@ -53,8 +53,8 @@
     <string name="kg_wrong_password" msgid="4143127991071670512">"Password errata"</string>
     <string name="kg_wrong_pin" msgid="4160978845968732624">"PIN errato"</string>
     <plurals name="kg_too_many_failed_attempts_countdown" formatted="false" msgid="991400408675793914">
+      <item quantity="one">Try again in <xliff:g id="NUMBER">%d</xliff:g> seconds.</item>
       <item quantity="other">Riprova fra <xliff:g id="NUMBER">%d</xliff:g> secondi.</item>
-      <item quantity="one">Riprova fra 1 secondo.</item>
     </plurals>
     <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Inserisci il PIN della SIM."</string>
     <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Inserisci il PIN della SIM \"<xliff:g id="CARRIER">%1$s</xliff:g>\"."</string>
@@ -71,13 +71,13 @@
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"<xliff:g id="NUMBER_0">%1$d</xliff:g> tentativi errati di inserimento della sequenza di sblocco. \n\nRiprova tra <xliff:g id="NUMBER_1">%2$d</xliff:g> secondi."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Codice PIN della SIM errato. Devi contattare l\'operatore per sbloccare il dispositivo."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
+      <item quantity="one">Incorrect SIM PIN code, you have <xliff:g id="NUMBER_1">%d</xliff:g> remaining attempts.</item>
       <item quantity="other">Codice PIN della SIM errato. Hai ancora <xliff:g id="NUMBER_1">%d</xliff:g> tentativi a disposizione.</item>
-      <item quantity="one">Codice PIN della SIM errato. Hai ancora <xliff:g id="NUMBER_0">%d</xliff:g> tentativo a disposizione, dopodiché dovrai contattare l\'operatore per sbloccare il dispositivo.</item>
     </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="3698285357028468617">"SIM inutilizzabile. Contatta il tuo operatore."</string>
     <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="3937306685604862886">
+      <item quantity="one">Incorrect SIM PUK code, you have <xliff:g id="NUMBER_1">%d</xliff:g> remaining attempts before SIM becomes permanently unusable.</item>
       <item quantity="other">Codice PUK della SIM errato. Hai ancora <xliff:g id="NUMBER_1">%d</xliff:g> tentativi a disposizione prima che la SIM diventi definitivamente inutilizzabile.</item>
-      <item quantity="one">Codice PUK della SIM errato. Hai ancora <xliff:g id="NUMBER_0">%d</xliff:g> tentativo a disposizione prima che la SIM diventi definitivamente inutilizzabile.</item>
     </plurals>
     <string name="kg_password_pin_failed" msgid="5136259126330604009">"Operazione con PIN della SIM non riuscita."</string>
     <string name="kg_password_puk_failed" msgid="6778867411556937118">"Operazione con PUK della SIM non riuscita."</string>
@@ -94,12 +94,12 @@
     <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"Non riconosciuto"</string>
     <string name="kg_face_not_recognized" msgid="7903950626744419160">"Non riconosciuto"</string>
     <plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
+      <item quantity="one">Enter SIM PIN. You have <xliff:g id="NUMBER_1">%d</xliff:g> remaining attempts.</item>
       <item quantity="other">Inserisci il codice PIN della SIM. Hai ancora <xliff:g id="NUMBER_1">%d</xliff:g> tentativi a disposizione.</item>
-      <item quantity="one">Inserisci il codice PIN della SIM. Hai ancora <xliff:g id="NUMBER_0">%d</xliff:g> tentativo a disposizione, dopodiché dovrai contattare l\'operatore per sbloccare il dispositivo.</item>
     </plurals>
     <plurals name="kg_password_default_puk_message" formatted="false" msgid="571308542462946935">
+      <item quantity="one">SIM is now disabled. Enter PUK code to continue. You have <xliff:g id="_NUMBER_1">%d</xliff:g> remaining attempts before SIM becomes permanently unusable. Contact carrier for details.</item>
       <item quantity="other">La scheda SIM è ora disattivata. Inserisci il codice PUK per continuare. Hai ancora <xliff:g id="_NUMBER_1">%d</xliff:g> tentativi a disposizione prima che la SIM diventi definitivamente inutilizzabile. Per informazioni dettagliate, contatta l\'operatore.</item>
-      <item quantity="one">La scheda SIM è ora disattivata. Inserisci il codice PUK per continuare. Hai ancora <xliff:g id="_NUMBER_0">%d</xliff:g> tentativo a disposizione prima che la SIM diventi definitivamente inutilizzabile. Per informazioni dettagliate, contatta l\'operatore.</item>
     </plurals>
     <string name="clock_title_default" msgid="6342735240617459864">"Predefinito"</string>
     <string name="clock_title_bubble" msgid="2204559396790593213">"Bolla"</string>
diff --git a/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml b/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml
index 5b0da18..da663f0 100644
--- a/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml
@@ -53,8 +53,8 @@
     <string name="kg_wrong_password" msgid="4143127991071670512">"Palavra-passe incorreta."</string>
     <string name="kg_wrong_pin" msgid="4160978845968732624">"PIN incorreto"</string>
     <plurals name="kg_too_many_failed_attempts_countdown" formatted="false" msgid="991400408675793914">
-      <item quantity="other">Tente novamente dentro de <xliff:g id="NUMBER">%d</xliff:g> segundos.</item>
       <item quantity="one">Tente novamente dentro de 1 segundo.</item>
+      <item quantity="other">Tente novamente dentro de <xliff:g id="NUMBER">%d</xliff:g> segundos.</item>
     </plurals>
     <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Introduza o PIN do cartão SIM."</string>
     <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Introduza o PIN do cartão SIM \"<xliff:g id="CARRIER">%1$s</xliff:g>\"."</string>
@@ -71,13 +71,13 @@
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Desenhou a sua padrão de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. \n\nTente novamente dentro de <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Código PIN do cartão SIM incorreto. Tem de contactar o seu operador para desbloquear o dispositivo."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
-      <item quantity="other">Código PIN do cartão SIM incorreto. Tem mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas.</item>
       <item quantity="one">Código PIN do cartão SIM incorreto. Tem mais <xliff:g id="NUMBER_0">%d</xliff:g> tentativa antes de precisar de contactar o seu operador para desbloquear o dispositivo.</item>
+      <item quantity="other">Código PIN do cartão SIM incorreto. Tem mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas.</item>
     </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="3698285357028468617">"Cartão SIM inutilizável. Contacte o seu operador."</string>
     <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="3937306685604862886">
-      <item quantity="other">Código PUK do cartão SIM incorreto. Tem mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas antes de o cartão SIM ficar permanentemente inutilizável.</item>
       <item quantity="one">Código PUK do cartão SIM incorreto. Tem mais <xliff:g id="NUMBER_0">%d</xliff:g> tentativa antes de o cartão SIM ficar permanentemente inutilizável.</item>
+      <item quantity="other">Código PUK do cartão SIM incorreto. Tem mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas antes de o cartão SIM ficar permanentemente inutilizável.</item>
     </plurals>
     <string name="kg_password_pin_failed" msgid="5136259126330604009">"Falha ao introduzir o PIN do cartão SIM!"</string>
     <string name="kg_password_puk_failed" msgid="6778867411556937118">"Falha ao introduzir o PUK do cartão SIM!"</string>
@@ -94,12 +94,12 @@
     <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"Não reconhecido."</string>
     <string name="kg_face_not_recognized" msgid="7903950626744419160">"Não reconhecido."</string>
     <plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
-      <item quantity="other">Introduza o PIN do cartão SIM. Tem mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas.</item>
       <item quantity="one">Introduza o PIN do cartão SIM. Tem mais <xliff:g id="NUMBER_0">%d</xliff:g> tentativa antes de ser necessário contactar o operador para desbloquear o dispositivo.</item>
+      <item quantity="other">Introduza o PIN do cartão SIM. Tem mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas.</item>
     </plurals>
     <plurals name="kg_password_default_puk_message" formatted="false" msgid="571308542462946935">
-      <item quantity="other">O SIM encontra-se desativado. Introduza o código PUK para continuar. Tem mais <xliff:g id="_NUMBER_1">%d</xliff:g> tentativas antes de o cartão SIM ficar permanentemente inutilizável. Contacte o operador para obter mais detalhes.</item>
       <item quantity="one">O SIM encontra-se desativado. Introduza o código PUK para continuar. Tem mais <xliff:g id="_NUMBER_0">%d</xliff:g> tentativa antes de o cartão SIM ficar permanentemente inutilizável. Contacte o operador para obter mais detalhes.</item>
+      <item quantity="other">O SIM encontra-se desativado. Introduza o código PUK para continuar. Tem mais <xliff:g id="_NUMBER_1">%d</xliff:g> tentativas antes de o cartão SIM ficar permanentemente inutilizável. Contacte o operador para obter mais detalhes.</item>
     </plurals>
     <string name="clock_title_default" msgid="6342735240617459864">"Predefinido"</string>
     <string name="clock_title_bubble" msgid="2204559396790593213">"Balão"</string>
diff --git a/packages/SystemUI/res/drawable/qs_dialog_btn_filled.xml b/packages/SystemUI/res/drawable/qs_dialog_btn_filled.xml
index 1a128df..14cb1de9 100644
--- a/packages/SystemUI/res/drawable/qs_dialog_btn_filled.xml
+++ b/packages/SystemUI/res/drawable/qs_dialog_btn_filled.xml
@@ -16,8 +16,8 @@
   -->
 <inset xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
-       android:insetTop="@dimen/qs_dialog_button_vertical_inset"
-       android:insetBottom="@dimen/qs_dialog_button_vertical_inset">
+       android:insetTop="@dimen/dialog_button_vertical_inset"
+       android:insetBottom="@dimen/dialog_button_vertical_inset">
     <ripple android:color="?android:attr/colorControlHighlight">
         <item android:id="@android:id/mask">
             <shape android:shape="rectangle">
@@ -29,10 +29,10 @@
             <shape android:shape="rectangle">
                 <corners android:radius="?android:attr/buttonCornerRadius"/>
                 <solid android:color="?androidprv:attr/colorAccentPrimary"/>
-                <padding android:left="@dimen/qs_dialog_button_horizontal_padding"
-                         android:top="@dimen/qs_dialog_button_vertical_padding"
-                         android:right="@dimen/qs_dialog_button_horizontal_padding"
-                         android:bottom="@dimen/qs_dialog_button_vertical_padding"/>
+                <padding android:left="@dimen/dialog_button_horizontal_padding"
+                         android:top="@dimen/dialog_button_vertical_padding"
+                         android:right="@dimen/dialog_button_horizontal_padding"
+                         android:bottom="@dimen/dialog_button_vertical_padding"/>
             </shape>
         </item>
     </ripple>
diff --git a/packages/SystemUI/res/drawable/qs_dialog_btn_outline.xml b/packages/SystemUI/res/drawable/qs_dialog_btn_outline.xml
index 467c20f..665b456 100644
--- a/packages/SystemUI/res/drawable/qs_dialog_btn_outline.xml
+++ b/packages/SystemUI/res/drawable/qs_dialog_btn_outline.xml
@@ -16,8 +16,8 @@
   -->
 <inset xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
-       android:insetTop="@dimen/qs_dialog_button_vertical_inset"
-       android:insetBottom="@dimen/qs_dialog_button_vertical_inset">
+       android:insetTop="@dimen/dialog_button_vertical_inset"
+       android:insetBottom="@dimen/dialog_button_vertical_inset">
     <ripple android:color="?android:attr/colorControlHighlight">
         <item android:id="@android:id/mask">
             <shape android:shape="rectangle">
@@ -32,10 +32,10 @@
                 <stroke android:color="?androidprv:attr/colorAccentPrimary"
                         android:width="1dp"
                 />
-                <padding android:left="@dimen/qs_dialog_button_horizontal_padding"
-                         android:top="@dimen/qs_dialog_button_vertical_padding"
-                         android:right="@dimen/qs_dialog_button_horizontal_padding"
-                         android:bottom="@dimen/qs_dialog_button_vertical_padding"/>
+                <padding android:left="@dimen/dialog_button_horizontal_padding"
+                         android:top="@dimen/dialog_button_vertical_padding"
+                         android:right="@dimen/dialog_button_horizontal_padding"
+                         android:bottom="@dimen/dialog_button_vertical_padding"/>
             </shape>
         </item>
     </ripple>
diff --git a/packages/SystemUI/res/layout-land-television/volume_dialog_row.xml b/packages/SystemUI/res/layout-land-television/volume_dialog_row.xml
index 0dec981..991dc63e 100644
--- a/packages/SystemUI/res/layout-land-television/volume_dialog_row.xml
+++ b/packages/SystemUI/res/layout-land-television/volume_dialog_row.xml
@@ -35,7 +35,7 @@
             android:id="@+id/volume_number"
             android:layout_width="@dimen/tv_volume_dialog_bubble_size"
             android:layout_height="@dimen/tv_volume_dialog_bubble_size"
-            android:maxLength="2"
+            android:maxLength="3"
             android:gravity="center"
             android:fontFeatureSettings="tnum"
             android:background="@drawable/tv_volume_dialog_circle"
diff --git a/packages/SystemUI/res/layout/alert_dialog_button_bar_systemui.xml b/packages/SystemUI/res/layout/alert_dialog_button_bar_systemui.xml
new file mode 100644
index 0000000..a3e289a
--- /dev/null
+++ b/packages/SystemUI/res/layout/alert_dialog_button_bar_systemui.xml
@@ -0,0 +1,63 @@
+<?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.
+  -->
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@*android:id/buttonPanel"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:scrollbarAlwaysDrawVerticalTrack="true"
+    android:scrollIndicators="top|bottom"
+    android:fillViewport="true"
+    android:paddingTop="@dimen/dialog_button_bar_top_padding"
+    android:paddingStart="@dimen/dialog_side_padding"
+    android:paddingEnd="@dimen/dialog_side_padding"
+    android:paddingBottom="@dimen/dialog_bottom_padding"
+    style="?android:attr/buttonBarStyle">
+    <com.android.internal.widget.ButtonBarLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layoutDirection="locale"
+        android:orientation="horizontal"
+        android:gravity="bottom">
+
+        <Button
+            android:id="@android:id/button3"
+            style="?android:attr/buttonBarNeutralButtonStyle"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content" />
+
+        <Space
+            android:id="@*android:id/spacer"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:layout_weight="1"
+            android:visibility="invisible" />
+
+        <Button
+            android:id="@android:id/button2"
+            style="?android:attr/buttonBarNegativeButtonStyle"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content" />
+
+        <Button
+            android:id="@android:id/button1"
+            style="?android:attr/buttonBarPositiveButtonStyle"
+            android:layout_marginStart="8dp"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content" />
+    </com.android.internal.widget.ButtonBarLayout>
+</ScrollView>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/alert_dialog_systemui.xml b/packages/SystemUI/res/layout/alert_dialog_systemui.xml
new file mode 100644
index 0000000..f280cbd
--- /dev/null
+++ b/packages/SystemUI/res/layout/alert_dialog_systemui.xml
@@ -0,0 +1,91 @@
+<?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.internal.widget.AlertDialogLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@*android:id/parentPanel"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:gravity="center_horizontal|top"
+    android:orientation="vertical"
+    android:paddingTop="@dimen/dialog_top_padding"
+    >
+
+    <include layout="@layout/alert_dialog_title_systemui" />
+
+    <FrameLayout
+        android:id="@*android:id/contentPanel"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:minHeight="48dp"
+        android:paddingStart="@dimen/dialog_side_padding"
+        android:paddingEnd="@dimen/dialog_side_padding"
+        >
+
+        <ScrollView
+            android:id="@*android:id/scrollView"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:clipToPadding="false">
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="vertical">
+
+                <Space
+                    android:id="@*android:id/textSpacerNoTitle"
+                    android:visibility="gone"
+                    android:layout_width="match_parent"
+                    android:layout_height="0dp" />
+
+                <TextView
+                    android:id="@*android:id/message"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    style="@style/TextAppearance.Dialog.Body.Message" />
+
+                <Space
+                    android:id="@*android:id/textSpacerNoButtons"
+                    android:visibility="gone"
+                    android:layout_width="match_parent"
+                    android:layout_height="6dp" />
+            </LinearLayout>
+        </ScrollView>
+    </FrameLayout>
+
+    <FrameLayout
+        android:id="@*android:id/customPanel"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:minHeight="48dp"
+        android:paddingStart="@dimen/dialog_side_padding"
+        android:paddingEnd="@dimen/dialog_side_padding"
+        >
+
+        <FrameLayout
+            android:id="@*android:id/custom"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content" />
+    </FrameLayout>
+
+    <include
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        layout="@layout/alert_dialog_button_bar_systemui" />
+
+</com.android.internal.widget.AlertDialogLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/alert_dialog_title_systemui.xml b/packages/SystemUI/res/layout/alert_dialog_title_systemui.xml
new file mode 100644
index 0000000..480ba00
--- /dev/null
+++ b/packages/SystemUI/res/layout/alert_dialog_title_systemui.xml
@@ -0,0 +1,63 @@
+<?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.
+  -->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+    android:id="@*android:id/topPanel"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical"
+    android:paddingStart="@dimen/dialog_side_padding"
+    android:paddingEnd="@dimen/dialog_side_padding"
+>
+
+    <!-- If the client uses a customTitle, it will be added here. -->
+
+    <LinearLayout
+        android:id="@*android:id/title_template"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical"
+        android:gravity="center_horizontal|top">
+
+        <ImageView
+            android:id="@*android:id/icon"
+            android:layout_width="32dp"
+            android:layout_height="32dp"
+            android:layout_marginBottom="16dp"
+            android:scaleType="fitCenter"
+            android:src="@null"
+            android:tint="?androidprv:attr/colorAccentPrimaryVariant"
+            />
+
+        <com.android.internal.widget.DialogTitle
+            android:id="@*android:id/alertTitle"
+            android:singleLine="true"
+            android:ellipsize="end"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginBottom="16dp"
+            style="@style/TextAppearance.Dialog.Title" />
+    </LinearLayout>
+
+    <Space
+        android:id="@*android:id/titleDividerNoCustom"
+        android:visibility="gone"
+        android:layout_width="match_parent"
+        android:layout_height="0dp" />
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
index 86e2661..98518c2 100644
--- a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
+++ b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
@@ -156,6 +156,14 @@
                             style="@style/InternetDialog.NetworkSummary"/>
                     </LinearLayout>
 
+                    <View
+                        android:id="@+id/mobile_toggle_divider"
+                        android:layout_width="1dp"
+                        android:layout_height="28dp"
+                        android:layout_marginEnd="16dp"
+                        android:layout_gravity="center_vertical"
+                        android:background="?android:attr/textColorSecondary"/>
+
                     <FrameLayout
                         android:layout_width="@dimen/settingslib_switch_track_width"
                         android:layout_height="48dp"
@@ -367,8 +375,9 @@
                 android:id="@+id/done_layout"
                 android:layout_width="67dp"
                 android:layout_height="48dp"
+                android:layout_marginTop="8dp"
                 android:layout_marginEnd="24dp"
-                android:layout_marginBottom="40dp"
+                android:layout_marginBottom="34dp"
                 android:layout_gravity="end|center_vertical"
                 android:clickable="true"
                 android:focusable="true">
diff --git a/packages/SystemUI/res/layout/privacy_dialog.xml b/packages/SystemUI/res/layout/privacy_dialog.xml
index ee4530c..9368a6a 100644
--- a/packages/SystemUI/res/layout/privacy_dialog.xml
+++ b/packages/SystemUI/res/layout/privacy_dialog.xml
@@ -22,10 +22,9 @@
     android:layout_height="wrap_content"
     android:layout_marginStart="@dimen/ongoing_appops_dialog_side_margins"
     android:layout_marginEnd="@dimen/ongoing_appops_dialog_side_margins"
-    android:layout_marginTop="8dp"
     android:orientation="vertical"
     android:paddingBottom="8dp"
-    android:paddingTop="12dp"
+    android:paddingTop="8dp"
     android:paddingHorizontal="@dimen/ongoing_appops_dialog_side_padding"
     android:background="@drawable/qs_dialog_bg"
 />
diff --git a/packages/SystemUI/res/layout/qs_user_detail.xml b/packages/SystemUI/res/layout/qs_user_detail.xml
index 91d3a53..1aec296 100644
--- a/packages/SystemUI/res/layout/qs_user_detail.xml
+++ b/packages/SystemUI/res/layout/qs_user_detail.xml
@@ -22,6 +22,6 @@
         xmlns:sysui="http://schemas.android.com/apk/res-auto"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        sysui:verticalSpacing="4dp"
+        sysui:verticalSpacing="20dp"
         sysui:horizontalSpacing="4dp"
         style="@style/UserDetailView" />
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/qs_user_detail_item.xml b/packages/SystemUI/res/layout/qs_user_detail_item.xml
index cc6c5d3..91b11fc 100644
--- a/packages/SystemUI/res/layout/qs_user_detail_item.xml
+++ b/packages/SystemUI/res/layout/qs_user_detail_item.xml
@@ -24,8 +24,6 @@
         android:layout_height="wrap_content"
         android:orientation="vertical"
         android:gravity="top|center_horizontal"
-        android:paddingTop="16dp"
-        android:minHeight="112dp"
         android:clipChildren="false"
         android:clipToPadding="false"
         android:focusable="true"
diff --git a/packages/SystemUI/res/layout/qs_user_dialog_content.xml b/packages/SystemUI/res/layout/qs_user_dialog_content.xml
index 9495ee6..355df2c 100644
--- a/packages/SystemUI/res/layout/qs_user_dialog_content.xml
+++ b/packages/SystemUI/res/layout/qs_user_dialog_content.xml
@@ -15,75 +15,19 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-
-<androidx.constraintlayout.widget.ConstraintLayout
+<FrameLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:sysui="http://schemas.android.com/apk/res-auto"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:padding="24dp"
-    android:layout_marginStart="16dp"
-    android:layout_marginEnd="16dp"
->
-    <TextView
-        android:id="@+id/title"
-        android:layout_height="wrap_content"
-        android:layout_width="0dp"
-        android:textAlignment="center"
-        android:text="@string/qs_user_switch_dialog_title"
-        android:textAppearance="@style/TextAppearance.QSDialog.Title"
-        android:layout_marginBottom="32dp"
-        sysui:layout_constraintTop_toTopOf="parent"
-        sysui:layout_constraintStart_toStartOf="parent"
-        sysui:layout_constraintEnd_toEndOf="parent"
-        sysui:layout_constraintBottom_toTopOf="@id/grid"
-        />
-
+    >
     <com.android.systemui.qs.PseudoGridView
-        android:id="@+id/grid"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_marginBottom="28dp"
-        sysui:verticalSpacing="4dp"
-        sysui:horizontalSpacing="4dp"
-        sysui:fixedChildWidth="80dp"
-        sysui:layout_constraintTop_toBottomOf="@id/title"
-        sysui:layout_constraintStart_toStartOf="parent"
-        sysui:layout_constraintEnd_toEndOf="parent"
-        sysui:layout_constraintBottom_toTopOf="@id/barrier"
-    />
-
-    <androidx.constraintlayout.widget.Barrier
-        android:id="@+id/barrier"
-        android:layout_height="wrap_content"
-        android:layout_width="wrap_content"
-        sysui:barrierDirection="top"
-        sysui:constraint_referenced_ids="settings,done"
+            android:id="@+id/grid"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center"
+            sysui:verticalSpacing="20dp"
+            sysui:horizontalSpacing="4dp"
+            sysui:fixedChildWidth="80dp"
         />
-
-    <Button
-        android:id="@+id/settings"
-        android:layout_width="wrap_content"
-        android:layout_height="48dp"
-        android:text="@string/quick_settings_more_user_settings"
-        sysui:layout_constraintTop_toBottomOf="@id/barrier"
-        sysui:layout_constraintBottom_toBottomOf="parent"
-        sysui:layout_constraintStart_toStartOf="parent"
-        sysui:layout_constraintEnd_toStartOf="@id/done"
-        sysui:layout_constraintHorizontal_chainStyle="spread_inside"
-        style="@style/Widget.QSDialog.Button.BorderButton"
-        />
-
-    <Button
-        android:id="@+id/done"
-        android:layout_width="wrap_content"
-        android:layout_height="48dp"
-        android:text="@string/quick_settings_done"
-        sysui:layout_constraintTop_toBottomOf="@id/barrier"
-        sysui:layout_constraintBottom_toBottomOf="parent"
-        sysui:layout_constraintStart_toEndOf="@id/settings"
-        sysui:layout_constraintEnd_toEndOf="parent"
-        style="@style/Widget.QSDialog.Button"
-        />
-
-</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
+</FrameLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 4015762..f2d27c4 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -69,8 +69,7 @@
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Die program of jou organisasie laat nie toe dat skermkiekies geneem word nie"</string>
     <string name="screenshot_edit_label" msgid="8754981973544133050">"Wysig"</string>
     <string name="screenshot_edit_description" msgid="3333092254706788906">"Wysig skermkiekie"</string>
-    <!-- no translation found for screenshot_share_description (2861628935812656612) -->
-    <skip />
+    <string name="screenshot_share_description" msgid="2861628935812656612">"Deel skermskoot"</string>
     <string name="screenshot_scroll_label" msgid="2930198809899329367">"Vang meer vas"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Maak skermkiekie toe"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Skermkiekievoorskou"</string>
@@ -108,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"Foon"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Stembystand"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"Beursie"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"Ontsluit"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"Toestel is gesluit"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"Skandeer tans gesig"</string>
@@ -465,6 +466,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Ontsluit om te gebruik"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Kon nie jou kaarte kry nie; probeer later weer"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Sluitskerminstellings"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"Werkprofiel"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Vliegtuigmodus"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Jy sal nie jou volgende wekker <xliff:g id="WHEN">%1$s</xliff:g> hoor nie"</string>
diff --git a/packages/SystemUI/res/values-af/tiles_states_strings.xml b/packages/SystemUI/res/values-af/tiles_states_strings.xml
index 5ce5340..c7e76180 100644
--- a/packages/SystemUI/res/values-af/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-af/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"Af"</item>
     <item msgid="6866424167599381915">"Aan"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"Onbeskikbaar"</item>
     <item msgid="2710157085538036590">"Af"</item>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 723f766..b71cf7a 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -69,8 +69,7 @@
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"ቅጽበታዊ ገጽ እይታዎችን ማንሳት በመተግበሪያው ወይም በእርስዎ ድርጅት አይፈቀድም"</string>
     <string name="screenshot_edit_label" msgid="8754981973544133050">"አርትዕ ያድርጉ"</string>
     <string name="screenshot_edit_description" msgid="3333092254706788906">"ቅጽበታዊ ገጽ ዕይታን አርትዕ ያድርጉ"</string>
-    <!-- no translation found for screenshot_share_description (2861628935812656612) -->
-    <skip />
+    <string name="screenshot_share_description" msgid="2861628935812656612">"ቅጽበታዊ ገጽ እይታን ያጋሩ"</string>
     <string name="screenshot_scroll_label" msgid="2930198809899329367">"ተጨማሪ ይቅረጹ"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"ቅጽበታዊ ገጽ ዕይታን አሰናብት"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"የቅጽበታዊ ገጽ ዕይታ ቅድመ-ዕይታ"</string>
@@ -108,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"ስልክ"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"የድምጽ እርዳታ"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"የኪስ ቦርሳ"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"ክፈት"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"መሣሪያ ተቆልፏል"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"የቅኝት ፊት"</string>
@@ -465,6 +466,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ለማየት ይክፈቱ"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"የእርስዎን ካርዶች ማግኘት ላይ ችግር ነበር፣ እባክዎ ቆይተው እንደገና ይሞክሩ"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"የገጽ መቆለፊያ ቅንብሮች"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"የስራ መገለጫ"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"የአውሮፕላን ሁነታ"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"የእርስዎን ቀጣይ ማንቂያ <xliff:g id="WHEN">%1$s</xliff:g> አይሰሙም"</string>
diff --git a/packages/SystemUI/res/values-am/tiles_states_strings.xml b/packages/SystemUI/res/values-am/tiles_states_strings.xml
index 0a53d20..e5be860 100644
--- a/packages/SystemUI/res/values-am/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-am/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"ጠፍቷል"</item>
     <item msgid="6866424167599381915">"በርቷል"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"አይገኝም"</item>
     <item msgid="2710157085538036590">"ጠፍቷል"</item>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index a163a9b..4141969 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -69,8 +69,7 @@
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"يحظر التطبيق أو تحظر مؤسستك التقاط لقطات شاشة"</string>
     <string name="screenshot_edit_label" msgid="8754981973544133050">"تعديل"</string>
     <string name="screenshot_edit_description" msgid="3333092254706788906">"تعديل لقطة الشاشة"</string>
-    <!-- no translation found for screenshot_share_description (2861628935812656612) -->
-    <skip />
+    <string name="screenshot_share_description" msgid="2861628935812656612">"مشاركة لقطة الشاشة"</string>
     <string name="screenshot_scroll_label" msgid="2930198809899329367">"التقاط المزيد من المحتوى"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"إغلاق لقطة الشاشة"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"معاينة لقطة الشاشة"</string>
@@ -108,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"الهاتف"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"المساعد الصوتي"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"المحفظة"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"فتح القفل"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"الجهاز مُقفل."</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"مسح الوجه"</string>
@@ -477,6 +478,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"فتح القفل للاستخدام"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"حدثت مشكلة أثناء الحصول على البطاقات، يُرجى إعادة المحاولة لاحقًا."</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"إعدادات شاشة القفل"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"الملف الشخصي للعمل"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"وضع الطيران"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"لن تسمع المنبّه القادم في <xliff:g id="WHEN">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-ar/tiles_states_strings.xml b/packages/SystemUI/res/values-ar/tiles_states_strings.xml
index 90baf04..e2b8632 100644
--- a/packages/SystemUI/res/values-ar/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ar/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"الميزة غير مفعّلة"</item>
     <item msgid="6866424167599381915">"الميزة مفعّلة"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"الميزة غير متاحة"</item>
     <item msgid="2710157085538036590">"الميزة غير مفعّلة"</item>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index a36532a..7c7d95b 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -107,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"ফ\'ন"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"কণ্ঠধ্বনিৰে সহায়"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"ৱালেট"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"আনলক কৰক"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"ডিভাইচটো লক হৈ আছে"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"চেহেৰা স্কেন কৰি থকা হৈছে"</string>
@@ -464,6 +466,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ব্যৱহাৰ কৰিবলৈ আনলক কৰক"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"আপোনাৰ কাৰ্ড লাভ কৰোঁতে এটা সমস্যা হৈছে, অনুগ্ৰহ কৰি পাছত পুনৰ চেষ্টা কৰক"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"লক স্ক্ৰীনৰ ছেটিং"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"কৰ্মস্থানৰ প্ৰ\'ফাইল"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"এয়াৰপ্লেইন ম\'ড"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"আপুনি আপোনাৰ পিছৰটো এলাৰ্ম <xliff:g id="WHEN">%1$s</xliff:g> বজাত শুনা নাপাব"</string>
diff --git a/packages/SystemUI/res/values-as/tiles_states_strings.xml b/packages/SystemUI/res/values-as/tiles_states_strings.xml
index fa333df..43957f4 100644
--- a/packages/SystemUI/res/values-as/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-as/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"অফ আছে"</item>
     <item msgid="6866424167599381915">"অন কৰা আছে"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"উপলব্ধ নহয়"</item>
     <item msgid="2710157085538036590">"অফ আছে"</item>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index 5a53dd8..8e27b0f 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -69,8 +69,7 @@
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Skrinşot çəkməyə tətbiq və ya təşkilat tərəfindən icazə verilmir"</string>
     <string name="screenshot_edit_label" msgid="8754981973544133050">"Redaktə edin"</string>
     <string name="screenshot_edit_description" msgid="3333092254706788906">"Skrinşota düzəliş edin"</string>
-    <!-- no translation found for screenshot_share_description (2861628935812656612) -->
-    <skip />
+    <string name="screenshot_share_description" msgid="2861628935812656612">"Skrinşotu paylaşın"</string>
     <string name="screenshot_scroll_label" msgid="2930198809899329367">"Genişləndirin"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Ekran şəklini ötürün"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Ekran şəklinə önbaxış"</string>
@@ -108,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"Telefon"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Səs Yardımçısı"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"Pulqabı"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"Kiliddən çıxarın"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"Cihaz kilidlənib"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"Üzün skan edilməsi"</string>
@@ -465,6 +466,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"İstifadə etmək üçün kiliddən çıxarın"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Kartların əldə edilməsində problem oldu, sonra yenidən cəhd edin"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Kilid ekranı ayarları"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"İş profili"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Təyyarə rejimi"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"<xliff:g id="WHEN">%1$s</xliff:g> zaman növbəti xəbərdarlığınızı eşitməyəcəksiniz"</string>
diff --git a/packages/SystemUI/res/values-az/tiles_states_strings.xml b/packages/SystemUI/res/values-az/tiles_states_strings.xml
index 1a3a2dc..4baea08 100644
--- a/packages/SystemUI/res/values-az/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-az/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"Deaktiv"</item>
     <item msgid="6866424167599381915">"Aktiv"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"Əlçatan deyil"</item>
     <item msgid="2710157085538036590">"Deaktiv"</item>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index db3d917..6d5e75a 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -69,8 +69,7 @@
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Aplikacija ili organizacija ne dozvoljavaju pravljenje snimaka ekrana"</string>
     <string name="screenshot_edit_label" msgid="8754981973544133050">"Izmeni"</string>
     <string name="screenshot_edit_description" msgid="3333092254706788906">"Izmenite snimak ekrana"</string>
-    <!-- no translation found for screenshot_share_description (2861628935812656612) -->
-    <skip />
+    <string name="screenshot_share_description" msgid="2861628935812656612">"Delite snimak ekrana"</string>
     <string name="screenshot_scroll_label" msgid="2930198809899329367">"Snimite još"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Odbacite snimak ekrana"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Pregled snimka ekrana"</string>
@@ -108,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"Telefon"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Glasovna pomoć"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"Novčanik"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"Otključajte"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"Uređaj je zaključan"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"Skeniranje lica"</string>
@@ -468,6 +469,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Otključaj radi korišćenja"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Došlo je do problema pri preuzimanju kartica. Probajte ponovo kasnije"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Podešavanja zaključanog ekrana"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"Poslovni profil"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Režim rada u avionu"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Nećete čuti sledeći alarm u <xliff:g id="WHEN">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/tiles_states_strings.xml b/packages/SystemUI/res/values-b+sr+Latn/tiles_states_strings.xml
index 5622a82..90b8cce 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"Isključeno"</item>
     <item msgid="6866424167599381915">"Uključeno"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"Nedostupno"</item>
     <item msgid="2710157085538036590">"Isključeno"</item>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 262752c..e98c498 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -69,8 +69,7 @@
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Рабіць здымкі экрана не дазваляе праграма ці ваша арганізацыя"</string>
     <string name="screenshot_edit_label" msgid="8754981973544133050">"Змяніць"</string>
     <string name="screenshot_edit_description" msgid="3333092254706788906">"Змяніць здымак экрана"</string>
-    <!-- no translation found for screenshot_share_description (2861628935812656612) -->
-    <skip />
+    <string name="screenshot_share_description" msgid="2861628935812656612">"Абагуліць здымак экрана"</string>
     <string name="screenshot_scroll_label" msgid="2930198809899329367">"Зняць больш"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Адхіліць здымак экрана"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Перадпрагляд здымка экрана"</string>
@@ -108,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"Тэлефон"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Галасавая дапамога"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"Кашалёк"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"Разблакiраваць"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"Прылада заблакіравана"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"Сканіраванне твару"</string>
@@ -285,7 +286,7 @@
     <string name="quick_settings_night_secondary_label_on_at" msgid="3584738542293528235">"Уключыць у <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_secondary_label_until" msgid="1883981263191927372">"Да <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_ui_mode_night_label" msgid="1398928270610780470">"Цёмная тэма"</string>
-    <string name="quick_settings_dark_mode_secondary_label_battery_saver" msgid="4990712734503013251">"Эканомія зараду"</string>
+    <string name="quick_settings_dark_mode_secondary_label_battery_saver" msgid="4990712734503013251">"Энергазберажэнне"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at_sunset" msgid="6017379738102015710">"Уключана ўвечары"</string>
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Да ўсходу сонца"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Уключана ў <xliff:g id="TIME">%s</xliff:g>"</string>
@@ -471,6 +472,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Разблакіраваць для выкарыстання"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Узнікла праблема з загрузкай вашых карт. Паўтарыце спробу пазней"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Налады экрана блакіроўкі"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"Працоўны профіль"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Рэжым палёту"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Вы не пачуеце наступны будзільнік <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -546,7 +551,7 @@
       <item quantity="many">%d хвілін</item>
       <item quantity="other">%d хвіліны</item>
     </plurals>
-    <string name="battery_detail_switch_title" msgid="6940976502957380405">"Эканомія зараду"</string>
+    <string name="battery_detail_switch_title" msgid="6940976502957380405">"Рэжым энергазберажэння"</string>
     <string name="keyboard_key_button_template" msgid="8005673627272051429">"Кнопка <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_key_home" msgid="3734400625170020657">"Home"</string>
     <string name="keyboard_key_back" msgid="4185420465469481999">"Назад"</string>
diff --git a/packages/SystemUI/res/values-be/tiles_states_strings.xml b/packages/SystemUI/res/values-be/tiles_states_strings.xml
index b70a813..4ad97d2 100644
--- a/packages/SystemUI/res/values-be/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-be/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"Выключана"</item>
     <item msgid="6866424167599381915">"Уключана"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"Недаступна"</item>
     <item msgid="2710157085538036590">"Выключана"</item>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 8d090e4..951714e 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -107,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"Телефон"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Гласова помощ"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"Портфейл"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"Отключване"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"Устройството е заключено"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"Извършва се сканиране на лице"</string>
@@ -464,6 +466,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Отключване с цел използване"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"При извличането на картите ви възникна проблем. Моля, опитайте отново по-късно"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Настройки за заключения екран"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"Потребителски профил в Work"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Самолетен режим"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Няма да чуете следващия си будилник в <xliff:g id="WHEN">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-bg/tiles_states_strings.xml b/packages/SystemUI/res/values-bg/tiles_states_strings.xml
index 85d9393..e7cc889 100644
--- a/packages/SystemUI/res/values-bg/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-bg/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"Изкл."</item>
     <item msgid="6866424167599381915">"Вкл."</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"Не е налице"</item>
     <item msgid="2710157085538036590">"Изкл."</item>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index ac6aaeb..217f9e3 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -69,8 +69,7 @@
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"এই অ্যাপ বা আপনার প্রতিষ্ঠান স্ক্রিনশট নেওয়ার অনুমতি দেয়নি"</string>
     <string name="screenshot_edit_label" msgid="8754981973544133050">"এডিট করুন"</string>
     <string name="screenshot_edit_description" msgid="3333092254706788906">"স্ক্রিনশট এডিট করুন"</string>
-    <!-- no translation found for screenshot_share_description (2861628935812656612) -->
-    <skip />
+    <string name="screenshot_share_description" msgid="2861628935812656612">"স্ক্রিনশট শেয়ার করুন"</string>
     <string name="screenshot_scroll_label" msgid="2930198809899329367">"আরও বেশি ক্যাপচার করুন"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"স্ক্রিনশট বাতিল করুন"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"স্ক্রিনশটের প্রিভিউ"</string>
@@ -108,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"ফোন"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"ভয়েস সহায়তা"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"ওয়ালেট"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"আনলক করুন"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"ডিভাইস লক করা আছে"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"ফেস স্ক্যান করা হচ্ছে"</string>
@@ -465,6 +466,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ব্যবহার করতে আনলক করুন"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"আপনার কার্ড সংক্রান্ত তথ্য পেতে সমস্যা হয়েছে, পরে আবার চেষ্টা করুন"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"লক স্ক্রিন সেটিংস"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"কাজের প্রোফাইল"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"বিমান মোড"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"আপনি আপনার পরবর্তী <xliff:g id="WHEN">%1$s</xliff:g> অ্যালার্ম শুনতে পাবেন না"</string>
diff --git a/packages/SystemUI/res/values-bn/tiles_states_strings.xml b/packages/SystemUI/res/values-bn/tiles_states_strings.xml
index 631446d..584de5e 100644
--- a/packages/SystemUI/res/values-bn/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-bn/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"বন্ধ আছে"</item>
     <item msgid="6866424167599381915">"চালু আছে"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"উপলভ্য নেই"</item>
     <item msgid="2710157085538036590">"বন্ধ আছে"</item>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 4680da9..efcb4d4 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -69,8 +69,7 @@
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Ova aplikacija ili vaša organizacija ne dozvoljavaju snimanje ekrana"</string>
     <string name="screenshot_edit_label" msgid="8754981973544133050">"Uredite"</string>
     <string name="screenshot_edit_description" msgid="3333092254706788906">"Uredite snimak ekrana"</string>
-    <!-- no translation found for screenshot_share_description (2861628935812656612) -->
-    <skip />
+    <string name="screenshot_share_description" msgid="2861628935812656612">"Dijeljenje snimka ekrana"</string>
     <string name="screenshot_scroll_label" msgid="2930198809899329367">"Snimite više"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Odbacite snimak ekrana"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Pregled snimka ekrana"</string>
@@ -108,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"Telefon"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Glasovna pomoć"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"Novčanik"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"Otključaj"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"Uređaj je zaključan"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"Skeniranje lica"</string>
@@ -468,6 +469,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Otključajte da koristite"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Došlo je do problema prilikom preuzimanja vaših kartica. Pokušajte ponovo kasnije"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Postavke zaključavanja ekrana"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"Profil za posao"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Način rada u avionu"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Nećete čuti sljedeći alarm u <xliff:g id="WHEN">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-bs/tiles_states_strings.xml b/packages/SystemUI/res/values-bs/tiles_states_strings.xml
index 5622a82..90b8cce 100644
--- a/packages/SystemUI/res/values-bs/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-bs/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"Isključeno"</item>
     <item msgid="6866424167599381915">"Uključeno"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"Nedostupno"</item>
     <item msgid="2710157085538036590">"Isključeno"</item>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 778a52c..8ddc456 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -69,8 +69,7 @@
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"L\'aplicació o la teva organització no permeten fer captures de pantalla"</string>
     <string name="screenshot_edit_label" msgid="8754981973544133050">"Edita"</string>
     <string name="screenshot_edit_description" msgid="3333092254706788906">"Edita la captura de pantalla"</string>
-    <!-- no translation found for screenshot_share_description (2861628935812656612) -->
-    <skip />
+    <string name="screenshot_share_description" msgid="2861628935812656612">"Comparteix la captura de pantalla"</string>
     <string name="screenshot_scroll_label" msgid="2930198809899329367">"Captura més"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Ignora la captura de pantalla"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Previsualització de la captura de pantalla"</string>
@@ -108,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"Telèfon"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Assistència per veu"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"Cartera"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"Desbloqueja"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"Dispositiu bloquejat"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"S\'està escanejant la cara"</string>
@@ -465,6 +466,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Desbloqueja per utilitzar"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Hi ha hagut un problema en obtenir les teves targetes; torna-ho a provar més tard"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Configuració de la pantalla de bloqueig"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"Perfil de treball"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Mode d\'avió"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"<xliff:g id="WHEN">%1$s</xliff:g> no sentiràs la pròxima alarma"</string>
diff --git a/packages/SystemUI/res/values-ca/tiles_states_strings.xml b/packages/SystemUI/res/values-ca/tiles_states_strings.xml
index ddb9dc8..27bfb9c 100644
--- a/packages/SystemUI/res/values-ca/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ca/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"Desactivat"</item>
     <item msgid="6866424167599381915">"Activat"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"No disponible"</item>
     <item msgid="2710157085538036590">"Desactivat"</item>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 3c9a9c4..55c5333 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -69,8 +69,7 @@
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Aplikace nebo organizace zakazuje pořizování snímků obrazovky"</string>
     <string name="screenshot_edit_label" msgid="8754981973544133050">"Upravit"</string>
     <string name="screenshot_edit_description" msgid="3333092254706788906">"Upravit snímek obrazovky"</string>
-    <!-- no translation found for screenshot_share_description (2861628935812656612) -->
-    <skip />
+    <string name="screenshot_share_description" msgid="2861628935812656612">"Sdílet snímek obrazovky"</string>
     <string name="screenshot_scroll_label" msgid="2930198809899329367">"Zvětšit záběr snímku"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Zavřít snímek obrazovky"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Náhled snímku obrazovky"</string>
@@ -108,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"Telefon"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Hlasová asistence"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"Peněženka"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"Odemknout"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"Zařízení uzamčeno"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"Skenování obličeje"</string>
@@ -471,6 +472,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Odemknout a použít"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Při načítání karet došlo k problému, zkuste to později"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Nastavení obrazovky uzamčení"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"Pracovní profil"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Režim Letadlo"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Svůj další budík <xliff:g id="WHEN">%1$s</xliff:g> neuslyšíte"</string>
diff --git a/packages/SystemUI/res/values-cs/tiles_states_strings.xml b/packages/SystemUI/res/values-cs/tiles_states_strings.xml
index 427770d..ee1f8fb8 100644
--- a/packages/SystemUI/res/values-cs/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-cs/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"Vyp"</item>
     <item msgid="6866424167599381915">"Zap"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"Nedostupné"</item>
     <item msgid="2710157085538036590">"Vyp"</item>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 9fa3baec..2420c7f 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -69,8 +69,7 @@
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Appen eller din organisation tillader ikke, at du tager screenshots"</string>
     <string name="screenshot_edit_label" msgid="8754981973544133050">"Rediger"</string>
     <string name="screenshot_edit_description" msgid="3333092254706788906">"Rediger screenshot"</string>
-    <!-- no translation found for screenshot_share_description (2861628935812656612) -->
-    <skip />
+    <string name="screenshot_share_description" msgid="2861628935812656612">"Del screenshottet"</string>
     <string name="screenshot_scroll_label" msgid="2930198809899329367">"Medtag mere"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Luk screenshot"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Forhåndsvisning af screenshot"</string>
@@ -108,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"Telefon"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Taleassistent"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"Wallet"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"Lås op"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"Enheden er låst"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"Scanner ansigt"</string>
@@ -465,6 +466,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Lås op for at bruge"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Dine kort kunne ikke hentes. Prøv igen senere."</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Lås skærmindstillinger"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"Arbejdsprofil"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Flytilstand"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Du vil ikke kunne høre din næste alarm <xliff:g id="WHEN">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-da/tiles_states_strings.xml b/packages/SystemUI/res/values-da/tiles_states_strings.xml
index 6c7d4d9..770c2ed 100644
--- a/packages/SystemUI/res/values-da/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-da/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"Fra"</item>
     <item msgid="6866424167599381915">"Til"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"Ikke tilgængelig"</item>
     <item msgid="2710157085538036590">"Fra"</item>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 7241836..61d489c 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -107,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"Telefonnummer"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Sprachassistent"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"Wallet"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"Entsperren"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"Gerät gesperrt"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"Gesicht wird gescannt"</string>
@@ -464,6 +466,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Zum Verwenden entsperren"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Beim Abrufen deiner Karten ist ein Fehler aufgetreten – bitte versuch es später noch einmal"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Einstellungen für den Sperrbildschirm"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"Arbeitsprofil"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Flugmodus"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Lautloser Weckruf <xliff:g id="WHEN">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-de/tiles_states_strings.xml b/packages/SystemUI/res/values-de/tiles_states_strings.xml
index 19ceead..50d0ed5 100644
--- a/packages/SystemUI/res/values-de/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-de/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"Aus"</item>
     <item msgid="6866424167599381915">"An"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"Nicht verfügbar"</item>
     <item msgid="2710157085538036590">"Aus"</item>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 8ca961a..0bd3940 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -69,8 +69,7 @@
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Η λήψη στιγμιότυπων οθόνης δεν επιτρέπεται από την εφαρμογή ή τον οργανισμό σας"</string>
     <string name="screenshot_edit_label" msgid="8754981973544133050">"Επεξεργασία"</string>
     <string name="screenshot_edit_description" msgid="3333092254706788906">"Επεξεργασία στιγμιότυπου οθόνης"</string>
-    <!-- no translation found for screenshot_share_description (2861628935812656612) -->
-    <skip />
+    <string name="screenshot_share_description" msgid="2861628935812656612">"Κοινοποίηση στιγμιότυπου οθόνης"</string>
     <string name="screenshot_scroll_label" msgid="2930198809899329367">"Λήψη περισσότερων"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Παράβλεψη στιγμιότυπου οθόνης"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Προεπισκόπηση στιγμιότυπου οθόνης"</string>
@@ -108,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"Τηλέφωνο"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Φωνητική υποβοήθηση"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"Πορτοφόλι"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"Ξεκλείδωμα"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"Η συσκευή κλειδώθηκε"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"Σάρωση προσώπου"</string>
@@ -465,6 +466,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Ξεκλείδωμα για χρήση"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Παρουσιάστηκε πρόβλημα με τη λήψη των καρτών σας. Δοκιμάστε ξανά αργότερα"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Ρυθμίσεις κλειδώματος οθόνης"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"Προφίλ εργασίας"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Λειτουργία πτήσης"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Δεν θα ακούσετε το επόμενο ξυπνητήρι σας <xliff:g id="WHEN">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-el/tiles_states_strings.xml b/packages/SystemUI/res/values-el/tiles_states_strings.xml
index 1dbaaa6..76f98f5 100644
--- a/packages/SystemUI/res/values-el/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-el/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"Ανενεργό"</item>
     <item msgid="6866424167599381915">"Ενεργό"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"Μη διαθέσιμο"</item>
     <item msgid="2710157085538036590">"Ανενεργό"</item>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index c1950be..9807774 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -107,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"Phone"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Voice Assist"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"Wallet"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"Unlock"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"Device locked"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"Scanning face"</string>
@@ -464,6 +466,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Unlock to use"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"There was a problem getting your cards. Please try again later."</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Lock screen settings"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"Work profile"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Aeroplane mode"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"You won\'t hear your next alarm <xliff:g id="WHEN">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/tiles_states_strings.xml b/packages/SystemUI/res/values-en-rAU/tiles_states_strings.xml
index 0496502..2215f2d 100644
--- a/packages/SystemUI/res/values-en-rAU/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"Off"</item>
     <item msgid="6866424167599381915">"On"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"Unavailable"</item>
     <item msgid="2710157085538036590">"Off"</item>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index 393289e..246d580 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -107,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"Phone"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Voice Assist"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"Wallet"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"Unlock"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"Device locked"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"Scanning face"</string>
@@ -464,6 +466,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Unlock to use"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"There was a problem getting your cards. Please try again later."</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Lock screen settings"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"Work profile"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Airplane mode"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"You won\'t hear your next alarm <xliff:g id="WHEN">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-en-rCA/tiles_states_strings.xml b/packages/SystemUI/res/values-en-rCA/tiles_states_strings.xml
index 0496502..2215f2d 100644
--- a/packages/SystemUI/res/values-en-rCA/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"Off"</item>
     <item msgid="6866424167599381915">"On"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"Unavailable"</item>
     <item msgid="2710157085538036590">"Off"</item>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index c1950be..9807774 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -107,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"Phone"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Voice Assist"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"Wallet"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"Unlock"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"Device locked"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"Scanning face"</string>
@@ -464,6 +466,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Unlock to use"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"There was a problem getting your cards. Please try again later."</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Lock screen settings"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"Work profile"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Aeroplane mode"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"You won\'t hear your next alarm <xliff:g id="WHEN">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/tiles_states_strings.xml b/packages/SystemUI/res/values-en-rGB/tiles_states_strings.xml
index 0496502..2215f2d 100644
--- a/packages/SystemUI/res/values-en-rGB/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"Off"</item>
     <item msgid="6866424167599381915">"On"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"Unavailable"</item>
     <item msgid="2710157085538036590">"Off"</item>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index c1950be..9807774 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -107,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"Phone"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Voice Assist"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"Wallet"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"Unlock"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"Device locked"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"Scanning face"</string>
@@ -464,6 +466,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Unlock to use"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"There was a problem getting your cards. Please try again later."</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Lock screen settings"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"Work profile"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Aeroplane mode"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"You won\'t hear your next alarm <xliff:g id="WHEN">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/tiles_states_strings.xml b/packages/SystemUI/res/values-en-rIN/tiles_states_strings.xml
index 0496502..2215f2d 100644
--- a/packages/SystemUI/res/values-en-rIN/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"Off"</item>
     <item msgid="6866424167599381915">"On"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"Unavailable"</item>
     <item msgid="2710157085538036590">"Off"</item>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index 44471bd..95d8074 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -107,6 +107,7 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‏‏‎‎‎‏‎‎‎‏‏‎‎‏‏‎‏‎‏‎‎‏‏‏‎‎‏‏‏‏‎‎‎‏‏‎‏‏‏‏‎‏‎‎‎‎‎‎‎‎‎‎‎‎‏‎‏‏‎Phone‎‏‎‎‏‎"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‎‎‎‏‎‏‏‎‎‎‏‏‏‏‏‎‏‏‎‏‏‏‏‎‏‏‎‎‏‏‎‎‎‏‎‎‎‎‎‏‎‎‏‎‏‏‏‎‏‏‎‎‎‏‏‏‎‎Voice Assist‎‏‎‎‏‎"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‎‎‎‎‏‏‏‏‎‎‏‏‎‎‎‏‏‎‏‎‏‎‎‎‏‏‎‎‏‎‏‎‏‎‏‏‎‎‎‎‏‎‎‏‏‏‏‎‏‎‏‏‏‏‎‎‏‏‎Wallet‎‏‎‎‏‎"</string>
+    <string name="accessibility_qr_code_scanner_button" msgid="7521277927692910795">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‎‏‏‎‎‎‎‎‏‏‏‏‎‎‏‎‎‏‏‎‏‏‎‏‎‎‎‎‎‎‎‏‎‎‎‏‏‏‏‏‎‏‎‎‎‎‎‎‏‏‎‎‏‎‏‏‎QR Code Scanner‎‏‎‎‏‎"</string>
     <string name="accessibility_unlock_button" msgid="122785427241471085">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‎‏‏‏‎‏‏‎‏‎‎‎‎‏‏‏‎‎‎‏‎‏‏‎‎‏‎‎‎‎‎‏‏‏‎‎‏‎‏‎‎‏‎‏‎‎‎‏‏‎‎‎‏‏‎‏‏‎‏‎Unlock‎‏‎‎‏‎"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‏‎‎‏‎‏‏‏‎‎‎‎‏‏‎‎‎‎‎‏‏‏‏‎‎‎‏‎‎‎‏‎‏‏‏‎‎‎‏‏‏‏‏‏‎‏‎‏‏‎‎‏‏‏‏‏‏‎Device locked‎‏‎‎‏‎"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‎‏‏‏‎‏‏‏‏‎‏‏‏‏‏‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‏‎‏‏‏‏‏‎‎‎‏‏‎‎‎‏‏‎‏‎‎‎‎‏‎‏‏‎Scanning face‎‏‎‎‏‎"</string>
@@ -464,6 +465,8 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‏‏‏‏‎‏‎‏‎‎‎‏‎‏‏‎‏‏‎‎‎‏‎‏‎‏‎‏‏‎‎‎‎‎‎‏‏‎‎‏‏‏‎‏‎‏‏‏‏‎‏‎‎‎‏‎‏‎‎Unlock to use‎‏‎‎‏‎"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‏‏‏‎‎‏‎‎‏‏‏‎‎‎‏‏‎‎‏‏‏‏‎‎‎‎‏‏‏‏‎‎‏‎‏‏‎‎‎‎‎‎‎‎‎‏‎‎‎‏‏‎‎‏‏‎‏‏‎There was a problem getting your cards, please try again later‎‏‎‎‏‎"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‎‏‎‎‎‏‏‏‎‏‎‏‏‎‏‏‎‏‏‎‎‎‎‏‎‏‎‎‏‎‏‎‎‏‎‎‎‏‎‏‎‎‏‏‎‎‎‏‏‏‏‏‎‏‎‎‏‎‎Lock screen settings‎‏‎‎‏‎"</string>
+    <string name="qr_code_scanner_title" msgid="1598912458255252498">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‏‎‎‎‏‏‎‎‎‎‎‏‏‏‏‎‏‎‎‏‏‎‏‎‎‎‏‏‎‎‏‏‎‏‎‏‎‎‎‎‎‎‎‎‏‏‏‏‎‎‎‎‎‏‎‎‏‎‎Scan QR‎‏‎‎‏‎"</string>
+    <string name="qr_code_scanner_description" msgid="7452098243938659945">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‏‏‎‏‎‏‏‎‎‏‎‏‎‏‏‏‏‎‏‏‏‏‎‏‎‏‏‎‏‎‏‎‏‎‎‎‏‏‎‏‎‏‎‏‏‏‎‎‏‏‎‏‎‎‏‎Click to scan a QR code‎‏‎‎‏‎"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‎‏‎‏‏‎‎‏‏‎‏‏‎‎‏‎‏‎‎‎‏‏‎‎‏‎‎‎‎‏‏‎‏‎‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‏‏‏‎‎‎‎‎Work profile‎‏‎‎‏‎"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‏‎‏‎‎‏‎‏‎‎‎‎‎‏‏‎‏‎‎‏‏‏‏‎‏‏‏‏‏‏‎‏‏‏‎‏‎‏‏‏‏‏‏‏‏‏‏‎‎‎‏‎‏‎‎‎‏‎Airplane mode‎‏‎‎‏‎"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‎‏‏‏‎‎‏‎‎‏‎‎‎‎‎‎‏‏‏‏‎‎‎‎‎‎‏‎‎‎‎‏‏‏‎‏‎‎‎‏‏‏‎‏‏‏‏‏‎‏‏‏‏‏‎You won\'t hear your next alarm ‎‏‎‎‏‏‎<xliff:g id="WHEN">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
diff --git a/packages/SystemUI/res/values-en-rXC/tiles_states_strings.xml b/packages/SystemUI/res/values-en-rXC/tiles_states_strings.xml
index 3bc03c0..2432ea3 100644
--- a/packages/SystemUI/res/values-en-rXC/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/tiles_states_strings.xml
@@ -151,6 +151,11 @@
     <item msgid="7571394439974244289">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‏‎‎‎‏‎‎‏‎‏‏‏‏‏‏‏‏‎‎‏‎‎‎‎‎‏‏‎‏‎‎‎‏‎‎‎‎‏‎‎‎‎‏‎‎‏‏‏‏‏‏‎‎‎‎‎‏‎Off‎‏‎‎‏‎"</item>
     <item msgid="6866424167599381915">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‏‎‏‎‎‏‎‏‎‎‏‏‏‎‎‎‎‎‏‏‎‎‏‏‎‏‎‎‎‏‎‏‎‏‏‏‎‏‎‏‏‎‎‎‏‏‏‎‏‏‎‎‏‏‎‏‏‎On‎‏‎‎‏‎"</item>
   </string-array>
+  <string-array name="tile_states_qr_code_scanner">
+    <item msgid="7435143266149257618">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‎‏‎‏‏‏‎‏‏‏‎‏‏‏‏‎‏‏‎‏‎‎‎‎‏‎‏‎‎‎‎‏‏‏‏‎‏‏‎‏‏‎‏‎‎‎‏‏‎‎‏‎‎‏‎‎Unavailable‎‏‎‎‏‎"</item>
+    <item msgid="3301403109049256043">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‎‏‏‏‎‏‎‎‎‎‏‏‏‏‎‎‎‎‏‎‏‎‎‎‏‎‏‏‎‏‎‏‏‏‎‏‎‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‎‏‎‏‏‎Off‎‏‎‎‏‎"</item>
+    <item msgid="8878684975184010135">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‎‏‏‏‎‏‏‎‏‏‎‎‏‏‏‏‎‎‎‏‏‎‎‏‎‎‏‎‎‏‏‏‎‎‎‎‏‏‎‏‏‎‏‏‏‎‎‏‎‏‏‏‎On‎‏‎‎‏‎"</item>
+  </string-array>
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‎‏‎‎‎‎‎‏‎‎‎‎‏‎‏‏‎‏‏‏‏‎‏‎‎‎‏‎‏‎‎‏‏‎‏‎‏‎‎‏‏‏‎‎‎‎‏‎‏‎‏‎‏‏‎‎‎‎Unavailable‎‏‎‎‏‎"</item>
     <item msgid="2710157085538036590">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‏‏‎‎‏‏‏‎‎‎‏‏‎‏‎‎‏‏‎‎‎‎‎‏‎‏‎‏‎‎‎‎‏‎‎‎‎‎‎‎‎‏‎‏‎‏‎‏‏‎‏‏‎‏‏‏‎‎Off‎‏‎‎‏‎"</item>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index caa77dd..bcacd1b 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -69,8 +69,7 @@
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"La app o tu organización no permiten las capturas de pantalla"</string>
     <string name="screenshot_edit_label" msgid="8754981973544133050">"Editar"</string>
     <string name="screenshot_edit_description" msgid="3333092254706788906">"Editar captura de pantalla"</string>
-    <!-- no translation found for screenshot_share_description (2861628935812656612) -->
-    <skip />
+    <string name="screenshot_share_description" msgid="2861628935812656612">"Compartir captura"</string>
     <string name="screenshot_scroll_label" msgid="2930198809899329367">"Capturar más"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Descartar captura de pantalla"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Vista previa de la captura de pantalla"</string>
@@ -108,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"Teléfono"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Asistente voz"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"Wallet"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"Desbloquear"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"Dispositivo bloqueado"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"Escaneando rostro"</string>
@@ -465,6 +466,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Desbloquear para usar"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Ocurrió un problema al obtener las tarjetas; vuelve a intentarlo más tarde"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Configuración de pantalla de bloqueo"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"Perfil de trabajo"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Modo de avión"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"No oirás la próxima alarma a la(s) <xliff:g id="WHEN">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/tiles_states_strings.xml b/packages/SystemUI/res/values-es-rUS/tiles_states_strings.xml
index 4f738c5..cc167d5 100644
--- a/packages/SystemUI/res/values-es-rUS/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"Desactivado"</item>
     <item msgid="6866424167599381915">"Activado"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"No disponible"</item>
     <item msgid="2710157085538036590">"Desactivado"</item>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 8152879..88235fd 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -69,8 +69,7 @@
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"La aplicación o tu organización no permiten realizar capturas de pantalla"</string>
     <string name="screenshot_edit_label" msgid="8754981973544133050">"Editar"</string>
     <string name="screenshot_edit_description" msgid="3333092254706788906">"Editar captura de pantalla"</string>
-    <!-- no translation found for screenshot_share_description (2861628935812656612) -->
-    <skip />
+    <string name="screenshot_share_description" msgid="2861628935812656612">"Compartir captura de pantalla"</string>
     <string name="screenshot_scroll_label" msgid="2930198809899329367">"Capturar más"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Cerrar captura de pantalla"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Vista previa de captura de pantalla"</string>
@@ -108,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"Teléfono"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Asistente voz"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"Cartera"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"Desbloquear"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"Dispositivo bloqueado"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"Escaneando cara"</string>
@@ -465,6 +466,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Desbloquear para usar"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Se ha producido un problema al obtener tus tarjetas. Inténtalo de nuevo más tarde."</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Ajustes de pantalla de bloqueo"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"Perfil de trabajo"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Modo avión"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"No oirás la próxima alarma (<xliff:g id="WHEN">%1$s</xliff:g>)"</string>
diff --git a/packages/SystemUI/res/values-es/tiles_states_strings.xml b/packages/SystemUI/res/values-es/tiles_states_strings.xml
index 1c2f211..1d1cd71 100644
--- a/packages/SystemUI/res/values-es/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-es/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"Desactivado"</item>
     <item msgid="6866424167599381915">"Activado"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"No disponible"</item>
     <item msgid="2710157085538036590">"Desactivado"</item>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index e798f9f..c1b463f 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -69,8 +69,7 @@
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Rakendus või teie organisatsioon ei luba ekraanipilte jäädvustada"</string>
     <string name="screenshot_edit_label" msgid="8754981973544133050">"Muutmine"</string>
     <string name="screenshot_edit_description" msgid="3333092254706788906">"Ekraanipildi muutmine"</string>
-    <!-- no translation found for screenshot_share_description (2861628935812656612) -->
-    <skip />
+    <string name="screenshot_share_description" msgid="2861628935812656612">"Jaga ekraanipilti"</string>
     <string name="screenshot_scroll_label" msgid="2930198809899329367">"Jäädvustage rohkem"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Ekraanipildist loobumine"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Ekraanipildi eelvaade"</string>
@@ -108,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"Telefon"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Häälabi"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"Rahakott"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"Luku avamine"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"Seade on lukustatud"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"Näo skannimine"</string>
@@ -465,6 +466,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Avage kasutamiseks"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Teie kaartide hankimisel ilmnes probleem, proovige hiljem uuesti"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Lukustuskuva seaded"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"Tööprofiil"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Lennukirežiim"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Te ei kuule järgmist äratust kell <xliff:g id="WHEN">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-et/tiles_states_strings.xml b/packages/SystemUI/res/values-et/tiles_states_strings.xml
index bba2d82..044954d 100644
--- a/packages/SystemUI/res/values-et/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-et/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"Väljas"</item>
     <item msgid="6866424167599381915">"Sees"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"Pole saadaval"</item>
     <item msgid="2710157085538036590">"Väljas"</item>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 96378d7..a9a325a 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -107,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"Telefonoa"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Ahots-laguntza"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"Zorroa"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"Desblokeatu"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"Gailua blokeatuta dago"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"Aurpegia eskaneatzen"</string>
@@ -464,6 +466,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Desblokeatu erabiltzeko"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Arazo bat izan da txartelak eskuratzean. Saiatu berriro geroago."</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Pantaila blokeatuaren ezarpenak"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"Work profila"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Hegaldi modua"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Ez duzu entzungo hurrengo alarma (<xliff:g id="WHEN">%1$s</xliff:g>)"</string>
diff --git a/packages/SystemUI/res/values-eu/tiles_states_strings.xml b/packages/SystemUI/res/values-eu/tiles_states_strings.xml
index 2fcddd4..bb6c384 100644
--- a/packages/SystemUI/res/values-eu/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-eu/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"Desaktibatuta"</item>
     <item msgid="6866424167599381915">"Aktibatuta"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"Ez dago erabilgarri"</item>
     <item msgid="2710157085538036590">"Desaktibatuta"</item>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index e79eba0..9260abd 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -69,8 +69,7 @@
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"برنامه یا سازمان شما اجازه نمی‌دهند نماگرفت بگیرید."</string>
     <string name="screenshot_edit_label" msgid="8754981973544133050">"ویرایش"</string>
     <string name="screenshot_edit_description" msgid="3333092254706788906">"ویرایش نماگرفت"</string>
-    <!-- no translation found for screenshot_share_description (2861628935812656612) -->
-    <skip />
+    <string name="screenshot_share_description" msgid="2861628935812656612">"هم‌رسانی نماگرفت"</string>
     <string name="screenshot_scroll_label" msgid="2930198809899329367">"ضبط محتوای بیشتر"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"رد کردن نماگرفت"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"پیش‌نمایش نماگرفت"</string>
@@ -108,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"تلفن"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"دستیار صوتی"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"Wallet"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"باز کردن قفل"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"دستگاه قفل است"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"درحال اسکن کردن چهره"</string>
@@ -465,6 +466,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"برای استفاده، قفل را باز کنید"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"هنگام دریافت کارت‌ها مشکلی پیش آمد، لطفاً بعداً دوباره امتحان کنید"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"تنظیمات صفحه قفل"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"نمایه کاری"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"حالت هواپیما"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"در ساعت <xliff:g id="WHEN">%1$s</xliff:g>، دیگر صدای زنگ ساعت را نمی‌شنوید"</string>
diff --git a/packages/SystemUI/res/values-fa/tiles_states_strings.xml b/packages/SystemUI/res/values-fa/tiles_states_strings.xml
index d3662f9..13c7f41 100644
--- a/packages/SystemUI/res/values-fa/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-fa/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"خاموش"</item>
     <item msgid="6866424167599381915">"روشن"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"دردسترس نیست"</item>
     <item msgid="2710157085538036590">"خاموش"</item>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 4009669..5c36c7c 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -107,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"Puhelin"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Ääniapuri"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"Wallet"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"Avaa lukitus"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"Laite lukittu"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"Kasvojen skannaus"</string>
@@ -464,6 +466,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Avaa lukitus ja käytä"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Korttien noutamisessa oli ongelma, yritä myöhemmin uudelleen"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Lukitusnäytön asetukset"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"Työprofiili"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Lentokonetila"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Et kuule seuraavaa hälytystäsi (<xliff:g id="WHEN">%1$s</xliff:g>)."</string>
diff --git a/packages/SystemUI/res/values-fi/tiles_states_strings.xml b/packages/SystemUI/res/values-fi/tiles_states_strings.xml
index 5a88f19..47013d1 100644
--- a/packages/SystemUI/res/values-fi/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-fi/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"Poissa päältä"</item>
     <item msgid="6866424167599381915">"Päällä"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"Ei saatavilla"</item>
     <item msgid="2710157085538036590">"Poissa päältä"</item>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 1d19d0e..c5d8a48 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -69,8 +69,7 @@
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"L\'application ou votre organisation n\'autorise pas les saisies d\'écran"</string>
     <string name="screenshot_edit_label" msgid="8754981973544133050">"Modifier"</string>
     <string name="screenshot_edit_description" msgid="3333092254706788906">"Modifier la capture d\'écran"</string>
-    <!-- no translation found for screenshot_share_description (2861628935812656612) -->
-    <skip />
+    <string name="screenshot_share_description" msgid="2861628935812656612">"Partagez la capture d\'écran"</string>
     <string name="screenshot_scroll_label" msgid="2930198809899329367">"Capturer plus"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Fermer la capture d\'écran"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Aperçu de la capture d\'écran"</string>
@@ -108,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"Téléphone"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Assistance vocale"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"Portefeuille"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"Déverrouiller"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"Appareil verrouillé"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"Numérisation du visage"</string>
@@ -465,6 +466,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Déverrouiller pour utiliser"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Un problème est survenu lors de la récupération de vos cartes, veuillez réessayer plus tard"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Paramètres de l\'écran de verrouillage"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"Profil professionnel"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Mode Avion"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Vous n\'entendrez pas votre prochaine alarme à <xliff:g id="WHEN">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/tiles_states_strings.xml b/packages/SystemUI/res/values-fr-rCA/tiles_states_strings.xml
index 30870dd..fb929fc 100644
--- a/packages/SystemUI/res/values-fr-rCA/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"Désactivé"</item>
     <item msgid="6866424167599381915">"Activé"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"Non disponible"</item>
     <item msgid="2710157085538036590">"Désactivée"</item>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index b571e0c..ead26a3 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -69,8 +69,7 @@
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Les captures d\'écran ne sont pas autorisées par l\'application ni par votre organisation"</string>
     <string name="screenshot_edit_label" msgid="8754981973544133050">"Modifier"</string>
     <string name="screenshot_edit_description" msgid="3333092254706788906">"Modifier la capture d\'écran"</string>
-    <!-- no translation found for screenshot_share_description (2861628935812656612) -->
-    <skip />
+    <string name="screenshot_share_description" msgid="2861628935812656612">"Partager la capture d\'écran"</string>
     <string name="screenshot_scroll_label" msgid="2930198809899329367">"Capturer plus"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Fermer la capture d\'écran"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Aperçu de la capture d\'écran"</string>
@@ -108,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"Téléphoner"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Assistance vocale"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"Portefeuille"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"Déverrouiller"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"Appareil verrouillé"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"Analyse du visage en cours"</string>
@@ -465,6 +466,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Déverrouiller pour utiliser"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Problème de récupération de vos cartes. Réessayez plus tard"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Paramètres de l\'écran de verrouillage"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"Profil professionnel"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Mode Avion"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Vous n\'entendrez pas votre prochaine alarme <xliff:g id="WHEN">%1$s</xliff:g>."</string>
diff --git a/packages/SystemUI/res/values-fr/tiles_states_strings.xml b/packages/SystemUI/res/values-fr/tiles_states_strings.xml
index c987cd6..971477d 100644
--- a/packages/SystemUI/res/values-fr/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-fr/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"Désactivé"</item>
     <item msgid="6866424167599381915">"Activé"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"Indisponible"</item>
     <item msgid="2710157085538036590">"Désactivée"</item>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index ef91651..3aa3e3f 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -69,8 +69,7 @@
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"A aplicación ou a túa organización non permite realizar capturas de pantalla"</string>
     <string name="screenshot_edit_label" msgid="8754981973544133050">"Editar"</string>
     <string name="screenshot_edit_description" msgid="3333092254706788906">"Editar a captura de pantalla"</string>
-    <!-- no translation found for screenshot_share_description (2861628935812656612) -->
-    <skip />
+    <string name="screenshot_share_description" msgid="2861628935812656612">"Compartir captura de pantalla"</string>
     <string name="screenshot_scroll_label" msgid="2930198809899329367">"Capturar máis"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Ignorar a captura de pantalla"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Vista previa da captura de pantalla"</string>
@@ -108,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"Teléfono"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Asistente de voz"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"Wallet"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"Desbloquear"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"Dispositivo bloqueado"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"Analizando cara"</string>
@@ -465,6 +466,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Desbloquear para usar"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Produciuse un problema ao obter as tarxetas. Téntao de novo máis tarde"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Configuración da pantalla de bloqueo"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"Perfil de traballo"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Modo avión"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Non escoitarás a alarma seguinte <xliff:g id="WHEN">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-gl/tiles_states_strings.xml b/packages/SystemUI/res/values-gl/tiles_states_strings.xml
index c627ec0..e362238 100644
--- a/packages/SystemUI/res/values-gl/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-gl/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"Non"</item>
     <item msgid="6866424167599381915">"Si"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"Non dispoñible"</item>
     <item msgid="2710157085538036590">"Non"</item>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index 1483cc9..be707d8 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -69,8 +69,7 @@
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"ઍપ્લિકેશન કે તમારી સંસ્થા દ્વારા સ્ક્રીનશૉટ લેવાની મંજૂરી નથી"</string>
     <string name="screenshot_edit_label" msgid="8754981973544133050">"ફેરફાર કરો"</string>
     <string name="screenshot_edit_description" msgid="3333092254706788906">"સ્ક્રીનશૉટમાં ફેરફાર કરો"</string>
-    <!-- no translation found for screenshot_share_description (2861628935812656612) -->
-    <skip />
+    <string name="screenshot_share_description" msgid="2861628935812656612">"સ્ક્રીનશૉટ શેર કરો"</string>
     <string name="screenshot_scroll_label" msgid="2930198809899329367">"વધુ કૅપ્ચર કરો"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"સ્ક્રીનશૉટ છોડી દો"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"સ્ક્રીનશૉટનો પ્રીવ્યૂ"</string>
@@ -108,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"ફોન"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"વૉઇસ સહાય"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"વૉલેટ"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"અનલૉક કરો"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"ડિવાઇસ લૉક કરેલું છે"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"ચહેરો સ્કૅન કરવો"</string>
@@ -465,6 +466,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ઉપયોગ કરવા માટે અનલૉક કરો"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"તમારા કાર્ડની માહિતી મેળવવામાં સમસ્યા આવી હતી, કૃપા કરીને થોડા સમય પછી ફરી પ્રયાસ કરો"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"લૉક સ્ક્રીનના સેટિંગ"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"ઑફિસની પ્રોફાઇલ"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"એરપ્લેન મોડ"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"તમે <xliff:g id="WHEN">%1$s</xliff:g> એ તમારો આગલો એલાર્મ સાંભળશો નહીં"</string>
diff --git a/packages/SystemUI/res/values-gu/tiles_states_strings.xml b/packages/SystemUI/res/values-gu/tiles_states_strings.xml
index 67dfb34..12c2de7 100644
--- a/packages/SystemUI/res/values-gu/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-gu/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"બંધ છે"</item>
     <item msgid="6866424167599381915">"ચાલુ છે"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"ઉપલબ્ધ નથી"</item>
     <item msgid="2710157085538036590">"બંધ છે"</item>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 08417e4..80b52d2 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -107,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"फ़ोन"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"आवाज़ से डिवाइस का इस्तेमाल"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"वॉलेट बटन"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"अनलॉक करें"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"डिवाइस लॉक है"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"डिवाइस अनलॉक करने के लिए चेहरा स्कैन किया जाता है"</string>
@@ -464,6 +466,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"इस्तेमाल करने के लिए, डिवाइस अनलॉक करें"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"आपके कार्ड की जानकारी पाने में कोई समस्या हुई है. कृपया बाद में कोशिश करें"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"लॉक स्क्रीन की सेटिंग"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"वर्क प्रोफ़ाइल"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"हवाई जहाज़ मोड"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"आपको <xliff:g id="WHEN">%1$s</xliff:g> पर अपना अगला अलार्म नहीं सुनाई देगा"</string>
diff --git a/packages/SystemUI/res/values-hi/tiles_states_strings.xml b/packages/SystemUI/res/values-hi/tiles_states_strings.xml
index 40d15e7..f7fce26 100644
--- a/packages/SystemUI/res/values-hi/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-hi/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"बंद है"</item>
     <item msgid="6866424167599381915">"चालू है"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"उपलब्ध नहीं है"</item>
     <item msgid="2710157085538036590">"बंद है"</item>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 59aa397..8864901 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -69,8 +69,7 @@
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Aplikacija ili vaša organizacija ne dopuštaju snimanje zaslona"</string>
     <string name="screenshot_edit_label" msgid="8754981973544133050">"Uredi"</string>
     <string name="screenshot_edit_description" msgid="3333092254706788906">"Uređivanje snimke zaslona"</string>
-    <!-- no translation found for screenshot_share_description (2861628935812656612) -->
-    <skip />
+    <string name="screenshot_share_description" msgid="2861628935812656612">"Podijeli snimku zaslona"</string>
     <string name="screenshot_scroll_label" msgid="2930198809899329367">"Snimi više"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Odbacivanje snimke zaslona"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Pregled snimke zaslona"</string>
@@ -108,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"Telefon"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Glasovna pomoć"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"Wallet"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"Otključavanje"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"Uređaj je zaključan"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"Skeniranje lica"</string>
@@ -468,6 +469,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Otključajte da biste koristili"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Pojavio se problem prilikom dohvaćanja kartica, pokušajte ponovo kasnije"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Postavke zaključanog zaslona"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"Poslovni profil"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Način rada u zrakoplovu"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Nećete čuti sljedeći alarm <xliff:g id="WHEN">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-hr/tiles_states_strings.xml b/packages/SystemUI/res/values-hr/tiles_states_strings.xml
index 5622a82..90b8cce 100644
--- a/packages/SystemUI/res/values-hr/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-hr/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"Isključeno"</item>
     <item msgid="6866424167599381915">"Uključeno"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"Nedostupno"</item>
     <item msgid="2710157085538036590">"Isključeno"</item>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index fbcaa99..d8f2238 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -69,8 +69,7 @@
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Az alkalmazás vagy az Ön szervezete nem engedélyezi képernyőkép készítését"</string>
     <string name="screenshot_edit_label" msgid="8754981973544133050">"Szerkesztés"</string>
     <string name="screenshot_edit_description" msgid="3333092254706788906">"Képernyőkép szerkesztése"</string>
-    <!-- no translation found for screenshot_share_description (2861628935812656612) -->
-    <skip />
+    <string name="screenshot_share_description" msgid="2861628935812656612">"Képernyőkép megosztása"</string>
     <string name="screenshot_scroll_label" msgid="2930198809899329367">"Több rögzítése"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Képernyőkép elvetése"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Képernyőkép előnézete"</string>
@@ -108,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"Telefon"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Hangsegéd"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"Wallet"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"Feloldás"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"Az eszköz zárolva van"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"Arc keresése"</string>
@@ -465,6 +466,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Oldja fel a használathoz"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Probléma merült fel a kártyák lekérésekor, próbálja újra később"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Lezárási képernyő beállításai"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"Munkahelyi profil"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Repülős üzemmód"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Nem fogja hallani az ébresztést ekkor: <xliff:g id="WHEN">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-hu/tiles_states_strings.xml b/packages/SystemUI/res/values-hu/tiles_states_strings.xml
index 113e61f..6e1d636 100644
--- a/packages/SystemUI/res/values-hu/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-hu/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"Ki"</item>
     <item msgid="6866424167599381915">"Be"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"Nem áll rendelkezésre"</item>
     <item msgid="2710157085538036590">"Ki"</item>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index b70be8a..c5f5595 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -107,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"Հեռախոս"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Ձայնային հուշումներ"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"Դրամապանակ"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"Ապակողպել"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"Սարքը կողպված է"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"Դեմքի սկանավորում"</string>
@@ -464,6 +466,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Ապակողպել՝ օգտագործելու համար"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Չհաջողվեց բեռնել քարտերը։ Նորից փորձեք։"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Կողպէկրանի կարգավորումներ"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"Android for Work-ի պրոֆիլ"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Ավիառեժիմ"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Ժամը <xliff:g id="WHEN">%1$s</xliff:g>-ի զարթուցիչը չի զանգի"</string>
diff --git a/packages/SystemUI/res/values-hy/tiles_states_strings.xml b/packages/SystemUI/res/values-hy/tiles_states_strings.xml
index a8d89d22..3e9c28c 100644
--- a/packages/SystemUI/res/values-hy/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-hy/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"Անջատված է"</item>
     <item msgid="6866424167599381915">"Միացված է"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"Հասանելի չէ"</item>
     <item msgid="2710157085538036590">"Անջատված է"</item>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 3333a28..1bae18e 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -108,6 +108,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"Telepon"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Bantuan Suara"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"Wallet"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"Buka kunci"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"Perangkat terkunci"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"Memindai wajah"</string>
@@ -465,6 +467,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Buka kunci untuk menggunakan"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Terjadi masalah saat mendapatkan kartu Anda, coba lagi nanti"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Setelan layar kunci"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"Profil kerja"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Mode pesawat"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Anda tidak akan mendengar alarm berikutnya <xliff:g id="WHEN">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-in/tiles_states_strings.xml b/packages/SystemUI/res/values-in/tiles_states_strings.xml
index 84a9342..70ee1bc 100644
--- a/packages/SystemUI/res/values-in/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-in/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"Nonaktif"</item>
     <item msgid="6866424167599381915">"Aktif"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"Tidak tersedia"</item>
     <item msgid="2710157085538036590">"Nonaktif"</item>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 060cb77..9c3889d 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -69,8 +69,7 @@
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Forritið eða fyrirtækið þitt leyfir ekki skjámyndatöku"</string>
     <string name="screenshot_edit_label" msgid="8754981973544133050">"Breyta"</string>
     <string name="screenshot_edit_description" msgid="3333092254706788906">"Breyta skjámynd"</string>
-    <!-- no translation found for screenshot_share_description (2861628935812656612) -->
-    <skip />
+    <string name="screenshot_share_description" msgid="2861628935812656612">"Deila skjámynd"</string>
     <string name="screenshot_scroll_label" msgid="2930198809899329367">"Mynda meira"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Loka skjámynd"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Forskoðun skjámyndar"</string>
@@ -108,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"Sími"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Raddaðstoð"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"Veski"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"Taka úr lás"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"Tækið er læst"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"Andlit skannað"</string>
@@ -465,6 +466,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Taktu úr lás til að nota"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Vandamál kom upp við að sækja kortin þín. Reyndu aftur síðar"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Stillingar fyrir læstan skjá"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"Vinnusnið"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Flugstilling"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Ekki mun heyrast í vekjaranum <xliff:g id="WHEN">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-is/tiles_states_strings.xml b/packages/SystemUI/res/values-is/tiles_states_strings.xml
index 5616d74..3565a9c 100644
--- a/packages/SystemUI/res/values-is/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-is/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"Slökkt"</item>
     <item msgid="6866424167599381915">"Kveikt"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"Ekki í boði"</item>
     <item msgid="2710157085538036590">"Slökkt"</item>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index f99b6ba..4a5530f 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -69,8 +69,7 @@
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"L\'acquisizione di screenshot non è consentita dall\'app o dall\'organizzazione"</string>
     <string name="screenshot_edit_label" msgid="8754981973544133050">"Modifica"</string>
     <string name="screenshot_edit_description" msgid="3333092254706788906">"Modifica screenshot"</string>
-    <!-- no translation found for screenshot_share_description (2861628935812656612) -->
-    <skip />
+    <string name="screenshot_share_description" msgid="2861628935812656612">"Condividi screenshot"</string>
     <string name="screenshot_scroll_label" msgid="2930198809899329367">"Acquisisci di più"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Ignora screenshot"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Anteprima screenshot"</string>
@@ -108,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"Telefono"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Voice Assist"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"Portafoglio"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"Sblocca"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"Dispositivo bloccato"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"Scansione del viso"</string>
@@ -212,8 +213,8 @@
     <string name="accessibility_clear_all" msgid="970525598287244592">"Cancella tutte le notifiche."</string>
     <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192">
+      <item quantity="one"><xliff:g id="NUMBER_1">%s</xliff:g> more notifications inside.</item>
       <item quantity="other">Altre <xliff:g id="NUMBER_1">%s</xliff:g> notifiche nel gruppo.</item>
-      <item quantity="one"><xliff:g id="NUMBER_0">%s</xliff:g> altra notifica nel gruppo.</item>
     </plurals>
     <string name="accessibility_rotation_lock_on_landscape" msgid="936972553861524360">"Lo schermo è bloccato in orientamento orizzontale."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="2356633398683813837">"Lo schermo è bloccato in orientamento verticale."</string>
@@ -262,8 +263,8 @@
     <string name="quick_settings_hotspot_secondary_label_transient" msgid="7585604088079160564">"Attivazione…"</string>
     <string name="quick_settings_hotspot_secondary_label_data_saver_enabled" msgid="1280433136266439372">"Risp. dati attivo"</string>
     <plurals name="quick_settings_hotspot_secondary_label_num_devices" formatted="false" msgid="3142308865165871976">
+      <item quantity="one">%d devices</item>
       <item quantity="other">%d dispositivi</item>
-      <item quantity="one">%d dispositivo</item>
     </plurals>
     <string name="quick_settings_flashlight_label" msgid="4904634272006284185">"Torcia"</string>
     <string name="quick_settings_flashlight_camera_in_use" msgid="4820591564526512571">"Fotocamera in uso"</string>
@@ -342,8 +343,8 @@
     <string name="user_add_user_message_short" msgid="2599370307878014791">"Il nuovo utente, una volta aggiunto, deve impostare il proprio spazio.\n\nQualsiasi utente può aggiornare le app per tutti gli altri."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"Limite di utenti raggiunto"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
+      <item quantity="one">You can add up to <xliff:g id="COUNT">%d</xliff:g> users.</item>
       <item quantity="other">Puoi aggiungere fino a <xliff:g id="COUNT">%d</xliff:g> utenti.</item>
-      <item quantity="one">È possibile creare un solo utente.</item>
     </plurals>
     <string name="user_remove_user_title" msgid="9124124694835811874">"Rimuovere l\'utente?"</string>
     <string name="user_remove_user_message" msgid="6702834122128031833">"Tutte le app e i dati di questo utente verranno eliminati."</string>
@@ -465,6 +466,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Sblocca per usare"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Si è verificato un problema durante il recupero delle tue carte. Riprova più tardi."</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Impostazioni schermata di blocco"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"Profilo di lavoro"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Modalità aereo"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Non sentirai la tua prossima sveglia <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -529,12 +534,12 @@
     <string name="snooze_undo" msgid="2738844148845992103">"Annulla"</string>
     <string name="snoozed_for_time" msgid="7586689374860469469">"Posticipato di <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
     <plurals name="snoozeHourOptions" formatted="false" msgid="2066838694120718170">
+      <item quantity="one">%d hours</item>
       <item quantity="other">%d ore</item>
-      <item quantity="one">%d ora</item>
     </plurals>
     <plurals name="snoozeMinuteOptions" formatted="false" msgid="8998483159208055980">
+      <item quantity="one">%d minutes</item>
       <item quantity="other">%d minuti</item>
-      <item quantity="one">%d minuto</item>
     </plurals>
     <string name="battery_detail_switch_title" msgid="6940976502957380405">"Risparmio energetico"</string>
     <string name="keyboard_key_button_template" msgid="8005673627272051429">"Pulsante <xliff:g id="NAME">%1$s</xliff:g>"</string>
@@ -756,8 +761,8 @@
     <string name="quick_controls_title" msgid="6839108006171302273">"Controllo dispositivi"</string>
     <string name="controls_providers_title" msgid="6879775889857085056">"Scegli un\'app per aggiungere controlli"</string>
     <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
+      <item quantity="one"><xliff:g id="NUMBER_1">%s</xliff:g> controlli aggiunti.</item>
       <item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> controlli aggiunti.</item>
-      <item quantity="one"><xliff:g id="NUMBER_0">%s</xliff:g> controllo aggiunto.</item>
     </plurals>
     <string name="controls_removed" msgid="3731789252222856959">"Rimosso"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"Aggiunto ai preferiti"</string>
diff --git a/packages/SystemUI/res/values-it/tiles_states_strings.xml b/packages/SystemUI/res/values-it/tiles_states_strings.xml
index f18536c..a9c67d5 100644
--- a/packages/SystemUI/res/values-it/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-it/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"Off"</item>
     <item msgid="6866424167599381915">"On"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"Non disponibile"</item>
     <item msgid="2710157085538036590">"Off"</item>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 98fcf42..9368808 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -69,8 +69,7 @@
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"האפליקציה או הארגון שלך אינם מתירים ליצור צילומי מסך"</string>
     <string name="screenshot_edit_label" msgid="8754981973544133050">"עריכה"</string>
     <string name="screenshot_edit_description" msgid="3333092254706788906">"עריכת צילום מסך"</string>
-    <!-- no translation found for screenshot_share_description (2861628935812656612) -->
-    <skip />
+    <string name="screenshot_share_description" msgid="2861628935812656612">"שיתוף של צילום מסך"</string>
     <string name="screenshot_scroll_label" msgid="2930198809899329367">"צילום תוכן נוסף"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"סגירת צילום מסך"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"תצוגה מקדימה של צילום מסך"</string>
@@ -108,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"טלפון"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"האסיסטנט"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"ארנק"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"ביטול נעילה"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"המכשיר נעול"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"סורק פנים"</string>
@@ -471,6 +472,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"יש לבטל את הנעילה כדי להשתמש"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"הייתה בעיה בקבלת הכרטיסים שלך. כדאי לנסות שוב מאוחר יותר"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"הגדרות מסך הנעילה"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"פרופיל עבודה"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"מצב טיסה"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"לא ניתן יהיה לשמוע את ההתראה הבאה שלך <xliff:g id="WHEN">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-iw/tiles_states_strings.xml b/packages/SystemUI/res/values-iw/tiles_states_strings.xml
index 0be95b8..c769a84 100644
--- a/packages/SystemUI/res/values-iw/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-iw/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"כבוי"</item>
     <item msgid="6866424167599381915">"פועל"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"לא זמין"</item>
     <item msgid="2710157085538036590">"כבוי"</item>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 3eb2b65..bb35ad8 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -107,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"電話"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"音声アシスト"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"ウォレット"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"ロック解除"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"デバイスはロックされています"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"顔のスキャン"</string>
@@ -464,6 +466,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ロックを解除して使用"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"カードの取得中に問題が発生しました。しばらくしてからもう一度お試しください"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"ロック画面の設定"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"仕事用プロファイル"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"機内モード"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"次回のアラーム(<xliff:g id="WHEN">%1$s</xliff:g>)は鳴りません"</string>
diff --git a/packages/SystemUI/res/values-ja/tiles_states_strings.xml b/packages/SystemUI/res/values-ja/tiles_states_strings.xml
index bee2deb..6383acc 100644
--- a/packages/SystemUI/res/values-ja/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ja/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"OFF"</item>
     <item msgid="6866424167599381915">"ON"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"使用不可"</item>
     <item msgid="2710157085538036590">"OFF"</item>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index d788fdb..94eb7c2 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -69,8 +69,7 @@
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"ეკრანის ანაბეჭდების შექმნა არ არის ნებადართული აპის ან თქვენი ორგანიზაციის მიერ"</string>
     <string name="screenshot_edit_label" msgid="8754981973544133050">"რედაქტირება"</string>
     <string name="screenshot_edit_description" msgid="3333092254706788906">"ეკრანის ანაბეჭდის რედაქტირება"</string>
-    <!-- no translation found for screenshot_share_description (2861628935812656612) -->
-    <skip />
+    <string name="screenshot_share_description" msgid="2861628935812656612">"ეკრანის ანაბეჭდის გაზიარება"</string>
     <string name="screenshot_scroll_label" msgid="2930198809899329367">"მეტის აღბეჭდვა"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"ეკრანის ანაბეჭდის დახურვა"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"ეკრანის ანაბეჭდის გადახედვა"</string>
@@ -108,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"ტელეფონი"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"ხმოვანი დახმარება"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"Wallet"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"განბლოკვა"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"მოწყობილობა ჩაკეტილია"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"მიმდინარეობს სახის სკანირება"</string>
@@ -465,6 +466,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"გამოსაყენებლად განბლოკვა"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"თქვენი ბარათების მიღებისას პრობლემა წარმოიშვა. ცადეთ ხელახლა მოგვიანებით"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"ჩაკეტილი ეკრანის პარამეტრები"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"სამსახურის პროფილი"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"თვითმფრინავის რეჟიმი"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"ვერ გაიგონებთ მომდევნო მაღვიძარას <xliff:g id="WHEN">%1$s</xliff:g>-ზე"</string>
diff --git a/packages/SystemUI/res/values-ka/tiles_states_strings.xml b/packages/SystemUI/res/values-ka/tiles_states_strings.xml
index eb5f4704..4c23237 100644
--- a/packages/SystemUI/res/values-ka/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ka/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"გამორთულია"</item>
     <item msgid="6866424167599381915">"ჩართულია"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"მიუწვდომელია"</item>
     <item msgid="2710157085538036590">"გამორთულია"</item>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index ad345a9..18ce927 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -69,8 +69,7 @@
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Қолданба немесе ұйым скриншоттар түсіруге рұқсат етпейді"</string>
     <string name="screenshot_edit_label" msgid="8754981973544133050">"Өзгерту"</string>
     <string name="screenshot_edit_description" msgid="3333092254706788906">"Скриншотты өзгерту"</string>
-    <!-- no translation found for screenshot_share_description (2861628935812656612) -->
-    <skip />
+    <string name="screenshot_share_description" msgid="2861628935812656612">"Скриншотты бөлісу"</string>
     <string name="screenshot_scroll_label" msgid="2930198809899329367">"Тағы суретке түсіру"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Скриншотты жабу"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Скриншотты алдын ала қарау"</string>
@@ -108,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"Телефон"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Дауыс көмекшісі"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"Әмиян"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"Бекітпесін ашу"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"Құрылғы құлыпталды."</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"Бетті сканерлеу"</string>
@@ -465,6 +466,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Пайдалану үшін құлыпты ашу"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Карталарыңыз алынбады, кейінірек қайталап көріңіз."</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Экран құлпының параметрлері"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"Жұмыс профилі"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Ұшақ режимі"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Келесі <xliff:g id="WHEN">%1$s</xliff:g> дабылыңызды есітпейсіз"</string>
diff --git a/packages/SystemUI/res/values-kk/tiles_states_strings.xml b/packages/SystemUI/res/values-kk/tiles_states_strings.xml
index cdb5530..7a4676f 100644
--- a/packages/SystemUI/res/values-kk/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-kk/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"Өшірулі"</item>
     <item msgid="6866424167599381915">"Қосулы"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"Қолжетімсіз"</item>
     <item msgid="2710157085538036590">"Өшірулі"</item>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 7f35811..b86f9b5 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -69,8 +69,7 @@
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"ការថត​រូបអេក្រង់​មិនត្រូវ​បាន​អនុញ្ញាត​ដោយ​កម្មវិធី​នេះ ឬ​ស្ថាប័ន​របស់អ្នក"</string>
     <string name="screenshot_edit_label" msgid="8754981973544133050">"កែ"</string>
     <string name="screenshot_edit_description" msgid="3333092254706788906">"កែ​រូបថត​អេក្រង់"</string>
-    <!-- no translation found for screenshot_share_description (2861628935812656612) -->
-    <skip />
+    <string name="screenshot_share_description" msgid="2861628935812656612">"ចែករំលែករូបថតអេក្រង់"</string>
     <string name="screenshot_scroll_label" msgid="2930198809899329367">"ថត​ច្រើនទៀត"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"ច្រានចោល​រូបថត​អេក្រង់"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"ការមើល​រូបថត​អេក្រង់​សាកល្បង"</string>
@@ -108,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"ទូរសព្ទ"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"ជំនួយសំឡេង"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"កាបូប"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"ដោះ​​សោ"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"បានចាក់សោ​ឧបករណ៍"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"ការ​ស្កេន​មុខ"</string>
@@ -465,6 +466,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ដោះសោដើម្បីប្រើប្រាស់"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"មានបញ្ហា​ក្នុងការទាញយក​កាត​របស់អ្នក សូម​ព្យាយាមម្ដងទៀត​នៅពេលក្រោយ"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"ការកំណត់អេក្រង់ចាក់សោ"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"ប្រវត្តិរូបការងារ"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"ពេលជិះយន្តហោះ"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"អ្នកនឹងមិនលឺម៉ោងរោទ៍ <xliff:g id="WHEN">%1$s</xliff:g> បន្ទាប់របស់អ្នកទេ"</string>
diff --git a/packages/SystemUI/res/values-km/tiles_states_strings.xml b/packages/SystemUI/res/values-km/tiles_states_strings.xml
index 4ac3c83..be3f754 100644
--- a/packages/SystemUI/res/values-km/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-km/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"បិទ"</item>
     <item msgid="6866424167599381915">"បើក"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"មិនមានទេ"</item>
     <item msgid="2710157085538036590">"បិទ"</item>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 1d818ce..614b0ca 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -69,8 +69,7 @@
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"ಅಪ್ಲಿಕೇಶನ್ ಅಥವಾ ಸಂಸ್ಥೆಯು ಸ್ಕ್ರೀನ್‌ಶಾಟ್‌ಗಳನ್ನು ತೆಗೆಯುವುದನ್ನು ಅನುಮತಿಸುವುದಿಲ್ಲ"</string>
     <string name="screenshot_edit_label" msgid="8754981973544133050">"ಎಡಿಟ್ ಮಾಡಿ"</string>
     <string name="screenshot_edit_description" msgid="3333092254706788906">"ಸ್ಕ್ರೀನ್‌ಶಾಟ್‌ ಅನ್ನು ಎಡಿಟ್ ಮಾಡಿ"</string>
-    <!-- no translation found for screenshot_share_description (2861628935812656612) -->
-    <skip />
+    <string name="screenshot_share_description" msgid="2861628935812656612">"ಸ್ಕ್ರೀನ್‌ಶಾಟ್ ಅನ್ನು ಹಂಚಿಕೊಳ್ಳಿ"</string>
     <string name="screenshot_scroll_label" msgid="2930198809899329367">"ಇನ್ನಷ್ಟು ಕ್ಯಾಪ್ಚರ್ ಮಾಡಿ"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"ಸ್ಕ್ರೀನ್‌ಶಾಟ್ ಅನ್ನು ವಜಾಗೊಳಿಸಿ"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"ಸ್ಕ್ರೀನ್‍ಶಾಟ್‍ನ ಪೂರ್ವವೀಕ್ಷಣೆ"</string>
@@ -108,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"ಫೋನ್"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"ಧ್ವನಿ ಸಹಾಯಕ"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"Wallet"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"ಅನ್‌ಲಾಕ್"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"ಸಾಧನ ಲಾಕ್ ಆಗಿದೆ"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"ಮುಖವನ್ನು ಸ್ಕ್ಯಾನ್ ಮಾಡಲಾಗುತ್ತಿದೆ"</string>
@@ -465,6 +466,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ಬಳಸಲು ಅನ್‌ಲಾಕ್ ಮಾಡಿ"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"ನಿಮ್ಮ ಕಾರ್ಡ್‌ಗಳನ್ನು ಪಡೆಯುವಾಗ ಸಮಸ್ಯೆ ಉಂಟಾಗಿದೆ, ನಂತರ ಪುನಃ ಪ್ರಯತ್ನಿಸಿ"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"ಲಾಕ್ ಸ್ಕ್ರ್ರೀನ್ ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"ಕೆಲಸದ ಪ್ರೊಫೈಲ್"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"ಏರ್‌ಪ್ಲೇನ್ ಮೋಡ್"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"ನಿಮ್ಮ ಮುಂದಿನ <xliff:g id="WHEN">%1$s</xliff:g> ಅಲಾರಮ್ ಅನ್ನು ನೀವು ಆಲಿಸುವುದಿಲ್ಲ"</string>
diff --git a/packages/SystemUI/res/values-kn/tiles_states_strings.xml b/packages/SystemUI/res/values-kn/tiles_states_strings.xml
index ae8f5a2..7eea89d 100644
--- a/packages/SystemUI/res/values-kn/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-kn/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"ಆಫ್ ಮಾಡಿ"</item>
     <item msgid="6866424167599381915">"ಆನ್ ಮಾಡಿ"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"ಲಭ್ಯವಿಲ್ಲ"</item>
     <item msgid="2710157085538036590">"ಆಫ್ ಮಾಡಿ"</item>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 0e01272..fff2b55 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -107,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"전화"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"음성 지원"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"지갑"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"잠금 해제"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"기기 잠김"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"얼굴 스캔 중"</string>
@@ -464,6 +466,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"잠금 해제하여 사용"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"카드를 가져오는 중에 문제가 발생했습니다. 나중에 다시 시도해 보세요."</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"잠금 화면 설정"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"직장 프로필"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"비행기 모드"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"<xliff:g id="WHEN">%1$s</xliff:g>에 다음 알람을 들을 수 없습니다."</string>
diff --git a/packages/SystemUI/res/values-ko/tiles_states_strings.xml b/packages/SystemUI/res/values-ko/tiles_states_strings.xml
index b583f24..fd03b4d 100644
--- a/packages/SystemUI/res/values-ko/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ko/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"꺼짐"</item>
     <item msgid="6866424167599381915">"켜짐"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"이용 불가"</item>
     <item msgid="2710157085538036590">"꺼짐"</item>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index 2456ad4..81e3d5d 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -69,8 +69,7 @@
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Скриншот тартууга колдонмо же ишканаңыз тыюу салган."</string>
     <string name="screenshot_edit_label" msgid="8754981973544133050">"Түзөтүү"</string>
     <string name="screenshot_edit_description" msgid="3333092254706788906">"Скриншотту түзөтүү"</string>
-    <!-- no translation found for screenshot_share_description (2861628935812656612) -->
-    <skip />
+    <string name="screenshot_share_description" msgid="2861628935812656612">"Скриншотту бөлүшүү"</string>
     <string name="screenshot_scroll_label" msgid="2930198809899329367">"Көбүрөөк тартуу"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Скриншотту четке кагуу"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Скриншотту алдын ала көрүү"</string>
@@ -108,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"Телефон"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Үн жардамчысы"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"Капчык"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"Кулпусун ачуу"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"Түзмөк кулпуланды"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"Жүз скандалууда"</string>
@@ -465,6 +466,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Колдонуу үчүн кулпусун ачыңыз"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Кыйытмаларды алууда ката кетти. Бир аздан кийин кайталап көрүңүз."</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Кулпуланган экран жөндөөлөрү"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"Жумуш профили"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Учак режими"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"<xliff:g id="WHEN">%1$s</xliff:g> боло турган кийинки эскертмени укпайсыз"</string>
diff --git a/packages/SystemUI/res/values-ky/tiles_states_strings.xml b/packages/SystemUI/res/values-ky/tiles_states_strings.xml
index 6e75bf3..27aabb8 100644
--- a/packages/SystemUI/res/values-ky/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ky/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"Өчүк"</item>
     <item msgid="6866424167599381915">"Күйүк"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"Жеткиликсиз"</item>
     <item msgid="2710157085538036590">"Өчүк"</item>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index edbda76..ed5db04 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -69,8 +69,7 @@
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"ແອັບ ຫຼື ອົງກອນຂອງທ່ານບໍ່ອະນຸຍາດໃຫ້ຖ່າຍຮູບໜ້າຈໍ"</string>
     <string name="screenshot_edit_label" msgid="8754981973544133050">"ແກ້ໄຂ"</string>
     <string name="screenshot_edit_description" msgid="3333092254706788906">"ແກ້ໄຂຮູບໜ້າຈໍ"</string>
-    <!-- no translation found for screenshot_share_description (2861628935812656612) -->
-    <skip />
+    <string name="screenshot_share_description" msgid="2861628935812656612">"ແບ່ງປັນຮູບໜ້າຈໍ"</string>
     <string name="screenshot_scroll_label" msgid="2930198809899329367">"ຖ່າຍຮູບເພີ່ມເຕີມ"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"ປິດຮູບໜ້າຈໍ"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"ຕົວຢ່າງຮູບໜ້າຈໍ"</string>
@@ -108,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"ໂທລະສັບ"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"ຊ່ວຍ​ເຫຼືອ​ທາງ​ສຽງ"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"ກະເປົາ"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"ປົດລັອກ"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"ອຸປະກອນຖືກລັອກໄວ້"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"ການສະແກນໜ້າ"</string>
@@ -465,6 +466,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ປົດລັອກເພື່ອໃຊ້"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"ເກີດບັນຫາໃນການໂຫຼດບັດຂອງທ່ານ, ກະລຸນາລອງໃໝ່ໃນພາຍຫຼັງ"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"ການຕັ້ງຄ່າໜ້າຈໍລັອກ"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"​ໂປຣ​ໄຟລ໌​ບ່ອນ​ເຮັດ​ວຽກ"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"ໂໝດເຮືອ​ບິນ"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"ທ່ານ​ຈະ​ບໍ່​ໄດ້​ຍິນ​ສຽງ​ໂມງ​ປ <xliff:g id="WHEN">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-lo/tiles_states_strings.xml b/packages/SystemUI/res/values-lo/tiles_states_strings.xml
index ac5da6f..cbb4e9d 100644
--- a/packages/SystemUI/res/values-lo/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-lo/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"ປິດ"</item>
     <item msgid="6866424167599381915">"ເປີດ"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"ບໍ່ສາມາດໃຊ້ໄດ້"</item>
     <item msgid="2710157085538036590">"ປິດ"</item>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 0f6d53e..b040dde 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -69,8 +69,7 @@
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Jūsų organizacijoje arba naudojant šią programą neleidžiama daryti ekrano kopijų"</string>
     <string name="screenshot_edit_label" msgid="8754981973544133050">"Redaguoti"</string>
     <string name="screenshot_edit_description" msgid="3333092254706788906">"Redaguoti ekrano kopiją"</string>
-    <!-- no translation found for screenshot_share_description (2861628935812656612) -->
-    <skip />
+    <string name="screenshot_share_description" msgid="2861628935812656612">"Bendrinti ekrano kopiją"</string>
     <string name="screenshot_scroll_label" msgid="2930198809899329367">"Fiksuoti daugiau"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Praleisti ekrano kopiją"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Ekrano kopijos peržiūra"</string>
@@ -108,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"Telefonas"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Voice Assist"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"Piniginė"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"Atrakinti"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"Įrenginys užrakintas"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"Nuskaitomas veidas"</string>
@@ -471,6 +472,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Atrakinti, kad būtų galima naudoti"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Gaunant korteles kilo problema, bandykite dar kartą vėliau"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Užrakinimo ekrano nustatymai"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"Darbo profilis"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Lėktuvo režimas"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Negirdėsite kito signalo <xliff:g id="WHEN">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-lt/tiles_states_strings.xml b/packages/SystemUI/res/values-lt/tiles_states_strings.xml
index 4b32820..c881b1e 100644
--- a/packages/SystemUI/res/values-lt/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-lt/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"Išjungta"</item>
     <item msgid="6866424167599381915">"Įjungta"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"Nepasiekiama"</item>
     <item msgid="2710157085538036590">"Išjungta"</item>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 50154bc..031f09e 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -69,8 +69,7 @@
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Lietotne vai jūsu organizācija neatļauj veikt ekrānuzņēmumus."</string>
     <string name="screenshot_edit_label" msgid="8754981973544133050">"Rediģēt"</string>
     <string name="screenshot_edit_description" msgid="3333092254706788906">"Rediģēt ekrānuzņēmumu"</string>
-    <!-- no translation found for screenshot_share_description (2861628935812656612) -->
-    <skip />
+    <string name="screenshot_share_description" msgid="2861628935812656612">"Kopīgot ekrānuzņēmumu"</string>
     <string name="screenshot_scroll_label" msgid="2930198809899329367">"Tvert vairāk"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Nerādīt ekrānuzņēmumu"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Ekrānuzņēmuma priekšskatījums"</string>
@@ -108,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"Tālruņa numurs"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Balss palīgs"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"Maks"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"Atbloķēt"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"Ierīce ir bloķēta"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"Sejas skenēšana"</string>
@@ -468,6 +469,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Lai izmantotu, atbloķējiet ekrānu"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Ienesot jūsu kartes, radās problēma. Lūdzu, vēlāk mēģiniet vēlreiz."</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Bloķēšanas ekrāna iestatījumi"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"Darba profils"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Lidojuma režīms"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Nākamais signāls (<xliff:g id="WHEN">%1$s</xliff:g>) netiks atskaņots."</string>
diff --git a/packages/SystemUI/res/values-lv/tiles_states_strings.xml b/packages/SystemUI/res/values-lv/tiles_states_strings.xml
index d000b7c..2f170e0 100644
--- a/packages/SystemUI/res/values-lv/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-lv/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"Izslēgts"</item>
     <item msgid="6866424167599381915">"Ieslēgts"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"Nav pieejams"</item>
     <item msgid="2710157085538036590">"Izslēgts"</item>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index 6148344..ad7818a 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -69,8 +69,7 @@
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Апликацијата или вашата организација не дозволува снимање слики од екранот"</string>
     <string name="screenshot_edit_label" msgid="8754981973544133050">"Измени"</string>
     <string name="screenshot_edit_description" msgid="3333092254706788906">"Изменете ја сликата од екранот"</string>
-    <!-- no translation found for screenshot_share_description (2861628935812656612) -->
-    <skip />
+    <string name="screenshot_share_description" msgid="2861628935812656612">"Споделете слика од екранот"</string>
     <string name="screenshot_scroll_label" msgid="2930198809899329367">"Сними повеќе"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Отфрлете ја сликата од екранот"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Преглед на слика од екранот"</string>
@@ -108,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"Телефон"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Гласовна помош"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"Паричник"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"Отклучување"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"Уредот е заклучен"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"Скенирање лице"</string>
@@ -465,6 +466,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Отклучете за да користите"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Имаше проблем при преземањето на картичките. Обидете се повторно подоцна"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Поставки за заклучен екран"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"Работен профил"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Авионски режим"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Нема да го слушнете следниот аларм <xliff:g id="WHEN">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-mk/tiles_states_strings.xml b/packages/SystemUI/res/values-mk/tiles_states_strings.xml
index 9d0c495..912746a 100644
--- a/packages/SystemUI/res/values-mk/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-mk/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"Исклучено"</item>
     <item msgid="6866424167599381915">"Вклучено"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"Недостапно"</item>
     <item msgid="2710157085538036590">"Исклучено"</item>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 28f0238..552d228 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -107,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"ഫോണ്‍"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"വോയ്‌സ് സഹായം"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"വാലറ്റ്"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"അണ്‍ലോക്ക് ചെയ്യുക"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"ഉപകരണം ലോക്ക് ചെയ്തു"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"മുഖം സ്കാൻ ചെയ്യുന്നു"</string>
@@ -464,6 +466,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ഉപയോഗിക്കാൻ അൺലോക്ക് ചെയ്യുക"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"നിങ്ങളുടെ കാർഡുകൾ ലഭ്യമാക്കുന്നതിൽ ഒരു പ്രശ്‌നമുണ്ടായി, പിന്നീട് വീണ്ടും ശ്രമിക്കുക"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"ലോക്ക് സ്ക്രീൻ ക്രമീകരണം"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"ഔദ്യോഗിക പ്രൊഫൈൽ"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"ഫ്ലൈറ്റ് മോഡ്"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"<xliff:g id="WHEN">%1$s</xliff:g>-നുള്ള നിങ്ങളുടെ അടുത്ത അലാറം കേൾക്കില്ല"</string>
diff --git a/packages/SystemUI/res/values-ml/tiles_states_strings.xml b/packages/SystemUI/res/values-ml/tiles_states_strings.xml
index af2b960..bdbf600 100644
--- a/packages/SystemUI/res/values-ml/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ml/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"ഓഫാണ്"</item>
     <item msgid="6866424167599381915">"ഓണാണ്"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"ലഭ്യമല്ല"</item>
     <item msgid="2710157085538036590">"ഓഫാണ്"</item>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 42bae51..817fc14 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -69,8 +69,7 @@
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Таны апп, байгууллагад дэлгэцийн зураг авахыг зөвшөөрдөггүй"</string>
     <string name="screenshot_edit_label" msgid="8754981973544133050">"Засах"</string>
     <string name="screenshot_edit_description" msgid="3333092254706788906">"Дэлгэцийн агшныг засах"</string>
-    <!-- no translation found for screenshot_share_description (2861628935812656612) -->
-    <skip />
+    <string name="screenshot_share_description" msgid="2861628935812656612">"Дэлгэцийн агшныг хуваалцах"</string>
     <string name="screenshot_scroll_label" msgid="2930198809899329367">"Ихийг багтаасан зураг авах"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Дэлгэцийн агшныг хаах"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Дэлгэцийн агшныг урьдчилан үзэх"</string>
@@ -108,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"Утас"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Дуут туслах"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"Түрийвч"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"Тайлах"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"Төхөөрөмжийг түгжсэн"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"Скан хийх нүүр царай"</string>
@@ -465,6 +466,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Ашиглахын тулд түгжээг тайлах"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Таны картыг авахад асуудал гарлаа. Дараа дахин оролдоно уу"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Түгжигдсэн дэлгэцийн тохиргоо"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"Ажлын профайл"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Нислэгийн горим"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"<xliff:g id="WHEN">%1$s</xliff:g>-т та дараагийн сэрүүлгээ сонсохгүй"</string>
diff --git a/packages/SystemUI/res/values-mn/tiles_states_strings.xml b/packages/SystemUI/res/values-mn/tiles_states_strings.xml
index 47a42ff..81b1b1d 100644
--- a/packages/SystemUI/res/values-mn/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-mn/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"Унтраалттай"</item>
     <item msgid="6866424167599381915">"Асаалттай"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"Боломжгүй"</item>
     <item msgid="2710157085538036590">"Унтраалттай"</item>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index f7004b3..ccbf77b 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -107,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"फोन"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"व्हॉइस सहाय्य"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"वॉलेट"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"अनलॉक करा"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"डिव्हाइस लॉक केले"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"चेहरा स्कॅन करत आहे"</string>
@@ -438,7 +440,7 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"रिंग करा"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"व्हायब्रेट"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"म्यूट करा"</string>
-    <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. सशब्द करण्यासाठी टॅप करा."</string>
+    <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. अनम्यूट करण्यासाठी टॅप करा."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. व्हायब्रेट सेट करण्यासाठी टॅप करा. प्रवेशयोग्यता सेवा म्यूट केल्या जाऊ शकतात."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. म्यूट करण्यासाठी टॅप करा. प्रवेशक्षमता सेवा म्यूट केल्या जाऊ शकतात."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. व्हायब्रेट सेट करण्यासाठी टॅप करा."</string>
@@ -464,6 +466,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"वापरण्यासाठी अनलॉक करा"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"तुमची कार्ड मिळवताना समस्या आली, कृपया नंतर पुन्हा प्रयत्न करा"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"लॉक स्क्रीन सेटिंग्ज"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"कार्य प्रोफाईल"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"विमान मोड"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"तुम्ही तुमचा <xliff:g id="WHEN">%1$s</xliff:g> वाजता होणारा पुढील अलार्म ऐकणार नाही"</string>
diff --git a/packages/SystemUI/res/values-mr/tiles_states_strings.xml b/packages/SystemUI/res/values-mr/tiles_states_strings.xml
index 4a638b5..560194a 100644
--- a/packages/SystemUI/res/values-mr/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-mr/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"बंद आहे"</item>
     <item msgid="6866424167599381915">"सुरू आहे"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"उपलब्ध नाही"</item>
     <item msgid="2710157085538036590">"बंद आहे"</item>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 35ba5a1..82174ab 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -108,6 +108,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"Telefon"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Bantuan Suara"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"Dompet"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"Buka kunci"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"Peranti dikunci"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"Mengimbas wajah"</string>
@@ -465,6 +467,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Buka kunci untuk menggunakan"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Terdapat masalah sewaktu mendapatkan kad anda. Sila cuba sebentar lagi"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Tetapan skrin kunci"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"Profil kerja"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Mod pesawat"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Anda tidak akan mendengar penggera yang seterusnya <xliff:g id="WHEN">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-ms/tiles_states_strings.xml b/packages/SystemUI/res/values-ms/tiles_states_strings.xml
index 93d4e6d..fef4b1d 100644
--- a/packages/SystemUI/res/values-ms/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ms/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"Mati"</item>
     <item msgid="6866424167599381915">"Hidup"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"Tidak tersedia"</item>
     <item msgid="2710157085538036590">"Mati"</item>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index d2722b2..281ad88 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -108,6 +108,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"ဖုန်း"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"အသံ အကူအညီ"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"Wallet"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"သော့ဖွင့်ရန်"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"စက်ပစ္စည်းကို လော့ခ်ချထားသည်"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"မျက်နှာ စကင်ဖတ်နေသည်"</string>
@@ -465,6 +467,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"သုံးရန် လော့ခ်ဖွင့်ပါ"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"သင်၏ကတ်များ ရယူရာတွင် ပြဿနာရှိနေသည်၊ နောက်မှ ထပ်စမ်းကြည့်ပါ"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"လော့ခ်မျက်နှာပြင် ဆက်တင်များ"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"အလုပ် ပရိုဖိုင်"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"လေယာဉ်ပျံမုဒ်"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"<xliff:g id="WHEN">%1$s</xliff:g> ၌သင့်နောက်ထပ် နှိုးစက်ကို ကြားမည်မဟုတ်ပါ"</string>
diff --git a/packages/SystemUI/res/values-my/tiles_states_strings.xml b/packages/SystemUI/res/values-my/tiles_states_strings.xml
index 3adb16e..898fca3 100644
--- a/packages/SystemUI/res/values-my/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-my/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"ပိတ်"</item>
     <item msgid="6866424167599381915">"ဖွင့်"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"မရနိုင်ပါ"</item>
     <item msgid="2710157085538036590">"ပိတ်"</item>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index a5957cb..3e5f11d 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -107,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"Telefonnummer"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Talehjelp"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"Wallet"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"Lås opp"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"Enheten er låst"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"Skanning av ansikt"</string>
@@ -464,6 +466,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Lås opp for å bruke"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Det oppsto et problem med henting av kortene. Prøv igjen senere"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Innstillinger for låseskjermen"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"Work-profil"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Flymodus"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Du hører ikke neste innstilte alarm <xliff:g id="WHEN">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-nb/tiles_states_strings.xml b/packages/SystemUI/res/values-nb/tiles_states_strings.xml
index 8ebe050..c0e5b3a 100644
--- a/packages/SystemUI/res/values-nb/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-nb/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"Av"</item>
     <item msgid="6866424167599381915">"På"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"Utilgjengelig"</item>
     <item msgid="2710157085538036590">"Av"</item>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 89c66e3..77cdd51 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -107,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"फोन"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"आवाज सहायता"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"वालेट"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"खोल्नुहोस्"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"यन्त्र लक गरिएको छ"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"अनुहार स्क्यान गर्दै"</string>
@@ -464,6 +466,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"यो वालेट प्रयोग गर्न डिभाइस अनलक गर्नुहोस्"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"तपाईंका कार्डहरू प्राप्त गर्ने क्रममा समस्या भयो, कृपया पछि फेरि प्रयास गर्नुहोस्"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"लक स्क्रिनसम्बन्धी सेटिङ"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"कार्य प्रोफाइल"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"हवाइजहाज मोड"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"तपाईँले आफ्नो अर्को अलार्म <xliff:g id="WHEN">%1$s</xliff:g> सुन्नुहुने छैन"</string>
diff --git a/packages/SystemUI/res/values-ne/tiles_states_strings.xml b/packages/SystemUI/res/values-ne/tiles_states_strings.xml
index a1cf9ac..571e128 100644
--- a/packages/SystemUI/res/values-ne/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ne/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"अफ छ"</item>
     <item msgid="6866424167599381915">"अन छ"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"उपलब्ध छैन"</item>
     <item msgid="2710157085538036590">"अफ छ"</item>
diff --git a/packages/SystemUI/res/values-night/styles.xml b/packages/SystemUI/res/values-night/styles.xml
index 07e28b6..cb963e6 100644
--- a/packages/SystemUI/res/values-night/styles.xml
+++ b/packages/SystemUI/res/values-night/styles.xml
@@ -16,9 +16,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android">
 
-    <style name="Theme.SystemUI.Dialog" parent="@android:style/Theme.DeviceDefault.Dialog">
-        <item name="android:buttonCornerRadius">28dp</item>
-    </style>
+    <style name="Theme.SystemUI.DayNightDialog" parent="@android:style/Theme.DeviceDefault.Dialog"/>
 
     <style name="Theme.SystemUI.Dialog.Alert" parent="@*android:style/Theme.DeviceDefault.Dialog.Alert" />
 
@@ -53,13 +51,17 @@
     <style name="TextAppearance.InternetDialog.Active">
         <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
         <item name="android:textSize">16sp</item>
-        <item name="android:textColor">@color/connected_network_primary_color</item>
+        <item name="android:textColor">?android:attr/textColorPrimaryInverse</item>
         <item name="android:textDirection">locale</item>
     </style>
 
     <style name="TextAppearance.InternetDialog.Secondary.Active">
         <item name="android:textSize">14sp</item>
-        <item name="android:textColor">@color/connected_network_secondary_color</item>
+        <item name="android:textColor">?android:attr/textColorSecondaryInverse</item>
+    </style>
+
+    <style name="InternetDialog.Divider.Active">
+        <item name="android:background">?android:attr/textColorSecondaryInverse</item>
     </style>
 
 </resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 530669b..0e8fd0d 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -69,8 +69,7 @@
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Het maken van screenshots wordt niet toegestaan door de app of je organisatie"</string>
     <string name="screenshot_edit_label" msgid="8754981973544133050">"Bewerken"</string>
     <string name="screenshot_edit_description" msgid="3333092254706788906">"Screenshot bewerken"</string>
-    <!-- no translation found for screenshot_share_description (2861628935812656612) -->
-    <skip />
+    <string name="screenshot_share_description" msgid="2861628935812656612">"Screenshot delen"</string>
     <string name="screenshot_scroll_label" msgid="2930198809899329367">"Meer opnemen"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Screenshot sluiten"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Voorbeeld van screenshot"</string>
@@ -108,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"Telefoon"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Spraakassistent"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"Portemonnee"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"Ontgrendelen"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"Apparaat vergrendeld"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"Gezicht scannen"</string>
@@ -465,6 +466,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Ontgrendelen om te gebruiken"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Er is een probleem opgetreden bij het ophalen van je kaarten. Probeer het later opnieuw."</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Instellingen voor vergrendelscherm"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"Werkprofiel"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Vliegtuigmodus"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Je hoort je volgende wekker niet <xliff:g id="WHEN">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-nl/tiles_states_strings.xml b/packages/SystemUI/res/values-nl/tiles_states_strings.xml
index 06b1048..9293f52 100644
--- a/packages/SystemUI/res/values-nl/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-nl/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"Uit"</item>
     <item msgid="6866424167599381915">"Aan"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"Niet beschikbaar"</item>
     <item msgid="2710157085538036590">"Uit"</item>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index bc4e7d1..d02dafb 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -107,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"ଫୋନ୍‍"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"ଭଏସ୍‌ ସହାୟକ"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"ୱାଲେଟ୍"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"ଅନଲକ୍‌ କରନ୍ତୁ"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"ଡିଭାଇସ୍ ଲକ୍ ହୋଇଯାଇଛି"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"ଫେସ୍ ସ୍କାନିଙ୍ଗ କରାଯାଉଛି"</string>
@@ -464,6 +466,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ବ୍ୟବହାର କରିବାକୁ ଅନଲକ୍ କରନ୍ତୁ"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"ଆପଣଙ୍କ କାର୍ଡଗୁଡ଼ିକ ପାଇବାରେ ଏକ ସମସ୍ୟା ହୋଇଥିଲା। ଦୟାକରି ପରେ ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"ସ୍କ୍ରିନ୍ ଲକ୍ ସେଟିଂସ୍"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"ୱର୍କ ପ୍ରୋଫାଇଲ୍‌"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"ଏରୋପ୍ଲେନ୍‍ ମୋଡ୍"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"<xliff:g id="WHEN">%1$s</xliff:g>ବେଳେ ଆପଣ ନିଜର ପରବର୍ତ୍ତୀ ଆଲାର୍ମ ଶୁଣିପାରିବେ ନାହିଁ"</string>
diff --git a/packages/SystemUI/res/values-or/tiles_states_strings.xml b/packages/SystemUI/res/values-or/tiles_states_strings.xml
index 7129c11..848d382 100644
--- a/packages/SystemUI/res/values-or/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-or/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"ବନ୍ଦ ଅଛି"</item>
     <item msgid="6866424167599381915">"ଚାଲୁ ଅଛି"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"ଉପଲବ୍ଧ ନାହିଁ"</item>
     <item msgid="2710157085538036590">"ବନ୍ଦ ଅଛି"</item>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index de918aa..f3ea051 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -107,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"ਫ਼ੋਨ ਕਰੋ"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"ਅਵਾਜ਼ੀ ਸਹਾਇਕ"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"ਵਾਲੇਟ"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"ਅਣਲਾਕ ਕਰੋ"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"ਡੀਵਾਈਸ ਲਾਕ ਹੈ"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"ਚਿਹਰਾ ਸਕੈਨ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ"</string>
@@ -464,6 +466,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ਵਰਤਣ ਲਈ ਅਣਲਾਕ ਕਰੋ"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"ਤੁਹਾਡੇ ਕਾਰਡ ਪ੍ਰਾਪਤ ਕਰਨ ਵਿੱਚ ਕੋਈ ਸਮੱਸਿਆ ਆਈ, ਕਿਰਪਾ ਕਰਕੇ ਬਾਅਦ ਵਿੱਚ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"ਲਾਕ ਸਕ੍ਰੀਨ ਸੈਟਿੰਗਾਂ"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"ਹਵਾਈ-ਜਹਾਜ਼ ਮੋਡ"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"ਤੁਸੀਂ <xliff:g id="WHEN">%1$s</xliff:g> ਵਜੇ ਆਪਣਾ ਅਗਲਾ ਅਲਾਰਮ ਨਹੀਂ ਸੁਣੋਗੇ"</string>
diff --git a/packages/SystemUI/res/values-pa/tiles_states_strings.xml b/packages/SystemUI/res/values-pa/tiles_states_strings.xml
index fbb3888..409b456 100644
--- a/packages/SystemUI/res/values-pa/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-pa/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"ਬੰਦ ਹੈ"</item>
     <item msgid="6866424167599381915">"ਚਾਲੂ ਹੈ"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"ਅਣਉਪਲਬਧ ਹੈ"</item>
     <item msgid="2710157085538036590">"ਬੰਦ ਹੈ"</item>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 0245d36..1532645 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -107,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"Telefon"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Asystent głosowy"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"Portfel"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"Odblokuj"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"Urządzenie zablokowane"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"Skanowanie twarzy"</string>
@@ -470,6 +472,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Odblokuj, aby użyć"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Podczas pobierania kart wystąpił problem. Spróbuj ponownie później."</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Ustawienia ekranu blokady"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"Profil służbowy"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Tryb samolotowy"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Nie usłyszysz swojego następnego alarmu <xliff:g id="WHEN">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-pl/tiles_states_strings.xml b/packages/SystemUI/res/values-pl/tiles_states_strings.xml
index 1b213b3..2e6df68 100644
--- a/packages/SystemUI/res/values-pl/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-pl/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"Wyłączony"</item>
     <item msgid="6866424167599381915">"Włączony"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"Niedostępny"</item>
     <item msgid="2710157085538036590">"Wyłączony"</item>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 75b0b24..226220b 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -69,8 +69,7 @@
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"O app ou a organização não permitem capturas de tela"</string>
     <string name="screenshot_edit_label" msgid="8754981973544133050">"Editar"</string>
     <string name="screenshot_edit_description" msgid="3333092254706788906">"Editar captura de tela"</string>
-    <!-- no translation found for screenshot_share_description (2861628935812656612) -->
-    <skip />
+    <string name="screenshot_share_description" msgid="2861628935812656612">"Compartilhar captura de tela"</string>
     <string name="screenshot_scroll_label" msgid="2930198809899329367">"Capturar mais"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Dispensar captura de tela"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Visualização de captura de tela"</string>
@@ -108,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"Telefone"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Assistência de voz"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"Carteira"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"Desbloquear"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"Dispositivo bloqueado"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"Verificando rosto"</string>
@@ -465,6 +466,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Desbloquear para usar"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Ocorreu um problema ao carregar os cards. Tente novamente mais tarde"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Configurações de tela de bloqueio"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"Perfil de trabalho"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Modo avião"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Você não ouvirá o próximo alarme às <xliff:g id="WHEN">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/tiles_states_strings.xml b/packages/SystemUI/res/values-pt-rBR/tiles_states_strings.xml
index 5801d30..6647221 100644
--- a/packages/SystemUI/res/values-pt-rBR/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"Desativado"</item>
     <item msgid="6866424167599381915">"Ativado"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"Indisponível"</item>
     <item msgid="2710157085538036590">"Desativado"</item>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 94946af..d98900f 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -69,8 +69,7 @@
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"A app ou a sua entidade não permitem tirar capturas de ecrã"</string>
     <string name="screenshot_edit_label" msgid="8754981973544133050">"Editar"</string>
     <string name="screenshot_edit_description" msgid="3333092254706788906">"Editar captura de ecrã"</string>
-    <!-- no translation found for screenshot_share_description (2861628935812656612) -->
-    <skip />
+    <string name="screenshot_share_description" msgid="2861628935812656612">"Partilhar captura de ecrã"</string>
     <string name="screenshot_scroll_label" msgid="2930198809899329367">"Capturar mais"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Ignorar captura de ecrã"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Pré-visualização da captura de ecrã"</string>
@@ -108,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"Telemóvel"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Assistente de voz"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"Carteira"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"Desbloquear"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"Dispositivo bloqueado"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"A analisar o rosto…"</string>
@@ -212,8 +213,8 @@
     <string name="accessibility_clear_all" msgid="970525598287244592">"Limpar todas as notificações."</string>
     <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192">
-      <item quantity="other">Mais <xliff:g id="NUMBER_1">%s</xliff:g> notificações no grupo.</item>
       <item quantity="one">Mais <xliff:g id="NUMBER_0">%s</xliff:g> notificação no grupo.</item>
+      <item quantity="other">Mais <xliff:g id="NUMBER_1">%s</xliff:g> notificações no grupo.</item>
     </plurals>
     <string name="accessibility_rotation_lock_on_landscape" msgid="936972553861524360">"O ecrã está bloqueado na orientação horizontal."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="2356633398683813837">"O ecrã está bloqueado na orientação vertical."</string>
@@ -262,8 +263,8 @@
     <string name="quick_settings_hotspot_secondary_label_transient" msgid="7585604088079160564">"A ativar..."</string>
     <string name="quick_settings_hotspot_secondary_label_data_saver_enabled" msgid="1280433136266439372">"Poup. dados ativada"</string>
     <plurals name="quick_settings_hotspot_secondary_label_num_devices" formatted="false" msgid="3142308865165871976">
-      <item quantity="other">%d dispositivos</item>
       <item quantity="one">%d dispositivo</item>
+      <item quantity="other">%d dispositivos</item>
     </plurals>
     <string name="quick_settings_flashlight_label" msgid="4904634272006284185">"Lanterna"</string>
     <string name="quick_settings_flashlight_camera_in_use" msgid="4820591564526512571">"Câmara em utilização"</string>
@@ -342,8 +343,8 @@
     <string name="user_add_user_message_short" msgid="2599370307878014791">"Ao adicionar um novo utilizador, essa pessoa tem de configurar o respetivo espaço.\n\nQualquer utilizador pode atualizar apps para todos os outros utilizadores."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"Limite de utilizadores alcançado"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
-      <item quantity="other">Pode adicionar até <xliff:g id="COUNT">%d</xliff:g> utilizadores.</item>
       <item quantity="one">Apenas é possível criar um utilizador.</item>
+      <item quantity="other">Pode adicionar até <xliff:g id="COUNT">%d</xliff:g> utilizadores.</item>
     </plurals>
     <string name="user_remove_user_title" msgid="9124124694835811874">"Remover o utilizador?"</string>
     <string name="user_remove_user_message" msgid="6702834122128031833">"Serão eliminados todos os dados e todas as aplicações deste utilizador."</string>
@@ -465,6 +466,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Desbloquear para utilizar"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Ocorreu um problema ao obter os seus cartões. Tente novamente mais tarde."</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Definições do ecrã de bloqueio"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"Perfil de trabalho"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Modo de avião"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Não vai ouvir o próximo alarme às <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -529,12 +534,12 @@
     <string name="snooze_undo" msgid="2738844148845992103">"Anular"</string>
     <string name="snoozed_for_time" msgid="7586689374860469469">"Suspensa por <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
     <plurals name="snoozeHourOptions" formatted="false" msgid="2066838694120718170">
-      <item quantity="other">%d horas</item>
       <item quantity="one">%d hora</item>
+      <item quantity="other">%d horas</item>
     </plurals>
     <plurals name="snoozeMinuteOptions" formatted="false" msgid="8998483159208055980">
-      <item quantity="other">%d minutos</item>
       <item quantity="one">%d minuto</item>
+      <item quantity="other">%d minutos</item>
     </plurals>
     <string name="battery_detail_switch_title" msgid="6940976502957380405">"Poupança de bateria"</string>
     <string name="keyboard_key_button_template" msgid="8005673627272051429">"Botão <xliff:g id="NAME">%1$s</xliff:g>"</string>
@@ -756,8 +761,8 @@
     <string name="quick_controls_title" msgid="6839108006171302273">"Controlos de dispositivos"</string>
     <string name="controls_providers_title" msgid="6879775889857085056">"Escolha uma app para adicionar controlos"</string>
     <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
-      <item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> controlos adicionados.</item>
       <item quantity="one"><xliff:g id="NUMBER_0">%s</xliff:g> controlo adicionado.</item>
+      <item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> controlos adicionados.</item>
     </plurals>
     <string name="controls_removed" msgid="3731789252222856959">"Removido"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"Adicionado aos favoritos"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/tiles_states_strings.xml b/packages/SystemUI/res/values-pt-rPT/tiles_states_strings.xml
index 9ee9fc2..fc3795a 100644
--- a/packages/SystemUI/res/values-pt-rPT/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"Desligado"</item>
     <item msgid="6866424167599381915">"Ligado"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"Indisponível"</item>
     <item msgid="2710157085538036590">"Desligado"</item>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 75b0b24..226220b 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -69,8 +69,7 @@
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"O app ou a organização não permitem capturas de tela"</string>
     <string name="screenshot_edit_label" msgid="8754981973544133050">"Editar"</string>
     <string name="screenshot_edit_description" msgid="3333092254706788906">"Editar captura de tela"</string>
-    <!-- no translation found for screenshot_share_description (2861628935812656612) -->
-    <skip />
+    <string name="screenshot_share_description" msgid="2861628935812656612">"Compartilhar captura de tela"</string>
     <string name="screenshot_scroll_label" msgid="2930198809899329367">"Capturar mais"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Dispensar captura de tela"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Visualização de captura de tela"</string>
@@ -108,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"Telefone"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Assistência de voz"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"Carteira"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"Desbloquear"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"Dispositivo bloqueado"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"Verificando rosto"</string>
@@ -465,6 +466,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Desbloquear para usar"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Ocorreu um problema ao carregar os cards. Tente novamente mais tarde"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Configurações de tela de bloqueio"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"Perfil de trabalho"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Modo avião"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Você não ouvirá o próximo alarme às <xliff:g id="WHEN">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-pt/tiles_states_strings.xml b/packages/SystemUI/res/values-pt/tiles_states_strings.xml
index 5801d30..6647221 100644
--- a/packages/SystemUI/res/values-pt/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-pt/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"Desativado"</item>
     <item msgid="6866424167599381915">"Ativado"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"Indisponível"</item>
     <item msgid="2710157085538036590">"Desativado"</item>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index d59403e..9e4c7da 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -69,8 +69,7 @@
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Crearea capturilor de ecran nu este permisă de aplicație sau de organizația dvs."</string>
     <string name="screenshot_edit_label" msgid="8754981973544133050">"Editați"</string>
     <string name="screenshot_edit_description" msgid="3333092254706788906">"Editați captura de ecran"</string>
-    <!-- no translation found for screenshot_share_description (2861628935812656612) -->
-    <skip />
+    <string name="screenshot_share_description" msgid="2861628935812656612">"Trimiteți captura de ecran"</string>
     <string name="screenshot_scroll_label" msgid="2930198809899329367">"Surprindeți mai mult"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Închideți captura de ecran"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Previzualizare a capturii de ecran"</string>
@@ -108,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"Telefon"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Asistent vocal"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"Wallet"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"Deblocați"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"Dispozitiv blocat"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"Scanarea chipului"</string>
@@ -468,6 +469,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Deblocați pentru a folosi"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"A apărut o problemă la preluarea cardurilor. Încercați din nou mai târziu"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Setările ecranului de blocare"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"Profil de serviciu"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Mod Avion"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Nu veți auzi următoarea alarmă <xliff:g id="WHEN">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-ro/tiles_states_strings.xml b/packages/SystemUI/res/values-ro/tiles_states_strings.xml
index 3f56424..53d5fa2 100644
--- a/packages/SystemUI/res/values-ro/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ro/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"Dezactivat"</item>
     <item msgid="6866424167599381915">"Activat"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"Indisponibilă"</item>
     <item msgid="2710157085538036590">"Dezactivată"</item>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 1364c1d..66e32f2 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -108,6 +108,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"Телефон."</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Аудиоподсказки"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"Кошелек"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"Разблокировать."</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"Устройство заблокировано"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"Сканирование лица"</string>
@@ -471,6 +473,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Разблокировать для использования"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Не удалось получить информацию о картах. Повторите попытку позже."</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Настройки заблокированного экрана"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"Рабочий профиль"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Режим полета"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Следующий будильник: <xliff:g id="WHEN">%1$s</xliff:g>. Звук отключен."</string>
diff --git a/packages/SystemUI/res/values-ru/tiles_states_strings.xml b/packages/SystemUI/res/values-ru/tiles_states_strings.xml
index 29556da..14098fc 100644
--- a/packages/SystemUI/res/values-ru/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ru/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"Откл."</item>
     <item msgid="6866424167599381915">"Вкл."</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"Функция недоступна"</item>
     <item msgid="2710157085538036590">"Откл."</item>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index a780614..a25672c 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -107,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"දුරකථනය"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"හඬ සහාය"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"පසුම්බිය"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"අඟුල අරින්න"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"උපාංගය අගුලු දමා ඇත"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"මුහුණ ස්කෑන් කිරීම"</string>
@@ -464,6 +466,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"භාවිත කිරීමට අගුලු හරින්න"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"ඔබගේ කාඩ්පත ලබා ගැනීමේ ගැටලුවක් විය, කරුණාකර පසුව නැවත උත්සාහ කරන්න"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"අගුලු තිර සැකසීම්"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"කාර්යාල පැතිකඩ"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"ගුවන්යානා ප්‍රකාරය"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"ඔබට ඔබේ ඊළඟ එලාමය <xliff:g id="WHEN">%1$s</xliff:g> නොඇසෙනු ඇත"</string>
diff --git a/packages/SystemUI/res/values-si/tiles_states_strings.xml b/packages/SystemUI/res/values-si/tiles_states_strings.xml
index 9ca8198..ed39e4a 100644
--- a/packages/SystemUI/res/values-si/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-si/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"අක්‍රියයි"</item>
     <item msgid="6866424167599381915">"සක්‍රියයි"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"නොමැත"</item>
     <item msgid="2710157085538036590">"අක්‍රියයි"</item>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 5e0b172..4c672bf 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -69,8 +69,7 @@
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Vytváranie snímok obrazovky je zakázané aplikáciou alebo vašou organizáciou"</string>
     <string name="screenshot_edit_label" msgid="8754981973544133050">"Upraviť"</string>
     <string name="screenshot_edit_description" msgid="3333092254706788906">"Upraviť snímku obrazovky"</string>
-    <!-- no translation found for screenshot_share_description (2861628935812656612) -->
-    <skip />
+    <string name="screenshot_share_description" msgid="2861628935812656612">"Zdieľať snímku obrazovky"</string>
     <string name="screenshot_scroll_label" msgid="2930198809899329367">"Zachytiť viac"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Zavrieť snímku obrazovky"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Ukážka snímky obrazovky"</string>
@@ -108,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"Telefón"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Hlasový asistent"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"Peňaženka"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"Odomknúť"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"Zariadenie je uzamknuté"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"Skenovanie tváre"</string>
@@ -471,6 +472,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Odomknúť a použiť"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Pri načítavaní kariet sa vyskytol problém. Skúste to neskôr."</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Nastavenia uzamknutej obrazovky"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"Pracovný profil"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Režim v lietadle"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Váš budík o <xliff:g id="WHEN">%1$s</xliff:g> sa nespustí"</string>
diff --git a/packages/SystemUI/res/values-sk/tiles_states_strings.xml b/packages/SystemUI/res/values-sk/tiles_states_strings.xml
index 2e80a80..817e8fb 100644
--- a/packages/SystemUI/res/values-sk/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-sk/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"Vypnuté"</item>
     <item msgid="6866424167599381915">"Zapnuté"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"Nie je k dispozícii"</item>
     <item msgid="2710157085538036590">"Vypnuté"</item>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 339bad5..43df9e7 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -107,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"Telefon"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Glasovni pomočnik"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"Google Denarnica"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"Odkleni"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"Naprava je zaklenjena."</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"Optično branje obraza"</string>
@@ -470,6 +472,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Odklenite za uporabo"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Pri pridobivanju kartic je prišlo do težave. Poskusite znova pozneje."</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Nastavitve zaklepanja zaslona"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"Profil za Android Work"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Način za letalo"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Naslednjega alarma ob <xliff:g id="WHEN">%1$s</xliff:g> ne boste slišali"</string>
diff --git a/packages/SystemUI/res/values-sl/tiles_states_strings.xml b/packages/SystemUI/res/values-sl/tiles_states_strings.xml
index f1d1aabb..6f6a8f1 100644
--- a/packages/SystemUI/res/values-sl/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-sl/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"Izklopljeno"</item>
     <item msgid="6866424167599381915">"Vklopljeno"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"Ni na voljo"</item>
     <item msgid="2710157085538036590">"Izklopljeno"</item>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index bddfcbb..bc9018772 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -108,6 +108,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"Telefoni"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Ndihma zanore"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"Wallet"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"Shkyç"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"Pajisja është e kyçur"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"Po skanon fytyrën"</string>
@@ -465,6 +467,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Shkyçe për ta përdorur"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Pati një problem me marrjen e kartave të tua. Provo përsëri më vonë"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Cilësimet e ekranit të kyçjes"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"Profili i punës"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Modaliteti i aeroplanit"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Nuk do ta dëgjosh alarmin e radhës në <xliff:g id="WHEN">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-sq/tiles_states_strings.xml b/packages/SystemUI/res/values-sq/tiles_states_strings.xml
index 83069c9..a88c530 100644
--- a/packages/SystemUI/res/values-sq/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-sq/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"Joaktiv"</item>
     <item msgid="6866424167599381915">"Aktiv"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"Nuk ofrohet"</item>
     <item msgid="2710157085538036590">"Joaktiv"</item>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 5035e8a..0606d0e 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -69,8 +69,7 @@
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Апликација или организација не дозвољавају прављење снимака екрана"</string>
     <string name="screenshot_edit_label" msgid="8754981973544133050">"Измени"</string>
     <string name="screenshot_edit_description" msgid="3333092254706788906">"Измените снимак екрана"</string>
-    <!-- no translation found for screenshot_share_description (2861628935812656612) -->
-    <skip />
+    <string name="screenshot_share_description" msgid="2861628935812656612">"Делите снимак екрана"</string>
     <string name="screenshot_scroll_label" msgid="2930198809899329367">"Снимите још"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Одбаците снимак екрана"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Преглед снимка екрана"</string>
@@ -108,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"Телефон"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Гласовна помоћ"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"Новчаник"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"Откључајте"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"Уређај је закључан"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"Скенирање лица"</string>
@@ -468,6 +469,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Откључај ради коришћења"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Дошло је до проблема при преузимању картица. Пробајте поново касније"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Подешавања закључаног екрана"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"Пословни профил"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Режим рада у авиону"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Нећете чути следећи аларм у <xliff:g id="WHEN">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-sr/tiles_states_strings.xml b/packages/SystemUI/res/values-sr/tiles_states_strings.xml
index cec05da..e2f9c62 100644
--- a/packages/SystemUI/res/values-sr/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-sr/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"Искључено"</item>
     <item msgid="6866424167599381915">"Укључено"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"Недоступно"</item>
     <item msgid="2710157085538036590">"Искључено"</item>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 79aac89..60b0097 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -69,8 +69,7 @@
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Appen eller organisationen tillåter inte att du tar skärmbilder"</string>
     <string name="screenshot_edit_label" msgid="8754981973544133050">"Redigera"</string>
     <string name="screenshot_edit_description" msgid="3333092254706788906">"Redigera skärmbild"</string>
-    <!-- no translation found for screenshot_share_description (2861628935812656612) -->
-    <skip />
+    <string name="screenshot_share_description" msgid="2861628935812656612">"Dela skärmbild"</string>
     <string name="screenshot_scroll_label" msgid="2930198809899329367">"Fånga mer"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Stäng skärmbild"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Förhandsgranskning av skärmbild"</string>
@@ -108,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"Mobil"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Röstassistent"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"Wallet"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"Lås upp"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"Enheten är låst"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"Registrerar ansikte"</string>
@@ -465,6 +466,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Lås upp för att använda"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Det gick inte att hämta dina kort. Försök igen senare."</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Inställningar för låsskärm"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"Jobbprofil"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Flygplansläge"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Nästa alarm, kl. <xliff:g id="WHEN">%1$s</xliff:g>, kommer inte att höras"</string>
diff --git a/packages/SystemUI/res/values-sv/tiles_states_strings.xml b/packages/SystemUI/res/values-sv/tiles_states_strings.xml
index dbe32da..a7ba12b 100644
--- a/packages/SystemUI/res/values-sv/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-sv/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"Av"</item>
     <item msgid="6866424167599381915">"På"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"Inte tillgängligt"</item>
     <item msgid="2710157085538036590">"Av"</item>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index a4d0118..22e138f 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -69,8 +69,7 @@
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Programu au shirika lako halikuruhusu kupiga picha za skrini"</string>
     <string name="screenshot_edit_label" msgid="8754981973544133050">"Badilisha"</string>
     <string name="screenshot_edit_description" msgid="3333092254706788906">"Badilisha picha ya skrini"</string>
-    <!-- no translation found for screenshot_share_description (2861628935812656612) -->
-    <skip />
+    <string name="screenshot_share_description" msgid="2861628935812656612">"Shiriki picha ya skrini"</string>
     <string name="screenshot_scroll_label" msgid="2930198809899329367">"Nasa zaidi"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Ondoa picha ya skrini"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Onyesho la kukagua picha ya skrini"</string>
@@ -108,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"Simu"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Mapendekezo ya Sauti"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"Wallet"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"Fungua"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"Kifaa kimefungwa"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"Inachanganua uso"</string>
@@ -465,6 +466,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Fungua ili utumie"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Hitilafu imetokea wakati wa kuleta kadi zako, tafadhali jaribu tena baadaye"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Mipangilio ya kufunga skrini"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"Wasifu wa kazini"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Hali ya ndegeni"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Hutasikia kengele yako inayofuata ya saa <xliff:g id="WHEN">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-sw/tiles_states_strings.xml b/packages/SystemUI/res/values-sw/tiles_states_strings.xml
index 93f99b7..f1fbf38 100644
--- a/packages/SystemUI/res/values-sw/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-sw/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"Kimezimwa"</item>
     <item msgid="6866424167599381915">"Kimewashwa"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"Hakipatikani"</item>
     <item msgid="2710157085538036590">"Kimezimwa"</item>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 430d00b..c2a3ed4 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -69,8 +69,7 @@
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"ஸ்கிரீன் ஷாட்டுகளை எடுப்பதை, ஆப்ஸ் அல்லது உங்கள் நிறுவனம் அனுமதிக்கவில்லை"</string>
     <string name="screenshot_edit_label" msgid="8754981973544133050">"திருத்து"</string>
     <string name="screenshot_edit_description" msgid="3333092254706788906">"ஸ்கிரீன்ஷாட்டைத் திருத்தும்"</string>
-    <!-- no translation found for screenshot_share_description (2861628935812656612) -->
-    <skip />
+    <string name="screenshot_share_description" msgid="2861628935812656612">"ஸ்கிரீன்ஷாட்டைப் பகிர்"</string>
     <string name="screenshot_scroll_label" msgid="2930198809899329367">"கூடுதலாகப் படமெடு"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"ஸ்கிரீன்ஷாட்டை நிராகரிக்கும்"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"ஸ்கிரீன்ஷாட்டின் மாதிரிக்காட்சி"</string>
@@ -108,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"ஃபோன்"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"குரல் உதவி"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"வாலட்"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"அன்லாக் செய்"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"சாதனம் பூட்டப்பட்டுள்ளது"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"முகத்தை ஸ்கேன் செய்கிறது"</string>
@@ -465,6 +466,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"பயன்படுத்துவதற்கு அன்லாக் செய்க"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"உங்கள் கார்டுகளின் விவரங்களைப் பெறுவதில் சிக்கல் ஏற்பட்டது, பிறகு முயலவும்"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"பூட்டுத் திரை அமைப்புகள்"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"பணிக் கணக்கு"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"விமானப் பயன்முறை"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"அடுத்த அலாரத்தை <xliff:g id="WHEN">%1$s</xliff:g> மணிக்கு கேட்க மாட்டீர்கள்"</string>
diff --git a/packages/SystemUI/res/values-ta/tiles_states_strings.xml b/packages/SystemUI/res/values-ta/tiles_states_strings.xml
index d2ba6a5..b2cc840 100644
--- a/packages/SystemUI/res/values-ta/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ta/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"முடக்கப்பட்டுள்ளது"</item>
     <item msgid="6866424167599381915">"இயக்கப்பட்டுள்ளது"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"கிடைக்கவில்லை"</item>
     <item msgid="2710157085538036590">"முடக்கப்பட்டுள்ளது"</item>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 2c392db..d8a4c21 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -107,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"ఫోన్"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"వాయిస్ అసిస్టెంట్"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"వాలెట్"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"అన్‌లాక్ చేయి"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"పరికరం లాక్ చేయబడింది"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"ముఖాన్ని స్కాన్ చేస్తోంది"</string>
@@ -450,7 +452,7 @@
     <string name="volume_dialog_title" msgid="6502703403483577940">"%s వాల్యూమ్ నియంత్రణలు"</string>
     <string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"కాల్స్‌ మరియు నోటిఫికేషన్‌లు రింగ్ అవుతాయి (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
     <string name="system_ui_tuner" msgid="1471348823289954729">"సిస్టమ్ UI ట్యూనర్"</string>
-    <string name="status_bar" msgid="4357390266055077437">"స్థితి పట్టీ"</string>
+    <string name="status_bar" msgid="4357390266055077437">"స్టేటస్‌ పట్టీ"</string>
     <string name="demo_mode" msgid="263484519766901593">"సిస్టమ్ UI డెమో మోడ్"</string>
     <string name="enable_demo_mode" msgid="3180345364745966431">"డెమో మోడ్ ప్రారంభించండి"</string>
     <string name="show_demo_mode" msgid="3677956462273059726">"డెమో మోడ్ చూపు"</string>
@@ -464,6 +466,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ఉపయోగించడానికి అన్‌లాక్ చేయండి"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"మీ కార్డ్‌లను పొందడంలో సమస్య ఉంది, దయచేసి తర్వాత మళ్లీ ట్రై చేయండి"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"లాక్ స్క్రీన్ సెట్టింగ్‌లు"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"ఆఫీస్ ప్రొఫైల్‌"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"ఎయిర్‌ప్లేన్ మోడ్"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"మీరు <xliff:g id="WHEN">%1$s</xliff:g> సెట్ చేసిన మీ తర్వాత అలారం మీకు వినిపించదు"</string>
@@ -483,7 +489,7 @@
     <string name="enable_bluetooth_message" msgid="6740938333772779717">"మీ కీబోర్డ్‌ను మీ టాబ్లెట్‌తో కనెక్ట్ చేయడానికి, మీరు ముందుగా బ్లూటూత్ ఆన్ చేయాలి."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="2866408183324184876">"ఆన్ చేయి"</string>
     <string name="tuner_full_importance_settings" msgid="1388025816553459059">"పవర్ నోటిఫికేషన్ నియంత్రణలు"</string>
-    <string name="power_notification_controls_description" msgid="1334963837572708952">"పవర్ నోటిఫికేషన్ నియంత్రణలతో, మీరు యాప్ నోటిఫికేషన్‌ల కోసం ప్రాముఖ్యత స్థాయిని 0 నుండి 5 వరకు సెట్ చేయవచ్చు. \n\n"<b>"స్థాయి 5"</b>" \n- నోటిఫికేషన్ లిస్ట్‌ పైభాగంలో చూపబడతాయి \n- పూర్తి స్క్రీన్ అంతరాయం అనుమతించబడుతుంది \n- ఎల్లప్పుడూ త్వరిత వీక్షణ అందించబడుతుంది \n\n"<b>"స్థాయి 4"</b>\n"- పూర్తి స్క్రీన్ అంతరాయం నిరోధించబడుతుంది \n- ఎల్లప్పుడూ త్వరిత వీక్షణ అందించబడుతుంది \n\n"<b>"స్థాయి 3"</b>" \n- పూర్తి స్క్రీన్ అంతరాయం నిరోధించబడుతుంది \n- ఎప్పుడూ త్వరిత వీక్షణ అందించబడదు \n\n"<b>"స్థాయి 2"</b>" \n- పూర్తి స్క్రీన్ అంతరాయం నిరోధించబడుతుంది \n- ఎప్పుడూ త్వరిత వీక్షణ అందించబడదు \n- ఎప్పుడూ శబ్దం మరియు వైబ్రేషన్ చేయవు \n\n"<b>"స్థాయి 1"</b>" \n- పూర్తి స్క్రీన్ అంతరాయం నిరోధించబడుతుంది \n- ఎప్పుడూ త్వరిత వీక్షణ అందించబడదు \n- ఎప్పుడూ శబ్దం లేదా వైబ్రేట్ చేయవు \n- లాక్ స్క్రీన్ మరియు స్థితి పట్టీ నుండి దాచబడతాయి \n- నోటిఫికేషన్ లిస్ట్‌ దిగువ భాగంలో చూపబడతాయి \n\n"<b>"స్థాయి 0"</b>" \n- యాప్ నుండి అన్ని నోటిఫికేషన్‌లు బ్లాక్ చేయబడతాయి"</string>
+    <string name="power_notification_controls_description" msgid="1334963837572708952">"పవర్ నోటిఫికేషన్ కంట్రోల్స్ సాయంతో, మీరు యాప్ నోటిఫికేషన్‌లకు ప్రాముఖ్యతా స్థాయిని 0 నుండి 5 వరకు సెట్ చేయవచ్చు. \n\n"<b>"స్థాయి 5"</b>" \n- నోటిఫికేషన్ లిస్ట్‌ పైభాగంలో చూపబడతాయి \n- ఫుల్-స్క్రీన్ అంతరాయం అనుమతించబడుతుంది \n- ఎల్లప్పుడూ క్విక్ వీక్షణ అందించబడుతుంది \n\n"<b>"స్థాయి 4"</b>\n"- ఫుల్-స్క్రీన్ అంతరాయం నిరోధించబడుతుంది \n- ఎల్లప్పుడూ క్విక్ వీక్షణ అందించబడుతుంది \n\n"<b>"స్థాయి 3"</b>" \n- ఫుల్-స్క్రీన్ అంతరాయం నిరోధించబడుతుంది \n- ఎప్పుడూ క్విక్ వీక్షణ అందించబడదు \n\n"<b>"స్థాయి 2"</b>" \n- ఫుల్-స్క్రీన్ అంతరాయం నిరోధించబడుతుంది \n- ఎప్పుడూ క్విక్ వీక్షణ అందించబడదు \n- ఎప్పుడూ శబ్దం మరియు వైబ్రేషన్ చేయవు \n\n"<b>"స్థాయి 1"</b>" \n- ఫుల్-స్క్రీన్ అంతరాయం నిరోధించబడుతుంది \n- ఎప్పుడూ క్విక్ వీక్షణ అందించబడదు \n- ఎప్పుడూ శబ్దం లేదా వైబ్రేట్ చేయవు \n- లాక్ స్క్రీన్, స్టేటస్ బార్‌ల నుండి దాచబడతాయి \n- నోటిఫికేషన్ లిస్ట్‌ దిగువ భాగంలో చూపబడతాయి \n\n"<b>"స్థాయి 0"</b>" \n- యాప్ నుండి అన్ని నోటిఫికేషన్‌లు బ్లాక్ చేయబడతాయి"</string>
     <string name="inline_done_button" msgid="6043094985588909584">"పూర్తయింది"</string>
     <string name="inline_ok_button" msgid="603075490581280343">"అప్లయి చేయి"</string>
     <string name="inline_turn_off_notifications" msgid="8543989584403106071">"నోటిఫికేషన్‌లను ఆఫ్ చేయి"</string>
@@ -803,7 +809,7 @@
     <string name="controls_error_removed_title" msgid="1207794911208047818">"కంట్రోల్ అందుబాటులో లేదు"</string>
     <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g>ను యాక్సెస్ చేయడం సాధ్యపడలేదు. <xliff:g id="APPLICATION">%2$s</xliff:g> యాప్‌ను తనిఖీ చేసి, కంట్రోల్ ఇప్పటికీ అందుబాటులో ఉందని, యాప్ సెట్టింగ్‌లు మారలేదని నిర్ధారించుకోండి."</string>
     <string name="controls_open_app" msgid="483650971094300141">"యాప్‌ను తెరువు"</string>
-    <string name="controls_error_generic" msgid="352500456918362905">"స్థితిని లోడ్ చేయడం సాధ్యపడదు"</string>
+    <string name="controls_error_generic" msgid="352500456918362905">"స్టేటస్ లోడ్ చేయడం సాధ్యపడలేదు"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"ఎర్రర్, మళ్లీ ప్రయత్నించండి"</string>
     <string name="controls_menu_add" msgid="4447246119229920050">"కంట్రోల్స్‌ను జోడించండి"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"కంట్రోల్స్‌ను ఎడిట్ చేయండి"</string>
diff --git a/packages/SystemUI/res/values-te/tiles_states_strings.xml b/packages/SystemUI/res/values-te/tiles_states_strings.xml
index bbe5c8e..3a2dca0 100644
--- a/packages/SystemUI/res/values-te/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-te/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"ఆఫ్‌లో ఉంది"</item>
     <item msgid="6866424167599381915">"ఆన్‌లో ఉంది"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"అందుబాటులో లేదు"</item>
     <item msgid="2710157085538036590">"ఆఫ్‌లో ఉంది"</item>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 8e54bc1..5922678 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -108,6 +108,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"โทรศัพท์"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"ตัวช่วยเสียง"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"Wallet"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"ปลดล็อก"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"อุปกรณ์ถูกล็อก"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"กำลังสแกนใบหน้า"</string>
@@ -465,6 +467,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ปลดล็อกเพื่อใช้"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"เกิดปัญหาในการดึงข้อมูลบัตรของคุณ โปรดลองอีกครั้งในภายหลัง"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"การตั้งค่าหน้าจอล็อก"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"โปรไฟล์งาน"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"โหมดบนเครื่องบิน"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"คุณจะไม่ได้ยินเสียงปลุกครั้งถัดไปในเวลา <xliff:g id="WHEN">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-th/tiles_states_strings.xml b/packages/SystemUI/res/values-th/tiles_states_strings.xml
index 2152e1c..170a9be 100644
--- a/packages/SystemUI/res/values-th/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-th/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"ปิด"</item>
     <item msgid="6866424167599381915">"เปิด"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"ไม่พร้อมใช้งาน"</item>
     <item msgid="2710157085538036590">"ปิด"</item>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 218b21f..05efac2 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -108,6 +108,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"Telepono"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Voice Assist"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"Wallet"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"I-unlock"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"Naka-lock ang device"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"Sina-scan ang mukha"</string>
@@ -465,6 +467,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"I-unlock para magamit"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Nagkaproblema sa pagkuha ng iyong mga card, pakisubukan ulit sa ibang pagkakataon"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Mga setting ng lock screen"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"Profile sa trabaho"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Airplane mode"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Hindi mo maririnig ang iyong susunod na alarm ng <xliff:g id="WHEN">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-tl/tiles_states_strings.xml b/packages/SystemUI/res/values-tl/tiles_states_strings.xml
index 83b9f18..6935782 100644
--- a/packages/SystemUI/res/values-tl/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-tl/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"Naka-off"</item>
     <item msgid="6866424167599381915">"Naka-on"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"Hindi available"</item>
     <item msgid="2710157085538036590">"Naka-off"</item>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 8d1c890..87803f3 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -69,8 +69,7 @@
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Uygulama veya kuruluşunuz, ekran görüntüsü alınmasına izin vermiyor."</string>
     <string name="screenshot_edit_label" msgid="8754981973544133050">"Düzenle"</string>
     <string name="screenshot_edit_description" msgid="3333092254706788906">"Ekran görüntüsünü düzenle"</string>
-    <!-- no translation found for screenshot_share_description (2861628935812656612) -->
-    <skip />
+    <string name="screenshot_share_description" msgid="2861628935812656612">"Ekranı paylaş"</string>
     <string name="screenshot_scroll_label" msgid="2930198809899329367">"Daha fazla ekran görüntüsü al"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Ekran görüntüsünü kapat"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Ekran görüntüsü önizlemesi"</string>
@@ -108,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"Telefon"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Sesli Yardım"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"Cüzdan"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"Kilidi aç"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"Cihaz kilitlendi"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"Yüz taranıyor"</string>
@@ -465,6 +466,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Kullanmak için kilidi aç"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Kartlarınız alınırken bir sorun oluştu. Lütfen daha sonra tekrar deneyin"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Kilit ekranı ayarları"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"İş profili"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Uçak modu"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"<xliff:g id="WHEN">%1$s</xliff:g> olarak ayarlanmış bir sonraki alarmınızı duymayacaksınız"</string>
diff --git a/packages/SystemUI/res/values-tr/tiles_states_strings.xml b/packages/SystemUI/res/values-tr/tiles_states_strings.xml
index c550004..34179b5 100644
--- a/packages/SystemUI/res/values-tr/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-tr/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"Kapalı"</item>
     <item msgid="6866424167599381915">"Açık"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"Kullanılamıyor"</item>
     <item msgid="2710157085538036590">"Kapalı"</item>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index b635714..0dbb0db 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -69,8 +69,7 @@
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Додаток або адміністратор вашої організації не дозволяють робити знімки екрана"</string>
     <string name="screenshot_edit_label" msgid="8754981973544133050">"Редагувати"</string>
     <string name="screenshot_edit_description" msgid="3333092254706788906">"Редагувати знімок екрана"</string>
-    <!-- no translation found for screenshot_share_description (2861628935812656612) -->
-    <skip />
+    <string name="screenshot_share_description" msgid="2861628935812656612">"Поділитися знімком екрана"</string>
     <string name="screenshot_scroll_label" msgid="2930198809899329367">"Включити більше деталей"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Закрити знімок екрана"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Перегляд знімка екрана"</string>
@@ -108,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"Номер телефону"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Голосові підказки"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"Гаманець"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"Розблокувати"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"Пристрій заблоковано"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"Сканування обличчя"</string>
@@ -471,6 +472,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Розблокувати, щоб використовувати"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Не вдалось отримати ваші картки. Повторіть спробу пізніше."</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Параметри блокування екрана"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"Робочий профіль"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Режим польоту"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Наступний сигнал о <xliff:g id="WHEN">%1$s</xliff:g> не пролунає"</string>
diff --git a/packages/SystemUI/res/values-uk/tiles_states_strings.xml b/packages/SystemUI/res/values-uk/tiles_states_strings.xml
index 6420647..21e0128 100644
--- a/packages/SystemUI/res/values-uk/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-uk/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"Вимкнено"</item>
     <item msgid="6866424167599381915">"Увімкнено"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"Недоступно"</item>
     <item msgid="2710157085538036590">"Вимкнено"</item>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index ca50746..1d4b0b0 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -69,8 +69,7 @@
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"ایپ یا آپ کی تنظیم کی جانب سے اسکرین شاٹس لینے کی اجازت نہیں ہے"</string>
     <string name="screenshot_edit_label" msgid="8754981973544133050">"ترمیم کریں"</string>
     <string name="screenshot_edit_description" msgid="3333092254706788906">"اسکرین شاٹ میں ترمیم کریں"</string>
-    <!-- no translation found for screenshot_share_description (2861628935812656612) -->
-    <skip />
+    <string name="screenshot_share_description" msgid="2861628935812656612">"اسکرین شاٹ کا اشتراک کریں"</string>
     <string name="screenshot_scroll_label" msgid="2930198809899329367">"مزید کیپچر کریں"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"اسکرین شاٹ برخاست کریں"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"اسکرین شاٹ کا پیش منظر"</string>
@@ -108,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"فون"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"صوتی معاون"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"Wallet"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"غیر مقفل کریں"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"آلہ مقفل کر دیا گیا"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"اسکیننگ چہرہ"</string>
@@ -465,6 +466,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"استعمال کرنے کے لیے غیر مقفل کریں"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"آپ کے کارڈز حاصل کرنے میں ایک مسئلہ درپیش تھا، براہ کرم بعد میں دوبارہ کوشش کریں"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"مقفل اسکرین کی ترتیبات"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"دفتری پروفائل"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"ہوائی جہاز وضع"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"آپ کو <xliff:g id="WHEN">%1$s</xliff:g> بجے اپنا اگلا الارم سنائی نہیں دے گا"</string>
diff --git a/packages/SystemUI/res/values-ur/tiles_states_strings.xml b/packages/SystemUI/res/values-ur/tiles_states_strings.xml
index b8d8cf5..71f2a08 100644
--- a/packages/SystemUI/res/values-ur/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ur/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"آف ہے"</item>
     <item msgid="6866424167599381915">"آن ہے"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"دستیاب نہیں ہے"</item>
     <item msgid="2710157085538036590">"آف ہے"</item>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index a3955ad..eb02d15 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -107,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"Telefon"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Ovozli yordam"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"Wallet"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"Qulfdan chiqarish"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"Qurilma qulflandi"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"Yuzni skanerlash"</string>
@@ -464,6 +466,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Foydalanish uchun qulfdan chiqarish"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Bildirgilarni yuklashda xatolik yuz berdi, keyinroq qaytadan urining"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Qulflangan ekran sozlamalari"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"Ish profili"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Parvoz rejimi"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Keyingi signal (<xliff:g id="WHEN">%1$s</xliff:g>) chalinmaydi"</string>
diff --git a/packages/SystemUI/res/values-uz/tiles_states_strings.xml b/packages/SystemUI/res/values-uz/tiles_states_strings.xml
index dad93cb..f69166e 100644
--- a/packages/SystemUI/res/values-uz/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-uz/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"Oʻchiq"</item>
     <item msgid="6866424167599381915">"Yoniq"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"Ishlamaydi"</item>
     <item msgid="2710157085538036590">"Oʻchiq"</item>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 3396f98..5444f4c 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -69,8 +69,7 @@
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Ứng dụng hoặc tổ chức của bạn không cho phép chụp ảnh màn hình"</string>
     <string name="screenshot_edit_label" msgid="8754981973544133050">"Chỉnh sửa"</string>
     <string name="screenshot_edit_description" msgid="3333092254706788906">"Chỉnh sửa ảnh chụp màn hình"</string>
-    <!-- no translation found for screenshot_share_description (2861628935812656612) -->
-    <skip />
+    <string name="screenshot_share_description" msgid="2861628935812656612">"Chia sẻ ảnh chụp màn hình"</string>
     <string name="screenshot_scroll_label" msgid="2930198809899329367">"Chụp thêm"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Đóng ảnh chụp màn hình"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Xem trước ảnh chụp màn hình"</string>
@@ -108,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"Điện thoại"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Trợ lý thoại"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"Ví"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"Mở khóa"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"Đã khóa thiết bị"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"Quét tìm khuôn mặt"</string>
@@ -465,6 +466,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Mở khóa để sử dụng"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Đã xảy ra sự cố khi tải thẻ của bạn. Vui lòng thử lại sau"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Cài đặt màn hình khóa"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"Hồ sơ công việc"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Chế độ máy bay"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Bạn sẽ không nghe thấy báo thức tiếp theo lúc <xliff:g id="WHEN">%1$s</xliff:g> của mình"</string>
diff --git a/packages/SystemUI/res/values-vi/tiles_states_strings.xml b/packages/SystemUI/res/values-vi/tiles_states_strings.xml
index df16b22..a973ffc 100644
--- a/packages/SystemUI/res/values-vi/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-vi/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"Đang tắt"</item>
     <item msgid="6866424167599381915">"Đang bật"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"Không hoạt động"</item>
     <item msgid="2710157085538036590">"Đang tắt"</item>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 54c329c..e54fa0d 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -107,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"电话"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"语音助理"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"电子钱包"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"解锁"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"设备已锁定"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"正在扫描面孔"</string>
@@ -464,6 +466,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"解锁设备即可使用"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"获取您的卡片时出现问题,请稍后重试"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"锁定屏幕设置"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"工作资料"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"飞行模式"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"您在<xliff:g id="WHEN">%1$s</xliff:g>将不会听到下次闹钟响铃"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/tiles_states_strings.xml b/packages/SystemUI/res/values-zh-rCN/tiles_states_strings.xml
index 0bf0322..e4a6dcd 100644
--- a/packages/SystemUI/res/values-zh-rCN/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"已关闭"</item>
     <item msgid="6866424167599381915">"已开启"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"不可用"</item>
     <item msgid="2710157085538036590">"已关闭"</item>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index f210619..d791554 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -107,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"電話"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"語音助手"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"電子錢包"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"解鎖"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"裝置已上鎖"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"掃瞄緊面孔"</string>
@@ -464,6 +466,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"解鎖即可使用"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"擷取資訊卡時發生問題,請稍後再試。"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"上鎖畫面設定"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"工作設定檔"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"飛行模式"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"您不會<xliff:g id="WHEN">%1$s</xliff:g>聽到鬧鐘"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/tiles_states_strings.xml b/packages/SystemUI/res/values-zh-rHK/tiles_states_strings.xml
index 7339a52..4e6af22 100644
--- a/packages/SystemUI/res/values-zh-rHK/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"已關閉"</item>
     <item msgid="6866424167599381915">"已開啟"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"無法使用"</item>
     <item msgid="2710157085538036590">"已關閉"</item>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index f96c36a..628e4d4 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -69,8 +69,7 @@
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"這個應用程式或貴機構不允許擷取螢幕畫面"</string>
     <string name="screenshot_edit_label" msgid="8754981973544133050">"編輯"</string>
     <string name="screenshot_edit_description" msgid="3333092254706788906">"編輯螢幕截圖"</string>
-    <!-- no translation found for screenshot_share_description (2861628935812656612) -->
-    <skip />
+    <string name="screenshot_share_description" msgid="2861628935812656612">"分享螢幕截圖"</string>
     <string name="screenshot_scroll_label" msgid="2930198809899329367">"擴大螢幕截圖範圍"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"關閉螢幕截圖"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"螢幕截圖預覽"</string>
@@ -108,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"電話"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"語音小幫手"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"電子錢包"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"解除鎖定"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"裝置已鎖定"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"掃描臉孔"</string>
@@ -465,6 +466,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"解鎖即可使用"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"擷取卡片時發生問題,請稍後再試"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"螢幕鎖定設定"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"工作資料夾"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"飛航模式"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"你不會聽到下一個<xliff:g id="WHEN">%1$s</xliff:g> 的鬧鐘"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/tiles_states_strings.xml b/packages/SystemUI/res/values-zh-rTW/tiles_states_strings.xml
index 7339a52..4e6af22 100644
--- a/packages/SystemUI/res/values-zh-rTW/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"已關閉"</item>
     <item msgid="6866424167599381915">"已開啟"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"無法使用"</item>
     <item msgid="2710157085538036590">"已關閉"</item>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index d06b166..cea362b 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -69,8 +69,7 @@
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Ukuthatha izithombe-skrini akuvunyelwe uhlelo lokusebenza noma inhlangano yakho"</string>
     <string name="screenshot_edit_label" msgid="8754981973544133050">"Hlela"</string>
     <string name="screenshot_edit_description" msgid="3333092254706788906">"Hlela isithombe-skrini"</string>
-    <!-- no translation found for screenshot_share_description (2861628935812656612) -->
-    <skip />
+    <string name="screenshot_share_description" msgid="2861628935812656612">"Yabelana ngesithombe-skrini"</string>
     <string name="screenshot_scroll_label" msgid="2930198809899329367">"Thwebula okuningi"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Cashisa isithombe-skrini"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Ukubuka kuqala isithombe-skrini"</string>
@@ -108,6 +107,8 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"Ifoni"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Isisekeli sezwi"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"I-wallet"</string>
+    <!-- no translation found for accessibility_qr_code_scanner_button (7521277927692910795) -->
+    <skip />
     <string name="accessibility_unlock_button" msgid="122785427241471085">"Vula"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"Idivayisi ikhiyiwe"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"Ukuskena ubuso"</string>
@@ -465,6 +466,10 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Vula ukuze usebenzise"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Kube khona inkinga yokuthola amakhadi akho, sicela uzame futhi ngemuva kwesikhathi"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Amasethingi okukhiya isikrini"</string>
+    <!-- no translation found for qr_code_scanner_title (1598912458255252498) -->
+    <skip />
+    <!-- no translation found for qr_code_scanner_description (7452098243938659945) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"Iphrofayela yomsebenzi"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Imodi yendiza"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Ngeke uzwe i-alamu yakho elandelayo ngo-<xliff:g id="WHEN">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-zu/tiles_states_strings.xml b/packages/SystemUI/res/values-zu/tiles_states_strings.xml
index fa2d972..201aa10 100644
--- a/packages/SystemUI/res/values-zu/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-zu/tiles_states_strings.xml
@@ -151,6 +151,9 @@
     <item msgid="7571394439974244289">"Valiwe"</item>
     <item msgid="6866424167599381915">"Vuliwe"</item>
   </string-array>
+    <!-- no translation found for tile_states_qr_code_scanner:0 (7435143266149257618) -->
+    <!-- no translation found for tile_states_qr_code_scanner:1 (3301403109049256043) -->
+    <!-- no translation found for tile_states_qr_code_scanner:2 (8878684975184010135) -->
   <string-array name="tile_states_alarm">
     <item msgid="4936533380177298776">"Akutholakali"</item>
     <item msgid="2710157085538036590">"Valiwe"</item>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 3ed363f..56464e4 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -82,7 +82,7 @@
 
     <!-- Tiles native to System UI. Order should match "quick_settings_tiles_default" -->
     <string name="quick_settings_tiles_stock" translatable="false">
-        internet,bt,flashlight,dnd,alarm,airplane,controls,wallet,rotation,battery,cast,screenrecord,mictoggle,cameratoggle,location,hotspot,inversion,saver,dark,work,night,reverse,reduce_brightness,qr_code_scanner
+        internet,bt,flashlight,dnd,alarm,airplane,controls,wallet,rotation,battery,cast,screenrecord,mictoggle,cameratoggle,location,hotspot,inversion,saver,dark,work,night,reverse,reduce_brightness,qr_code_scanner,onehanded
     </string>
 
     <!-- The tiles to display in QuickSettings -->
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 059aad7..aee1f43 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1276,10 +1276,19 @@
     <dimen name="qs_tile_service_request_tile_width">192dp</dimen>
     <dimen name="qs_tile_service_request_content_space">24dp</dimen>
 
-    <dimen name="qs_dialog_button_horizontal_padding">16dp</dimen>
-    <dimen name="qs_dialog_button_vertical_padding">8dp</dimen>
+    <!-- Dimensions for unified SystemUI dialogs styling. Used by Theme.SystemUI.Dialog and
+         alert_dialog_systemui.xml
+      -->
+    <dimen name="dialog_button_horizontal_padding">16dp</dimen>
+    <dimen name="dialog_button_vertical_padding">8dp</dimen>
     <!-- The button will be 48dp tall, but the background needs to be 36dp tall -->
-    <dimen name="qs_dialog_button_vertical_inset">6dp</dimen>
+    <dimen name="dialog_button_vertical_inset">6dp</dimen>
+    <dimen name="dialog_top_padding">24dp</dimen>
+    <dimen name="dialog_bottom_padding">18dp</dimen>
+    <dimen name="dialog_side_padding">24dp</dimen>
+    <dimen name="dialog_button_bar_top_padding">32dp</dimen>
+
+    <!-- ************************************************************************* -->
 
     <dimen name="keyguard_unfold_translation_x">16dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 937cbed..21b4a42 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -722,6 +722,9 @@
     <!-- QuickSettings: Text to prompt the user to stop an ongoing recording [CHAR LIMIT=20] -->
     <string name="quick_settings_screen_record_stop">Stop</string>
 
+    <!-- QuickSettings: Label for the toggle that controls whether One-handed mode is enabled. [CHAR LIMIT=NONE] -->
+    <string name="quick_settings_onehanded_label">One-handed mode</string>
+
     <!--- Title of dialog triggered if the microphone is disabled but an app tried to access it. [CHAR LIMIT=150] -->
     <string name="sensor_privacy_start_use_mic_dialog_title">Unblock device microphone?</string>
     <!--- Title of dialog triggered if the camera is disabled but an app tried to access it. [CHAR LIMIT=150] -->
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index d972b7fc..b6cdd1b 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -14,8 +14,8 @@
      limitations under the License.
 -->
 
-<resources xmlns:android="http://schemas.android.com/apk/res/android">
-    <!-- NOTE: Adding the androidprv: namespace to this file will break the studio build. -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+           xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
 
     <!-- HybridNotification themes and styles -->
 
@@ -351,11 +351,19 @@
         <item name="android:windowIsFloating">true</item>
     </style>
 
-    <style name="Theme.SystemUI.Dialog" parent="@android:style/Theme.DeviceDefault.Light.Dialog">
+    <style name="Theme.SystemUI.DayNightDialog" parent="@android:style/Theme.DeviceDefault.Light.Dialog"/>
+
+    <style name="Theme.SystemUI.Dialog" parent="@style/Theme.SystemUI.DayNightDialog">
         <item name="android:buttonCornerRadius">28dp</item>
-        <item name="android:buttonBarPositiveButtonStyle">@style/Widget.QSDialog.Button</item>
-        <item name="android:buttonBarNegativeButtonStyle">@style/Widget.QSDialog.Button.BorderButton</item>
-        <item name="android:buttonBarNeutralButtonStyle">@style/Widget.QSDialog.Button.BorderButton</item>
+        <item name="android:buttonBarPositiveButtonStyle">@style/Widget.Dialog.Button</item>
+        <item name="android:buttonBarNegativeButtonStyle">@style/Widget.Dialog.Button.BorderButton</item>
+        <item name="android:buttonBarNeutralButtonStyle">@style/Widget.Dialog.Button.BorderButton</item>
+        <item name="android:colorBackground">?androidprv:attr/colorSurface</item>
+        <item name="android:alertDialogStyle">@style/AlertDialogStyle</item>
+    </style>
+
+    <style name="AlertDialogStyle" parent="@androidprv:style/AlertDialog.DeviceDefault">
+        <item name="android:layout">@layout/alert_dialog_systemui</item>
     </style>
 
     <style name="Theme.SystemUI.Dialog.Alert" parent="@*android:style/Theme.DeviceDefault.Light.Dialog.Alert" />
@@ -863,24 +871,37 @@
         <item name="actionDividerHeight">32dp</item>
     </style>
 
-    <style name="TextAppearance.QSDialog.Title" parent="Theme.SystemUI.Dialog">
+    <style name="TextAppearance.Dialog.Title" parent="@android:style/TextAppearance.DeviceDefault.Large">
         <item name="android:textColor">?android:attr/textColorPrimary</item>
         <item name="android:textSize">24sp</item>
         <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
         <item name="android:lineHeight">32sp</item>
+        <item name="android:gravity">center</item>
+        <item name="android:textAlignment">center</item>
     </style>
 
-    <style name="Widget.QSDialog.Button" parent = "Theme.SystemUI.Dialog">
+    <style name="TextAppearance.Dialog.Body" parent="@android:style/TextAppearance.DeviceDefault.Medium">
+        <item name="android:textColor">?android:attr/textColorSecondary</item>
+        <item name="android:textSize">14sp</item>
+        <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
+        <item name="android:lineHeight">20sp</item>
+    </style>
+
+    <style name="TextAppearance.Dialog.Body.Message">
+        <item name="android:gravity">center</item>
+        <item name="android:textAlignment">center</item>
+    </style>
+
+    <style name="Widget.Dialog.Button" parent = "Theme.SystemUI.Dialog">
         <item name="android:background">@drawable/qs_dialog_btn_filled</item>
-        <item name="android:textColor">@color/prv_text_color_on_accent</item>
+        <item name="android:textColor">?androidprv:attr/textColorOnAccent</item>
         <item name="android:textSize">14sp</item>
         <item name="android:lineHeight">20sp</item>
-        <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item>
+        <item name="android:fontFamily">@*android:string/config_bodyFontFamilyMedium</item>
         <item name="android:stateListAnimator">@null</item>
-        <item name="android:layout_marginHorizontal">4dp</item>
     </style>
 
-    <style name="Widget.QSDialog.Button.BorderButton">
+    <style name="Widget.Dialog.Button.BorderButton">
         <item name="android:background">@drawable/qs_dialog_btn_outline</item>
         <item name="android:textColor">?android:attr/textColorPrimary</item>
     </style>
@@ -957,4 +978,10 @@
 
     <style name="TextAppearance.InternetDialog.Secondary.Active"/>
 
+    <style name="InternetDialog.Divider">
+        <item name="android:background">?android:attr/textColorSecondary</item>
+    </style>
+
+    <style name="InternetDialog.Divider.Active"/>
+
 </resources>
diff --git a/packages/SystemUI/res/values/tiles_states_strings.xml b/packages/SystemUI/res/values/tiles_states_strings.xml
index 2d51cbe..ed29bc7 100644
--- a/packages/SystemUI/res/values/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values/tiles_states_strings.xml
@@ -291,4 +291,11 @@
         <item>Off</item>
         <item>On</item>
     </string-array>
+
+    <!-- State names for One-handed mode tile: unavailable, off, on [CHAR LIMIT=32] -->
+    <string-array name="tile_states_onehanded">
+        <item>Unavailable</item>
+        <item>Off</item>
+        <item>On</item>
+    </string-array>
 </resources>
\ No newline at end of file
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
index 8bd0f91..0149751 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
@@ -95,4 +95,9 @@
      * Sent when screen turned on and ready to use (blocker scrim is hidden)
      */
     void onScreenTurnedOn() = 21;
+
+    /**
+     * Sent when the desired dark intensity of the nav buttons has changed
+     */
+    void onNavButtonsDarkIntensityChanged(float darkIntensity) = 22;
 }
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 3128ffd..675dc9b5 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
@@ -28,6 +28,7 @@
 import android.os.Parcelable;
 import android.view.ViewDebug;
 
+import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
 import java.io.PrintWriter;
@@ -50,6 +51,7 @@
         @ViewDebug.ExportedProperty(category="recents")
         public int windowingMode;
         @ViewDebug.ExportedProperty(category="recents")
+        @NonNull
         public final Intent baseIntent;
         @ViewDebug.ExportedProperty(category="recents")
         public final int userId;
@@ -83,7 +85,7 @@
             updateHashCode();
         }
 
-        public TaskKey(int id, int windowingMode, Intent intent,
+        public TaskKey(int id, int windowingMode, @NonNull Intent intent,
                 ComponentName sourceComponent, int userId, long lastActiveTime) {
             this.id = id;
             this.windowingMode = windowingMode;
@@ -95,7 +97,7 @@
             updateHashCode();
         }
 
-        public TaskKey(int id, int windowingMode, Intent intent,
+        public TaskKey(int id, int windowingMode, @NonNull Intent intent,
                 ComponentName sourceComponent, int userId, long lastActiveTime, int displayId) {
             this.id = id;
             this.windowingMode = windowingMode;
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/Utilities.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/Utilities.java
index 6154d84..8d98a75 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/Utilities.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/Utilities.java
@@ -18,7 +18,6 @@
 
 import static android.app.StatusBarManager.NAVIGATION_HINT_BACK_ALT;
 import static android.app.StatusBarManager.NAVIGATION_HINT_IME_SHOWN;
-import static android.util.DisplayMetrics.DENSITY_DEVICE_STABLE;
 
 import android.annotation.TargetApi;
 import android.content.Context;
@@ -126,10 +125,9 @@
         final WindowManager windowManager = context.getSystemService(WindowManager.class);
         final Rect bounds = windowManager.getCurrentWindowMetrics().getBounds();
 
-        float originalSmallestWidth = dpiFromPx(Math.min(bounds.width(), bounds.height()),
+        float smallestWidth = dpiFromPx(Math.min(bounds.width(), bounds.height()),
                 context.getResources().getConfiguration().densityDpi);
-        return dpiFromPx(Math.min(bounds.width(), bounds.height()), DENSITY_DEVICE_STABLE)
-                >= TABLET_MIN_DPS && originalSmallestWidth >= TABLET_MIN_DPS;
+        return smallestWidth >= TABLET_MIN_DPS;
     }
 
     public static float dpiFromPx(float size, int densityDpi) {
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
index 954cf9f..a319b40 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
@@ -321,7 +321,7 @@
                     // re-showing it's task).
                     final WindowContainerTransaction wct = new WindowContainerTransaction();
                     final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
-                    for (int i = mPausingTasks.size() - 1; i >= 0; ++i) {
+                    for (int i = mPausingTasks.size() - 1; i >= 0; --i) {
                         // reverse order so that index 0 ends up on top
                         wct.reorder(mPausingTasks.get(i), true /* onTop */);
                         t.show(mInfo.getChange(mPausingTasks.get(i)).getLeash());
diff --git a/packages/SystemUI/src-debug/com/android/systemui/flags/FlagsModule.kt b/packages/SystemUI/src-debug/com/android/systemui/flags/FlagsModule.kt
index bee4d7d..10ceee9 100644
--- a/packages/SystemUI/src-debug/com/android/systemui/flags/FlagsModule.kt
+++ b/packages/SystemUI/src-debug/com/android/systemui/flags/FlagsModule.kt
@@ -20,16 +20,23 @@
 import android.os.Handler
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.util.settings.SettingsUtilModule
+import dagger.Binds
 import dagger.Module
 import dagger.Provides
 
 @Module(includes = [
     SettingsUtilModule::class
 ])
-object FlagsModule {
-    @JvmStatic
-    @Provides
-    fun provideFlagManager(context: Context, @Main handler: Handler): FlagManager {
-        return FlagManager(context, handler)
+abstract class FlagsModule {
+    @Binds
+    abstract fun bindsFeatureFlagDebug(impl: FeatureFlagsDebug): FeatureFlags
+
+    @Module
+    companion object {
+        @JvmStatic
+        @Provides
+        fun provideFlagManager(context: Context, @Main handler: Handler): FlagManager {
+            return FlagManager(context, handler)
+        }
     }
 }
\ No newline at end of file
diff --git a/packages/SystemUI/src-release/com/android/systemui/flags/FlagsModule.kt b/packages/SystemUI/src-release/com/android/systemui/flags/FlagsModule.kt
index 7647135..ab9e01e 100644
--- a/packages/SystemUI/src-release/com/android/systemui/flags/FlagsModule.kt
+++ b/packages/SystemUI/src-release/com/android/systemui/flags/FlagsModule.kt
@@ -16,7 +16,11 @@
 
 package com.android.systemui.flags
 
+import dagger.Binds
 import dagger.Module
 
 @Module
-object FlagsModule
\ No newline at end of file
+abstract class FlagsModule {
+    @Binds
+    abstract fun bindsFeatureFlagRelease(impl: FeatureFlagsRelease): FeatureFlags
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
index 3d4e896..9238b82 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
@@ -11,7 +11,6 @@
 import android.util.TypedValue;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.ViewTreeObserver.OnPreDrawListener;
 import android.widget.FrameLayout;
 import android.widget.RelativeLayout;
 
@@ -89,7 +88,6 @@
 
     private int mClockSwitchYAmount;
     @VisibleForTesting boolean mChildrenAreLaidOut = false;
-    private OnPreDrawListener mPreDrawListener;
 
     public KeyguardClockSwitch(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -284,30 +282,21 @@
         // translate them properly
         if (mChildrenAreLaidOut) {
             animateClockChange(clockSize == LARGE);
-            mDisplayedClockSize = clockSize;
-        } else if (mPreDrawListener == null) {
-            mPreDrawListener = () -> {
-                switchToClock(clockSize);
-                getViewTreeObserver().removeOnPreDrawListener(mPreDrawListener);
-                mPreDrawListener = null;
-                return true;
-            };
-            getViewTreeObserver().addOnPreDrawListener(mPreDrawListener);
         }
+
+        mDisplayedClockSize = clockSize;
         return true;
     }
 
     @Override
     protected void onLayout(boolean changed, int l, int t, int r, int b) {
         super.onLayout(changed, l, t, r, b);
-        mChildrenAreLaidOut = true;
-    }
 
-    void onViewDetached() {
-        if (mPreDrawListener != null) {
-            getViewTreeObserver().removeOnPreDrawListener(mPreDrawListener);
-            mPreDrawListener = null;
+        if (mDisplayedClockSize != null && !mChildrenAreLaidOut) {
+            animateClockChange(mDisplayedClockSize == LARGE);
         }
+
+        mChildrenAreLaidOut = true;
     }
 
     public Paint getPaint() {
@@ -368,5 +357,6 @@
         pw.println("  mDarkAmount: " + mDarkAmount);
         pw.println("  mSupportsDarkText: " + mSupportsDarkText);
         pw.println("  mColorPalette: " + Arrays.toString(mColorPalette));
+        pw.println("  mDisplayedClockSize: " + mDisplayedClockSize);
     }
 }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
index 905495d..c628d44 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
@@ -23,6 +23,8 @@
 
 import android.app.WallpaperManager;
 import android.content.res.Resources;
+import android.database.ContentObserver;
+import android.provider.Settings;
 import android.text.TextUtils;
 import android.view.View;
 import android.view.ViewGroup;
@@ -49,11 +51,13 @@
 import com.android.systemui.statusbar.phone.NotificationIconContainer;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.util.ViewController;
+import com.android.systemui.util.settings.SecureSettings;
 
 import java.util.HashSet;
 import java.util.Locale;
 import java.util.Set;
 import java.util.TimeZone;
+import java.util.concurrent.Executor;
 
 import javax.inject.Inject;
 
@@ -72,6 +76,7 @@
     private final BatteryController mBatteryController;
     private final LockscreenSmartspaceController mSmartspaceController;
     private final Resources mResources;
+    private final SecureSettings mSecureSettings;
 
     /**
      * Clock for both small and large sizes
@@ -109,6 +114,14 @@
     private SmartspaceTransitionController mSmartspaceTransitionController;
 
     private boolean mOnlyClock = false;
+    private Executor mUiExecutor;
+    private boolean mCanShowDoubleLineClock = true;
+    private ContentObserver mDoubleLineClockObserver = new ContentObserver(null) {
+        @Override
+        public void onChange(boolean change) {
+            updateDoubleLineClock();
+        }
+    };
 
     @Inject
     public KeyguardClockSwitchController(
@@ -125,6 +138,8 @@
             LockscreenSmartspaceController smartspaceController,
             KeyguardUnlockAnimationController keyguardUnlockAnimationController,
             SmartspaceTransitionController smartspaceTransitionController,
+            SecureSettings secureSettings,
+            @Main Executor uiExecutor,
             @Main Resources resources) {
         super(keyguardClockSwitch);
         mStatusBarStateController = statusBarStateController;
@@ -138,7 +153,8 @@
         mBypassController = bypassController;
         mSmartspaceController = smartspaceController;
         mResources = resources;
-
+        mSecureSettings = secureSettings;
+        mUiExecutor = uiExecutor;
         mKeyguardUnlockAnimationController = keyguardUnlockAnimationController;
         mSmartspaceTransitionController = smartspaceTransitionController;
     }
@@ -223,6 +239,14 @@
             updateClockLayout();
             mSmartspaceTransitionController.setLockscreenSmartspace(mSmartspaceView);
         }
+
+        mSecureSettings.registerContentObserver(
+                Settings.Secure.getUriFor(Settings.Secure.LOCKSCREEN_USE_DOUBLE_LINE_CLOCK),
+                false, /* notifyForDescendants */
+                mDoubleLineClockObserver
+        );
+
+        updateDoubleLineClock();
     }
 
     int getNotificationIconAreaHeight() {
@@ -236,7 +260,8 @@
         }
         mColorExtractor.removeOnColorsChangedListener(mColorsListener);
         mView.setClockPlugin(null, mStatusBarStateController.getState());
-        mView.onViewDetached();
+
+        mSecureSettings.unregisterContentObserver(mDoubleLineClockObserver);
     }
 
     /**
@@ -268,6 +293,10 @@
      * hidden.
      */
     public void displayClock(@KeyguardClockSwitch.ClockSize int clockSize) {
+        if (!mCanShowDoubleLineClock && clockSize == KeyguardClockSwitch.LARGE) {
+            return;
+        }
+
         boolean appeared = mView.switchToClock(clockSize);
         if (appeared && clockSize == LARGE) {
             mLargeClockViewController.animateAppear();
@@ -410,4 +439,13 @@
     private int getCurrentLayoutDirection() {
         return TextUtils.getLayoutDirectionFromLocale(Locale.getDefault());
     }
+
+    private void updateDoubleLineClock() {
+        mCanShowDoubleLineClock = mSecureSettings.getInt(
+            Settings.Secure.LOCKSCREEN_USE_DOUBLE_LINE_CLOCK, 1) != 0;
+
+        if (!mCanShowDoubleLineClock) {
+            mUiExecutor.execute(() -> displayClock(KeyguardClockSwitch.SMALL));
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index e24f07c..b56d189 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -801,13 +801,16 @@
             mHandler.postDelayed(mRetryFingerprintAuthentication, HAL_ERROR_RETRY_TIMEOUT);
         }
 
+        boolean lockedOutStateChanged = false;
         if (msgId == FingerprintManager.FINGERPRINT_ERROR_LOCKOUT_PERMANENT) {
+            lockedOutStateChanged |= !mFingerprintLockedOutPermanent;
             mFingerprintLockedOutPermanent = true;
             requireStrongAuthIfAllLockedOut();
         }
 
         if (msgId == FingerprintManager.FINGERPRINT_ERROR_LOCKOUT
                 || msgId == FingerprintManager.FINGERPRINT_ERROR_LOCKOUT_PERMANENT) {
+            lockedOutStateChanged |= !mFingerprintLockedOut;
             mFingerprintLockedOut = true;
             if (isUdfpsEnrolled()) {
                 updateFingerprintListeningState();
@@ -820,9 +823,14 @@
                 cb.onBiometricError(msgId, errString, BiometricSourceType.FINGERPRINT);
             }
         }
+
+        if (lockedOutStateChanged) {
+            notifyLockedOutStateChanged(BiometricSourceType.FINGERPRINT);
+        }
     }
 
     private void handleFingerprintLockoutReset() {
+        boolean changed = mFingerprintLockedOut || mFingerprintLockedOutPermanent;
         mFingerprintLockedOut = false;
         mFingerprintLockedOutPermanent = false;
 
@@ -837,6 +845,10 @@
         } else {
             updateFingerprintListeningState();
         }
+
+        if (changed) {
+            notifyLockedOutStateChanged(BiometricSourceType.FINGERPRINT);
+        }
     }
 
     private void setFingerprintRunningState(int fingerprintRunningState) {
@@ -999,7 +1011,9 @@
             }
         }
 
+        boolean lockedOutStateChanged = false;
         if (msgId == FaceManager.FACE_ERROR_LOCKOUT_PERMANENT) {
+            lockedOutStateChanged = !mFaceLockedOutPermanent;
             mFaceLockedOutPermanent = true;
             requireStrongAuthIfAllLockedOut();
         }
@@ -1011,11 +1025,21 @@
                         BiometricSourceType.FACE);
             }
         }
+
+        if (lockedOutStateChanged) {
+            notifyLockedOutStateChanged(BiometricSourceType.FACE);
+        }
     }
 
     private void handleFaceLockoutReset() {
+        boolean changed = mFaceLockedOutPermanent;
         mFaceLockedOutPermanent = false;
+
         updateFaceListeningState();
+
+        if (changed) {
+            notifyLockedOutStateChanged(BiometricSourceType.FACE);
+        }
     }
 
     private void setFaceRunningState(int faceRunningState) {
@@ -1237,6 +1261,16 @@
         }
     }
 
+    private void notifyLockedOutStateChanged(BiometricSourceType type) {
+        Assert.isMainThread();
+        for (int i = 0; i < mCallbacks.size(); i++) {
+            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+            if (cb != null) {
+                cb.onLockedOutStateChanged(type);
+            }
+        }
+    }
+
     public boolean isScreenOn() {
         return mScreenOn;
     }
@@ -2454,6 +2488,10 @@
         }
     }
 
+    public boolean isFingerprintLockedOut() {
+        return mFingerprintLockedOut || mFingerprintLockedOutPermanent;
+    }
+
     /**
      * If biometrics hardware is available, not disabled, and user has enrolled templates.
      * This does NOT check if the device is encrypted or in lockdown.
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index 12431984..8170a81 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -292,6 +292,11 @@
     public void onStrongAuthStateChanged(int userId) { }
 
     /**
+     * When the current user's locked out state changed.
+     */
+    public void onLockedOutStateChanged(BiometricSourceType biometricSourceType) { }
+
+    /**
      * Called when the dream's window state is changed.
      * @param dreaming true if the dream's window has been created and is visible
      */
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
index 8847639..ffa764a 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
@@ -33,8 +33,8 @@
 import android.hardware.biometrics.BiometricSourceType;
 import android.hardware.biometrics.SensorLocationInternal;
 import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
-import android.media.AudioAttributes;
 import android.os.Process;
+import android.os.VibrationAttributes;
 import android.os.Vibrator;
 import android.util.DisplayMetrics;
 import android.util.MathUtils;
@@ -86,11 +86,8 @@
     private static final float sDefaultDensity =
             (float) DisplayMetrics.DENSITY_DEVICE_STABLE / (float) DisplayMetrics.DENSITY_DEFAULT;
     private static final int sLockIconRadiusPx = (int) (sDefaultDensity * 36);
-    private static final AudioAttributes VIBRATION_SONIFICATION_ATTRIBUTES =
-            new AudioAttributes.Builder()
-                .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
-                .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
-                .build();
+    private static final VibrationAttributes TOUCH_VIBRATION_ATTRIBUTES =
+            VibrationAttributes.createForUsage(VibrationAttributes.USAGE_TOUCH);
 
     @NonNull private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
     @NonNull private final KeyguardViewController mKeyguardViewController;
@@ -587,7 +584,7 @@
                                 getContext().getOpPackageName(),
                                 UdfpsController.EFFECT_CLICK,
                                 "lockIcon-onDown",
-                                VIBRATION_SONIFICATION_ATTRIBUTES);
+                                TOUCH_VIBRATION_ATTRIBUTES);
                     }
 
                     mDownDetected = true;
@@ -606,7 +603,7 @@
                                 getContext().getOpPackageName(),
                                 UdfpsController.EFFECT_CLICK,
                                 "lockIcon-onLongPress",
-                                VIBRATION_SONIFICATION_ATTRIBUTES);
+                                TOUCH_VIBRATION_ATTRIBUTES);
                     }
                 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index e84024d..33538ec 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -87,7 +87,7 @@
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.qs.SecureSetting;
+import com.android.systemui.qs.SettingObserver;
 import com.android.systemui.settings.UserTracker;
 import com.android.systemui.statusbar.events.PrivacyDotViewController;
 import com.android.systemui.tuner.TunerService;
@@ -155,7 +155,7 @@
     private float mDensity;
     private WindowManager mWindowManager;
     private int mRotation;
-    private SecureSetting mColorInversionSetting;
+    private SettingObserver mColorInversionSetting;
     private DelayableExecutor mExecutor;
     private Handler mHandler;
     private boolean mPendingRotationChange;
@@ -346,7 +346,7 @@
 
             // Watch color inversion and invert the overlay as needed.
             if (mColorInversionSetting == null) {
-                mColorInversionSetting = new SecureSetting(mSecureSettings, mHandler,
+                mColorInversionSetting = new SettingObserver(mSecureSettings, mHandler,
                         Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED,
                         mUserTracker.getUserId()) {
                     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index 43a38aa..8a99728 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -31,8 +31,6 @@
 import com.android.systemui.navigationbar.gestural.BackGestureTfClassifierProvider;
 import com.android.systemui.screenshot.ScreenshotNotificationSmartActionsProvider;
 import com.android.wm.shell.transition.ShellTransitions;
-import com.android.wm.shell.transition.Transitions;
-import com.android.wm.shell.recents.RecentTasks;
 
 import java.util.Optional;
 import java.util.concurrent.ExecutionException;
@@ -122,7 +120,8 @@
                     .setStartingSurface(mWMComponent.getStartingSurface())
                     .setDisplayAreaHelper(mWMComponent.getDisplayAreaHelper())
                     .setTaskSurfaceHelper(mWMComponent.getTaskSurfaceHelper())
-                    .setRecentTasks(mWMComponent.getRecentTasks());
+                    .setRecentTasks(mWMComponent.getRecentTasks())
+                    .setSizeCompatUI(Optional.of(mWMComponent.getSizeCompatUI()));
         } else {
             // TODO: Call on prepareSysUIComponentBuilder but not with real components. Other option
             // is separating this logic into newly creating SystemUITestsFactory.
@@ -140,7 +139,8 @@
                     .setDisplayAreaHelper(Optional.ofNullable(null))
                     .setStartingSurface(Optional.ofNullable(null))
                     .setTaskSurfaceHelper(Optional.ofNullable(null))
-                    .setRecentTasks(Optional.ofNullable(null));
+                    .setRecentTasks(Optional.ofNullable(null))
+                    .setSizeCompatUI(Optional.ofNullable(null));
         }
         mSysUIComponent = builder.build();
         if (mInitializeComponents) {
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
index 33ce206..794b9dd5 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
@@ -68,15 +68,15 @@
     private Configuration mLastConfiguration;
     private SysUiState mSysUiState;
 
-    private static class AnimationControllerSupplier extends
-            DisplayIdIndexSupplier<WindowMagnificationAnimationController> {
+    private static class ControllerSupplier extends
+            DisplayIdIndexSupplier<WindowMagnificationController> {
 
         private final Context mContext;
         private final Handler mHandler;
         private final WindowMagnifierCallback mWindowMagnifierCallback;
         private final SysUiState mSysUiState;
 
-        AnimationControllerSupplier(Context context, Handler handler,
+        ControllerSupplier(Context context, Handler handler,
                 WindowMagnifierCallback windowMagnifierCallback,
                 DisplayManager displayManager, SysUiState sysUiState) {
             super(displayManager);
@@ -87,19 +87,19 @@
         }
 
         @Override
-        protected WindowMagnificationAnimationController createInstance(Display display) {
+        protected WindowMagnificationController createInstance(Display display) {
             final Context windowContext = mContext.createWindowContext(display,
                     TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY, /* options */ null);
-            final WindowMagnificationController controller = new WindowMagnificationController(
+            return new WindowMagnificationController(
                     windowContext,
-                    mHandler, new SfVsyncFrameCallbackProvider(), null,
+                    mHandler, new WindowMagnificationAnimationController(windowContext),
+                    new SfVsyncFrameCallbackProvider(), null,
                     new SurfaceControl.Transaction(), mWindowMagnifierCallback, mSysUiState);
-            return new WindowMagnificationAnimationController(windowContext, controller);
         }
     }
 
     @VisibleForTesting
-    DisplayIdIndexSupplier<WindowMagnificationAnimationController> mAnimationControllerSupplier;
+    DisplayIdIndexSupplier<WindowMagnificationController> mMagnificationControllerSupplier;
 
     @Inject
     public WindowMagnification(Context context, @Main Handler mainHandler,
@@ -113,7 +113,7 @@
         mModeSwitchesController = modeSwitchesController;
         mSysUiState = sysUiState;
         mOverviewProxyService = overviewProxyService;
-        mAnimationControllerSupplier = new AnimationControllerSupplier(context,
+        mMagnificationControllerSupplier = new ControllerSupplier(context,
                 mHandler, this, context.getSystemService(DisplayManager.class), sysUiState);
     }
 
@@ -121,8 +121,9 @@
     public void onConfigurationChanged(Configuration newConfig) {
         final int configDiff = newConfig.diff(mLastConfiguration);
         mLastConfiguration.setTo(newConfig);
-        mAnimationControllerSupplier.forEach(
-                animationController -> animationController.onConfigurationChanged(configDiff));
+        mMagnificationControllerSupplier.forEach(
+                magnificationController -> magnificationController.onConfigurationChanged(
+                        configDiff));
         if (mModeSwitchesController != null) {
             mModeSwitchesController.onConfigurationChanged(configDiff);
         }
@@ -143,10 +144,10 @@
 
     private void updateSysUiStateFlag() {
         //TODO(b/187510533): support multi-display once SysuiState supports it.
-        final WindowMagnificationAnimationController controller =
-                mAnimationControllerSupplier.valueAt(Display.DEFAULT_DISPLAY);
+        final WindowMagnificationController controller =
+                mMagnificationControllerSupplier.valueAt(Display.DEFAULT_DISPLAY);
         if (controller != null) {
-            controller.updateSysUiStateFlag();
+            controller.updateSysUIStateFlag();
         } else {
             // The instance is initialized when there is an IPC request. Considering
             // self-crash cases, we need to reset the flag in such situation.
@@ -158,39 +159,39 @@
     @MainThread
     void enableWindowMagnification(int displayId, float scale, float centerX, float centerY,
             @Nullable IRemoteMagnificationAnimationCallback callback) {
-        final WindowMagnificationAnimationController windowMagnificationAnimationController =
-                mAnimationControllerSupplier.get(displayId);
-        if (windowMagnificationAnimationController != null) {
-            windowMagnificationAnimationController.enableWindowMagnification(scale, centerX,
+        final WindowMagnificationController windowMagnificationController =
+                mMagnificationControllerSupplier.get(displayId);
+        if (windowMagnificationController != null) {
+            windowMagnificationController.enableWindowMagnification(scale, centerX,
                     centerY, callback);
         }
     }
 
     @MainThread
     void setScale(int displayId, float scale) {
-        final WindowMagnificationAnimationController windowMagnificationAnimationController =
-                mAnimationControllerSupplier.get(displayId);
-        if (windowMagnificationAnimationController != null) {
-            windowMagnificationAnimationController.setScale(scale);
+        final WindowMagnificationController windowMagnificationController =
+                mMagnificationControllerSupplier.get(displayId);
+        if (windowMagnificationController != null) {
+            windowMagnificationController.setScale(scale);
         }
     }
 
     @MainThread
     void moveWindowMagnifier(int displayId, float offsetX, float offsetY) {
-        final WindowMagnificationAnimationController windowMagnificationAnimationController =
-                mAnimationControllerSupplier.get(displayId);
-        if (windowMagnificationAnimationController != null) {
-            windowMagnificationAnimationController.moveWindowMagnifier(offsetX, offsetY);
+        final WindowMagnificationController windowMagnificationcontroller =
+                mMagnificationControllerSupplier.get(displayId);
+        if (windowMagnificationcontroller != null) {
+            windowMagnificationcontroller.moveWindowMagnifier(offsetX, offsetY);
         }
     }
 
     @MainThread
     void disableWindowMagnification(int displayId,
             @Nullable IRemoteMagnificationAnimationCallback callback) {
-        final WindowMagnificationAnimationController windowMagnificationAnimationController =
-                mAnimationControllerSupplier.get(displayId);
-        if (windowMagnificationAnimationController != null) {
-            windowMagnificationAnimationController.deleteWindowMagnification(callback);
+        final WindowMagnificationController windowMagnificationController =
+                mMagnificationControllerSupplier.get(displayId);
+        if (windowMagnificationController != null) {
+            windowMagnificationController.deleteWindowMagnification(callback);
         }
     }
 
@@ -234,8 +235,8 @@
     @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.println(TAG);
-        mAnimationControllerSupplier.forEach(
-                animationController -> animationController.dump(pw));
+        mMagnificationControllerSupplier.forEach(
+                magnificationController -> magnificationController.dump(pw));
     }
 
     private void setWindowMagnificationConnection() {
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationAnimationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationAnimationController.java
index 8cb608f..1bfa9c1 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationAnimationController.java
@@ -19,6 +19,7 @@
 import android.animation.Animator;
 import android.animation.ValueAnimator;
 import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UiContext;
 import android.content.Context;
@@ -31,7 +32,6 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.R;
 
-import java.io.PrintWriter;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
@@ -54,11 +54,11 @@
     // The window magnification is enabled.
     private static final int STATE_ENABLED = 1;
     // The window magnification is going to be disabled when the animation is end.
-    private  static final int STATE_DISABLING = 2;
+    private static final int STATE_DISABLING = 2;
     // The animation is running for enabling the window magnification.
     private static final int STATE_ENABLING = 3;
 
-    private final WindowMagnificationController mController;
+    private WindowMagnificationController mController;
     private final ValueAnimator mValueAnimator;
     private final AnimationSpec mStartSpec = new AnimationSpec();
     private final AnimationSpec mEndSpec = new AnimationSpec();
@@ -71,21 +71,22 @@
     @MagnificationState
     private int mState = STATE_DISABLED;
 
-    WindowMagnificationAnimationController(@UiContext Context context,
-            WindowMagnificationController controller) {
-        this(context, controller, newValueAnimator(context.getResources()));
+    WindowMagnificationAnimationController(@UiContext Context context) {
+        this(context, newValueAnimator(context.getResources()));
     }
 
     @VisibleForTesting
-    WindowMagnificationAnimationController(Context context,
-            WindowMagnificationController controller, ValueAnimator valueAnimator) {
+    WindowMagnificationAnimationController(Context context, ValueAnimator valueAnimator) {
         mContext = context;
-        mController = controller;
         mValueAnimator = valueAnimator;
         mValueAnimator.addUpdateListener(this);
         mValueAnimator.addListener(this);
     }
 
+    void setWindowMagnificationController(@NonNull WindowMagnificationController controller) {
+        mController = controller;
+    }
+
     /**
      * Wraps {@link WindowMagnificationController#enableWindowMagnification(float, float, float)}
      * with transition animation. If the window magnification is not enabled, the scale will start
@@ -105,6 +106,9 @@
      */
     void enableWindowMagnification(float scale, float centerX, float centerY,
             @Nullable IRemoteMagnificationAnimationCallback animationCallback) {
+        if (mController == null) {
+            return;
+        }
         sendAnimationCallback(false);
         // Enable window magnification without animation immediately.
         if (animationCallback == null) {
@@ -139,6 +143,9 @@
     }
 
     private void setupEnableAnimationSpecs(float scale, float centerX, float centerY) {
+        if (mController == null) {
+            return;
+        }
         final float currentScale = mController.getScale();
         final float currentCenterX = mController.getCenterX();
         final float currentCenterY = mController.getCenterY();
@@ -160,15 +167,9 @@
         }
     }
 
-    /**
-     * Wraps {@link WindowMagnificationController#setScale(float)}. If the animation is
-     * running, it has no effect.
-     */
-    void setScale(float scale) {
-        if (mValueAnimator.isRunning()) {
-            return;
-        }
-        mController.setScale(scale);
+    /** Returns {@code true} if the animator is running. */
+    boolean isAnimating() {
+        return mValueAnimator.isRunning();
     }
 
     /**
@@ -181,6 +182,9 @@
      */
     void deleteWindowMagnification(
             @Nullable IRemoteMagnificationAnimationCallback animationCallback) {
+        if (mController == null) {
+            return;
+        }
         sendAnimationCallback(false);
         // Delete window magnification without animation.
         if (animationCallback == null) {
@@ -206,25 +210,6 @@
         setState(STATE_DISABLING);
     }
 
-    /**
-     * Wraps {@link WindowMagnificationController#moveWindowMagnifier(float, float)}. If the
-     * animation is running, it has no effect.
-     * @param offsetX The amount in pixels to offset the window magnifier in the X direction, in
-     *                current screen pixels.
-     * @param offsetY The amount in pixels to offset the window magnifier in the Y direction, in
-     *                current screen pixels.
-     */
-    void moveWindowMagnifier(float offsetX, float offsetY) {
-        if (mValueAnimator.isRunning()) {
-            return;
-        }
-        mController.moveWindowMagnifier(offsetX, offsetY);
-    }
-
-    void onConfigurationChanged(int configDiff) {
-        mController.onConfigurationChanged(configDiff);
-    }
-
     private void setState(@MagnificationState int state) {
         if (DEBUG) {
             Log.d(TAG, "setState from " + mState + " to " + state);
@@ -239,7 +224,7 @@
 
     @Override
     public void onAnimationEnd(Animator animation, boolean isReverse) {
-        if (mEndAnimationCanceled) {
+        if (mEndAnimationCanceled || mController == null) {
             return;
         }
         if (Float.isNaN(mController.getScale())) {
@@ -279,6 +264,9 @@
 
     @Override
     public void onAnimationUpdate(ValueAnimator animation) {
+        if (mController == null) {
+            return;
+        }
         final float fract = animation.getAnimatedFraction();
         final float sentScale = mStartSpec.mScale + (mEndSpec.mScale - mStartSpec.mScale) * fract;
         final float centerX =
@@ -288,14 +276,6 @@
         mController.enableWindowMagnification(sentScale, centerX, centerY);
     }
 
-    public void updateSysUiStateFlag() {
-        mController.updateSysUIStateFlag();
-    }
-
-    void dump(PrintWriter pw) {
-        mController.dump(pw);
-    }
-
     private static ValueAnimator newValueAnimator(Resources resources) {
         final ValueAnimator valueAnimator = new ValueAnimator();
         valueAnimator.setDuration(
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
index b48def2..2507004 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
@@ -59,6 +59,7 @@
 import android.view.WindowMetrics;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
+import android.view.accessibility.IRemoteMagnificationAnimationCallback;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
@@ -133,6 +134,7 @@
     // The top Y of the system gesture rect at the bottom. Set to -1 if it is invalid.
     private int mSystemGestureTop = -1;
 
+    private final WindowMagnificationAnimationController mAnimationController;
     private final SfVsyncFrameCallbackProvider mSfVsyncFrameProvider;
     private final MagnificationGestureDetector mGestureDetector;
     private final int mBounceEffectDuration;
@@ -148,11 +150,14 @@
     private MirrorWindowControl mMirrorWindowControl;
 
     WindowMagnificationController(@UiContext Context context, @NonNull Handler handler,
+            @NonNull WindowMagnificationAnimationController animationController,
             SfVsyncFrameCallbackProvider sfVsyncFrameProvider,
             MirrorWindowControl mirrorWindowControl, SurfaceControl.Transaction transaction,
             @NonNull WindowMagnifierCallback callback, SysUiState sysUiState) {
         mContext = context;
         mHandler = handler;
+        mAnimationController = animationController;
+        mAnimationController.setWindowMagnificationController(this);
         mSfVsyncFrameProvider = sfVsyncFrameProvider;
         mWindowMagnifierCallback = callback;
         mSysUiState = sysUiState;
@@ -259,6 +264,19 @@
     }
 
     /**
+     * Wraps {@link WindowMagnificationController#deleteWindowMagnification()}} with transition
+     * animation. If the window magnification is enabling, it runs the animation in reverse.
+     *
+     * @param animationCallback Called when the transition is complete, the given arguments
+     *                          are as same as current values, or the transition is interrupted
+     *                          due to the new transition request.
+     */
+    void deleteWindowMagnification(
+            @Nullable IRemoteMagnificationAnimationCallback animationCallback) {
+        mAnimationController.deleteWindowMagnification(animationCallback);
+    }
+
+    /**
      * Deletes the magnification window.
      */
     void deleteWindowMagnification() {
@@ -693,6 +711,27 @@
     }
 
     /**
+     * Wraps {@link WindowMagnificationController#enableWindowMagnification(float, float, float)}
+     * with transition animation. If the window magnification is not enabled, the scale will start
+     * from 1.0 and the center won't be changed during the animation. If animator is
+     * {@code STATE_DISABLING}, the animation runs in reverse.
+     *
+     * @param scale   The target scale, or {@link Float#NaN} to leave unchanged.
+     * @param centerX The screen-relative X coordinate around which to center,
+     *                or {@link Float#NaN} to leave unchanged.
+     * @param centerY The screen-relative Y coordinate around which to center,
+     *                or {@link Float#NaN} to leave unchanged.
+     * @param animationCallback Called when the transition is complete, the given arguments
+     *                          are as same as current values, or the transition is interrupted
+     *                          due to the new transition request.
+     */
+    void enableWindowMagnification(float scale, float centerX, float centerY,
+            @Nullable IRemoteMagnificationAnimationCallback animationCallback) {
+        mAnimationController.enableWindowMagnification(scale, centerX,
+                centerY, animationCallback);
+    }
+
+    /**
      * Enables window magnification with specified parameters. If the given scale is <strong>less
      * than or equal to 1.0f<strong>, then
      * {@link WindowMagnificationController#deleteWindowMagnification()} will be called instead to
@@ -732,7 +771,7 @@
      * @param scale the target scale, or {@link Float#NaN} to leave unchanged
      */
     void setScale(float scale) {
-        if (!isWindowVisible() || mScale == scale) {
+        if (mAnimationController.isAnimating() || !isWindowVisible() || mScale == scale) {
             return;
         }
         enableWindowMagnification(scale, Float.NaN, Float.NaN);
@@ -749,7 +788,7 @@
      *                current screen pixels.
      */
     void moveWindowMagnifier(float offsetX, float offsetY) {
-        if (mMirrorSurfaceView == null) {
+        if (mAnimationController.isAnimating() || mMirrorSurfaceView == null) {
             return;
         }
         if (updateMagnificationFramePosition((int) offsetX, (int) offsetY)) {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index d60edbf..0ff3dbc 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -39,12 +39,12 @@
 import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
 import android.hardware.fingerprint.IUdfpsOverlayController;
 import android.hardware.fingerprint.IUdfpsOverlayControllerCallback;
-import android.media.AudioAttributes;
 import android.os.Handler;
 import android.os.PowerManager;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.Trace;
+import android.os.VibrationAttributes;
 import android.os.VibrationEffect;
 import android.os.Vibrator;
 import android.provider.Settings;
@@ -166,11 +166,10 @@
     private final VibrationEffect mLowTick;
 
     @VisibleForTesting
-    public static final AudioAttributes VIBRATION_SONIFICATION_ATTRIBUTES =
-            new AudioAttributes.Builder()
-                    .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
+    public static final VibrationAttributes VIBRATION_ATTRIBUTES =
+            new VibrationAttributes.Builder()
                     // vibration will bypass battery saver mode:
-                    .setUsage(AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY)
+                    .setUsage(VibrationAttributes.USAGE_COMMUNICATION_REQUEST)
                     .build();
 
     // haptic to use for successful device entry
@@ -639,7 +638,7 @@
                     mContext.getOpPackageName(),
                     mLowTick,
                     "udfps-onStart-tick",
-                    VIBRATION_SONIFICATION_ATTRIBUTES);
+                    VIBRATION_ATTRIBUTES);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
index 223eb78..8f4d6f6 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
@@ -255,7 +255,6 @@
     private void maybeShowInputBouncer() {
         if (mShowingUdfpsBouncer && hasUdfpsBouncerShownWithMinTime()) {
             mKeyguardViewManager.showBouncer(true);
-            mKeyguardViewManager.resetAlternateAuth(false);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/communal/CommunalSource.java b/packages/SystemUI/src/com/android/systemui/communal/CommunalSource.java
index 99c311e..53586f5 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/CommunalSource.java
+++ b/packages/SystemUI/src/com/android/systemui/communal/CommunalSource.java
@@ -23,6 +23,8 @@
 
 import com.google.common.util.concurrent.ListenableFuture;
 
+import java.util.Optional;
+
 /**
  * {@link CommunalSource} defines an interface for working with a source for communal data. Clients
  * may request a communal surface that can be shown within a {@link android.view.SurfaceView}.
@@ -30,6 +32,28 @@
  */
 public interface CommunalSource {
     /**
+     * {@link Connector} defines an interface for {@link CommunalSource} instances to be generated.
+     */
+    interface Connector {
+        ListenableFuture<Optional<CommunalSource>> connect();
+    }
+
+    /**
+     * The {@link Observer} interface specifies an entity which {@link CommunalSource} listeners
+     * can be informed of changes to the source, which will require updating. Note that this deals
+     * with changes to the source itself, not content which will be updated through the
+     * {@link CommunalSource} interface.
+     */
+    interface Observer {
+        interface Callback {
+            void onSourceChanged();
+        }
+
+        void addCallback(Callback callback);
+        void removeCallback(Callback callback);
+    }
+
+    /**
      * {@link CommunalViewResult} is handed back from {@link #requestCommunalView(Context)} and
      * contains the view to be displayed and its associated controller.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/communal/CommunalSourcePrimer.java b/packages/SystemUI/src/com/android/systemui/communal/CommunalSourcePrimer.java
new file mode 100644
index 0000000..3c2b79e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/communal/CommunalSourcePrimer.java
@@ -0,0 +1,161 @@
+/*
+ * 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.communal;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.util.Log;
+
+import com.android.systemui.CoreStartable;
+import com.android.systemui.R;
+import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.util.concurrency.DelayableExecutor;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+import java.util.Optional;
+
+import javax.inject.Inject;
+
+/**
+ * The {@link CommunalSourcePrimer} is responsible for priming SystemUI with a pre-configured
+ * Communal source. The SystemUI service binds to the component to retrieve the
+ * {@link CommunalSource}. {@link CommunalSourcePrimer} has no effect
+ * if there is no pre-defined value.
+ */
+@SysUISingleton
+public class CommunalSourcePrimer extends CoreStartable {
+    private static final String TAG = "CommunalSourcePrimer";
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+    private final DelayableExecutor mMainExecutor;
+    private final CommunalSourceMonitor mMonitor;
+    private final int mBaseReconnectDelayMs;
+    private final int mMaxReconnectAttempts;
+
+    private int mReconnectAttempts = 0;
+    private Runnable mCurrentReconnectCancelable;
+    private ListenableFuture<Optional<CommunalSource>> mGetSourceFuture;
+
+    private final Optional<CommunalSource.Connector> mConnector;
+    private final Optional<CommunalSource.Observer> mObserver;
+
+    private final Runnable mConnectRunnable = new Runnable() {
+        @Override
+        public void run() {
+            mCurrentReconnectCancelable = null;
+            connect();
+        }
+    };
+
+    @Inject
+    public CommunalSourcePrimer(Context context, @Main Resources resources,
+            DelayableExecutor mainExecutor,
+            CommunalSourceMonitor monitor,
+            Optional<CommunalSource.Connector> connector,
+            Optional<CommunalSource.Observer> observer) {
+        super(context);
+        mMainExecutor = mainExecutor;
+        mMonitor = monitor;
+        mConnector = connector;
+        mObserver = observer;
+
+        mMaxReconnectAttempts = resources.getInteger(
+                R.integer.config_communalSourceMaxReconnectAttempts);
+        mBaseReconnectDelayMs = resources.getInteger(
+                R.integer.config_communalSourceReconnectBaseDelay);
+    }
+
+    @Override
+    public void start() {
+    }
+
+    private void initiateConnectionAttempt() {
+        // Reset attempts
+        mReconnectAttempts = 0;
+        mMonitor.setSource(null);
+
+        // The first attempt is always a direct invocation rather than delayed.
+        connect();
+    }
+
+    private void scheduleConnectionAttempt() {
+        // always clear cancelable if present.
+        if (mCurrentReconnectCancelable != null) {
+            mCurrentReconnectCancelable.run();
+            mCurrentReconnectCancelable = null;
+        }
+
+        if (mReconnectAttempts >= mMaxReconnectAttempts) {
+            if (DEBUG) {
+                Log.d(TAG, "exceeded max connection attempts.");
+            }
+            return;
+        }
+
+        final long reconnectDelayMs =
+                (long) Math.scalb(mBaseReconnectDelayMs, mReconnectAttempts);
+
+        if (DEBUG) {
+            Log.d(TAG,
+                    "scheduling connection attempt in " + reconnectDelayMs + "milliseconds");
+        }
+
+        mCurrentReconnectCancelable = mMainExecutor.executeDelayed(mConnectRunnable,
+                reconnectDelayMs);
+
+        mReconnectAttempts++;
+    }
+
+    @Override
+    protected void onBootCompleted() {
+        if (mObserver.isPresent()) {
+            mObserver.get().addCallback(() -> initiateConnectionAttempt());
+        }
+        initiateConnectionAttempt();
+    }
+
+    private void connect() {
+        if (DEBUG) {
+            Log.d(TAG, "attempting to communal to communal source");
+        }
+
+        if (mGetSourceFuture != null) {
+            if (DEBUG) {
+                Log.d(TAG, "canceling in-flight connection");
+            }
+            mGetSourceFuture.cancel(true);
+        }
+
+        mGetSourceFuture = mConnector.get().connect();
+        mGetSourceFuture.addListener(() -> {
+            try {
+                Optional<CommunalSource> result = mGetSourceFuture.get();
+                if (result.isPresent()) {
+                    final CommunalSource source = result.get();
+                    source.addCallback(() -> initiateConnectionAttempt());
+                    mMonitor.setSource(source);
+                } else {
+                    scheduleConnectionAttempt();
+                }
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }, mMainExecutor);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
index a9fb743..5fdf026 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
@@ -37,6 +37,7 @@
 import com.android.wm.shell.onehanded.OneHanded;
 import com.android.wm.shell.pip.Pip;
 import com.android.wm.shell.recents.RecentTasks;
+import com.android.wm.shell.sizecompatui.SizeCompatUI;
 import com.android.wm.shell.splitscreen.SplitScreen;
 import com.android.wm.shell.startingsurface.StartingSurface;
 import com.android.wm.shell.tasksurfacehelper.TaskSurfaceHelper;
@@ -107,6 +108,9 @@
         @BindsInstance
         Builder setRecentTasks(Optional<RecentTasks> r);
 
+        @BindsInstance
+        Builder setSizeCompatUI(Optional<SizeCompatUI> s);
+
         SysUIComponent build();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index 383c442..a64351f 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -38,10 +38,6 @@
 import com.android.systemui.doze.dagger.DozeComponent;
 import com.android.systemui.dreams.dagger.DreamModule;
 import com.android.systemui.dump.DumpManager;
-import com.android.systemui.flags.FeatureFlagManager;
-import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.flags.FlagReader;
-import com.android.systemui.flags.FlagWriter;
 import com.android.systemui.flags.FlagsModule;
 import com.android.systemui.fragments.FragmentService;
 import com.android.systemui.log.dagger.LogModule;
@@ -55,6 +51,7 @@
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationShadeWindowController;
+import com.android.systemui.statusbar.notification.NotifPipelineFlags;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotifPipeline;
 import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinder;
@@ -161,12 +158,6 @@
         return state;
     }
 
-    @Binds
-    abstract FlagReader provideFlagReader(FeatureFlagManager impl);
-
-    @Binds
-    abstract FlagWriter provideFlagWriter(FeatureFlagManager impl);
-
     @BindsOptionalOf
     abstract CommandQueue optionalCommandQueue();
 
@@ -215,14 +206,15 @@
             NotificationInterruptStateProvider interruptionStateProvider,
             ZenModeController zenModeController, NotificationLockscreenUserManager notifUserManager,
             NotificationGroupManagerLegacy groupManager, NotificationEntryManager entryManager,
-            NotifPipeline notifPipeline, SysUiState sysUiState, FeatureFlags featureFlags,
-            DumpManager dumpManager, @Main Executor sysuiMainExecutor) {
+            NotifPipeline notifPipeline, SysUiState sysUiState,
+            NotifPipelineFlags notifPipelineFlags, DumpManager dumpManager,
+            @Main Executor sysuiMainExecutor) {
         return Optional.ofNullable(BubblesManager.create(context, bubblesOptional,
                 notificationShadeWindowController, statusBarStateController, shadeController,
                 configurationController, statusBarService, notificationManager,
                 visibilityProvider,
                 interruptionStateProvider, zenModeController, notifUserManager,
-                groupManager, entryManager, notifPipeline, sysUiState, featureFlags, dumpManager,
-                sysuiMainExecutor));
+                groupManager, entryManager, notifPipeline, sysUiState, notifPipelineFlags,
+                dumpManager, sysuiMainExecutor));
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
index d8b7742..543ba8f 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
@@ -20,13 +20,13 @@
 
 import com.android.systemui.SystemUIFactory;
 import com.android.systemui.tv.TvWMComponent;
-import com.android.wm.shell.dagger.TvWMShellModule;
-import com.android.wm.shell.dagger.WMShellModule;
 import com.android.wm.shell.ShellCommandHandler;
 import com.android.wm.shell.ShellInit;
 import com.android.wm.shell.TaskViewFactory;
 import com.android.wm.shell.apppairs.AppPairs;
 import com.android.wm.shell.bubbles.Bubbles;
+import com.android.wm.shell.dagger.TvWMShellModule;
+import com.android.wm.shell.dagger.WMShellModule;
 import com.android.wm.shell.dagger.WMSingleton;
 import com.android.wm.shell.displayareahelper.DisplayAreaHelper;
 import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout;
@@ -34,6 +34,7 @@
 import com.android.wm.shell.onehanded.OneHanded;
 import com.android.wm.shell.pip.Pip;
 import com.android.wm.shell.recents.RecentTasks;
+import com.android.wm.shell.sizecompatui.SizeCompatUI;
 import com.android.wm.shell.splitscreen.SplitScreen;
 import com.android.wm.shell.startingsurface.StartingSurface;
 import com.android.wm.shell.tasksurfacehelper.TaskSurfaceHelper;
@@ -115,4 +116,7 @@
 
     @WMSingleton
     Optional<RecentTasks> getRecentTasks();
+
+    @WMSingleton
+    SizeCompatUI getSizeCompatUI();
 }
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
index 5c3e07f..239109a 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.doze;
 
+import static com.android.systemui.doze.DozeLog.REASON_SENSOR_QUICK_PICKUP;
+import static com.android.systemui.doze.DozeLog.REASON_SENSOR_UDFPS_LONG_PRESS;
 import static com.android.systemui.plugins.SensorManagerPlugin.Sensor.TYPE_WAKE_DISPLAY;
 import static com.android.systemui.plugins.SensorManagerPlugin.Sensor.TYPE_WAKE_LOCK_SCREEN;
 
@@ -98,6 +100,7 @@
     private final DozeLog mDozeLog;
     private final SecureSettings mSecureSettings;
     private final DevicePostureController mDevicePostureController;
+    private final AuthController mAuthController;
     private final boolean mScreenOffUdfpsEnabled;
 
     // Sensors
@@ -115,6 +118,7 @@
     private boolean mListening;
     private boolean mListeningTouchScreenSensors;
     private boolean mListeningProxSensors;
+    private boolean mUdfpsEnrolled;
 
     @DevicePostureController.DevicePostureInt
     private int mDevicePosture;
@@ -169,10 +173,11 @@
                 config.screenOffUdfpsEnabled(KeyguardUpdateMonitor.getCurrentUser());
         mDevicePostureController = devicePostureController;
         mDevicePosture = mDevicePostureController.getDevicePosture();
+        mAuthController = authController;
 
-        boolean udfpsEnrolled =
-                authController.isUdfpsEnrolled(KeyguardUpdateMonitor.getCurrentUser());
-        boolean alwaysOn = mConfig.alwaysOnEnabled(UserHandle.USER_CURRENT);
+        mUdfpsEnrolled =
+                mAuthController.isUdfpsEnrolled(KeyguardUpdateMonitor.getCurrentUser());
+        mAuthController.addCallback(mAuthControllerCallback);
         mTriggerSensors = new TriggerSensor[] {
                 new TriggerSensor(
                         mSensorManager.getDefaultSensor(Sensor.TYPE_SIGNIFICANT_MOTION),
@@ -221,7 +226,7 @@
                         findSensor(config.udfpsLongPressSensorType()),
                         "doze_pulse_on_auth",
                         true /* settingDef */,
-                        udfpsEnrolled && (alwaysOn || mScreenOffUdfpsEnabled),
+                        udfpsLongPressConfigured(),
                         DozeLog.REASON_SENSOR_UDFPS_LONG_PRESS,
                         true /* reports touch coordinates */,
                         true /* touchscreen */,
@@ -230,7 +235,8 @@
                 new PluginSensor(
                         new SensorManagerPlugin.Sensor(TYPE_WAKE_DISPLAY),
                         Settings.Secure.DOZE_WAKE_DISPLAY_GESTURE,
-                        mConfig.wakeScreenGestureAvailable() && alwaysOn,
+                        mConfig.wakeScreenGestureAvailable()
+                          && mConfig.alwaysOnEnabled(UserHandle.USER_CURRENT),
                         DozeLog.REASON_SENSOR_WAKE_UP_PRESENCE,
                         false /* reports touch coordinates */,
                         false /* touchscreen */),
@@ -246,8 +252,7 @@
                         findSensor(config.quickPickupSensorType()),
                         Settings.Secure.DOZE_QUICK_PICKUP_GESTURE,
                         true /* setting default */,
-                        config.quickPickupSensorEnabled(KeyguardUpdateMonitor.getCurrentUser())
-                                && udfpsEnrolled,
+                        quickPickUpConfigured(),
                         DozeLog.REASON_SENSOR_QUICK_PICKUP,
                         false /* requiresTouchCoordinates */,
                         false /* requiresTouchscreen */,
@@ -265,6 +270,16 @@
         mDevicePostureController.addCallback(mDevicePostureCallback);
     }
 
+    private boolean udfpsLongPressConfigured() {
+        return mUdfpsEnrolled
+                && (mConfig.alwaysOnEnabled(UserHandle.USER_CURRENT) || mScreenOffUdfpsEnabled);
+    }
+
+    private boolean quickPickUpConfigured() {
+        return mUdfpsEnrolled
+                && mConfig.quickPickupSensorEnabled(KeyguardUpdateMonitor.getCurrentUser());
+    }
+
     /**
      *  Unregister all sensors and callbacks.
      */
@@ -276,6 +291,7 @@
         mProximitySensor.pause();
 
         mDevicePostureController.removeCallback(mDevicePostureCallback);
+        mAuthController.removeCallback(mAuthControllerCallback);
     }
 
     /**
@@ -450,6 +466,7 @@
         pw.println("mSelectivelyRegisterProxSensors=" + mSelectivelyRegisterProxSensors);
         pw.println("mListeningProxSensors=" + mListeningProxSensors);
         pw.println("mScreenOffUdfpsEnabled=" + mScreenOffUdfpsEnabled);
+        pw.println("mUdfpsEnrolled=" + mUdfpsEnrolled);
         IndentingPrintWriter idpw = new IndentingPrintWriter(pw);
         idpw.increaseIndent();
         for (TriggerSensor s : mTriggerSensors) {
@@ -468,7 +485,7 @@
     @VisibleForTesting
     class TriggerSensor extends TriggerEventListener {
         @NonNull final Sensor[] mSensors; // index = posture, value = sensor
-        final boolean mConfigured;
+        boolean mConfigured;
         final int mPulseReason;
         private final String mSetting;
         private final boolean mReportsTouchCoordinates;
@@ -496,10 +513,10 @@
                     true /* settingDef */,
                     configured,
                     pulseReason,
-                    false /* ignoresSetting */,
-                    false /* requiresProx */,
                     reportsTouchCoordinates,
-                    requiresTouchscreen
+                    requiresTouchscreen,
+                    false /* ignoresSetting */,
+                    false /* requiresProx */
             );
         }
 
@@ -606,8 +623,18 @@
             updateListening();
         }
 
+        /**
+         * Update configured state.
+         */
+        public void setConfigured(boolean configured) {
+            if (mConfigured == configured) return;
+            mConfigured = configured;
+            updateListening();
+        }
+
         public void updateListening() {
             final Sensor sensor = mSensors[mPosture];
+
             if (!mConfigured || sensor == null) return;
             if (mRequested && !mDisabled && (enabledBySetting() || mIgnoresSetting)) {
                 if (!mRegistered) {
@@ -791,6 +818,30 @@
         }
     };
 
+    private final AuthController.Callback mAuthControllerCallback = new AuthController.Callback() {
+        @Override
+        public void onAllAuthenticatorsRegistered() {
+            updateUdfpsEnrolled();
+        }
+
+        @Override
+        public void onEnrollmentsChanged() {
+            updateUdfpsEnrolled();
+        }
+
+        private void updateUdfpsEnrolled() {
+            mUdfpsEnrolled = mAuthController.isUdfpsEnrolled(
+                    KeyguardUpdateMonitor.getCurrentUser());
+            for (TriggerSensor sensor : mTriggerSensors) {
+                if (REASON_SENSOR_QUICK_PICKUP == sensor.mPulseReason) {
+                    sensor.setConfigured(quickPickUpConfigured());
+                } else if (REASON_SENSOR_UDFPS_LONG_PRESS == sensor.mPulseReason) {
+                    sensor.setConfigured(udfpsLongPressConfigured());
+                }
+            }
+        }
+    };
+
     public interface Callback {
 
         /**
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.java b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.java
index f8bdaf6..fbb78c8 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.java
@@ -16,114 +16,10 @@
 
 package com.android.systemui.flags;
 
-import android.content.Context;
-import android.util.FeatureFlagUtils;
-
-import com.android.systemui.dagger.SysUISingleton;
-
-import javax.inject.Inject;
-
 /**
  * Class to manage simple DeviceConfig-based feature flags.
  *
  * See {@link Flags} for instructions on defining new flags.
  */
-@SysUISingleton
-public class FeatureFlags {
-    private final FlagReader mFlagReader;
-
-    @Inject
-    public FeatureFlags(FlagReader flagReader) {
-        mFlagReader = flagReader;
-    }
-
-    /**
-     * @param flag The {@link BooleanFlag} of interest.
-     * @return The value of the flag.
-     */
-    public boolean isEnabled(BooleanFlag flag) {
-        return mFlagReader.isEnabled(flag);
-    }
-
-    public boolean isNewNotifPipelineRenderingEnabled() {
-        return isEnabled(Flags.NEW_NOTIFICATION_PIPELINE_RENDERING);
-    }
-
-    /** */
-    public boolean useNewLockscreenAnimations() {
-        return isEnabled(Flags.LOCKSCREEN_ANIMATIONS);
-    }
-
-    public boolean isPeopleTileEnabled() {
-        return isEnabled(Flags.PEOPLE_TILE);
-    }
-
-    public boolean isMonetEnabled() {
-        return isEnabled(Flags.MONET);
-    }
-
-    public boolean isPMLiteEnabled() {
-        return isEnabled(Flags.POWER_MENU_LITE);
-    }
-
-    public boolean isChargingRippleEnabled() {
-        return isEnabled(Flags.CHARGING_RIPPLE);
-    }
-
-    public boolean isOngoingCallStatusBarChipEnabled() {
-        return isEnabled(Flags.ONGOING_CALL_STATUS_BAR_CHIP);
-    }
-
-    public boolean isOngoingCallInImmersiveEnabled() {
-        return isOngoingCallStatusBarChipEnabled() && isEnabled(Flags.ONGOING_CALL_IN_IMMERSIVE);
-    }
-
-    public boolean isOngoingCallInImmersiveChipTapEnabled() {
-        return isOngoingCallInImmersiveEnabled()
-                && isEnabled(Flags.ONGOING_CALL_IN_IMMERSIVE_CHIP_TAP);
-    }
-
-    public boolean isSmartspaceEnabled() {
-        return isEnabled(Flags.SMARTSPACE);
-    }
-
-    public boolean isSmartspaceDedupingEnabled() {
-        return isSmartspaceEnabled() && isEnabled(Flags.SMARTSPACE_DEDUPING);
-    }
-
-    public boolean isNewKeyguardSwipeAnimationEnabled() {
-        return isEnabled(Flags.NEW_UNLOCK_SWIPE_ANIMATION);
-    }
-
-    public boolean isKeyguardQsUserDetailsShortcutEnabled() {
-        return isEnabled(Flags.QS_USER_DETAIL_SHORTCUT);
-    }
-
-    public boolean isSmartSpaceSharedElementTransitionEnabled() {
-        return isEnabled(Flags.SMARTSPACE_SHARED_ELEMENT_TRANSITION_ENABLED);
-    }
-
-    /** Whether or not to use the provider model behavior for the status bar icons */
-    public boolean isCombinedStatusBarSignalIconsEnabled() {
-        return isEnabled(Flags.COMBINED_STATUS_BAR_SIGNAL_ICONS);
-    }
-
-    /** System setting for provider model behavior */
-    public boolean isProviderModelSettingEnabled(Context context) {
-        return FeatureFlagUtils.isEnabled(context, FeatureFlagUtils.SETTINGS_PROVIDER_MODEL);
-    }
-
-    /**
-     * Use the new version of the user switcher
-     */
-    public boolean useNewUserSwitcher() {
-        return isEnabled(Flags.NEW_USER_SWITCHER);
-    }
-
-    /**
-     * Use the new single view QS headers
-     */
-    public boolean useCombinedQSHeaders() {
-        return isEnabled(Flags.COMBINED_QS_HEADERS);
-    }
+public interface FeatureFlags extends FlagReader {
 }
diff --git a/packages/SystemUI/src-debug/com/android/systemui/flags/FeatureFlagManager.java b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebug.java
similarity index 97%
rename from packages/SystemUI/src-debug/com/android/systemui/flags/FeatureFlagManager.java
rename to packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebug.java
index acfa3c8..0ee47a7 100644
--- a/packages/SystemUI/src-debug/com/android/systemui/flags/FeatureFlagManager.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebug.java
@@ -60,7 +60,7 @@
  * To restore a flag back to its default, leave the `--ez value <0|1>` off of the command.
  */
 @SysUISingleton
-public class FeatureFlagManager implements FlagReader, FlagWriter, Dumpable {
+public class FeatureFlagsDebug implements FeatureFlags, Dumpable {
     private static final String TAG = "SysUIFlags";
 
     private final FlagManager mFlagManager;
@@ -69,7 +69,7 @@
     private final Map<Integer, Boolean> mBooleanFlagCache = new HashMap<>();
 
     @Inject
-    public FeatureFlagManager(
+    public FeatureFlagsDebug(
             FlagManager flagManager,
             Context context,
             SecureSettings secureSettings,
@@ -126,7 +126,6 @@
     }
 
     /** Set whether a given {@link BooleanFlag} is enabled or not. */
-    @Override
     public void setEnabled(int id, boolean value) {
         Boolean currentValue = isEnabledInternal(id);
         if (currentValue != null && currentValue == value) {
diff --git a/packages/SystemUI/src-release/com/android/systemui/flags/FeatureFlagManager.java b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsRelease.java
similarity index 90%
rename from packages/SystemUI/src-release/com/android/systemui/flags/FeatureFlagManager.java
rename to packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsRelease.java
index 0934b32..bd6cb66 100644
--- a/packages/SystemUI/src-release/com/android/systemui/flags/FeatureFlagManager.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsRelease.java
@@ -36,10 +36,10 @@
  * how to set flags.
  */
 @SysUISingleton
-public class FeatureFlagManager implements FlagReader, FlagWriter, Dumpable {
+public class FeatureFlagsRelease implements FeatureFlags, Dumpable {
     SparseBooleanArray mAccessedFlags = new SparseBooleanArray();
     @Inject
-    public FeatureFlagManager(DumpManager dumpManager) {
+    public FeatureFlagsRelease(DumpManager dumpManager) {
         dumpManager.registerDumpable("SysUIFlags", this);
     }
 
@@ -59,8 +59,6 @@
         mAccessedFlags.append(key, defaultValue);
         return defaultValue;
     }
-    @Override
-    public void setEnabled(int key, boolean value) {}
 
     @Override
     public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.java b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
index c60e098..a1413f9 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
@@ -33,7 +33,7 @@
  * On public release builds, flags will always return their default value. There is no way to
  * change their value on release builds.
  *
- * See {@link FeatureFlagManager} for instructions on flipping the flags via adb.
+ * See {@link FeatureFlagsDebug} for instructions on flipping the flags via adb.
  */
 public class Flags {
     public static final BooleanFlag TEAMFOOD = new BooleanFlag(1, false);
diff --git a/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java b/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java
index b45dc52..10878dc 100644
--- a/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java
+++ b/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java
@@ -42,7 +42,6 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.HashMap;
 
@@ -308,22 +307,22 @@
             return instantiateWithInjections(context, className, arguments);
         }
 
-        private Fragment instantiateWithInjections(Context context, String className,
-                Bundle args) {
-            Method method = mManager.getInjectionMap().get(className);
-            if (method != null) {
+        private Fragment instantiateWithInjections(
+                Context context, String className, Bundle args) {
+            FragmentService.FragmentInstantiationInfo fragmentInstantiationInfo =
+                    mManager.getInjectionMap().get(className);
+            if (fragmentInstantiationInfo != null) {
                 try {
-                    Fragment f = (Fragment) method.invoke(mManager.getFragmentCreator());
+                    Fragment f = (Fragment) fragmentInstantiationInfo
+                            .mMethod
+                            .invoke(fragmentInstantiationInfo.mDaggerComponent);
                     // Setup the args, taken from Fragment#instantiate.
                     if (args != null) {
                         args.setClassLoader(f.getClass().getClassLoader());
                         f.setArguments(args);
                     }
                     return f;
-                } catch (IllegalAccessException e) {
-                    throw new Fragment.InstantiationException("Unable to instantiate " + className,
-                            e);
-                } catch (InvocationTargetException e) {
+                } catch (IllegalAccessException | InvocationTargetException e) {
                     throw new Fragment.InstantiationException("Unable to instantiate " + className,
                             e);
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java b/packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java
index 7f57fcc..2a5e653 100644
--- a/packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java
+++ b/packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java
@@ -18,13 +18,13 @@
 import android.content.res.Configuration;
 import android.os.Handler;
 import android.util.ArrayMap;
+import android.util.Log;
 import android.view.View;
 
 import com.android.systemui.Dumpable;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.qs.QSFragment;
-import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 
 import java.io.FileDescriptor;
@@ -46,9 +46,14 @@
     private static final String TAG = "FragmentService";
 
     private final ArrayMap<View, FragmentHostState> mHosts = new ArrayMap<>();
-    private final ArrayMap<String, Method> mInjectionMap = new ArrayMap<>();
+    /**
+     * A map with the means to create fragments via Dagger injection.
+     *
+     * key: the fragment class name.
+     * value: see {@link FragmentInstantiationInfo}.
+     */
+    private final ArrayMap<String, FragmentInstantiationInfo> mInjectionMap = new ArrayMap<>();
     private final Handler mHandler = new Handler();
-    private final FragmentCreator mFragmentCreator;
 
     private ConfigurationController.ConfigurationListener mConfigurationListener =
             new ConfigurationController.ConfigurationListener() {
@@ -65,26 +70,31 @@
             FragmentCreator.Factory fragmentCreatorFactory,
             ConfigurationController configurationController,
             DumpManager dumpManager) {
-        mFragmentCreator = fragmentCreatorFactory.build();
-        initInjectionMap();
+        addFragmentInstantiationProvider(fragmentCreatorFactory.build());
         configurationController.addCallback(mConfigurationListener);
 
         dumpManager.registerDumpable(getClass().getSimpleName(), this);
     }
 
-    ArrayMap<String, Method> getInjectionMap() {
+    ArrayMap<String, FragmentInstantiationInfo> getInjectionMap() {
         return mInjectionMap;
     }
 
-    FragmentCreator getFragmentCreator() {
-        return mFragmentCreator;
-    }
-
-    private void initInjectionMap() {
-        for (Method method : FragmentCreator.class.getDeclaredMethods()) {
+    /**
+     * Adds a new Dagger component object that provides method(s) to create fragments via injection.
+     */
+    public void addFragmentInstantiationProvider(Object daggerComponent) {
+        for (Method method : daggerComponent.getClass().getDeclaredMethods()) {
             if (Fragment.class.isAssignableFrom(method.getReturnType())
                     && (method.getModifiers() & Modifier.PUBLIC) != 0) {
-                mInjectionMap.put(method.getReturnType().getName(), method);
+                String fragmentName = method.getReturnType().getName();
+                if (mInjectionMap.containsKey(fragmentName)) {
+                    Log.w(TAG, "Fragment " + fragmentName + " is already provided by different"
+                            + " Dagger component; Not adding method");
+                    continue;
+                }
+                mInjectionMap.put(
+                        fragmentName, new FragmentInstantiationInfo(method, daggerComponent));
             }
         }
     }
@@ -134,9 +144,6 @@
          * Inject a QSFragment.
          */
         QSFragment createQSFragment();
-
-        /** Inject a CollapsedStatusBarFragment. */
-        CollapsedStatusBarFragment createCollapsedStatusBarFragment();
     }
 
     private class FragmentHostState {
@@ -161,4 +168,16 @@
             mFragmentHostManager.onConfigurationChanged(newConfig);
         }
     }
+
+    /** An object containing the information needed to instantiate a fragment. */
+    static class FragmentInstantiationInfo {
+        /** The method that returns a newly-created fragment of the given class. */
+        final Method mMethod;
+        /** The Dagger component that the method should be invoked on. */
+        final Object mDaggerComponent;
+        FragmentInstantiationInfo(Method method, Object daggerComponent) {
+            this.mMethod = method;
+            this.mDaggerComponent = daggerComponent;
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
index a6455e6..a801647 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
@@ -31,6 +31,7 @@
 import com.android.systemui.animation.Interpolators
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
 import com.android.systemui.shared.system.smartspace.SmartspaceTransitionController
 import com.android.systemui.statusbar.policy.KeyguardStateController
 import dagger.Lazy
@@ -354,7 +355,7 @@
      * keyguard visible.
      */
     private fun updateKeyguardViewMediatorIfThresholdsReached() {
-        if (!featureFlags.isNewKeyguardSwipeAnimationEnabled) {
+        if (!featureFlags.isEnabled(Flags.NEW_UNLOCK_SWIPE_ANIMATION)) {
             return
         }
 
@@ -410,7 +411,7 @@
      * know if it needs to do something as a result.
      */
     private fun updateSmartSpaceTransition() {
-        if (!featureFlags.isSmartSpaceSharedElementTransitionEnabled) {
+        if (!featureFlags.isEnabled(Flags.SMARTSPACE_SHARED_ELEMENT_TRANSITION_ENABLED)) {
             return
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index e97e762..fbc9ba6 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -793,7 +793,8 @@
                 return KeyguardSecurityView.PROMPT_REASON_DEVICE_ADMIN;
             } else if (trust && (strongAuth & SOME_AUTH_REQUIRED_AFTER_USER_REQUEST) != 0) {
                 return KeyguardSecurityView.PROMPT_REASON_USER_REQUEST;
-            } else if (any && (strongAuth & STRONG_AUTH_REQUIRED_AFTER_LOCKOUT) != 0) {
+            } else if (any && ((strongAuth & STRONG_AUTH_REQUIRED_AFTER_LOCKOUT) != 0
+                    || mUpdateMonitor.isFingerprintLockedOut())) {
                 return KeyguardSecurityView.PROMPT_REASON_AFTER_LOCKOUT;
             } else if (any && (strongAuth & STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE) != 0) {
                 return KeyguardSecurityView.PROMPT_REASON_PREPARE_FOR_UPDATE;
@@ -820,6 +821,7 @@
 
     private final KeyguardStateController mKeyguardStateController;
     private final Lazy<KeyguardUnlockAnimationController> mKeyguardUnlockAnimationControllerLazy;
+    private final InteractionJankMonitor mInteractionJankMonitor;
     private boolean mWallpaperSupportsAmbientMode;
 
     /**
@@ -845,7 +847,8 @@
             KeyguardStateController keyguardStateController,
             Lazy<KeyguardUnlockAnimationController> keyguardUnlockAnimationControllerLazy,
             UnlockedScreenOffAnimationController unlockedScreenOffAnimationController,
-            Lazy<NotificationShadeDepthController> notificationShadeDepthController) {
+            Lazy<NotificationShadeDepthController> notificationShadeDepthController,
+            InteractionJankMonitor interactionJankMonitor) {
         super(context);
         mFalsingCollector = falsingCollector;
         mLockPatternUtils = lockPatternUtils;
@@ -882,6 +885,7 @@
         mKeyguardStateController = keyguardStateController;
         mKeyguardUnlockAnimationControllerLazy = keyguardUnlockAnimationControllerLazy;
         mUnlockedScreenOffAnimationController = unlockedScreenOffAnimationController;
+        mInteractionJankMonitor = interactionJankMonitor;
     }
 
     public void userActivity() {
@@ -2245,8 +2249,7 @@
                                 onKeyguardExitFinished();
                                 mKeyguardViewControllerLazy.get().hide(0 /* startTime */,
                                         0 /* fadeoutDuration */);
-                                InteractionJankMonitor.getInstance()
-                                        .end(CUJ_LOCKSCREEN_UNLOCK_ANIMATION);
+                                mInteractionJankMonitor.end(CUJ_LOCKSCREEN_UNLOCK_ANIMATION);
                             }
 
                             @Override
@@ -2255,7 +2258,7 @@
                             }
                         };
                 try {
-                    InteractionJankMonitor.getInstance().begin(
+                    mInteractionJankMonitor.begin(
                             createInteractionJankMonitorConf("RunRemoteAnimation"));
                     runner.onAnimationStart(WindowManager.TRANSIT_KEYGUARD_GOING_AWAY, apps,
                             wallpapers, nonApps, callback);
@@ -2271,14 +2274,14 @@
                 mSurfaceBehindRemoteAnimationFinishedCallback = finishedCallback;
                 mSurfaceBehindRemoteAnimationRunning = true;
 
-                InteractionJankMonitor.getInstance().begin(
+                mInteractionJankMonitor.begin(
                         createInteractionJankMonitorConf("DismissPanel"));
 
                 // Pass the surface and metadata to the unlock animation controller.
                 mKeyguardUnlockAnimationControllerLazy.get().notifyStartKeyguardExitAnimation(
                         apps[0], startTime, mSurfaceBehindRemoteAnimationRequested);
             } else {
-                InteractionJankMonitor.getInstance().begin(
+                mInteractionJankMonitor.begin(
                         createInteractionJankMonitorConf("RemoteAnimationDisabled"));
 
                 mKeyguardViewControllerLazy.get().hide(startTime, fadeoutDuration);
@@ -2288,7 +2291,7 @@
                 // supported, so it's always null.
                 mContext.getMainExecutor().execute(() -> {
                     if (finishedCallback == null) {
-                        InteractionJankMonitor.getInstance().end(CUJ_LOCKSCREEN_UNLOCK_ANIMATION);
+                        mInteractionJankMonitor.end(CUJ_LOCKSCREEN_UNLOCK_ANIMATION);
                         return;
                     }
 
@@ -2316,8 +2319,7 @@
                             } catch (RemoteException e) {
                                 Slog.e(TAG, "RemoteException");
                             } finally {
-                                InteractionJankMonitor.getInstance()
-                                        .end(CUJ_LOCKSCREEN_UNLOCK_ANIMATION);
+                                mInteractionJankMonitor.end(CUJ_LOCKSCREEN_UNLOCK_ANIMATION);
                             }
                         }
 
@@ -2328,8 +2330,7 @@
                             } catch (RemoteException e) {
                                 Slog.e(TAG, "RemoteException");
                             } finally {
-                                InteractionJankMonitor.getInstance()
-                                        .cancel(CUJ_LOCKSCREEN_UNLOCK_ANIMATION);
+                                mInteractionJankMonitor.cancel(CUJ_LOCKSCREEN_UNLOCK_ANIMATION);
                             }
                         }
                     });
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
index cae9fee..8d23e9f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
@@ -22,6 +22,7 @@
 import android.content.pm.PackageManager;
 import android.os.PowerManager;
 
+import com.android.internal.jank.InteractionJankMonitor;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.keyguard.KeyguardDisplayManager;
 import com.android.keyguard.KeyguardUpdateMonitor;
@@ -97,7 +98,8 @@
             KeyguardStateController keyguardStateController,
             Lazy<KeyguardUnlockAnimationController> keyguardUnlockAnimationController,
             UnlockedScreenOffAnimationController unlockedScreenOffAnimationController,
-            Lazy<NotificationShadeDepthController> notificationShadeDepthController) {
+            Lazy<NotificationShadeDepthController> notificationShadeDepthController,
+            InteractionJankMonitor interactionJankMonitor) {
         return new KeyguardViewMediator(
                 context,
                 falsingCollector,
@@ -120,7 +122,8 @@
                 keyguardStateController,
                 keyguardUnlockAnimationController,
                 unlockedScreenOffAnimationController,
-                notificationShadeDepthController
+                notificationShadeDepthController,
+                interactionJankMonitor
         );
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/log/LogBufferFactory.kt b/packages/SystemUI/src/com/android/systemui/log/LogBufferFactory.kt
index 0622df3..5296ee6 100644
--- a/packages/SystemUI/src/com/android/systemui/log/LogBufferFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/log/LogBufferFactory.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.log
 
+import android.app.ActivityManager
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dump.DumpManager
 import javax.inject.Inject
@@ -25,9 +26,18 @@
     private val dumpManager: DumpManager,
     private val logcatEchoTracker: LogcatEchoTracker
 ) {
+    /* limit the size of maxPoolSize for low ram (Go) devices */
+    private fun poolLimit(maxPoolSize_requested: Int): Int {
+        if (ActivityManager.isLowRamDeviceStatic()) {
+            return minOf(maxPoolSize_requested, 20) /* low ram max log size*/
+        } else {
+            return maxPoolSize_requested
+        }
+    }
+
     @JvmOverloads
     fun create(name: String, maxPoolSize: Int, flexSize: Int = 10): LogBuffer {
-        val buffer = LogBuffer(name, maxPoolSize, flexSize, logcatEchoTracker)
+        val buffer = LogBuffer(name, poolLimit(maxPoolSize), flexSize, logcatEchoTracker)
         dumpManager.registerBuffer(name, buffer)
         return buffer
     }
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
index e87558e..d54b151 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
@@ -400,7 +400,7 @@
         }
         updatePageIndicator()
         mediaCarouselScrollHandler.onPlayersChanged()
-        mediaCarousel.requiresRemeasuring = true
+        mediaFrame.requiresRemeasuring = true
         // Check postcondition: mediaContent should have the same number of children as there are
         // elements in mediaPlayers.
         if (MediaPlayerData.players().size != mediaContent.childCount) {
@@ -439,7 +439,7 @@
         updatePlayerToState(newRecs, noAnimation = true)
         reorderAllPlayers(curVisibleMediaKey)
         updatePageIndicator()
-        mediaCarousel.requiresRemeasuring = true
+        mediaFrame.requiresRemeasuring = true
         // Check postcondition: mediaContent should have the same number of children as there are
         // elements in mediaPlayers.
         if (MediaPlayerData.players().size != mediaContent.childCount) {
@@ -833,12 +833,15 @@
     )
 
     private val comparator =
-            compareByDescending<MediaSortKey> { it.data.isPlaying == true && it.data.isLocalSession }
-                    .thenByDescending { it.data.isPlaying }
-                    .thenByDescending { if (shouldPrioritizeSs) it.isSsMediaRec else !it.isSsMediaRec }
-                    .thenByDescending { !it.data.resumption }
-                    .thenByDescending { it.updateTime }
-                    .thenByDescending { !it.data.isLocalSession }
+            compareByDescending<MediaSortKey> { it.data.isPlaying == true &&
+                        it.data.playbackLocation == MediaData.PLAYBACK_LOCAL }
+                .thenByDescending { it.data.isPlaying == true &&
+                        it.data.playbackLocation == MediaData.PLAYBACK_CAST_LOCAL }
+                .thenByDescending { if (shouldPrioritizeSs) it.isSsMediaRec else !it.isSsMediaRec }
+                .thenByDescending { !it.data.resumption }
+                .thenByDescending { it.data.playbackLocation != MediaData.PLAYBACK_CAST_REMOTE }
+                .thenByDescending { it.updateTime }
+                .thenByDescending { it.data.notificationKey }
 
     private val mediaPlayers = TreeMap<MediaSortKey, MediaControlPanel>(comparator)
     private val mediaData: MutableMap<String, MediaSortKey> = mutableMapOf()
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaData.kt b/packages/SystemUI/src/com/android/systemui/media/MediaData.kt
index 6f0c887..bda07f4 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaData.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaData.kt
@@ -82,9 +82,9 @@
      */
     var resumeAction: Runnable?,
     /**
-     * Local or remote playback
+     * Playback location: one of PLAYBACK_LOCAL, PLAYBACK_CAST_LOCAL, or PLAYBACK_CAST_REMOTE
      */
-    var isLocalSession: Boolean = true,
+    var playbackLocation: Int = PLAYBACK_LOCAL,
     /**
      * Indicates that this player is a resumption player (ie. It only shows a play actions which
      * will start the app and start playing).
@@ -110,7 +110,20 @@
      * Timestamp when this player was last active.
      */
     var lastActive: Long = 0L
-)
+) {
+    companion object {
+        /** Media is playing on the local device */
+        const val PLAYBACK_LOCAL = 0
+        /** Media is cast but originated on the local device */
+        const val PLAYBACK_CAST_LOCAL = 1
+        /** Media is from a remote cast notification */
+        const val PLAYBACK_CAST_REMOTE = 2
+    }
+
+    fun isLocalSession(): Boolean {
+        return playbackLocation == PLAYBACK_LOCAL
+    }
+}
 
 /** State of a media action. */
 data class MediaAction(
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
index 3631d2f..6e86bef 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
@@ -27,6 +27,8 @@
 import android.content.Context
 import android.content.Intent
 import android.content.IntentFilter
+import android.content.pm.ApplicationInfo
+import android.content.pm.PackageManager
 import android.graphics.Bitmap
 import android.graphics.Canvas
 import android.graphics.ImageDecoder
@@ -85,15 +87,7 @@
     "INVALID", null, emptyList(), null, 0)
 
 fun isMediaNotification(sbn: StatusBarNotification): Boolean {
-    if (!sbn.notification.hasMediaSession()) {
-        return false
-    }
-    val notificationStyle = sbn.notification.notificationStyle
-    if (Notification.DecoratedMediaCustomViewStyle::class.java.equals(notificationStyle) ||
-            Notification.MediaStyle::class.java.equals(notificationStyle)) {
-        return true
-    }
-    return false
+    return sbn.notification.isMediaNotification()
 }
 
 /**
@@ -153,6 +147,24 @@
     private var smartspaceSession: SmartspaceSession? = null
     private var allowMediaRecommendations = Utils.allowMediaRecommendations(context)
 
+    /**
+     * Check whether this notification is an RCN
+     * TODO(b/204910409) implement new API for explicitly declaring this
+     */
+    private fun isRemoteCastNotification(sbn: StatusBarNotification): Boolean {
+        val pm = context.packageManager
+        try {
+            val info = pm.getApplicationInfo(sbn.packageName, PackageManager.MATCH_SYSTEM_ONLY)
+            if (info.privateFlags and ApplicationInfo.PRIVATE_FLAG_PRIVILEGED != 0) {
+                val extras = sbn.notification.extras
+                if (extras.containsKey(Notification.EXTRA_SUBSTITUTE_APP_NAME)) {
+                    return true
+                }
+            }
+        } catch (e: PackageManager.NameNotFoundException) { }
+        return false
+    }
+
     @Inject
     constructor(
         context: Context,
@@ -442,7 +454,7 @@
         val existed = mediaEntries[key] != null
         backgroundExecutor.execute {
             mediaEntries[key]?.let { mediaData ->
-                if (mediaData.isLocalSession) {
+                if (mediaData.isLocalSession()) {
                     mediaData.token?.let {
                         val mediaController = mediaControllerFactory.create(it)
                         mediaController.transportControls.stop()
@@ -626,8 +638,11 @@
             }
         }
 
-        val isLocalSession = mediaController.playbackInfo?.playbackType ==
-            MediaController.PlaybackInfo.PLAYBACK_TYPE_LOCAL
+        val playbackLocation =
+                if (isRemoteCastNotification(sbn)) MediaData.PLAYBACK_CAST_REMOTE
+                else if (mediaController.playbackInfo?.playbackType ==
+                    MediaController.PlaybackInfo.PLAYBACK_TYPE_LOCAL) MediaData.PLAYBACK_LOCAL
+                else MediaData.PLAYBACK_CAST_LOCAL
         val isPlaying = mediaController.playbackState?.let { isPlayingState(it.state) } ?: null
         val lastActive = systemClock.elapsedRealtime()
         foregroundExecutor.execute {
@@ -637,7 +652,7 @@
             onMediaDataLoaded(key, oldKey, MediaData(sbn.normalizedUserId, true, bgColor, app,
                     smallIcon, artist, song, artWorkIcon, actionIcons,
                     actionsToShowCollapsed, sbn.packageName, token, notif.contentIntent, null,
-                    active, resumeAction = resumeAction, isLocalSession = isLocalSession,
+                    active, resumeAction = resumeAction, playbackLocation = playbackLocation,
                     notificationKey = key, hasCheckedForResume = hasCheckedForResume,
                     isPlaying = isPlaying, isClearable = sbn.isClearable(),
                     lastActive = lastActive))
@@ -762,7 +777,7 @@
     fun onNotificationRemoved(key: String) {
         Assert.isMainThread()
         val removed = mediaEntries.remove(key)
-        if (useMediaResumption && removed?.resumeAction != null && removed?.isLocalSession) {
+        if (useMediaResumption && removed?.resumeAction != null && removed?.isLocalSession()) {
             Log.d(TAG, "Not removing $key because resumable")
             // Move to resume key (aka package name) if that key doesn't already exist.
             val resumeAction = getResumeMediaAction(removed.resumeAction!!)
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt b/packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt
index 608c784..d8095f3 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt
@@ -193,7 +193,7 @@
                 mediaBrowser = null
             }
             // If we don't have a resume action, check if we haven't already
-            if (data.resumeAction == null && !data.hasCheckedForResume && data.isLocalSession) {
+            if (data.resumeAction == null && !data.hasCheckedForResume && data.isLocalSession()) {
                 // TODO also check for a media button receiver intended for restarting (b/154127084)
                 Log.d(TAG, "Checking for service component for " + data.packageName)
                 val pm = context.packageManager
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
index 1981269..6da4d48 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
@@ -242,7 +242,7 @@
         for (NotificationEntry entry
                 : mNotificationEntryManager.getActiveNotificationsForCurrentUser()) {
             final Notification notification = entry.getSbn().getNotification();
-            if (notification.hasMediaSession()
+            if (notification.isMediaNotification()
                     && TextUtils.equals(entry.getSbn().getPackageName(), mPackageName)) {
                 final Icon icon = notification.getLargeIcon();
                 if (icon == null) {
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java
new file mode 100644
index 0000000..52103d3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java
@@ -0,0 +1,246 @@
+/*
+ * 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.navigationbar;
+
+import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU;
+
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_CLICKABLE;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.view.accessibility.AccessibilityManager;
+
+import androidx.annotation.NonNull;
+
+import com.android.systemui.Dumpable;
+import com.android.systemui.accessibility.AccessibilityButtonModeObserver;
+import com.android.systemui.assist.AssistManager;
+import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dump.DumpManager;
+import com.android.systemui.recents.OverviewProxyService;
+import com.android.systemui.settings.UserTracker;
+import com.android.systemui.shared.system.QuickStepContract;
+import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.inject.Inject;
+
+import dagger.Lazy;
+
+/**
+ * Extracts shared elements between navbar and taskbar delegate to de-dupe logic and help them
+ * experience the joys of friendship.
+ * The events are then passed through
+ *
+ * Currently consolidates
+ * * A11y
+ * * Assistant
+ */
+@SysUISingleton
+public final class NavBarHelper implements
+        AccessibilityButtonModeObserver.ModeChangedListener,
+        OverviewProxyService.OverviewProxyListener, NavigationModeController.ModeChangedListener,
+        Dumpable {
+    private final AccessibilityManager mAccessibilityManager;
+    private final Lazy<AssistManager> mAssistManagerLazy;
+    private final UserTracker mUserTracker;
+    private final AccessibilityButtonModeObserver mAccessibilityButtonModeObserver;
+    private final List<NavbarTaskbarStateUpdater> mA11yEventListeners = new ArrayList<>();
+    private Context mContext;
+    private ContentResolver mContentResolver;
+    private boolean mAssistantAvailable;
+    private boolean mLongPressHomeEnabled;
+    private boolean mAssistantTouchGestureEnabled;
+    private int mNavBarMode;
+
+    private final ContentObserver mAssistContentObserver = new ContentObserver(
+            new Handler(Looper.getMainLooper())) {
+        @Override
+        public void onChange(boolean selfChange, Uri uri) {
+            updateAssitantAvailability();
+        }
+    };
+
+    @Inject
+    public NavBarHelper(AccessibilityManager accessibilityManager,
+            AccessibilityManagerWrapper accessibilityManagerWrapper,
+            AccessibilityButtonModeObserver accessibilityButtonModeObserver,
+            OverviewProxyService overviewProxyService,
+            Lazy<AssistManager> assistManagerLazy,
+            NavigationModeController navigationModeController,
+            UserTracker userTracker,
+            DumpManager dumpManager) {
+        mAccessibilityManager = accessibilityManager;
+        mAssistManagerLazy = assistManagerLazy;
+        mUserTracker = userTracker;
+        accessibilityManagerWrapper.addCallback(
+                accessibilityManager1 -> NavBarHelper.this.dispatchA11yEventUpdate());
+        mAccessibilityButtonModeObserver = accessibilityButtonModeObserver;
+
+        mAccessibilityButtonModeObserver.addListener(this);
+        mNavBarMode = navigationModeController.addListener(this);
+        overviewProxyService.addCallback(this);
+        dumpManager.registerDumpable(this);
+    }
+
+    public void init(Context context) {
+        mContext = context;
+        mContentResolver = mContext.getContentResolver();
+        mContentResolver.registerContentObserver(
+                Settings.Secure.getUriFor(Settings.Secure.ASSISTANT),
+                false /* notifyForDescendants */, mAssistContentObserver, UserHandle.USER_ALL);
+        mContentResolver.registerContentObserver(
+                Settings.Secure.getUriFor(Settings.Secure.ASSIST_LONG_PRESS_HOME_ENABLED),
+                false, mAssistContentObserver, UserHandle.USER_ALL);
+        mContentResolver.registerContentObserver(
+                Settings.Secure.getUriFor(Settings.Secure.ASSIST_TOUCH_GESTURE_ENABLED),
+                false, mAssistContentObserver, UserHandle.USER_ALL);
+        updateAssitantAvailability();
+    }
+
+    public void destroy() {
+        mContentResolver.unregisterContentObserver(mAssistContentObserver);
+    }
+
+    /**
+     * @param listener Will immediately get callbacks based on current state
+     */
+    public void registerNavTaskStateUpdater(NavbarTaskbarStateUpdater listener) {
+        mA11yEventListeners.add(listener);
+        listener.updateAccessibilityServicesState();
+        listener.updateAssistantAvailable(mAssistantAvailable);
+    }
+
+    public void removeNavTaskStateUpdater(NavbarTaskbarStateUpdater listener) {
+        mA11yEventListeners.remove(listener);
+    }
+
+    private void dispatchA11yEventUpdate() {
+        for (NavbarTaskbarStateUpdater listener : mA11yEventListeners) {
+            listener.updateAccessibilityServicesState();
+        }
+    }
+
+    private void dispatchAssistantEventUpdate(boolean assistantAvailable) {
+        for (NavbarTaskbarStateUpdater listener : mA11yEventListeners) {
+            listener.updateAssistantAvailable(assistantAvailable);
+        }
+    }
+
+    @Override
+    public void onAccessibilityButtonModeChanged(int mode) {
+        dispatchA11yEventUpdate();
+    }
+
+    /**
+     * See {@link QuickStepContract#SYSUI_STATE_A11Y_BUTTON_CLICKABLE} and
+     * {@link QuickStepContract#SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE}
+     *
+     * @return the a11y button clickable and long_clickable states, or 0 if there is no
+     *         a11y button in the navbar
+     */
+    public int getA11yButtonState() {
+        // AccessibilityManagerService resolves services for the current user since the local
+        // AccessibilityManager is created from a Context with the INTERACT_ACROSS_USERS permission
+        final List<String> a11yButtonTargets =
+                mAccessibilityManager.getAccessibilityShortcutTargets(
+                        AccessibilityManager.ACCESSIBILITY_BUTTON);
+        final int requestingServices = a11yButtonTargets.size();
+
+        // If accessibility button is floating menu mode, click and long click state should be
+        // disabled.
+        if (mAccessibilityButtonModeObserver.getCurrentAccessibilityButtonMode()
+                == ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU) {
+            return 0;
+        }
+
+        return (requestingServices >= 1 ? SYSUI_STATE_A11Y_BUTTON_CLICKABLE : 0)
+                | (requestingServices >= 2 ? SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE : 0);
+    }
+
+    @Override
+    public void onConnectionChanged(boolean isConnected) {
+        if (isConnected) {
+            updateAssitantAvailability();
+        }
+    }
+
+    private void updateAssitantAvailability() {
+        boolean assistantAvailableForUser = mAssistManagerLazy.get()
+                .getAssistInfoForUser(UserHandle.USER_CURRENT) != null;
+        boolean longPressDefault = mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_assistLongPressHomeEnabledDefault);
+        mLongPressHomeEnabled = Settings.Secure.getIntForUser(mContentResolver,
+                Settings.Secure.ASSIST_LONG_PRESS_HOME_ENABLED, longPressDefault ? 1 : 0,
+                mUserTracker.getUserId()) != 0;
+        boolean gestureDefault = mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_assistTouchGestureEnabledDefault);
+        mAssistantTouchGestureEnabled = Settings.Secure.getIntForUser(mContentResolver,
+                Settings.Secure.ASSIST_TOUCH_GESTURE_ENABLED, gestureDefault ? 1 : 0,
+                mUserTracker.getUserId()) != 0;
+
+        mAssistantAvailable = assistantAvailableForUser
+                && mAssistantTouchGestureEnabled
+                && QuickStepContract.isGesturalMode(mNavBarMode);
+        dispatchAssistantEventUpdate(mAssistantAvailable);
+    }
+
+    public boolean getLongPressHomeEnabled() {
+        return mLongPressHomeEnabled;
+    }
+
+    @Override
+    public void startAssistant(Bundle bundle) {
+        mAssistManagerLazy.get().startAssist(bundle);
+    }
+
+    @Override
+    public void onNavigationModeChanged(int mode) {
+        mNavBarMode = mode;
+        updateAssitantAvailability();
+    }
+
+    /**
+     * Callbacks will get fired once immediately after registering via
+     * {@link #registerNavTaskStateUpdater(NavbarTaskbarStateUpdater)}
+     */
+    public interface NavbarTaskbarStateUpdater {
+        void updateAccessibilityServicesState();
+        void updateAssistantAvailable(boolean available);
+    }
+
+    @Override
+    public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
+        pw.println("NavbarTaskbarFriendster");
+        pw.println("  longPressHomeEnabled=" + mLongPressHomeEnabled);
+        pw.println("  mAssistantTouchGestureEnabled=" + mAssistantTouchGestureEnabled);
+        pw.println("  mAssistantAvailable=" + mAssistantAvailable);
+        pw.println("  mNavBarMode=" + mNavBarMode);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
index 0e6e8a4..e0da9a0 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
@@ -67,22 +67,18 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.res.Configuration;
-import android.database.ContentObserver;
 import android.graphics.Insets;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.inputmethodservice.InputMethodService;
-import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
-import android.os.Looper;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.provider.DeviceConfig;
-import android.provider.Settings;
 import android.telecom.TelecomManager;
 import android.text.TextUtils;
 import android.util.Log;
@@ -97,6 +93,7 @@
 import android.view.Surface;
 import android.view.View;
 import android.view.ViewTreeObserver;
+import android.view.WindowInsets;
 import android.view.WindowInsetsController.Appearance;
 import android.view.WindowInsetsController.Behavior;
 import android.view.WindowManager;
@@ -199,8 +196,7 @@
     private final Handler mHandler;
     private final NavigationBarOverlayController mNavbarOverlayController;
     private final UiEventLogger mUiEventLogger;
-    private final NavigationBarA11yHelper mNavigationBarA11yHelper;
-    private final UserTracker mUserTracker;
+    private final NavBarHelper mNavBarHelper;
     private final NotificationShadeDepthController mNotificationShadeDepthController;
 
     private Bundle mSavedState;
@@ -212,9 +208,7 @@
     private int mNavigationIconHints = 0;
     private @TransitionMode int mNavigationBarMode;
     private ContentResolver mContentResolver;
-    private boolean mAssistantAvailable;
     private boolean mLongPressHomeEnabled;
-    private boolean mAssistantTouchGestureEnabled;
 
     private int mDisabledFlags1;
     private int mDisabledFlags2;
@@ -308,16 +302,31 @@
         }
     };
 
+    private final NavBarHelper.NavbarTaskbarStateUpdater mNavbarTaskbarStateUpdater =
+            new NavBarHelper.NavbarTaskbarStateUpdater() {
+                @Override
+                public void updateAccessibilityServicesState() {
+                    updateAcessibilityStateFlags();
+                }
+
+                @Override
+                public void updateAssistantAvailable(boolean available) {
+                    // TODO(b/198002034): Content observers currently can still be called back after
+                    //  being unregistered, and in this case we can ignore the change if the nav bar
+                    //  has been destroyed already
+                    if (mNavigationBarView == null) {
+                        return;
+                    }
+                    mLongPressHomeEnabled = mNavBarHelper.getLongPressHomeEnabled();
+                    updateAssistantEntrypoints(available);
+                }
+            };
+
     private final OverviewProxyListener mOverviewProxyListener = new OverviewProxyListener() {
         @Override
         public void onConnectionChanged(boolean isConnected) {
             mNavigationBarView.updateStates();
             updateScreenPinningGestures();
-
-            // Send the assistant availability upon connection
-            if (isConnected) {
-                updateAssistantEntrypoints();
-            }
         }
 
         @Override
@@ -420,20 +429,6 @@
         }
     };
 
-    private final ContentObserver mAssistContentObserver = new ContentObserver(
-            new Handler(Looper.getMainLooper())) {
-        @Override
-        public void onChange(boolean selfChange, Uri uri) {
-            // TODO(b/198002034): Content observers currently can still be called back after being
-            // unregistered, and in this case we can ignore the change if the nav bar has been
-            // destroyed already
-            if (mNavigationBarView == null) {
-                return;
-            }
-            updateAssistantEntrypoints();
-        }
-    };
-
     private final DeviceConfig.OnPropertiesChangedListener mOnPropertiesChangedListener =
             new DeviceConfig.OnPropertiesChangedListener() {
                 @Override
@@ -503,7 +498,7 @@
             @Main Handler mainHandler,
             NavigationBarOverlayController navbarOverlayController,
             UiEventLogger uiEventLogger,
-            NavigationBarA11yHelper navigationBarA11yHelper,
+            NavBarHelper navBarHelper,
             UserTracker userTracker,
             LightBarController mainLightBarController,
             LightBarController.Factory lightBarControllerFactory,
@@ -534,8 +529,7 @@
         mHandler = mainHandler;
         mNavbarOverlayController = navbarOverlayController;
         mUiEventLogger = uiEventLogger;
-        mNavigationBarA11yHelper = navigationBarA11yHelper;
-        mUserTracker = userTracker;
+        mNavBarHelper = navBarHelper;
         mNotificationShadeDepthController = notificationShadeDepthController;
         mMainLightBarController = mainLightBarController;
         mLightBarControllerFactory = lightBarControllerFactory;
@@ -567,18 +561,9 @@
         mIsOnDefaultDisplay = mDisplayId == DEFAULT_DISPLAY;
 
         mCommandQueue.addCallback(this);
-        mAssistantAvailable = mAssistManagerLazy.get()
-                .getAssistInfoForUser(UserHandle.USER_CURRENT) != null;
+        mLongPressHomeEnabled = mNavBarHelper.getLongPressHomeEnabled();
         mContentResolver = mContext.getContentResolver();
-        mContentResolver.registerContentObserver(
-                Settings.Secure.getUriFor(Settings.Secure.ASSISTANT),
-                false /* notifyForDescendants */, mAssistContentObserver, UserHandle.USER_ALL);
-        mContentResolver.registerContentObserver(
-                Settings.Secure.getUriFor(Settings.Secure.ASSIST_LONG_PRESS_HOME_ENABLED),
-                false, mAssistContentObserver, UserHandle.USER_ALL);
-        mContentResolver.registerContentObserver(
-                Settings.Secure.getUriFor(Settings.Secure.ASSIST_TOUCH_GESTURE_ENABLED),
-                false, mAssistContentObserver, UserHandle.USER_ALL);
+        mNavBarHelper.init(mContext);
         mAllowForceNavBarHandleOpaque = mContext.getResources().getBoolean(
                 R.bool.allow_force_nav_bar_handle_opaque);
         mForceNavBarHandleOpaque = DeviceConfig.getBoolean(
@@ -592,7 +577,6 @@
         )).filter(duration -> duration != 0);
         DeviceConfig.addOnPropertiesChangedListener(
                 DeviceConfig.NAMESPACE_SYSTEMUI, mHandler::post, mOnPropertiesChangedListener);
-        updateAssistantEntrypoints();
 
         if (savedState != null) {
             mDisabledFlags1 = savedState.getInt(EXTRA_DISABLE_STATE, 0);
@@ -619,8 +603,8 @@
         mWindowManager.removeViewImmediate(mNavigationBarView.getRootView());
         mNavigationModeController.removeListener(this);
 
-        mNavigationBarA11yHelper.removeA11yEventListener(mAccessibilityListener);
-        mContentResolver.unregisterContentObserver(mAssistContentObserver);
+        mNavBarHelper.removeNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
+        mNavBarHelper.destroy();
         mDeviceProvisionedController.removeCallback(mUserSetupListener);
         mNotificationShadeDepthController.removeListener(mDepthListener);
 
@@ -642,7 +626,7 @@
         mNavigationBarView.setWindowVisible(isNavBarWindowVisible());
         mNavigationBarView.setBehavior(mBehavior);
 
-        mNavigationBarA11yHelper.registerA11yEventListener(mAccessibilityListener);
+        mNavBarHelper.registerNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
 
         mSplitScreenOptional.ifPresent(mNavigationBarView::registerDockedListener);
         mPipOptional.ifPresent(mNavigationBarView::registerPipExclusionBoundsChangeListener);
@@ -715,7 +699,7 @@
         mHandler.removeCallbacks(mAutoDim);
         mHandler.removeCallbacks(mOnVariableDurationHomeLongClick);
         mHandler.removeCallbacks(mEnableLayoutTransitions);
-        mNavigationBarA11yHelper.removeA11yEventListener(mAccessibilityListener);
+        mNavBarHelper.removeNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
         mFrame = null;
         mNavigationBarView = null;
         mOrientationHandle = null;
@@ -884,7 +868,6 @@
         pw.println("  mCurrentRotation=" + mCurrentRotation);
         pw.println("  mHomeButtonLongPressDurationMs=" + mHomeButtonLongPressDurationMs);
         pw.println("  mLongPressHomeEnabled=" + mLongPressHomeEnabled);
-        pw.println("  mAssistantTouchGestureEnabled=" + mAssistantTouchGestureEnabled);
         pw.println("  mNavigationBarWindowState="
                 + windowStateToString(mNavigationBarWindowState));
         pw.println("  mNavigationBarMode="
@@ -901,7 +884,17 @@
         if (displayId != mDisplayId) {
             return;
         }
-        boolean imeShown = (vis & InputMethodService.IME_VISIBLE) != 0;
+        boolean imeVisibleOnShade = mStatusBarOptionalLazy.get().map(statusBar -> {
+            View shadeWindowView = statusBar.getNotificationShadeWindowView();
+            return shadeWindowView.isAttachedToWindow()
+                    && shadeWindowView.getRootWindowInsets().isVisible(WindowInsets.Type.ime());
+        }).orElse(false);
+        boolean isKeyguardShowing = mStatusBarOptionalLazy.get().map(
+                StatusBar::isKeyguardShowing).orElse(false);
+        boolean imeShown = imeVisibleOnShade
+                || (!isKeyguardShowing && (vis & InputMethodService.IME_VISIBLE) != 0);
+        showImeSwitcher = imeShown && showImeSwitcher;
+
         int hints = Utilities.calculateBackDispositionHints(mNavigationIconHints, backDisposition,
                 imeShown, showImeSwitcher);
         if (hints == mNavigationIconHints) return;
@@ -1164,7 +1157,7 @@
         ButtonDispatcher accessibilityButton = mNavigationBarView.getAccessibilityButton();
         accessibilityButton.setOnClickListener(this::onAccessibilityClick);
         accessibilityButton.setOnLongClickListener(this::onAccessibilityLongClick);
-        updateAccessibilityServicesState();
+        updateAcessibilityStateFlags();
 
         ButtonDispatcher imeSwitcherButton = mNavigationBarView.getImeSwitchButton();
         imeSwitcherButton.setOnClickListener(this::onImeSwitcherClick);
@@ -1389,8 +1382,8 @@
         return true;
     }
 
-    void updateAccessibilityServicesState() {
-        int a11yFlags = mNavigationBarA11yHelper.getA11yButtonState();
+    void updateAcessibilityStateFlags() {
+        int a11yFlags = mNavBarHelper.getA11yButtonState();
 
         if (mNavigationBarView != null) {
             boolean clickable = (a11yFlags & SYSUI_STATE_A11Y_BUTTON_CLICKABLE) != 0;
@@ -1402,7 +1395,7 @@
 
     public void updateSystemUiStateFlags(int a11yFlags) {
         if (a11yFlags < 0) {
-            a11yFlags = mNavigationBarA11yHelper.getA11yButtonState();
+            a11yFlags = mNavBarHelper.getA11yButtonState();
         }
         boolean clickable = (a11yFlags & SYSUI_STATE_A11Y_BUTTON_CLICKABLE) != 0;
         boolean longClickable = (a11yFlags & SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE) != 0;
@@ -1429,24 +1422,10 @@
         }
     }
 
-    private void updateAssistantEntrypoints() {
-        mAssistantAvailable = mAssistManagerLazy.get()
-                .getAssistInfoForUser(UserHandle.USER_CURRENT) != null;
-        boolean longPressDefault = mContext.getResources().getBoolean(
-                com.android.internal.R.bool.config_assistLongPressHomeEnabledDefault);
-        mLongPressHomeEnabled = Settings.Secure.getIntForUser(mContentResolver,
-                Settings.Secure.ASSIST_LONG_PRESS_HOME_ENABLED, longPressDefault ? 1 : 0,
-                mUserTracker.getUserId()) != 0;
-        boolean gestureDefault = mContext.getResources().getBoolean(
-                com.android.internal.R.bool.config_assistTouchGestureEnabledDefault);
-        mAssistantTouchGestureEnabled = Settings.Secure.getIntForUser(mContentResolver,
-                Settings.Secure.ASSIST_TOUCH_GESTURE_ENABLED, gestureDefault ? 1 : 0,
-                mUserTracker.getUserId()) != 0;
+    private void updateAssistantEntrypoints(boolean assistantAvailable) {
         if (mOverviewProxyService.getProxy() != null) {
             try {
-                mOverviewProxyService.getProxy().onAssistantAvailable(mAssistantAvailable
-                        && mAssistantTouchGestureEnabled
-                        && QuickStepContract.isGesturalMode(mNavBarMode));
+                mOverviewProxyService.getProxy().onAssistantAvailable(assistantAvailable);
             } catch (RemoteException e) {
                 Log.w(TAG, "Unable to send assistant availability data to launcher");
             }
@@ -1517,8 +1496,6 @@
     @Override
     public void onNavigationModeChanged(int mode) {
         mNavBarMode = mode;
-        // update assistant entry points on system navigation radio button click
-        updateAssistantEntrypoints();
 
         if (!QuickStepContract.isGesturalMode(mode)) {
             // Reset the override alpha
@@ -1557,9 +1534,6 @@
         mNavigationBarView.getBarTransitions().finishAnimations();
     }
 
-    private final NavigationBarA11yHelper.NavA11yEventListener mAccessibilityListener =
-            this::updateAccessibilityServicesState;
-
     private WindowManager.LayoutParams getBarLayoutParams(int rotation) {
         WindowManager.LayoutParams lp = getBarLayoutParamsForRotation(rotation);
         lp.paramsForRotation = new WindowManager.LayoutParams[4];
@@ -1663,7 +1637,7 @@
             }
             if (Intent.ACTION_USER_SWITCHED.equals(action)) {
                 // The accessibility settings may be different for the new user
-                updateAccessibilityServicesState();
+                updateAcessibilityStateFlags();
             }
         }
     };
@@ -1699,7 +1673,7 @@
         private final Handler mMainHandler;
         private final NavigationBarOverlayController mNavbarOverlayController;
         private final UiEventLogger mUiEventLogger;
-        private final NavigationBarA11yHelper mNavigationBarA11yHelper;
+        private final NavBarHelper mNavBarHelper;
         private final UserTracker mUserTracker;
         private final LightBarController mMainLightBarController;
         private final LightBarController.Factory mLightBarControllerFactory;
@@ -1732,7 +1706,7 @@
                 @Main Handler mainHandler,
                 NavigationBarOverlayController navbarOverlayController,
                 UiEventLogger uiEventLogger,
-                NavigationBarA11yHelper navigationBarA11yHelper,
+                NavBarHelper navBarHelper,
                 UserTracker userTracker,
                 LightBarController mainLightBarController,
                 LightBarController.Factory lightBarControllerFactory,
@@ -1762,7 +1736,7 @@
             mMainHandler = mainHandler;
             mNavbarOverlayController = navbarOverlayController;
             mUiEventLogger = uiEventLogger;
-            mNavigationBarA11yHelper = navigationBarA11yHelper;
+            mNavBarHelper = navBarHelper;
             mUserTracker = userTracker;
             mMainLightBarController = mainLightBarController;
             mLightBarControllerFactory = lightBarControllerFactory;
@@ -1783,7 +1757,7 @@
                     mSplitScreenOptional, mRecentsOptional, mStatusBarOptionalLazy,
                     mShadeController, mNotificationRemoteInputManager,
                     mNotificationShadeDepthController, mSystemActions, mMainHandler,
-                    mNavbarOverlayController, mUiEventLogger, mNavigationBarA11yHelper,
+                    mNavbarOverlayController, mUiEventLogger, mNavBarHelper,
                     mUserTracker, mMainLightBarController, mLightBarControllerFactory,
                     mMainAutoHideController, mAutoHideControllerFactory, mTelecomManagerOptional,
                     mInputMethodManager);
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarA11yHelper.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarA11yHelper.java
deleted file mode 100644
index 13e6d8b..0000000
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarA11yHelper.java
+++ /dev/null
@@ -1,90 +0,0 @@
-package com.android.systemui.navigationbar;
-
-import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU;
-
-import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_CLICKABLE;
-import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE;
-
-import android.view.accessibility.AccessibilityManager;
-
-import com.android.systemui.accessibility.AccessibilityButtonModeObserver;
-import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.shared.system.QuickStepContract;
-import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.inject.Inject;
-
-/**
- * Extracts shared elements of a11y necessary between navbar and taskbar delegate
- */
-@SysUISingleton
-public final class NavigationBarA11yHelper implements
-        AccessibilityButtonModeObserver.ModeChangedListener {
-    private final AccessibilityManager mAccessibilityManager;
-    private final AccessibilityButtonModeObserver mAccessibilityButtonModeObserver;
-    private final List<NavA11yEventListener> mA11yEventListeners = new ArrayList<>();
-
-    @Inject
-    public NavigationBarA11yHelper(AccessibilityManager accessibilityManager,
-            AccessibilityManagerWrapper accessibilityManagerWrapper,
-            AccessibilityButtonModeObserver accessibilityButtonModeObserver) {
-        mAccessibilityManager = accessibilityManager;
-        accessibilityManagerWrapper.addCallback(
-                accessibilityManager1 -> NavigationBarA11yHelper.this.dispatchEventUpdate());
-        mAccessibilityButtonModeObserver = accessibilityButtonModeObserver;
-
-        mAccessibilityButtonModeObserver.addListener(this);
-    }
-
-    public void registerA11yEventListener(NavA11yEventListener listener) {
-        mA11yEventListeners.add(listener);
-    }
-
-    public void removeA11yEventListener(NavA11yEventListener listener) {
-        mA11yEventListeners.remove(listener);
-    }
-
-    private void dispatchEventUpdate() {
-        for (NavA11yEventListener listener : mA11yEventListeners) {
-            listener.updateAccessibilityServicesState();
-        }
-    }
-
-    @Override
-    public void onAccessibilityButtonModeChanged(int mode) {
-        dispatchEventUpdate();
-    }
-
-    /**
-     * See {@link QuickStepContract#SYSUI_STATE_A11Y_BUTTON_CLICKABLE} and
-     * {@link QuickStepContract#SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE}
-     *
-     * @return the a11y button clickable and long_clickable states, or 0 if there is no
-     *         a11y button in the navbar
-     */
-    public int getA11yButtonState() {
-        // AccessibilityManagerService resolves services for the current user since the local
-        // AccessibilityManager is created from a Context with the INTERACT_ACROSS_USERS permission
-        final List<String> a11yButtonTargets =
-                mAccessibilityManager.getAccessibilityShortcutTargets(
-                        AccessibilityManager.ACCESSIBILITY_BUTTON);
-        final int requestingServices = a11yButtonTargets.size();
-
-        // If accessibility button is floating menu mode, click and long click state should be
-        // disabled.
-        if (mAccessibilityButtonModeObserver.getCurrentAccessibilityButtonMode()
-                == ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU) {
-            return 0;
-        }
-
-        return (requestingServices >= 1 ? SYSUI_STATE_A11Y_BUTTON_CLICKABLE : 0)
-                | (requestingServices >= 2 ? SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE : 0);
-    }
-
-    public interface NavA11yEventListener {
-        void updateAccessibilityServicesState();
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
index 3dc79c4..0429c02 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
@@ -57,6 +57,7 @@
 import com.android.systemui.statusbar.CommandQueue.Callbacks;
 import com.android.systemui.statusbar.phone.AutoHideController;
 import com.android.systemui.statusbar.phone.BarTransitions.TransitionMode;
+import com.android.systemui.statusbar.phone.LightBarController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 
 import java.io.FileDescriptor;
@@ -100,11 +101,12 @@
             CommandQueue commandQueue,
             @Main Handler mainHandler,
             ConfigurationController configurationController,
-            NavigationBarA11yHelper navigationBarA11yHelper,
+            NavBarHelper navBarHelper,
             TaskbarDelegate taskbarDelegate,
             NavigationBar.Factory navigationBarFactory,
             DumpManager dumpManager,
-            AutoHideController autoHideController) {
+            AutoHideController autoHideController,
+            LightBarController lightBarController) {
         mContext = context;
         mHandler = mainHandler;
         mNavigationBarFactory = navigationBarFactory;
@@ -115,8 +117,8 @@
         mNavMode = navigationModeController.addListener(this);
         mTaskbarDelegate = taskbarDelegate;
         mTaskbarDelegate.setDependencies(commandQueue, overviewProxyService,
-                navigationBarA11yHelper, navigationModeController, sysUiFlagsContainer,
-                dumpManager, autoHideController);
+                navBarHelper, navigationModeController, sysUiFlagsContainer,
+                dumpManager, autoHideController, lightBarController);
         mIsTablet = isTablet(mContext);
         dumpManager.registerDumpable(this);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
index d707dbd..3d58a5a 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
@@ -43,6 +43,8 @@
 import android.hardware.display.DisplayManager;
 import android.inputmethodservice.InputMethodService;
 import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
 import android.view.Display;
 import android.view.InsetsVisibilities;
 import android.view.View;
@@ -62,6 +64,9 @@
 import com.android.systemui.statusbar.AutoHideUiElement;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.phone.AutoHideController;
+import com.android.systemui.statusbar.phone.BarTransitions;
+import com.android.systemui.statusbar.phone.LightBarController;
+import com.android.systemui.statusbar.phone.LightBarTransitionsController;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -73,19 +78,32 @@
 public class TaskbarDelegate implements CommandQueue.Callbacks,
         OverviewProxyService.OverviewProxyListener, NavigationModeController.ModeChangedListener,
         ComponentCallbacks, Dumpable {
+    private static final String TAG = TaskbarDelegate.class.getSimpleName();
 
     private final EdgeBackGestureHandler mEdgeBackGestureHandler;
-
+    private boolean mInitialized;
     private CommandQueue mCommandQueue;
     private OverviewProxyService mOverviewProxyService;
-    private NavigationBarA11yHelper mNavigationBarA11yHelper;
+    private NavBarHelper mNavBarHelper;
     private NavigationModeController mNavigationModeController;
     private SysUiState mSysUiState;
     private AutoHideController mAutoHideController;
+    private LightBarController mLightBarController;
+    private LightBarTransitionsController mLightBarTransitionsController;
     private int mDisplayId;
     private int mNavigationIconHints;
-    private final NavigationBarA11yHelper.NavA11yEventListener mNavA11yEventListener =
-            this::updateSysuiFlags;
+    private final NavBarHelper.NavbarTaskbarStateUpdater mNavbarTaskbarStateUpdater =
+            new NavBarHelper.NavbarTaskbarStateUpdater() {
+                @Override
+                public void updateAccessibilityServicesState() {
+                    updateSysuiFlags();
+                }
+
+                @Override
+                public void updateAssistantAvailable(boolean available) {
+                    updateAssistantAvailability(available);
+                }
+            };
     private int mDisabledFlags;
     private @WindowVisibleState int mTaskBarWindowState = WINDOW_STATE_SHOWING;
     private @Behavior int mBehavior;
@@ -125,27 +143,56 @@
 
     public void setDependencies(CommandQueue commandQueue,
             OverviewProxyService overviewProxyService,
-            NavigationBarA11yHelper navigationBarA11yHelper,
+            NavBarHelper navBarHelper,
             NavigationModeController navigationModeController,
             SysUiState sysUiState, DumpManager dumpManager,
-            AutoHideController autoHideController) {
+            AutoHideController autoHideController,
+            LightBarController lightBarController) {
         // TODO: adding this in the ctor results in a dagger dependency cycle :(
         mCommandQueue = commandQueue;
         mOverviewProxyService = overviewProxyService;
-        mNavigationBarA11yHelper = navigationBarA11yHelper;
+        mNavBarHelper = navBarHelper;
         mNavigationModeController = navigationModeController;
         mSysUiState = sysUiState;
         dumpManager.registerDumpable(this);
         mAutoHideController = autoHideController;
+        mLightBarController = lightBarController;
+        mLightBarTransitionsController = createLightBarTransitionsController();
+    }
+
+    // Separated into a method to keep setDependencies() clean/readable.
+    private LightBarTransitionsController createLightBarTransitionsController() {
+        return new LightBarTransitionsController(mContext,
+                new LightBarTransitionsController.DarkIntensityApplier() {
+                    @Override
+                    public void applyDarkIntensity(float darkIntensity) {
+                        mOverviewProxyService.onNavButtonsDarkIntensityChanged(darkIntensity);
+                    }
+
+                    @Override
+                    public int getTintAnimationDuration() {
+                        return LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION;
+                    }
+                }, mCommandQueue) {
+            @Override
+            public boolean supportsIconTintForNavMode(int navigationMode) {
+                // Always tint taskbar nav buttons (region sampling handles gesture bar separately).
+                return true;
+            }
+        };
     }
 
     public void init(int displayId) {
+        if (mInitialized) {
+            return;
+        }
         mDisplayId = displayId;
         mCommandQueue.addCallback(this);
         mOverviewProxyService.addCallback(this);
         mEdgeBackGestureHandler.onNavigationModeChanged(
                 mNavigationModeController.addListener(this));
-        mNavigationBarA11yHelper.registerA11yEventListener(mNavA11yEventListener);
+        mNavBarHelper.registerNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
+        mNavBarHelper.init(mContext);
         mEdgeBackGestureHandler.onNavBarAttached();
         // Initialize component callback
         Display display = mDisplayManager.getDisplay(displayId);
@@ -154,23 +201,32 @@
         // Set initial state for any listeners
         updateSysuiFlags();
         mAutoHideController.setNavigationBar(mAutoHideUiElement);
+        mLightBarController.setNavigationBar(mLightBarTransitionsController);
+        mInitialized = true;
     }
 
     public void destroy() {
+        if (!mInitialized) {
+            return;
+        }
         mCommandQueue.removeCallback(this);
         mOverviewProxyService.removeCallback(this);
         mNavigationModeController.removeListener(this);
-        mNavigationBarA11yHelper.removeA11yEventListener(mNavA11yEventListener);
+        mNavBarHelper.removeNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
+        mNavBarHelper.destroy();
         mEdgeBackGestureHandler.onNavBarDetached();
         if (mWindowContext != null) {
             mWindowContext.unregisterComponentCallbacks(this);
             mWindowContext = null;
         }
         mAutoHideController.setNavigationBar(null);
+        mLightBarTransitionsController.destroy(mContext);
+        mLightBarController.setNavigationBar(null);
+        mInitialized = false;
     }
 
     private void updateSysuiFlags() {
-        int a11yFlags = mNavigationBarA11yHelper.getA11yButtonState();
+        int a11yFlags = mNavBarHelper.getA11yButtonState();
         boolean clickable = (a11yFlags & SYSUI_STATE_A11Y_BUTTON_CLICKABLE) != 0;
         boolean longClickable = (a11yFlags & SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE) != 0;
 
@@ -194,6 +250,18 @@
                 .commitUpdate(mDisplayId);
     }
 
+    private void updateAssistantAvailability(boolean assistantAvailable) {
+        if (mOverviewProxyService.getProxy() == null) {
+            return;
+        }
+
+        try {
+            mOverviewProxyService.getProxy().onAssistantAvailable(assistantAvailable);
+        } catch (RemoteException e) {
+            Log.e(TAG, "onAssistantAvailable() failed, available: " + assistantAvailable, e);
+        }
+    }
+
     @Override
     public void setImeWindowStatus(int displayId, IBinder token, int vis, int backDisposition,
             boolean showImeSwitcher) {
@@ -233,6 +301,10 @@
             AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme, int behavior,
             InsetsVisibilities requestedVisibilities, String packageName) {
         mOverviewProxyService.onSystemBarAttributesChanged(displayId, behavior);
+        if (mLightBarController != null && displayId == mDisplayId) {
+            mLightBarController.onNavigationBarAppearanceChanged(appearance, false/*nbModeChanged*/,
+                    BarTransitions.MODE_TRANSPARENT /*navigationBarMode*/, navbarColorManagedByIme);
+        }
         if (mBehavior != behavior) {
             mBehavior = behavior;
             updateSysuiFlags();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/FooterActionsController.kt b/packages/SystemUI/src/com/android/systemui/qs/FooterActionsController.kt
index 98b9146..fce0c0c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/FooterActionsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/FooterActionsController.kt
@@ -17,8 +17,10 @@
 package com.android.systemui.qs
 
 import android.content.Intent
+import android.os.Handler
 import android.os.UserManager
 import android.provider.Settings
+import android.provider.Settings.Global.USER_SWITCHER_ENABLED
 import android.view.View
 import android.widget.Toast
 import androidx.annotation.VisibleForTesting
@@ -35,6 +37,7 @@
 import com.android.systemui.qs.FooterActionsController.ExpansionState.COLLAPSED
 import com.android.systemui.qs.FooterActionsController.ExpansionState.EXPANDED
 import com.android.systemui.qs.dagger.QSFlagsModule.PM_LITE_ENABLED
+import com.android.systemui.settings.UserTracker
 import com.android.systemui.statusbar.phone.MultiUserSwitchController
 import com.android.systemui.statusbar.phone.SettingsButton
 import com.android.systemui.statusbar.policy.DeviceProvisionedController
@@ -42,6 +45,7 @@
 import com.android.systemui.statusbar.policy.UserInfoController.OnUserInfoChangedListener
 import com.android.systemui.tuner.TunerService
 import com.android.systemui.util.ViewController
+import com.android.systemui.util.settings.GlobalSettings
 import javax.inject.Inject
 import javax.inject.Named
 
@@ -55,6 +59,7 @@
     private val qsPanelController: QSPanelController,
     private val activityStarter: ActivityStarter,
     private val userManager: UserManager,
+    private val userTracker: UserTracker,
     private val userInfoController: UserInfoController,
     private val multiUserSwitchController: MultiUserSwitchController,
     private val deviceProvisionedController: DeviceProvisionedController,
@@ -64,7 +69,9 @@
     private val globalActionsDialog: GlobalActionsDialogLite,
     private val uiEventLogger: UiEventLogger,
     @Named(PM_LITE_ENABLED) private val showPMLiteButton: Boolean,
-    private val buttonsVisibleState: ExpansionState
+    private val buttonsVisibleState: ExpansionState,
+    private val globalSetting: GlobalSettings,
+    private val handler: Handler
 ) : ViewController<FooterActionsView>(view) {
 
     enum class ExpansionState { COLLAPSED, EXPANDED }
@@ -83,6 +90,16 @@
         mView.onUserInfoChanged(picture, isGuestUser)
     }
 
+    private val multiUserSetting =
+            object : SettingObserver(
+                    globalSetting, handler, USER_SWITCHER_ENABLED, userTracker.userId) {
+                override fun handleValueChanged(value: Int, observedChange: Boolean) {
+                    if (observedChange) {
+                        updateView()
+                    }
+                }
+            }
+
     private val onClickListener = View.OnClickListener { v ->
         // Don't do anything until views are unhidden. Don't do anything if the tap looks
         // suspicious.
@@ -182,6 +199,7 @@
             return
         }
         this.listening = listening
+        multiUserSetting.isListening = listening
         if (this.listening) {
             userInfoController.addCallback(onUserInfoChangedListener)
             updateView()
@@ -215,4 +233,4 @@
     }
 
     private fun isTunerEnabled() = tunerService.isTunerEnabled
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/FooterActionsControllerBuilder.kt b/packages/SystemUI/src/com/android/systemui/qs/FooterActionsControllerBuilder.kt
index f6c89a9..dd4dc87 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/FooterActionsControllerBuilder.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/FooterActionsControllerBuilder.kt
@@ -16,18 +16,22 @@
 
 package com.android.systemui.qs
 
+import android.os.Handler
 import android.os.UserManager
 import com.android.internal.logging.MetricsLogger
 import com.android.internal.logging.UiEventLogger
+import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.globalactions.GlobalActionsDialogLite
 import com.android.systemui.plugins.ActivityStarter
 import com.android.systemui.plugins.FalsingManager
 import com.android.systemui.qs.FooterActionsController.ExpansionState
 import com.android.systemui.qs.dagger.QSFlagsModule
+import com.android.systemui.settings.UserTracker
 import com.android.systemui.statusbar.phone.MultiUserSwitchController
 import com.android.systemui.statusbar.policy.DeviceProvisionedController
 import com.android.systemui.statusbar.policy.UserInfoController
 import com.android.systemui.tuner.TunerService
+import com.android.systemui.util.settings.GlobalSettings
 import javax.inject.Inject
 import javax.inject.Named
 
@@ -35,6 +39,7 @@
     private val qsPanelController: QSPanelController,
     private val activityStarter: ActivityStarter,
     private val userManager: UserManager,
+    private val userTracker: UserTracker,
     private val userInfoController: UserInfoController,
     private val multiUserSwitchControllerFactory: MultiUserSwitchController.Factory,
     private val deviceProvisionedController: DeviceProvisionedController,
@@ -43,7 +48,9 @@
     private val tunerService: TunerService,
     private val globalActionsDialog: GlobalActionsDialogLite,
     private val uiEventLogger: UiEventLogger,
-    @Named(QSFlagsModule.PM_LITE_ENABLED) private val showPMLiteButton: Boolean
+    @Named(QSFlagsModule.PM_LITE_ENABLED) private val showPMLiteButton: Boolean,
+    private val globalSettings: GlobalSettings,
+    @Main private val handler: Handler
 ) {
     private lateinit var view: FooterActionsView
     private lateinit var buttonsVisibleState: ExpansionState
@@ -60,8 +67,9 @@
 
     fun build(): FooterActionsController {
         return FooterActionsController(view, qsPanelController, activityStarter, userManager,
-                userInfoController, multiUserSwitchControllerFactory.create(view),
+                userTracker, userInfoController, multiUserSwitchControllerFactory.create(view),
                 deviceProvisionedController, falsingManager, metricsLogger, tunerService,
-                globalActionsDialog, uiEventLogger, showPMLiteButton, buttonsVisibleState)
+                globalActionsDialog, uiEventLogger, showPMLiteButton, buttonsVisibleState,
+                globalSettings, handler)
     }
 }
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/GlobalSetting.java b/packages/SystemUI/src/com/android/systemui/qs/GlobalSetting.java
deleted file mode 100644
index c169df0..0000000
--- a/packages/SystemUI/src/com/android/systemui/qs/GlobalSetting.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.qs;
-
-import android.content.Context;
-import android.database.ContentObserver;
-import android.os.Handler;
-import android.provider.Settings.Global;
-
-import com.android.systemui.statusbar.policy.Listenable;
-
-/** Helper for managing a global setting. **/
-public abstract class GlobalSetting extends ContentObserver implements Listenable {
-    private final Context mContext;
-    private final String mSettingName;
-
-    protected abstract void handleValueChanged(int value);
-
-    public GlobalSetting(Context context, Handler handler, String settingName) {
-        super(handler);
-        mContext = context;
-        mSettingName = settingName;
-    }
-
-    public int getValue() {
-        return Global.getInt(mContext.getContentResolver(), mSettingName, 0);
-    }
-
-    public void setValue(int value) {
-        Global.putInt(mContext.getContentResolver(), mSettingName, value);
-    }
-
-    @Override
-    public void setListening(boolean listening) {
-        if (listening) {
-            mContext.getContentResolver().registerContentObserver(
-                    Global.getUriFor(mSettingName), false, this);
-        } else {
-            mContext.getContentResolver().unregisterContentObserver(this);
-        }
-    }
-
-    @Override
-    public void onChange(boolean selfChange) {
-        handleValueChanged(getValue());
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PseudoGridView.java b/packages/SystemUI/src/com/android/systemui/qs/PseudoGridView.java
index 2f189be..768598a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PseudoGridView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PseudoGridView.java
@@ -133,10 +133,7 @@
                     x += width + mHorizontalSpacing;
                 }
             }
-            y += maxHeight;
-            if (row > 0) {
-                y += mVerticalSpacing;
-            }
+            y += maxHeight + mVerticalSpacing;
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 71eb4a2..d69deef 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -26,6 +26,7 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
+import android.util.ArrayMap;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.Gravity;
@@ -103,6 +104,8 @@
     protected LinearLayout mHorizontalContentContainer;
 
     protected QSTileLayout mTileLayout;
+    private float mSquishinessFraction = 1f;
+    private final ArrayMap<View, Integer> mChildrenLayoutTop = new ArrayMap<>();
 
     public QSPanel(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -179,10 +182,26 @@
         if (mTileLayout == null) {
             mTileLayout = (QSTileLayout) LayoutInflater.from(mContext)
                     .inflate(R.layout.qs_paged_tile_layout, this, false);
+            mTileLayout.setSquishinessFraction(mSquishinessFraction);
         }
         return mTileLayout;
     }
 
+    public void setSquishinessFraction(float squishinessFraction) {
+        if (Float.compare(squishinessFraction, mSquishinessFraction) == 0) {
+            return;
+        }
+        mSquishinessFraction = squishinessFraction;
+        if (mTileLayout == null) {
+            return;
+        }
+        mTileLayout.setSquishinessFraction(squishinessFraction);
+        if (getMeasuredWidth() == 0) {
+            return;
+        }
+        updateViewPositions();
+    }
+
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         if (mTileLayout instanceof PagedTileLayout) {
@@ -228,6 +247,39 @@
         setMeasuredDimension(getMeasuredWidth(), height);
     }
 
+    @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        super.onLayout(changed, l, t, r, b);
+        for (int i = 0; i < getChildCount(); i++) {
+            View child = getChildAt(i);
+            mChildrenLayoutTop.put(child, child.getTop());
+        }
+        updateViewPositions();
+    }
+
+    private void updateViewPositions() {
+        if (!(mTileLayout instanceof TileLayout)) {
+            return;
+        }
+        TileLayout layout = (TileLayout) mTileLayout;
+
+        // Adjust view positions based on tile squishing
+        int tileHeightOffset = layout.getTilesHeight() - layout.getHeight();
+
+        boolean move = false;
+        for (int i = 0; i < getChildCount(); i++) {
+            View child = getChildAt(i);
+            if (move) {
+                int top = mChildrenLayoutTop.get(child);
+                child.setLeftTopRightBottom(child.getLeft(), top + tileHeightOffset,
+                        child.getRight(), top + tileHeightOffset + child.getHeight());
+            }
+            if (child == mTileLayout) {
+                move = true;
+            }
+        }
+    }
+
     protected String getDumpableTag() {
         return TAG;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
index f7d1b1e..eddc206 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
@@ -147,6 +147,10 @@
         return mMediaHost;
     }
 
+    public void setSquishinessFraction(float squishinessFraction) {
+        mView.setSquishinessFraction(squishinessFraction);
+    }
+
     @Override
     protected void onViewAttached() {
         mQsTileRevealController = createTileRevealController();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSSquishinessController.kt b/packages/SystemUI/src/com/android/systemui/qs/QSSquishinessController.kt
index c1c146d..c680cb5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSSquishinessController.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSSquishinessController.kt
@@ -1,14 +1,10 @@
 package com.android.systemui.qs
 
-import android.view.ViewGroup
-import com.android.systemui.qs.dagger.QSFragmentModule.QQS_FOOTER
 import com.android.systemui.qs.dagger.QSScope
 import javax.inject.Inject
-import javax.inject.Named
 
 @QSScope
 class QSSquishinessController @Inject constructor(
-    @Named(QQS_FOOTER) private val qqsFooterActionsView: FooterActionsView,
     private val qsAnimator: QSAnimator,
     private val qsPanelController: QSPanelController,
     private val quickQSPanelController: QuickQSPanelController
@@ -33,23 +29,7 @@
      * Change the height of all tiles and repositions their siblings.
      */
     private fun updateSquishiness() {
-        (qsPanelController.tileLayout as QSPanel.QSTileLayout).setSquishinessFraction(squishiness)
-        val tileLayout = quickQSPanelController.tileLayout as TileLayout
-        tileLayout.setSquishinessFraction(squishiness)
-
-        // Calculate how much we should move the footer
-        val tileHeightOffset = tileLayout.height - tileLayout.tilesHeight
-        val footerTopMargin = (qqsFooterActionsView.layoutParams as ViewGroup.MarginLayoutParams)
-                .topMargin
-        val nextTop = tileLayout.bottom - tileHeightOffset + footerTopMargin
-        val amountMoved = nextTop - qqsFooterActionsView.top
-
-        // Move the footer and other siblings (MediaPlayer)
-        (qqsFooterActionsView.parent as ViewGroup?)?.let { parent ->
-            val index = parent.indexOfChild(qqsFooterActionsView)
-            for (i in index until parent.childCount) {
-                parent.getChildAt(i).top += amountMoved
-            }
-        }
+        qsPanelController.setSquishinessFraction(squishiness)
+        quickQSPanelController.setSquishinessFraction(squishiness)
     }
 }
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
index af191a1..c648e9b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
@@ -53,6 +53,7 @@
 import com.android.systemui.qs.logging.QSLogger;
 import com.android.systemui.settings.UserTracker;
 import com.android.systemui.shared.plugins.PluginManager;
+import com.android.systemui.statusbar.connectivity.StatusBarFlags;
 import com.android.systemui.statusbar.phone.AutoTileManager;
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
@@ -110,6 +111,7 @@
     private SecureSettings mSecureSettings;
 
     private final TileServiceRequestController mTileServiceRequestController;
+    private final StatusBarFlags mStatusBarFlags;
 
     @Inject
     public QSTileHost(Context context,
@@ -129,7 +131,8 @@
             SecureSettings secureSettings,
             CustomTileStatePersister customTileStatePersister,
             TileServiceRequestController.Builder tileServiceRequestControllerBuilder,
-            FeatureFlags featureFlags
+            FeatureFlags featureFlags,
+            StatusBarFlags statusBarFlags
     ) {
         mIconController = iconController;
         mContext = context;
@@ -141,6 +144,7 @@
         mUiEventLogger = uiEventLogger;
         mBroadcastDispatcher = broadcastDispatcher;
         mTileServiceRequestController = tileServiceRequestControllerBuilder.create(this);
+        mStatusBarFlags = statusBarFlags;
 
         mInstanceIdSequence = new InstanceIdSequence(MAX_QS_INSTANCE_ID);
         mServices = new TileServices(this, bgLooper, mBroadcastDispatcher, userTracker);
@@ -276,7 +280,7 @@
         if (newValue == null && UserManager.isDeviceInDemoMode(mContext)) {
             newValue = mContext.getResources().getString(R.string.quick_settings_tiles_retail_mode);
         }
-        final List<String> tileSpecs = loadTileSpecs(mContext, newValue, mFeatureFlags);
+        final List<String> tileSpecs = loadTileSpecs(mContext, newValue, mStatusBarFlags);
         int currentUser = mUserTracker.getUserId();
         if (currentUser != mCurrentUser) {
             mUserContext = mUserTracker.getUserContext();
@@ -345,7 +349,7 @@
         if (newTiles.isEmpty() && !tileSpecs.isEmpty()) {
             // If we didn't manage to create any tiles, set it to empty (default)
             Log.d(TAG, "No valid tiles on tuning changed. Setting to default.");
-            changeTiles(currentSpecs, loadTileSpecs(mContext, "", mFeatureFlags));
+            changeTiles(currentSpecs, loadTileSpecs(mContext, "", mStatusBarFlags));
         } else {
             for (int i = 0; i < mCallbacks.size(); i++) {
                 mCallbacks.get(i).onTilesChanged();
@@ -413,7 +417,7 @@
 
     private void changeTileSpecs(Predicate<List<String>> changeFunction) {
         final String setting = mSecureSettings.getStringForUser(TILES_SETTING, mCurrentUser);
-        final List<String> tileSpecs = loadTileSpecs(mContext, setting, mFeatureFlags);
+        final List<String> tileSpecs = loadTileSpecs(mContext, setting, mStatusBarFlags);
         if (changeFunction.test(tileSpecs)) {
             saveTilesToSettings(tileSpecs);
         }
@@ -503,7 +507,7 @@
     }
 
     protected static List<String> loadTileSpecs(
-            Context context, String tileList, FeatureFlags featureFlags) {
+            Context context, String tileList, StatusBarFlags statusBarFlags) {
         final Resources res = context.getResources();
 
         if (TextUtils.isEmpty(tileList)) {
@@ -536,7 +540,7 @@
                 }
             }
         }
-        if (featureFlags.isProviderModelSettingEnabled(context)) {
+        if (statusBarFlags.isProviderModelSettingEnabled()) {
             if (!tiles.contains("internet")) {
                 if (tiles.contains("wifi")) {
                     // Replace the WiFi with Internet, and remove the Cell
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
index 6a57e45..67fdf86 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
@@ -30,6 +30,7 @@
 import com.android.systemui.demomode.DemoMode;
 import com.android.systemui.demomode.DemoModeController;
 import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.privacy.OngoingPrivacyChip;
 import com.android.systemui.privacy.PrivacyChipEvent;
@@ -218,7 +219,7 @@
 
         List<String> rssiIgnoredSlots;
 
-        if (mFeatureFlags.isCombinedStatusBarSignalIconsEnabled()) {
+        if (mFeatureFlags.isEnabled(Flags.COMBINED_STATUS_BAR_SIGNAL_ICONS)) {
             rssiIgnoredSlots = List.of(
                     getResources().getString(com.android.internal.R.string.status_bar_no_calling),
                     getResources().getString(com.android.internal.R.string.status_bar_call_strength)
@@ -230,7 +231,7 @@
         }
 
         mView.onAttach(mIconManager, mQSExpansionPathInterpolator, rssiIgnoredSlots,
-                mInsetsProvider, mFeatureFlags.useCombinedQSHeaders());
+                mInsetsProvider, mFeatureFlags.isEnabled(Flags.COMBINED_QS_HEADERS));
 
         mDemoModeController.addCallback(mDemoModeReceiver);
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/SecureSetting.java b/packages/SystemUI/src/com/android/systemui/qs/SettingObserver.java
similarity index 63%
rename from packages/SystemUI/src/com/android/systemui/qs/SecureSetting.java
rename to packages/SystemUI/src/com/android/systemui/qs/SettingObserver.java
index d2bc38e..6b0abd4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/SecureSetting.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/SettingObserver.java
@@ -21,11 +21,18 @@
 import android.os.Handler;
 
 import com.android.systemui.statusbar.policy.Listenable;
+import com.android.systemui.util.settings.GlobalSettings;
 import com.android.systemui.util.settings.SecureSettings;
+import com.android.systemui.util.settings.SettingsProxy;
+import com.android.systemui.util.settings.SystemSettings;
 
-/** Helper for managing a secure setting. **/
-public abstract class SecureSetting extends ContentObserver implements Listenable {
-    private final SecureSettings mSecureSettings;
+/**
+ * Helper for managing secure, global, and system settings through use of {@link SettingsProxy},
+ * which is the common superclass of {@link SecureSettings}, {@link GlobalSettings}, and
+ * {@link SystemSettings}.
+ */
+public abstract class SettingObserver extends ContentObserver implements Listenable {
+    private final SettingsProxy mSettingsProxy;
     private final String mSettingName;
     private final int mDefaultValue;
 
@@ -35,19 +42,19 @@
 
     protected abstract void handleValueChanged(int value, boolean observedChange);
 
-    public SecureSetting(SecureSettings secureSettings, Handler handler, String settingName,
+    public SettingObserver(SettingsProxy settingsProxy, Handler handler, String settingName,
             int userId) {
-        this(secureSettings, handler, settingName, userId, 0);
+        this(settingsProxy, handler, settingName, userId, 0);
     }
 
-    public SecureSetting(SecureSettings secureSetting, Handler handler, String settingName) {
-        this(secureSetting, handler, settingName, ActivityManager.getCurrentUser());
+    public SettingObserver(SettingsProxy settingsProxy, Handler handler, String settingName) {
+        this(settingsProxy, handler, settingName, ActivityManager.getCurrentUser());
     }
 
-    public SecureSetting(SecureSettings secureSettings, Handler handler, String settingName,
+    public SettingObserver(SettingsProxy settingsProxy, Handler handler, String settingName,
             int userId, int defaultValue) {
         super(handler);
-        mSecureSettings = secureSettings;
+        mSettingsProxy = settingsProxy;
         mSettingName = settingName;
         mObservedValue = mDefaultValue = defaultValue;
         mUserId = userId;
@@ -57,12 +64,17 @@
         return mListening ? mObservedValue : getValueFromProvider();
     }
 
+    /**
+     * Set the value of the observed setting.
+     *
+     * @param value The new value for the setting.
+     */
     public void setValue(int value) {
-        mSecureSettings.putIntForUser(mSettingName, value, mUserId);
+        mSettingsProxy.putIntForUser(mSettingName, value, mUserId);
     }
 
     private int getValueFromProvider() {
-        return mSecureSettings.getIntForUser(mSettingName, mDefaultValue, mUserId);
+        return mSettingsProxy.getIntForUser(mSettingName, mDefaultValue, mUserId);
     }
 
     @Override
@@ -71,10 +83,10 @@
         mListening = listening;
         if (listening) {
             mObservedValue = getValueFromProvider();
-            mSecureSettings.registerContentObserverForUser(
-                    mSecureSettings.getUriFor(mSettingName), false, this, mUserId);
+            mSettingsProxy.registerContentObserverForUser(
+                    mSettingsProxy.getUriFor(mSettingName), false, this, mUserId);
         } else {
-            mSecureSettings.unregisterContentObserver(this);
+            mSettingsProxy.unregisterContentObserver(this);
             mObservedValue = mDefaultValue;
         }
     }
@@ -87,6 +99,9 @@
         handleValueChanged(value, changed);
     }
 
+    /**
+     * Set user handle for which to observe the setting.
+     */
     public void setUserId(int userId) {
         mUserId = userId;
         if (mListening) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java b/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java
index 141c246..4b705ad 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java
@@ -42,6 +42,7 @@
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.statusbar.connectivity.IconState;
 import com.android.systemui.statusbar.connectivity.MobileDataIndicators;
@@ -219,7 +220,7 @@
             CarrierConfigTracker carrierConfigTracker, FeatureFlags featureFlags,
             SlotIndexResolver slotIndexResolver) {
 
-        if (featureFlags.isCombinedStatusBarSignalIconsEnabled()) {
+        if (featureFlags.isEnabled(Flags.COMBINED_STATUS_BAR_SIGNAL_ICONS)) {
             mProviderModel = true;
         } else {
             mProviderModel = false;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
index eef3b45..7e410d0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
@@ -34,7 +34,6 @@
 import com.android.systemui.R;
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.plugins.qs.QSTile;
 import com.android.systemui.plugins.qs.QSTile.State;
 import com.android.systemui.qs.QSTileHost;
@@ -42,6 +41,7 @@
 import com.android.systemui.qs.external.CustomTile;
 import com.android.systemui.qs.tileimpl.QSTileImpl.DrawableIcon;
 import com.android.systemui.settings.UserTracker;
+import com.android.systemui.statusbar.connectivity.StatusBarFlags;
 import com.android.systemui.util.leak.GarbageMonitor;
 
 import java.util.ArrayList;
@@ -63,7 +63,7 @@
     private final Executor mBgExecutor;
     private final Context mContext;
     private final UserTracker mUserTracker;
-    private final FeatureFlags mFeatureFlags;
+    private final StatusBarFlags mStatusBarFlags;
     private TileStateListener mListener;
 
     private boolean mFinished;
@@ -74,13 +74,13 @@
             UserTracker userTracker,
             @Main Executor mainExecutor,
             @Background Executor bgExecutor,
-            FeatureFlags featureFlags
+            StatusBarFlags statusBarFlags
     ) {
         mContext = context;
         mMainExecutor = mainExecutor;
         mBgExecutor = bgExecutor;
         mUserTracker = userTracker;
-        mFeatureFlags = featureFlags;
+        mStatusBarFlags = statusBarFlags;
     }
 
     public void setListener(TileStateListener listener) {
@@ -121,7 +121,7 @@
         }
 
         final ArrayList<QSTile> tilesToAdd = new ArrayList<>();
-        if (mFeatureFlags.isProviderModelSettingEnabled(mContext)) {
+        if (mStatusBarFlags.isProviderModelSettingEnabled()) {
             possibleTiles.remove("cell");
             possibleTiles.remove("wifi");
         }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFlagsModule.java b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFlagsModule.java
index 103ac65..a1b617f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFlagsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFlagsModule.java
@@ -21,6 +21,7 @@
 
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
 import com.android.systemui.util.settings.GlobalSettings;
 
 import javax.inject.Named;
@@ -48,7 +49,7 @@
     @SysUISingleton
     @Named(PM_LITE_ENABLED)
     static boolean isPMLiteEnabled(FeatureFlags featureFlags, GlobalSettings globalSettings) {
-        return featureFlags.isPMLiteEnabled()
+        return featureFlags.isEnabled(Flags.POWER_MENU_LITE)
                 && globalSettings.getInt(PM_LITE_SETTING, PM_LITE_SETTING_DEFAULT) != 0;
     }
 }
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 3e850ab..16be998 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
@@ -43,6 +43,7 @@
 import com.android.systemui.qs.tiles.MicrophoneToggleTile;
 import com.android.systemui.qs.tiles.NfcTile;
 import com.android.systemui.qs.tiles.NightDisplayTile;
+import com.android.systemui.qs.tiles.OneHandedModeTile;
 import com.android.systemui.qs.tiles.QRCodeScannerTile;
 import com.android.systemui.qs.tiles.QuickAccessWalletTile;
 import com.android.systemui.qs.tiles.ReduceBrightColorsTile;
@@ -92,6 +93,7 @@
     private final Provider<AlarmTile> mAlarmTileProvider;
     private final Provider<QuickAccessWalletTile> mQuickAccessWalletTileProvider;
     private final Provider<QRCodeScannerTile> mQRCodeScannerTileProvider;
+    private final Provider<OneHandedModeTile> mOneHandedModeTileProvider;
 
     private final Lazy<QSHost> mQsHostLazy;
     private final Provider<CustomTile.Builder> mCustomTileBuilderProvider;
@@ -127,7 +129,8 @@
             Provider<DeviceControlsTile> deviceControlsTileProvider,
             Provider<AlarmTile> alarmTileProvider,
             Provider<QuickAccessWalletTile> quickAccessWalletTileProvider,
-            Provider<QRCodeScannerTile> qrCodeScannerTileProvider) {
+            Provider<QRCodeScannerTile> qrCodeScannerTileProvider,
+            Provider<OneHandedModeTile> oneHandedModeTileProvider) {
         mQsHostLazy = qsHostLazy;
         mCustomTileBuilderProvider = customTileBuilderProvider;
 
@@ -159,6 +162,7 @@
         mAlarmTileProvider = alarmTileProvider;
         mQuickAccessWalletTileProvider = quickAccessWalletTileProvider;
         mQRCodeScannerTileProvider = qrCodeScannerTileProvider;
+        mOneHandedModeTileProvider = oneHandedModeTileProvider;
     }
 
     public QSTile createTile(String tileSpec) {
@@ -227,6 +231,8 @@
                 return mQuickAccessWalletTileProvider.get();
             case "qr_code_scanner":
                 return mQRCodeScannerTileProvider.get();
+            case "onehanded":
+                return mOneHandedModeTileProvider.get();
         }
 
         // Custom tiles
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
index 25ed2e7..09fad30 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
@@ -247,7 +247,10 @@
         } else {
             measuredHeight
         }
-        bottom = top + (actualHeight * squishinessFraction).toInt()
+        // Limit how much we affect the height, so we don't have rounding artifacts when the tile
+        // is too short.
+        val constrainedSquishiness = 0.1f + squishinessFraction * 0.9f
+        bottom = top + (actualHeight * constrainedSquishiness).toInt()
         scrollY = (actualHeight - height) / 2
     }
 
@@ -648,7 +651,8 @@
         "controls" to R.array.tile_states_controls,
         "wallet" to R.array.tile_states_wallet,
         "qr_code_scanner" to R.array.tile_states_qr_code_scanner,
-        "alarm" to R.array.tile_states_alarm
+        "alarm" to R.array.tile_states_alarm,
+        "onehanded" to R.array.tile_states_onehanded
     )
 
     fun getSubtitleId(spec: String?): Int {
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 22cd6f8..5650a17 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
@@ -44,10 +44,11 @@
 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;
 import com.android.systemui.qs.QSHost;
+import com.android.systemui.qs.SettingObserver;
 import com.android.systemui.qs.logging.QSLogger;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
+import com.android.systemui.util.settings.GlobalSettings;
 
 import javax.inject.Inject;
 
@@ -56,7 +57,7 @@
 /** Quick settings tile: Airplane mode **/
 public class AirplaneModeTile extends QSTileImpl<BooleanState> {
     private final Icon mIcon = ResourceIcon.get(com.android.internal.R.drawable.ic_qs_airplane);
-    private final GlobalSetting mSetting;
+    private final SettingObserver mSetting;
     private final BroadcastDispatcher mBroadcastDispatcher;
     private final Lazy<ConnectivityManager> mLazyConnectivityManager;
 
@@ -73,16 +74,17 @@
             ActivityStarter activityStarter,
             QSLogger qsLogger,
             BroadcastDispatcher broadcastDispatcher,
-            Lazy<ConnectivityManager> lazyConnectivityManager
+            Lazy<ConnectivityManager> lazyConnectivityManager,
+            GlobalSettings globalSettings
     ) {
         super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
                 statusBarStateController, activityStarter, qsLogger);
         mBroadcastDispatcher = broadcastDispatcher;
         mLazyConnectivityManager = lazyConnectivityManager;
 
-        mSetting = new GlobalSetting(mContext, mHandler, Global.AIRPLANE_MODE_ON) {
+        mSetting = new SettingObserver(globalSettings, mHandler, Global.AIRPLANE_MODE_ON) {
             @Override
-            protected void handleValueChanged(int value) {
+            protected void handleValueChanged(int value, boolean observedChange) {
                 // mHandler is the background handler so calling this is OK
                 handleRefreshState(value);
             }
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 e3024fa..b8ef312 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java
@@ -36,7 +36,7 @@
 import com.android.systemui.plugins.qs.QSTile.BooleanState;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.QSHost;
-import com.android.systemui.qs.SecureSetting;
+import com.android.systemui.qs.SettingObserver;
 import com.android.systemui.qs.logging.QSLogger;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
 import com.android.systemui.statusbar.policy.BatteryController;
@@ -49,7 +49,7 @@
 
     private final BatteryController mBatteryController;
     @VisibleForTesting
-    protected final SecureSetting mSetting;
+    protected final SettingObserver mSetting;
 
     private int mLevel;
     private boolean mPowerSave;
@@ -76,7 +76,7 @@
         mBatteryController = batteryController;
         mBatteryController.observe(getLifecycle(), this);
         int currentUser = host.getUserContext().getUserId();
-        mSetting = new SecureSetting(
+        mSetting = new SettingObserver(
                 secureSettings,
                 mHandler,
                 Secure.LOW_POWER_WARNING_ACKNOWLEDGED,
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 5e502cc..d2d2180 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
@@ -17,7 +17,6 @@
 package com.android.systemui.qs.tiles;
 
 import android.content.Intent;
-import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
 import android.provider.Settings;
@@ -39,7 +38,7 @@
 import com.android.systemui.plugins.qs.QSTile.BooleanState;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.QSHost;
-import com.android.systemui.qs.SecureSetting;
+import com.android.systemui.qs.SettingObserver;
 import com.android.systemui.qs.logging.QSLogger;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
 import com.android.systemui.settings.UserTracker;
@@ -55,7 +54,7 @@
     private static final String COLOR_INVERSION_PREFERENCE_KEY = "toggle_inversion_preference";
 
     private final Icon mIcon = ResourceIcon.get(drawable.ic_invert_colors);
-    private final SecureSetting mSetting;
+    private final SettingObserver mSetting;
 
     private boolean mListening;
 
@@ -75,7 +74,7 @@
         super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
                 statusBarStateController, activityStarter, qsLogger);
 
-        mSetting = new SecureSetting(secureSettings, mHandler,
+        mSetting = new SettingObserver(secureSettings, mHandler,
                 Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, userTracker.getUserId()) {
             @Override
             protected void handleValueChanged(int value, boolean observedChange) {
@@ -110,11 +109,7 @@
 
     @Override
     public Intent getLongClickIntent() {
-        Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS);
-        Bundle bundle = new Bundle();
-        bundle.putString(EXTRA_FRAGMENT_ARGS_KEY, COLOR_INVERSION_PREFERENCE_KEY);
-        intent.putExtra(EXTRA_SHOW_FRAGMENT_ARGS_KEY, bundle);
-        return intent;
+        return new Intent(Settings.ACTION_COLOR_INVERSION_SETTINGS);
     }
 
     @Override
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 b1cd68e..18b401f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@@ -19,6 +19,7 @@
 import static android.provider.Settings.Global.ZEN_MODE_ALARMS;
 import static android.provider.Settings.Global.ZEN_MODE_OFF;
 
+import android.app.AlertDialog;
 import android.app.Dialog;
 import android.content.Context;
 import android.content.Intent;
@@ -41,7 +42,6 @@
 import android.view.View;
 import android.view.View.OnAttachStateChangeListener;
 import android.view.ViewGroup;
-import android.view.WindowManager;
 import android.widget.Switch;
 import android.widget.Toast;
 
@@ -53,6 +53,7 @@
 import com.android.systemui.Prefs;
 import com.android.systemui.R;
 import com.android.systemui.SysUIToast;
+import com.android.systemui.animation.DialogLaunchAnimator;
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.ActivityStarter;
@@ -61,7 +62,7 @@
 import com.android.systemui.plugins.qs.QSTile.BooleanState;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.QSHost;
-import com.android.systemui.qs.SecureSetting;
+import com.android.systemui.qs.SettingObserver;
 import com.android.systemui.qs.logging.QSLogger;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
 import com.android.systemui.statusbar.phone.SystemUIDialog;
@@ -83,7 +84,8 @@
     private final ZenModeController mController;
     private final DndDetailAdapter mDetailAdapter;
     private final SharedPreferences mSharedPreferences;
-    private final SecureSetting mSettingZenDuration;
+    private final SettingObserver mSettingZenDuration;
+    private final DialogLaunchAnimator mDialogLaunchAnimator;
 
     private boolean mListening;
     private boolean mShowingDetail;
@@ -100,7 +102,8 @@
             QSLogger qsLogger,
             ZenModeController zenModeController,
             @Main SharedPreferences sharedPreferences,
-            SecureSettings secureSettings
+            SecureSettings secureSettings,
+            DialogLaunchAnimator dialogLaunchAnimator
     ) {
         super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
                 statusBarStateController, activityStarter, qsLogger);
@@ -108,7 +111,8 @@
         mSharedPreferences = sharedPreferences;
         mDetailAdapter = new DndDetailAdapter();
         mController.observe(getLifecycle(), mZenCallback);
-        mSettingZenDuration = new SecureSetting(secureSettings, mUiHandler,
+        mDialogLaunchAnimator = dialogLaunchAnimator;
+        mSettingZenDuration = new SettingObserver(secureSettings, mUiHandler,
                 Settings.Secure.ZEN_DURATION, getHost().getUserId()) {
             @Override
             protected void handleValueChanged(int value, boolean observedChange) {
@@ -117,8 +121,6 @@
         };
     }
 
-
-
     public static void setVisible(Context context, boolean visible) {
         Prefs.putBoolean(context, Prefs.Key.DND_TILE_VISIBLE, visible);
     }
@@ -187,14 +189,17 @@
             switch (zenDuration) {
                 case Settings.Secure.ZEN_DURATION_PROMPT:
                     mUiHandler.post(() -> {
-                        Dialog mDialog = new EnableZenModeDialog(mContext).createDialog();
-                        mDialog.getWindow().setType(
-                                WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
-                        SystemUIDialog.setShowForAllUsers(mDialog, true);
-                        SystemUIDialog.registerDismissListener(mDialog);
-                        SystemUIDialog.setWindowOnTop(mDialog);
-                        mUiHandler.post(() -> mDialog.show());
-                        mHost.collapsePanels();
+                        Dialog dialog = makeZenModeDialog();
+                        if (view != null) {
+                            final Dialog hostDialog =
+                                    mDialogLaunchAnimator.showFromView(dialog, view, false);
+                            setDialogListeners(dialog, hostDialog);
+                        } else {
+                            // If we are not launching with animator, register default
+                            // dismiss listener
+                            SystemUIDialog.registerDismissListener(dialog);
+                            dialog.show();
+                        }
                     });
                     break;
                 case Settings.Secure.ZEN_DURATION_FOREVER:
@@ -209,6 +214,20 @@
         }
     }
 
+    private Dialog makeZenModeDialog() {
+        AlertDialog dialog = new EnableZenModeDialog(mContext, R.style.Theme_SystemUI_Dialog)
+                .createDialog();
+        SystemUIDialog.applyFlags(dialog);
+        SystemUIDialog.setShowForAllUsers(dialog, true);
+        return dialog;
+    }
+
+    private void setDialogListeners(Dialog zenModeDialog, Dialog hostDialog) {
+        // Zen mode dialog is never hidden.
+        SystemUIDialog.registerDismissListener(zenModeDialog, hostDialog::dismiss);
+        zenModeDialog.setOnCancelListener(dialog -> hostDialog.cancel());
+    }
+
     @Override
     protected void handleSecondaryClick(@Nullable View view) {
         if (mController.isVolumeRestricted()) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/OneHandedModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/OneHandedModeTile.java
new file mode 100644
index 0000000..521dbe71
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/OneHandedModeTile.java
@@ -0,0 +1,150 @@
+/*
+ * 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.qs.tiles;
+
+import android.content.Intent;
+import android.os.Handler;
+import android.os.Looper;
+import android.provider.Settings;
+import android.service.quicksettings.Tile;
+import android.view.View;
+import android.widget.Switch;
+
+import androidx.annotation.Nullable;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.logging.MetricsLogger;
+import com.android.systemui.R;
+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;
+import com.android.systemui.qs.SettingObserver;
+import com.android.systemui.qs.logging.QSLogger;
+import com.android.systemui.qs.tileimpl.QSTileImpl;
+import com.android.systemui.settings.UserTracker;
+import com.android.systemui.util.settings.SecureSettings;
+import com.android.wm.shell.onehanded.OneHanded;
+
+import javax.inject.Inject;
+
+/** Quick settings tile: One-handed mode **/
+public class OneHandedModeTile extends QSTileImpl<BooleanState> {
+    private final Icon mIcon = ResourceIcon.get(
+            com.android.internal.R.drawable.ic_qs_one_handed_mode);
+    private final SettingObserver mSetting;
+
+    @Inject
+    public OneHandedModeTile(
+            QSHost host,
+            @Background Looper backgroundLooper,
+            @Main Handler mainHandler,
+            FalsingManager falsingManager,
+            MetricsLogger metricsLogger,
+            StatusBarStateController statusBarStateController,
+            ActivityStarter activityStarter,
+            QSLogger qsLogger,
+            UserTracker userTracker,
+            SecureSettings secureSettings) {
+        super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
+                statusBarStateController, activityStarter, qsLogger);
+        mSetting = new SettingObserver(secureSettings, mHandler,
+                Settings.Secure.ONE_HANDED_MODE_ENABLED, userTracker.getUserId()) {
+            @Override
+            protected void handleValueChanged(int value, boolean observedChange) {
+                // mHandler is the background handler so calling this is OK
+                handleRefreshState(value);
+            }
+        };
+    }
+
+    @Override
+    public boolean isAvailable() {
+        return isSupportOneHandedMode();
+    }
+
+    @Override
+    protected void handleDestroy() {
+        super.handleDestroy();
+        mSetting.setListening(false);
+    }
+
+    @Override
+    public BooleanState newTileState() {
+        return new BooleanState();
+    }
+
+    @Override
+    public void handleSetListening(boolean listening) {
+        super.handleSetListening(listening);
+        mSetting.setListening(listening);
+    }
+
+    @Override
+    protected void handleUserSwitch(int newUserId) {
+        mSetting.setUserId(newUserId);
+        handleRefreshState(mSetting.getValue());
+    }
+
+    @Override
+    public Intent getLongClickIntent() {
+        // TODO(b/201743873) define new intent action ACTION_ONE_HANDED_SETTINGS in Settings.
+        return null;
+    }
+
+    @Override
+    protected void handleClick(@Nullable View view) {
+        mSetting.setValue(mState.value ? 0 : 1);
+    }
+
+    @Override
+    public CharSequence getTileLabel() {
+        return mContext.getString(R.string.quick_settings_onehanded_label);
+    }
+
+    @Override
+    protected void handleUpdateState(BooleanState state, Object arg) {
+        final int value = arg instanceof Integer ? (Integer) arg : mSetting.getValue();
+        final boolean enabled = value != 0;
+        state.value = enabled;
+        state.label = mContext.getString(R.string.quick_settings_onehanded_label);
+        state.icon = mIcon;
+        if (state.slash == null) {
+            state.slash = new SlashState();
+        }
+        state.slash.isSlashed = !state.value;
+        state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
+        state.contentDescription = state.label;
+        state.expandedAccessibilityClassName = Switch.class.getName();
+    }
+
+    @Override
+    public int getMetricsCategory() {
+        // MetricsProto/MetricsEvent is deprecated, and QSTileImpl has code to log events to Tron,
+        // as well as UiEventLogger, so just simply return 0 here.
+        return 0;
+    }
+
+    @VisibleForTesting
+    public boolean isSupportOneHandedMode() {
+        return OneHanded.sIsSupportOneHandedMode;
+    }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
index b718ebf..f793a50 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
@@ -29,6 +29,8 @@
 import android.view.View;
 import android.view.ViewGroup;
 
+import androidx.annotation.Nullable;
+
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.UiEventLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -38,10 +40,10 @@
 import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.qs.PseudoGridView;
 import com.android.systemui.qs.QSUserSwitcherEvent;
+import com.android.systemui.qs.user.UserSwitchDialogController;
+import com.android.systemui.statusbar.phone.SystemUIDialog;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
 
-import java.util.function.Consumer;
-
 import javax.inject.Inject;
 
 /**
@@ -78,7 +80,7 @@
         private View mCurrentUserView;
         private final UiEventLogger mUiEventLogger;
         private final FalsingManager mFalsingManager;
-        private Consumer<UserSwitcherController.UserRecord> mClickCallback;
+        private @Nullable UserSwitchDialogController.DialogShower mDialogShower;
 
         @Inject
         public Adapter(Context context, UserSwitcherController controller,
@@ -96,8 +98,17 @@
             return createUserDetailItemView(convertView, parent, item);
         }
 
-        public void injectCallback(Consumer<UserSwitcherController.UserRecord> clickCallback) {
-            mClickCallback = clickCallback;
+        /**
+         * If this adapter is inside a dialog, passing a
+         * {@link UserSwitchDialogController.DialogShower} will help animate to and from the parent
+         * dialog. This will also allow for dismissing the whole stack of dialogs in a single
+         * animation.
+         *
+         * @param shower
+         * @see SystemUIDialog#dismissStack()
+         */
+        public void injectDialogShower(UserSwitchDialogController.DialogShower shower) {
+            mDialogShower = shower;
         }
 
         public UserDetailItemView createUserDetailItemView(View convertView, ViewGroup parent,
@@ -174,12 +185,9 @@
                     }
                     view.setActivated(true);
                 }
-                onUserListItemClicked(tag);
+                onUserListItemClicked(tag, mDialogShower);
             }
             Trace.endSection();
-            if (mClickCallback != null) {
-                mClickCallback.accept(tag);
-            }
         }
 
         public void linkToViewGroup(ViewGroup viewGroup) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
index 77b9cc1..883552a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
@@ -56,6 +56,7 @@
 
 import com.android.internal.logging.UiEvent;
 import com.android.internal.logging.UiEventLogger;
+import com.android.settingslib.Utils;
 import com.android.systemui.Prefs;
 import com.android.systemui.R;
 import com.android.systemui.accessibility.floatingmenu.AnnotationLinkSpan;
@@ -120,6 +121,7 @@
     private TextView mMobileTitleText;
     private TextView mMobileSummaryText;
     private Switch mMobileDataToggle;
+    private View mMobileToggleDivider;
     private Switch mWiFiToggle;
     private FrameLayout mDoneLayout;
     private Drawable mBackgroundOn;
@@ -207,6 +209,7 @@
         mSignalIcon = mDialogView.requireViewById(R.id.signal_icon);
         mMobileTitleText = mDialogView.requireViewById(R.id.mobile_title);
         mMobileSummaryText = mDialogView.requireViewById(R.id.mobile_summary);
+        mMobileToggleDivider = mDialogView.requireViewById(R.id.mobile_toggle_divider);
         mMobileDataToggle = mDialogView.requireViewById(R.id.mobile_toggle);
         mWiFiToggle = mDialogView.requireViewById(R.id.wifi_toggle);
         mBackgroundOn = mContext.getDrawable(R.drawable.settingslib_switch_bar_bg_on);
@@ -378,6 +381,14 @@
             mMobileNetworkLayout.setBackground(
                     isCarrierNetworkConnected ? mBackgroundOn : mBackgroundOff);
 
+            TypedArray array = mContext.obtainStyledAttributes(
+                    R.style.InternetDialog_Divider_Active, new int[]{android.R.attr.background});
+            int dividerColor = Utils.getColorAttrDefaultColor(mContext,
+                    android.R.attr.textColorSecondary);
+            mMobileToggleDivider.setBackgroundColor(isCarrierNetworkConnected
+                    ? array.getColor(0, dividerColor) : dividerColor);
+            array.recycle();
+
             mMobileDataToggle.setVisibility(mCanConfigMobileData ? View.VISIBLE : View.INVISIBLE);
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
index 1c8bd78..2a7d2c3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
@@ -1077,6 +1077,9 @@
         params.width = WindowManager.LayoutParams.WRAP_CONTENT;
         params.format = PixelFormat.TRANSLUCENT;
         params.type = WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL;
+        params.flags = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
+                | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+                | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
         params.y = systemUIToast.getYOffset();
 
         int absGravity = Gravity.getAbsoluteGravity(systemUIToast.getGravity(),
diff --git a/packages/SystemUI/src/com/android/systemui/qs/user/UserDialog.kt b/packages/SystemUI/src/com/android/systemui/qs/user/UserDialog.kt
deleted file mode 100644
index 26d1bbd..0000000
--- a/packages/SystemUI/src/com/android/systemui/qs/user/UserDialog.kt
+++ /dev/null
@@ -1,82 +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.qs.user
-
-import android.content.Context
-import android.os.Bundle
-import android.view.Gravity
-import android.view.View
-import android.view.ViewGroup
-import android.view.WindowInsets
-import android.view.WindowManager
-import com.android.systemui.qs.PseudoGridView
-import com.android.systemui.statusbar.phone.SystemUIDialog
-import com.android.systemui.R
-
-/**
- * Dialog for switching users or creating new ones.
- */
-class UserDialog(
-    context: Context
-) : SystemUIDialog(context) {
-
-    // create() is no-op after creation
-    private lateinit var _doneButton: View
-    /**
-     * Button with text "Done" in dialog.
-     */
-    val doneButton: View
-        get() {
-            create()
-            return _doneButton
-        }
-
-    private lateinit var _settingsButton: View
-    /**
-     * Button with text "User Settings" in dialog.
-     */
-    val settingsButton: View
-        get() {
-            create()
-            return _settingsButton
-        }
-
-    private lateinit var _grid: PseudoGridView
-    /**
-     * Grid to populate with user avatar from adapter
-     */
-    val grid: ViewGroup
-        get() {
-            create()
-            return _grid
-        }
-
-    override fun onCreate(savedInstanceState: Bundle?) {
-        super.onCreate(savedInstanceState)
-        window?.apply {
-            setType(WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL)
-            attributes.fitInsetsTypes = attributes.fitInsetsTypes or WindowInsets.Type.statusBars()
-            attributes.receiveInsetsIgnoringZOrder = true
-            setGravity(Gravity.CENTER)
-        }
-        setContentView(R.layout.qs_user_dialog_content)
-
-        _doneButton = requireViewById(R.id.done)
-        _settingsButton = requireViewById(R.id.settings)
-        _grid = requireViewById(R.id.grid)
-    }
-}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/user/UserSwitchDialogController.kt b/packages/SystemUI/src/com/android/systemui/qs/user/UserSwitchDialogController.kt
index bae7996..00e0454 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/user/UserSwitchDialogController.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/user/UserSwitchDialogController.kt
@@ -16,16 +16,21 @@
 
 package com.android.systemui.qs.user
 
+import android.app.Dialog
 import android.content.Context
+import android.content.DialogInterface
 import android.content.Intent
 import android.provider.Settings
+import android.view.LayoutInflater
 import android.view.View
 import androidx.annotation.VisibleForTesting
+import com.android.systemui.R
 import com.android.systemui.animation.DialogLaunchAnimator
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.plugins.ActivityStarter
 import com.android.systemui.plugins.FalsingManager
 import com.android.systemui.qs.tiles.UserDetailView
+import com.android.systemui.statusbar.phone.SystemUIDialog
 import javax.inject.Inject
 import javax.inject.Provider
 
@@ -38,7 +43,7 @@
     private val activityStarter: ActivityStarter,
     private val falsingManager: FalsingManager,
     private val dialogLaunchAnimator: DialogLaunchAnimator,
-    private val dialogFactory: (Context) -> UserDialog
+    private val dialogFactory: (Context) -> SystemUIDialog
 ) {
 
     @Inject
@@ -52,7 +57,7 @@
         activityStarter,
         falsingManager,
         dialogLaunchAnimator,
-        { UserDialog(it) }
+        { SystemUIDialog(it) }
     )
 
     companion object {
@@ -69,9 +74,10 @@
         with(dialogFactory(view.context)) {
             setShowForAllUsers(true)
             setCanceledOnTouchOutside(true)
-            create() // Needs to be called before we can retrieve views
 
-            settingsButton.setOnClickListener {
+            setTitle(R.string.qs_user_switch_dialog_title)
+            setPositiveButton(R.string.quick_settings_done, null)
+            setNeutralButton(R.string.quick_settings_more_user_settings) { _, _ ->
                 if (!falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
                     dialogLaunchAnimator.disableAllCurrentDialogsExitAnimations()
                     activityStarter.postStartActivityDismissingKeyguard(
@@ -79,17 +85,33 @@
                         0
                     )
                 }
-                dismiss()
             }
-            doneButton.setOnClickListener { dismiss() }
+            val gridFrame = LayoutInflater.from(this.context)
+                .inflate(R.layout.qs_user_dialog_content, null)
+            setView(gridFrame)
 
             val adapter = userDetailViewAdapterProvider.get()
-            adapter.injectCallback {
-                dismiss()
-            }
-            adapter.linkToViewGroup(grid)
 
-            dialogLaunchAnimator.showFromView(this, view)
+            adapter.linkToViewGroup(gridFrame.findViewById(R.id.grid))
+
+            val hostDialog = dialogLaunchAnimator.showFromView(this, view)
+            adapter.injectDialogShower(DialogShowerImpl(hostDialog, dialogLaunchAnimator))
         }
     }
+
+    private class DialogShowerImpl(
+        private val hostDialog: Dialog,
+        private val dialogLaunchAnimator: DialogLaunchAnimator
+    ) : DialogInterface by hostDialog, DialogShower {
+        override fun showDialog(dialog: Dialog): Dialog {
+            return dialogLaunchAnimator.showFromDialog(
+                dialog,
+                parentHostDialog = hostDialog
+            )
+        }
+    }
+
+    interface DialogShower : DialogInterface {
+        fun showDialog(dialog: Dialog): Dialog
+    }
 }
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index fa874b1..3ed7e84 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -986,6 +986,18 @@
         }
     }
 
+    public void onNavButtonsDarkIntensityChanged(float darkIntensity) {
+        try {
+            if (mOverviewProxy != null) {
+                mOverviewProxy.onNavButtonsDarkIntensityChanged(darkIntensity);
+            } else {
+                Log.e(TAG_OPS, "Failed to get overview proxy to update nav buttons dark intensity");
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG_OPS, "Failed to call onNavButtonsDarkIntensityChanged()", e);
+        }
+    }
+
     private void updateEnabledState() {
         final int currentUser = ActivityManagerWrapper.getInstance().getCurrentUserId();
         mIsEnabled = mContext.getPackageManager().resolveServiceAsUser(mQuickStepIntent,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 75b3592..3cecbb7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -533,9 +533,13 @@
      * @param animate {@code true} to show animations.
      */
     public void recomputeDisableFlags(int displayId, boolean animate) {
-        int disabled1 = getDisabled1(displayId);
-        int disabled2 = getDisabled2(displayId);
-        disable(displayId, disabled1, disabled2, animate);
+        // This must update holding the lock otherwise it can clobber the disabled flags set on the
+        // binder thread from the disable() call
+        synchronized (mLock) {
+            int disabled1 = getDisabled1(displayId);
+            int disabled2 = getDisabled2(displayId);
+            disable(displayId, disabled1, disabled2, animate);
+        }
     }
 
     private void setDisabled(int displayId, int disabled1, int disabled2) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index ed36a27..190c773e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -138,6 +138,7 @@
 
     private boolean mPowerPluggedIn;
     private boolean mPowerPluggedInWired;
+    private boolean mPowerPluggedInWireless;
     private boolean mPowerCharged;
     private boolean mBatteryOverheated;
     private boolean mEnableBatteryDefender;
@@ -751,10 +752,14 @@
                             : R.string.keyguard_plugged_in;
                     break;
             }
-        } else {
+        } else if (mPowerPluggedInWireless) {
             chargingId = hasChargingTime
                     ? R.string.keyguard_indication_charging_time_wireless
                     : R.string.keyguard_plugged_in_wireless;
+        } else {
+            chargingId = hasChargingTime
+                    ? R.string.keyguard_indication_charging_time
+                    : R.string.keyguard_plugged_in;
         }
 
         String percentage = NumberFormat.getPercentInstance().format(mBatteryLevel / 100f);
@@ -866,6 +871,7 @@
                     || status.status == BatteryManager.BATTERY_STATUS_FULL;
             boolean wasPluggedIn = mPowerPluggedIn;
             mPowerPluggedInWired = status.isPluggedInWired() && isChargingOrFull;
+            mPowerPluggedInWireless = status.isPluggedInWireless() && isChargingOrFull;
             mPowerPluggedIn = status.isPluggedIn() && isChargingOrFull;
             mPowerCharged = status.isCharged();
             mChargingWattage = status.maxChargingWattage;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
index 3fbed64..efe02ad 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
@@ -51,12 +51,12 @@
 import com.android.systemui.colorextraction.SysuiColorExtractor;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dump.DumpManager;
-import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.media.MediaData;
 import com.android.systemui.media.MediaDataManager;
 import com.android.systemui.media.SmartspaceMediaData;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.dagger.StatusBarModule;
+import com.android.systemui.statusbar.notification.NotifPipelineFlags;
 import com.android.systemui.statusbar.notification.NotificationEntryListener;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotifCollection;
@@ -184,7 +184,7 @@
             KeyguardBypassController keyguardBypassController,
             NotifPipeline notifPipeline,
             NotifCollection notifCollection,
-            FeatureFlags featureFlags,
+            NotifPipelineFlags notifPipelineFlags,
             @Main DelayableExecutor mainExecutor,
             MediaDataManager mediaDataManager,
             DumpManager dumpManager) {
@@ -202,7 +202,7 @@
         mNotifPipeline = notifPipeline;
         mNotifCollection = notifCollection;
 
-        if (!featureFlags.isNewNotifPipelineRenderingEnabled()) {
+        if (!notifPipelineFlags.isNewPipelineEnabled()) {
             setupNEM();
             mUsingNotifPipeline = false;
         } else {
@@ -449,7 +449,8 @@
         NotificationEntry mediaNotification = null;
         MediaController controller = null;
         for (NotificationEntry entry : allNotifications) {
-            if (entry.isMediaNotification()) {
+            Notification notif = entry.getSbn().getNotification();
+            if (notif.isMediaNotification()) {
                 final MediaSession.Token token =
                         entry.getSbn().getNotification().extras.getParcelable(
                                 Notification.EXTRA_MEDIA_SESSION);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
index 022baf6..5635f65 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
@@ -53,9 +53,9 @@
 import com.android.systemui.R;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dump.DumpManager;
-import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.dagger.StatusBarDependenciesModule;
+import com.android.systemui.statusbar.notification.NotifPipelineFlags;
 import com.android.systemui.statusbar.notification.NotificationEntryListener;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -104,7 +104,7 @@
     private final Lazy<Optional<StatusBar>> mStatusBarOptionalLazy;
 
     protected final Context mContext;
-    protected final FeatureFlags mFeatureFlags;
+    protected final NotifPipelineFlags mNotifPipelineFlags;
     private final UserManager mUserManager;
     private final KeyguardManager mKeyguardManager;
     private final RemoteInputNotificationRebuilder mRebuilder;
@@ -255,7 +255,7 @@
      */
     public NotificationRemoteInputManager(
             Context context,
-            FeatureFlags featureFlags,
+            NotifPipelineFlags notifPipelineFlags,
             NotificationLockscreenUserManager lockscreenUserManager,
             SmartReplyController smartReplyController,
             NotificationVisibilityProvider visibilityProvider,
@@ -269,7 +269,7 @@
             ActionClickLogger logger,
             DumpManager dumpManager) {
         mContext = context;
-        mFeatureFlags = featureFlags;
+        mNotifPipelineFlags = notifPipelineFlags;
         mLockscreenUserManager = lockscreenUserManager;
         mSmartReplyController = smartReplyController;
         mVisibilityProvider = visibilityProvider;
@@ -281,7 +281,7 @@
                 ServiceManager.getService(Context.STATUS_BAR_SERVICE));
         mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
         mRebuilder = rebuilder;
-        if (!featureFlags.isNewNotifPipelineRenderingEnabled()) {
+        if (!mNotifPipelineFlags.isNewPipelineEnabled()) {
             mRemoteInputListener = createLegacyRemoteInputLifetimeExtender(mainHandler,
                     notificationEntryManager, smartReplyController);
         }
@@ -318,7 +318,7 @@
 
     /** Add a listener for various remote input events.  Works with NEW pipeline only. */
     public void setRemoteInputListener(@NonNull RemoteInputListener remoteInputListener) {
-        if (mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
+        if (mNotifPipelineFlags.isNewPipelineEnabled()) {
             if (mRemoteInputListener != null) {
                 throw new IllegalStateException("mRemoteInputListener is already set");
             }
@@ -376,7 +376,7 @@
                 }
             }
         });
-        if (!mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
+        if (!mNotifPipelineFlags.isNewPipelineEnabled()) {
             mSmartReplyController.setCallback((entry, reply) -> {
                 StatusBarNotification newSbn = mRebuilder.rebuildForSendingSmartReply(entry, reply);
                 mEntryManager.updateNotification(newSbn, null /* ranking */);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
index 18c8b7f..ecde001 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
@@ -150,7 +150,7 @@
             NotificationListContainer listContainer) {
         mPresenter = presenter;
         mListContainer = listContainer;
-        if (!mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
+        if (!mNotifPipelineFlags.isNewPipelineEnabled()) {
             mDynamicPrivacyController.addListener(this);
         }
     }
@@ -528,7 +528,7 @@
 
     @Override
     public void onDynamicPrivacyChanged() {
-        if (mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
+        if (mNotifPipelineFlags.isNewPipelineEnabled()) {
             throw new IllegalStateException("Old pipeline code running w/ new pipeline enabled");
         }
         if (mPerformingUpdate) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/charging/WiredChargingRippleController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/charging/WiredChargingRippleController.kt
index 04c60fc..fa99353 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/charging/WiredChargingRippleController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/charging/WiredChargingRippleController.kt
@@ -36,6 +36,7 @@
 import com.android.systemui.statusbar.policy.ConfigurationController
 import com.android.systemui.util.leak.RotationUtils
 import com.android.systemui.R
+import com.android.systemui.flags.Flags
 import com.android.systemui.util.time.SystemClock
 import java.io.PrintWriter
 import javax.inject.Inject
@@ -61,7 +62,7 @@
     private val uiEventLogger: UiEventLogger
 ) {
     private var pluggedIn: Boolean? = null
-    private val rippleEnabled: Boolean = featureFlags.isChargingRippleEnabled &&
+    private val rippleEnabled: Boolean = featureFlags.isEnabled(Flags.CHARGING_RIPPLE) &&
             !SystemProperties.getBoolean("persist.debug.suppress-charging-ripple", false)
     private var normalizedPortPosX: Float = context.resources.getFloat(
             R.dimen.physical_charger_port_location_normalized_x)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/MobileSignalController.java
index 82e1cf8..1d67062 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/MobileSignalController.java
@@ -55,6 +55,7 @@
 import com.android.settingslib.net.SignalStrengthUtil;
 import com.android.systemui.R;
 import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
 import com.android.systemui.util.CarrierConfigTracker;
 
 import java.io.PrintWriter;
@@ -192,7 +193,8 @@
             SubscriptionDefaults defaults,
             Looper receiverLooper,
             CarrierConfigTracker carrierConfigTracker,
-            FeatureFlags featureFlags
+            FeatureFlags featureFlags,
+            StatusBarFlags statusBarFlags
     ) {
         super("MobileSignalController(" + info.getSubscriptionId() + ")", context,
                 NetworkCapabilities.TRANSPORT_CELLULAR, callbackHandler,
@@ -226,8 +228,8 @@
         mImsMmTelManager = ImsMmTelManager.createForSubscriptionId(info.getSubscriptionId());
         mMobileStatusTracker = new MobileStatusTracker(mPhone, receiverLooper,
                 info, mDefaults, mMobileCallback);
-        mProviderModelBehavior = featureFlags.isCombinedStatusBarSignalIconsEnabled();
-        mProviderModelSetting = featureFlags.isProviderModelSettingEnabled(mContext);
+        mProviderModelBehavior = featureFlags.isEnabled(Flags.COMBINED_STATUS_BAR_SIGNAL_ICONS);
+        mProviderModelSetting = statusBarFlags.isProviderModelSettingEnabled();
     }
 
     void setConfiguration(Config config) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java
index a87efd7..03d443e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java
@@ -73,6 +73,7 @@
 import com.android.systemui.demomode.DemoModeController;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
 import com.android.systemui.qs.tiles.dialog.InternetDialogFactory;
 import com.android.systemui.qs.tiles.dialog.InternetDialogUtil;
 import com.android.systemui.settings.CurrentUserTracker;
@@ -135,6 +136,7 @@
     private Config mConfig;
     private final CarrierConfigTracker mCarrierConfigTracker;
     private final FeatureFlags mFeatureFlags;
+    private final StatusBarFlags mStatusBarFlags;
     private final DumpManager mDumpManager;
 
     private TelephonyCallback.ActiveDataSubscriptionIdListener mPhoneStateListener;
@@ -210,6 +212,7 @@
                     mReceiverHandler.post(() -> handleConfigurationChanged());
                 }
             };
+
     /**
      * Construct this controller object and register for updates.
      */
@@ -233,6 +236,7 @@
             @Main Handler handler,
             InternetDialogFactory internetDialogFactory,
             FeatureFlags featureFlags,
+            StatusBarFlags statusBarFlags,
             DumpManager dumpManager) {
         this(context, connectivityManager,
                 telephonyManager,
@@ -252,6 +256,7 @@
                 demoModeController,
                 carrierConfigTracker,
                 featureFlags,
+                statusBarFlags,
                 dumpManager);
         mReceiverHandler.post(mRegisterListeners);
         mMainHandler = handler;
@@ -275,6 +280,7 @@
             DemoModeController demoModeController,
             CarrierConfigTracker carrierConfigTracker,
             FeatureFlags featureFlags,
+            StatusBarFlags statusBarFlags,
             DumpManager dumpManager
     ) {
         mContext = context;
@@ -294,6 +300,7 @@
         mDemoModeController = demoModeController;
         mCarrierConfigTracker = carrierConfigTracker;
         mFeatureFlags = featureFlags;
+        mStatusBarFlags = statusBarFlags;
         mDumpManager = dumpManager;
 
         // telephony
@@ -316,7 +323,7 @@
         });
         mWifiSignalController = new WifiSignalController(mContext, mHasMobileDataFeature,
                 mCallbackHandler, this, mWifiManager, mConnectivityManager, networkScoreManager,
-                mFeatureFlags);
+                mStatusBarFlags);
 
         mEthernetSignalController = new EthernetSignalController(mContext, mCallbackHandler, this);
 
@@ -441,8 +448,8 @@
         };
 
         mDemoModeController.addCallback(this);
-        mProviderModelBehavior = mFeatureFlags.isCombinedStatusBarSignalIconsEnabled();
-        mProviderModelSetting = mFeatureFlags.isProviderModelSettingEnabled(mContext);
+        mProviderModelBehavior = mFeatureFlags.isEnabled(Flags.COMBINED_STATUS_BAR_SIGNAL_ICONS);
+        mProviderModelSetting = mStatusBarFlags.isProviderModelSettingEnabled();
 
         mDumpManager.registerDumpable(TAG, this);
     }
@@ -958,7 +965,7 @@
                         mHasMobileDataFeature, mPhone.createForSubscriptionId(subId),
                         mCallbackHandler, this, subscriptions.get(i),
                         mSubDefaults, mReceiverHandler.getLooper(), mCarrierConfigTracker,
-                        mFeatureFlags);
+                        mFeatureFlags, mStatusBarFlags);
                 controller.setUserSetupComplete(mUserSetup);
                 mMobileSignalControllers.put(subId, controller);
                 if (subscriptions.get(i).getSimSlotIndex() == 0) {
@@ -1436,7 +1443,7 @@
                 mConfig, mHasMobileDataFeature,
                 mPhone.createForSubscriptionId(info.getSubscriptionId()), mCallbackHandler, this,
                 info, mSubDefaults, mReceiverHandler.getLooper(), mCarrierConfigTracker,
-                mFeatureFlags);
+                mFeatureFlags, mStatusBarFlags);
         mMobileSignalControllers.put(id, controller);
         controller.getState().userSetup = true;
         return info;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/StatusBarFlags.java b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/StatusBarFlags.java
new file mode 100644
index 0000000..89d4bf5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/StatusBarFlags.java
@@ -0,0 +1,43 @@
+/*
+ * 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.statusbar.connectivity;
+
+import android.content.Context;
+import android.util.FeatureFlagUtils;
+
+import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.flags.FeatureFlags;
+
+import javax.inject.Inject;
+
+/**
+ * Class for providing StatusBar specific logic around {@link FeatureFlags}.
+ */
+@SysUISingleton
+public class StatusBarFlags {
+    private final Context mContext;
+
+    @Inject
+    public StatusBarFlags(Context context) {
+        mContext = context;
+    }
+
+    /** System setting for provider model behavior */
+    public boolean isProviderModelSettingEnabled() {
+        return FeatureFlagUtils.isEnabled(mContext, FeatureFlagUtils.SETTINGS_PROVIDER_MODEL);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/WifiSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/WifiSignalController.java
index b5d3637..f8f7b7f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/WifiSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/WifiSignalController.java
@@ -34,7 +34,6 @@
 import com.android.settingslib.mobile.TelephonyIcons;
 import com.android.settingslib.wifi.WifiStatusTracker;
 import com.android.systemui.R;
-import com.android.systemui.flags.FeatureFlags;
 
 import java.io.PrintWriter;
 
@@ -55,7 +54,7 @@
             WifiManager wifiManager,
             ConnectivityManager connectivityManager,
             NetworkScoreManager networkScoreManager,
-            FeatureFlags featureFlags) {
+            StatusBarFlags statusBarFlags) {
         super("WifiSignalController", context, NetworkCapabilities.TRANSPORT_WIFI,
                 callbackHandler, networkController);
         mWifiManager = wifiManager;
@@ -68,7 +67,7 @@
                     new WifiTrafficStateCallback());
         }
         mCurrentState.iconGroup = mLastState.iconGroup = mUnmergedWifiIconGroup;
-        mProviderModelSetting = featureFlags.isProviderModelSettingEnabled(mContext);
+        mProviderModelSetting = statusBarFlags.isProviderModelSettingEnabled();
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
index 77463fe..8c54de4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
@@ -71,6 +71,7 @@
 import com.android.systemui.statusbar.phone.StatusBarRemoteInputCallback;
 import com.android.systemui.statusbar.phone.SystemUIHostDialogProvider;
 import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController;
+import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallFlags;
 import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallLogger;
 import com.android.systemui.statusbar.policy.RemoteInputUriController;
 import com.android.systemui.statusbar.window.StatusBarWindowController;
@@ -99,7 +100,7 @@
     @Provides
     static NotificationRemoteInputManager provideNotificationRemoteInputManager(
             Context context,
-            FeatureFlags featureFlags,
+            NotifPipelineFlags notifPipelineFlags,
             NotificationLockscreenUserManager lockscreenUserManager,
             SmartReplyController smartReplyController,
             NotificationVisibilityProvider visibilityProvider,
@@ -114,7 +115,7 @@
             DumpManager dumpManager) {
         return new NotificationRemoteInputManager(
                 context,
-                featureFlags,
+                notifPipelineFlags,
                 lockscreenUserManager,
                 smartReplyController,
                 visibilityProvider,
@@ -142,7 +143,7 @@
             KeyguardBypassController keyguardBypassController,
             NotifPipeline notifPipeline,
             NotifCollection notifCollection,
-            FeatureFlags featureFlags,
+            NotifPipelineFlags notifPipelineFlags,
             @Main DelayableExecutor mainExecutor,
             MediaDataManager mediaDataManager,
             DumpManager dumpManager) {
@@ -156,7 +157,7 @@
                 keyguardBypassController,
                 notifPipeline,
                 notifCollection,
-                featureFlags,
+                notifPipelineFlags,
                 mainExecutor,
                 mediaDataManager,
                 dumpManager);
@@ -269,7 +270,6 @@
     @SysUISingleton
     static OngoingCallController provideOngoingCallController(
             CommonNotifCollection notifCollection,
-            FeatureFlags featureFlags,
             SystemClock systemClock,
             ActivityStarter activityStarter,
             @Main Executor mainExecutor,
@@ -278,19 +278,22 @@
             DumpManager dumpManager,
             StatusBarWindowController statusBarWindowController,
             SwipeStatusBarAwayGestureHandler swipeStatusBarAwayGestureHandler,
-            StatusBarStateController statusBarStateController) {
+            StatusBarStateController statusBarStateController,
+            OngoingCallFlags ongoingCallFlags) {
+
+        boolean ongoingCallInImmersiveEnabled = ongoingCallFlags.isInImmersiveEnabled();
         Optional<StatusBarWindowController> windowController =
-                featureFlags.isOngoingCallInImmersiveEnabled()
+                ongoingCallInImmersiveEnabled
                         ? Optional.of(statusBarWindowController)
                         : Optional.empty();
         Optional<SwipeStatusBarAwayGestureHandler> gestureHandler =
-                featureFlags.isOngoingCallInImmersiveEnabled()
+                ongoingCallInImmersiveEnabled
                         ? Optional.of(swipeStatusBarAwayGestureHandler)
                         : Optional.empty();
         OngoingCallController ongoingCallController =
                 new OngoingCallController(
                         notifCollection,
-                        featureFlags,
+                        ongoingCallFlags,
                         systemClock,
                         activityStarter,
                         mainExecutor,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
index 4e5bc8e..a44de2c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
@@ -44,6 +44,7 @@
 import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.settings.UserTracker
 import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
 import com.android.systemui.statusbar.policy.ConfigurationController
 import com.android.systemui.statusbar.policy.DeviceProvisionedController
 import com.android.systemui.util.concurrency.Execution
@@ -158,7 +159,7 @@
     fun isEnabled(): Boolean {
         execution.assertIsMainThread()
 
-        return featureFlags.isSmartspaceEnabled && plugin != null
+        return featureFlags.isEnabled(Flags.SMARTSPACE) && plugin != null
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotifPipelineFlags.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotifPipelineFlags.kt
index 914697b..0fb9fc8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotifPipelineFlags.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotifPipelineFlags.kt
@@ -20,6 +20,7 @@
 import android.util.Log
 import android.widget.Toast
 import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
 import javax.inject.Inject
 
 class NotifPipelineFlags @Inject constructor(
@@ -27,11 +28,18 @@
         val featureFlags: FeatureFlags
 ) {
     fun checkLegacyPipelineEnabled(): Boolean {
-        if (!featureFlags.isNewNotifPipelineRenderingEnabled) {
+        if (!featureFlags.isEnabled(Flags.NEW_NOTIFICATION_PIPELINE_RENDERING)) {
             return true
         }
         Log.d("NotifPipeline", "Old pipeline code running w/ new pipeline enabled", Exception())
         Toast.makeText(context, "Old pipeline code running!", Toast.LENGTH_SHORT).show()
         return false
     }
+
+    fun isNewPipelineEnabled(): Boolean = featureFlags.isEnabled(
+            Flags.NEW_NOTIFICATION_PIPELINE_RENDERING)
+
+    fun isSmartspaceDedupingEnabled(): Boolean =
+            featureFlags.isEnabled(Flags.SMARTSPACE)
+                    && featureFlags.isEnabled(Flags.SMARTSPACE_DEDUPING)
 }
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
index 2437415..0389a7b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
@@ -38,7 +38,6 @@
 import com.android.internal.statusbar.NotificationVisibility;
 import com.android.systemui.Dumpable;
 import com.android.systemui.dump.DumpManager;
-import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.statusbar.NotificationLifetimeExtender;
 import com.android.systemui.statusbar.NotificationListener;
 import com.android.systemui.statusbar.NotificationListener.NotificationHandler;
@@ -102,7 +101,7 @@
 
     private final NotificationEntryManagerLogger mLogger;
     private final NotificationGroupManagerLegacy mGroupManager;
-    private final FeatureFlags mFeatureFlags;
+    private final NotifPipelineFlags mNotifPipelineFlags;
     private final Lazy<NotificationRowBinder> mNotificationRowBinderLazy;
     private final Lazy<NotificationRemoteInputManager> mRemoteInputManagerLazy;
     private final LeakDetector mLeakDetector;
@@ -149,7 +148,7 @@
     public NotificationEntryManager(
             NotificationEntryManagerLogger logger,
             NotificationGroupManagerLegacy groupManager,
-            FeatureFlags featureFlags,
+            NotifPipelineFlags notifPipelineFlags,
             Lazy<NotificationRowBinder> notificationRowBinderLazy,
             Lazy<NotificationRemoteInputManager> notificationRemoteInputManagerLazy,
             LeakDetector leakDetector,
@@ -159,7 +158,7 @@
     ) {
         mLogger = logger;
         mGroupManager = groupManager;
-        mFeatureFlags = featureFlags;
+        mNotifPipelineFlags = notifPipelineFlags;
         mNotificationRowBinderLazy = notificationRowBinderLazy;
         mRemoteInputManagerLazy = notificationRemoteInputManagerLazy;
         mLeakDetector = leakDetector;
@@ -637,7 +636,7 @@
         }
 
         // Construct the expanded view.
-        if (!mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
+        if (!mNotifPipelineFlags.isNewPipelineEnabled()) {
             mNotificationRowBinderLazy.get().inflateViews(entry, null, mInflationCallback);
         }
 
@@ -694,7 +693,7 @@
             listener.onEntryUpdated(entry, fromSystem);
         }
 
-        if (!mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
+        if (!mNotifPipelineFlags.isNewPipelineEnabled()) {
             mNotificationRowBinderLazy.get().inflateViews(entry, null, mInflationCallback);
         }
 
@@ -721,12 +720,12 @@
      * @param reason why the notifications are updating
      */
     public void updateNotifications(String reason) {
-        if (mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
+        if (mNotifPipelineFlags.isNewPipelineEnabled()) {
             mLogger.logUseWhileNewPipelineActive("updateNotifications", reason);
             return;
         }
         reapplyFilterAndSort(reason);
-        if (mPresenter != null) {
+        if (mPresenter != null && !mNotifPipelineFlags.isNewPipelineEnabled()) {
             mPresenter.updateNotificationViews(reason);
         }
     }
@@ -792,6 +791,7 @@
      * these don't exist, although there are a couple exceptions.
      */
     public Iterable<NotificationEntry> getPendingNotificationsIterator() {
+        mNotifPipelineFlags.checkLegacyPipelineEnabled();
         return mPendingNotifications.values();
     }
 
@@ -804,6 +804,7 @@
      * @return a {@link NotificationEntry} if it has been prepared, else null
      */
     public NotificationEntry getActiveNotificationUnfiltered(String key) {
+        mNotifPipelineFlags.checkLegacyPipelineEnabled();
         return mActiveNotifications.get(key);
     }
 
@@ -812,6 +813,7 @@
      * notification doesn't exist.
      */
     public NotificationEntry getPendingOrActiveNotif(String key) {
+        mNotifPipelineFlags.checkLegacyPipelineEnabled();
         NotificationEntry entry = mPendingNotifications.get(key);
         if (entry != null) {
             return entry;
@@ -884,7 +886,7 @@
 
     /** Resorts / filters the current notification set with the current RankingMap */
     public void reapplyFilterAndSort(String reason) {
-        if (mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
+        if (mNotifPipelineFlags.isNewPipelineEnabled()) {
             mLogger.logUseWhileNewPipelineActive("reapplyFilterAndSort", reason);
             return;
         }
@@ -893,7 +895,7 @@
 
     /** Calls to NotificationRankingManager and updates mSortedAndFiltered */
     private void updateRankingAndSort(@NonNull RankingMap rankingMap, String reason) {
-        if (mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
+        if (mNotifPipelineFlags.isNewPipelineEnabled()) {
             mLogger.logUseWhileNewPipelineActive("updateRankingAndSort", reason);
             return;
         }
@@ -946,6 +948,7 @@
      * @return A read-only list of the currently active notifications
      */
     public List<NotificationEntry> getVisibleNotifications() {
+        mNotifPipelineFlags.checkLegacyPipelineEnabled();
         return mReadOnlyNotifications;
     }
 
@@ -955,17 +958,20 @@
      */
     @Override
     public Collection<NotificationEntry> getAllNotifs() {
+        mNotifPipelineFlags.checkLegacyPipelineEnabled();
         return mReadOnlyAllNotifications;
     }
 
     @Nullable
     @Override
     public NotificationEntry getEntry(String key) {
+        mNotifPipelineFlags.checkLegacyPipelineEnabled();
         return getPendingOrActiveNotif(key);
     }
 
     /** @return A count of the active notifications */
     public int getActiveNotificationsCount() {
+        mNotifPipelineFlags.checkLegacyPipelineEnabled();
         return mReadOnlyNotifications.size();
     }
 
@@ -973,6 +979,7 @@
      * @return {@code true} if there is at least one notification that should be visible right now
      */
     public boolean hasActiveNotifications() {
+        mNotifPipelineFlags.checkLegacyPipelineEnabled();
         return mReadOnlyNotifications.size() != 0;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
index f36f430..2d6522e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
@@ -66,7 +66,7 @@
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.dump.LogBufferEulogizer;
-import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.statusbar.notification.NotifPipelineFlags;
 import com.android.systemui.statusbar.notification.collection.coalescer.CoalescedEvent;
 import com.android.systemui.statusbar.notification.collection.coalescer.GroupCoalescer;
 import com.android.systemui.statusbar.notification.collection.coalescer.GroupCoalescer.BatchableNotificationHandler;
@@ -132,7 +132,7 @@
 public class NotifCollection implements Dumpable {
     private final IStatusBarService mStatusBarService;
     private final SystemClock mClock;
-    private final FeatureFlags mFeatureFlags;
+    private final NotifPipelineFlags mNotifPipelineFlags;
     private final NotifCollectionLogger mLogger;
     private final Handler mMainHandler;
     private final LogBufferEulogizer mEulogizer;
@@ -156,7 +156,7 @@
     public NotifCollection(
             IStatusBarService statusBarService,
             SystemClock clock,
-            FeatureFlags featureFlags,
+            NotifPipelineFlags notifPipelineFlags,
             NotifCollectionLogger logger,
             @Main Handler mainHandler,
             LogBufferEulogizer logBufferEulogizer,
@@ -164,7 +164,7 @@
         Assert.isMainThread();
         mStatusBarService = statusBarService;
         mClock = clock;
-        mFeatureFlags = featureFlags;
+        mNotifPipelineFlags = notifPipelineFlags;
         mLogger = logger;
         mMainHandler = mainHandler;
         mEulogizer = logBufferEulogizer;
@@ -395,7 +395,7 @@
         final NotificationEntry entry = mNotificationSet.get(sbn.getKey());
         if (entry == null) {
             // TODO (b/160008901): Throw an exception here
-            mLogger.logNoNotificationToRemoveWithKey(sbn.getKey());
+            mLogger.logNoNotificationToRemoveWithKey(sbn.getKey(), reason);
             return;
         }
 
@@ -503,7 +503,7 @@
                     // TODO: (b/145659174) update the sbn's overrideGroupKey in
                     //  NotificationEntry.setRanking instead of here once we fully migrate to the
                     //  NewNotifPipeline
-                    if (mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
+                    if (mNotifPipelineFlags.isNewPipelineEnabled()) {
                         final String newOverrideGroupKey = ranking.getOverrideGroupKey();
                         if (!Objects.equals(entry.getSbn().getOverrideGroupKey(),
                                 newOverrideGroupKey)) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/CommunalCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/CommunalCoordinator.java
index 992d898..bd011c3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/CommunalCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/CommunalCoordinator.java
@@ -19,6 +19,7 @@
 import androidx.annotation.NonNull;
 
 import com.android.systemui.communal.CommunalStateController;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotifPipeline;
@@ -26,6 +27,8 @@
 import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope;
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
 
+import java.util.concurrent.Executor;
+
 import javax.inject.Inject;
 
 /**
@@ -34,14 +37,17 @@
  */
 @CoordinatorScope
 public class CommunalCoordinator implements Coordinator {
+    final Executor mExecutor;
     final CommunalStateController mCommunalStateController;
     final NotificationEntryManager mNotificationEntryManager;
     final NotificationLockscreenUserManager mNotificationLockscreenUserManager;
 
     @Inject
-    public CommunalCoordinator(NotificationEntryManager notificationEntryManager,
+    public CommunalCoordinator(@Main Executor executor,
+            NotificationEntryManager notificationEntryManager,
             NotificationLockscreenUserManager notificationLockscreenUserManager,
             CommunalStateController communalStateController) {
+        mExecutor = executor;
         mNotificationEntryManager = notificationEntryManager;
         mNotificationLockscreenUserManager = notificationLockscreenUserManager;
         mCommunalStateController = communalStateController;
@@ -57,8 +63,10 @@
     final CommunalStateController.Callback mStateCallback = new CommunalStateController.Callback() {
         @Override
         public void onCommunalViewShowingChanged() {
-            mFilter.invalidateList();
-            mNotificationEntryManager.updateNotifications("Communal mode state changed");
+            mExecutor.execute(() -> {
+                mFilter.invalidateList();
+                mNotificationEntryManager.updateNotifications("Communal mode state changed");
+            });
         }
     };
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt
index 7cbda25d..dae76f8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt
@@ -17,13 +17,12 @@
 
 import com.android.systemui.Dumpable
 import com.android.systemui.dump.DumpManager
-import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.statusbar.notification.NotifPipelineFlags
 import com.android.systemui.statusbar.notification.collection.NotifPipeline
 import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner
 import java.io.FileDescriptor
 import java.io.PrintWriter
-import java.util.ArrayList
 import javax.inject.Inject
 
 /**
@@ -35,7 +34,7 @@
 @CoordinatorScope
 class NotifCoordinatorsImpl @Inject constructor(
     dumpManager: DumpManager,
-    featureFlags: FeatureFlags,
+    notifPipelineFlags: NotifPipelineFlags,
     hideLocallyDismissedNotifsCoordinator: HideLocallyDismissedNotifsCoordinator,
     hideNotifsForOtherUsersCoordinator: HideNotifsForOtherUsersCoordinator,
     keyguardCoordinator: KeyguardCoordinator,
@@ -80,10 +79,10 @@
         mCoordinators.add(visualStabilityCoordinator)
         mCoordinators.add(communalCoordinator)
         mCoordinators.add(sensitiveContentCoordinator)
-        if (featureFlags.isSmartspaceDedupingEnabled) {
+        if (notifPipelineFlags.isSmartspaceDedupingEnabled()) {
             mCoordinators.add(smartspaceDedupingCoordinator)
         }
-        if (featureFlags.isNewNotifPipelineRenderingEnabled) {
+        if (notifPipelineFlags.isNewPipelineEnabled()) {
             mCoordinators.add(headsUpCoordinator)
             mCoordinators.add(gutsCoordinator)
             mCoordinators.add(preparationCoordinator)
@@ -91,7 +90,7 @@
 
         // Manually add Ordered Sections
         // HeadsUp > FGS > People > Alerting > Silent > Unknown/Default
-        if (featureFlags.isNewNotifPipelineRenderingEnabled) {
+        if (notifPipelineFlags.isNewPipelineEnabled()) {
             mOrderedSections.add(headsUpCoordinator.sectioner) // HeadsUp
         }
         mOrderedSections.add(appOpsCoordinator.sectioner) // ForegroundService
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinator.kt
index 5b86de2..832df4d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinator.kt
@@ -19,9 +19,9 @@
 import com.android.internal.widget.MessagingGroup
 import com.android.internal.widget.MessagingMessage
 import com.android.keyguard.KeyguardUpdateMonitor
-import com.android.systemui.flags.FeatureFlags
 import com.android.systemui.statusbar.NotificationLockscreenUserManager.UserChangedListener
 import com.android.systemui.statusbar.NotificationLockscreenUserManagerImpl
+import com.android.systemui.statusbar.notification.NotifPipelineFlags
 import com.android.systemui.statusbar.notification.collection.NotifPipeline
 import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager
@@ -37,7 +37,7 @@
 class ViewConfigCoordinator @Inject internal constructor(
     configurationController: ConfigurationController,
     lockscreenUserManager: NotificationLockscreenUserManagerImpl,
-    featureFlags: FeatureFlags,
+    notifPipelineFlags: NotifPipelineFlags,
     private val mGutsManager: NotificationGutsManager,
     private val mKeyguardUpdateMonitor: KeyguardUpdateMonitor
 ) : Coordinator, UserChangedListener, ConfigurationController.ConfigurationListener {
@@ -47,7 +47,7 @@
     private var mPipeline: NotifPipeline? = null
 
     init {
-        if (featureFlags.isNewNotifPipelineRenderingEnabled) {
+        if (notifPipelineFlags.isNewPipelineEnabled()) {
             lockscreenUserManager.addUserChangedListener(this)
             configurationController.addCallback(this)
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NotifPipelineInitializer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NotifPipelineInitializer.java
index a98531f..a8f3730 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NotifPipelineInitializer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NotifPipelineInitializer.java
@@ -21,8 +21,8 @@
 import com.android.systemui.Dumpable;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dump.DumpManager;
-import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.statusbar.NotificationListener;
+import com.android.systemui.statusbar.notification.NotifPipelineFlags;
 import com.android.systemui.statusbar.notification.collection.NotifCollection;
 import com.android.systemui.statusbar.notification.collection.NotifInflaterImpl;
 import com.android.systemui.statusbar.notification.collection.NotifPipeline;
@@ -51,7 +51,7 @@
     private final NotifInflaterImpl mNotifInflater;
     private final DumpManager mDumpManager;
     private final ShadeViewManagerFactory mShadeViewManagerFactory;
-    private final FeatureFlags mFeatureFlags;
+    private final NotifPipelineFlags mNotifPipelineFlags;
 
 
     @Inject
@@ -64,7 +64,7 @@
             NotifInflaterImpl notifInflater,
             DumpManager dumpManager,
             ShadeViewManagerFactory shadeViewManagerFactory,
-            FeatureFlags featureFlags) {
+            NotifPipelineFlags notifPipelineFlags) {
         mPipelineWrapper = pipelineWrapper;
         mGroupCoalescer = groupCoalescer;
         mNotifCollection = notifCollection;
@@ -73,7 +73,7 @@
         mDumpManager = dumpManager;
         mNotifInflater = notifInflater;
         mShadeViewManagerFactory = shadeViewManagerFactory;
-        mFeatureFlags = featureFlags;
+        mNotifPipelineFlags = notifPipelineFlags;
     }
 
     /** Hooks the new pipeline up to NotificationManager */
@@ -85,7 +85,7 @@
         mDumpManager.registerDumpable("NotifPipeline", this);
 
         // Setup inflation
-        if (mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
+        if (mNotifPipelineFlags.isNewPipelineEnabled()) {
             mNotifInflater.setRowBinder(rowBinder);
         }
 
@@ -93,7 +93,7 @@
         mNotifPluggableCoordinators.attach(mPipelineWrapper);
 
         // Wire up pipeline
-        if (mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
+        if (mNotifPipelineFlags.isNewPipelineEnabled()) {
             mShadeViewManagerFactory.create(listContainer).attach(mListBuilder);
         }
         mListBuilder.attach(mNotifCollection);
@@ -101,7 +101,7 @@
         mGroupCoalescer.attach(notificationService);
 
         Log.d(TAG, "Notif pipeline initialized."
-                + " rendering=" + mFeatureFlags.isNewNotifPipelineRenderingEnabled());
+                + " rendering=" + mNotifPipelineFlags.isNewPipelineEnabled());
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionLogger.kt
index 1ebc66e..b4389b9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionLogger.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.statusbar.notification.collection.notifcollection
 
 import android.os.RemoteException
+import android.service.notification.NotificationListenerService
 import android.service.notification.NotificationListenerService.RankingMap
 import com.android.systemui.log.LogBuffer
 import com.android.systemui.log.LogLevel.DEBUG
@@ -25,9 +26,36 @@
 import com.android.systemui.log.LogLevel.WARNING
 import com.android.systemui.log.LogLevel.WTF
 import com.android.systemui.log.dagger.NotificationLog
+import com.android.systemui.statusbar.notification.collection.NotifCollection
+import com.android.systemui.statusbar.notification.collection.NotifCollection.CancellationReason
 import com.android.systemui.statusbar.notification.collection.NotificationEntry
 import javax.inject.Inject
 
+fun cancellationReasonDebugString(@CancellationReason reason: Int) =
+    "$reason:" + when (reason) {
+        -1 -> "REASON_NOT_CANCELED" // NotifCollection.REASON_NOT_CANCELED
+        NotifCollection.REASON_UNKNOWN -> "REASON_UNKNOWN"
+        NotificationListenerService.REASON_CLICK -> "REASON_CLICK"
+        NotificationListenerService.REASON_CANCEL_ALL -> "REASON_CANCEL_ALL"
+        NotificationListenerService.REASON_ERROR -> "REASON_ERROR"
+        NotificationListenerService.REASON_PACKAGE_CHANGED -> "REASON_PACKAGE_CHANGED"
+        NotificationListenerService.REASON_USER_STOPPED -> "REASON_USER_STOPPED"
+        NotificationListenerService.REASON_PACKAGE_BANNED -> "REASON_PACKAGE_BANNED"
+        NotificationListenerService.REASON_APP_CANCEL -> "REASON_APP_CANCEL"
+        NotificationListenerService.REASON_APP_CANCEL_ALL -> "REASON_APP_CANCEL_ALL"
+        NotificationListenerService.REASON_LISTENER_CANCEL -> "REASON_LISTENER_CANCEL"
+        NotificationListenerService.REASON_LISTENER_CANCEL_ALL -> "REASON_LISTENER_CANCEL_ALL"
+        NotificationListenerService.REASON_GROUP_SUMMARY_CANCELED -> "REASON_GROUP_SUMMARY_CANCELED"
+        NotificationListenerService.REASON_GROUP_OPTIMIZATION -> "REASON_GROUP_OPTIMIZATION"
+        NotificationListenerService.REASON_PACKAGE_SUSPENDED -> "REASON_PACKAGE_SUSPENDED"
+        NotificationListenerService.REASON_PROFILE_TURNED_OFF -> "REASON_PROFILE_TURNED_OFF"
+        NotificationListenerService.REASON_UNAUTOBUNDLED -> "REASON_UNAUTOBUNDLED"
+        NotificationListenerService.REASON_CHANNEL_BANNED -> "REASON_CHANNEL_BANNED"
+        NotificationListenerService.REASON_SNOOZED -> "REASON_SNOOZED"
+        NotificationListenerService.REASON_TIMEOUT -> "REASON_TIMEOUT"
+        else -> "unknown"
+    }
+
 class NotifCollectionLogger @Inject constructor(
     @NotificationLog private val buffer: LogBuffer
 ) {
@@ -56,12 +84,12 @@
         })
     }
 
-    fun logNotifRemoved(key: String, reason: Int) {
+    fun logNotifRemoved(key: String, @CancellationReason reason: Int) {
         buffer.log(TAG, INFO, {
             str1 = key
             int1 = reason
         }, {
-            "REMOVED $str1 reason=$int1"
+            "REMOVED $str1 reason=${cancellationReasonDebugString(int1)}"
         })
     }
 
@@ -141,11 +169,12 @@
         })
     }
 
-    fun logNoNotificationToRemoveWithKey(key: String) {
+    fun logNoNotificationToRemoveWithKey(key: String, @CancellationReason reason: Int) {
         buffer.log(TAG, ERROR, {
             str1 = key
+            int1 = reason
         }, {
-            "No notification to remove with key $str1"
+            "No notification to remove with key $str1 reason=${cancellationReasonDebugString(int1)}"
         })
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProvider.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProvider.java
index 0478658..e7ef2ec 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProvider.java
@@ -99,7 +99,7 @@
 
     private boolean hasHighPriorityCharacteristics(NotificationEntry entry) {
         return !hasUserSetImportance(entry)
-                && (entry.getSbn().getNotification().hasMediaSession()
+                && (entry.getSbn().getNotification().isMediaNotification()
                 || isPeopleNotification(entry)
                 || isMessagingStyle(entry));
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
index a19549c5..d25a2d3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
@@ -31,7 +31,6 @@
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dagger.qualifiers.UiBackground;
 import com.android.systemui.dump.DumpManager;
-import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.people.widget.PeopleSpaceWidgetManager;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -40,6 +39,7 @@
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
 import com.android.systemui.statusbar.notification.AssistantFeedbackController;
 import com.android.systemui.statusbar.notification.ForegroundServiceDismissalFeatureController;
+import com.android.systemui.statusbar.notification.NotifPipelineFlags;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.NotificationEntryManagerLogger;
 import com.android.systemui.statusbar.notification.collection.NotifCollection;
@@ -116,7 +116,7 @@
     static NotificationEntryManager provideNotificationEntryManager(
             NotificationEntryManagerLogger logger,
             NotificationGroupManagerLegacy groupManager,
-            FeatureFlags featureFlags,
+            NotifPipelineFlags notifPipelineFlags,
             Lazy<NotificationRowBinder> notificationRowBinderLazy,
             Lazy<NotificationRemoteInputManager> notificationRemoteInputManagerLazy,
             LeakDetector leakDetector,
@@ -126,7 +126,7 @@
         return new NotificationEntryManager(
                 logger,
                 groupManager,
-                featureFlags,
+                notifPipelineFlags,
                 notificationRowBinderLazy,
                 notificationRemoteInputManagerLazy,
                 leakDetector,
@@ -211,7 +211,7 @@
     static NotificationLogger provideNotificationLogger(
             NotificationListener notificationListener,
             @UiBackground Executor uiBgExecutor,
-            FeatureFlags featureFlags,
+            NotifPipelineFlags notifPipelineFlags,
             NotificationVisibilityProvider visibilityProvider,
             NotificationEntryManager entryManager,
             NotifPipeline notifPipeline,
@@ -221,7 +221,7 @@
         return new NotificationLogger(
                 notificationListener,
                 uiBgExecutor,
-                featureFlags,
+                notifPipelineFlags,
                 visibilityProvider,
                 entryManager,
                 notifPipeline,
@@ -241,9 +241,9 @@
     @SysUISingleton
     @Provides
     static GroupMembershipManager provideGroupMembershipManager(
-            FeatureFlags featureFlags,
+            NotifPipelineFlags notifPipelineFlags,
             Lazy<NotificationGroupManagerLegacy> groupManagerLegacy) {
-        return featureFlags.isNewNotifPipelineRenderingEnabled()
+        return notifPipelineFlags.isNewPipelineEnabled()
                 ? new GroupMembershipManagerImpl()
                 : groupManagerLegacy.get();
     }
@@ -252,10 +252,10 @@
     @SysUISingleton
     @Provides
     static GroupExpansionManager provideGroupExpansionManager(
-            FeatureFlags featureFlags,
+            NotifPipelineFlags notifPipelineFlags,
             Lazy<GroupMembershipManager> groupMembershipManager,
             Lazy<NotificationGroupManagerLegacy> groupManagerLegacy) {
-        return featureFlags.isNewNotifPipelineRenderingEnabled()
+        return notifPipelineFlags.isNewPipelineEnabled()
                 ? new GroupExpansionManagerImpl(groupMembershipManager.get())
                 : groupManagerLegacy.get();
     }
@@ -280,10 +280,11 @@
     @Provides
     @SysUISingleton
     static CommonNotifCollection provideCommonNotifCollection(
-            FeatureFlags featureFlags,
+            NotifPipelineFlags notifPipelineFlags,
             Lazy<NotifPipeline> pipeline,
             NotificationEntryManager entryManager) {
-        return featureFlags.isNewNotifPipelineRenderingEnabled() ? pipeline.get() : entryManager;
+        return notifPipelineFlags.isNewPipelineEnabled()
+                ? pipeline.get() : entryManager;
     }
 
     /**
@@ -292,10 +293,10 @@
     @Provides
     @SysUISingleton
     static NotificationVisibilityProvider provideNotificationVisibilityProvider(
-            FeatureFlags featureFlags,
+            NotifPipelineFlags notifPipelineFlags,
             Lazy<NotificationVisibilityProviderImpl> newProvider,
             Lazy<LegacyNotificationVisibilityProvider> legacyProvider) {
-        return featureFlags.isNewNotifPipelineRenderingEnabled()
+        return notifPipelineFlags.isNewPipelineEnabled()
                 ? newProvider.get()
                 : legacyProvider.get();
     }
@@ -306,10 +307,10 @@
     @Provides
     @SysUISingleton
     static NotifShadeEventSource provideNotifShadeEventSource(
-            FeatureFlags featureFlags,
+            NotifPipelineFlags notifPipelineFlags,
             Lazy<ShadeEventCoordinator> shadeEventCoordinatorLazy,
             Lazy<LegacyNotificationPresenterExtensions> legacyNotificationPresenterExtensionsLazy) {
-        return featureFlags.isNewNotifPipelineRenderingEnabled()
+        return notifPipelineFlags.isNewPipelineEnabled()
                 ? shadeEventCoordinatorLazy.get()
                 : legacyNotificationPresenterExtensionsLazy.get();
     }
@@ -321,7 +322,7 @@
     @Provides
     @SysUISingleton
     static OnUserInteractionCallback provideOnUserInteractionCallback(
-            FeatureFlags featureFlags,
+            NotifPipelineFlags notifPipelineFlags,
             HeadsUpManager headsUpManager,
             StatusBarStateController statusBarStateController,
             Lazy<NotifCollection> notifCollection,
@@ -330,7 +331,7 @@
             NotificationEntryManager entryManager,
             VisualStabilityManager visualStabilityManager,
             Lazy<GroupMembershipManager> groupMembershipManagerLazy) {
-        return featureFlags.isNewNotifPipelineRenderingEnabled()
+        return notifPipelineFlags.isNewPipelineEnabled()
                 ? new OnUserInteractionCallbackImpl(
                         visibilityProvider.get(),
                         notifCollection.get(),
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt
index 757f68a..999ef9c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt
@@ -20,10 +20,10 @@
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.people.widget.PeopleSpaceWidgetManager
 import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption
-import com.android.systemui.flags.FeatureFlags
 import com.android.systemui.statusbar.NotificationListener
 import com.android.systemui.statusbar.NotificationPresenter
 import com.android.systemui.statusbar.notification.AnimatedImageNotificationManager
+import com.android.systemui.statusbar.notification.NotifPipelineFlags
 import com.android.systemui.statusbar.notification.NotificationActivityStarter
 import com.android.systemui.statusbar.notification.NotificationClicker
 import com.android.systemui.statusbar.notification.NotificationEntryManager
@@ -59,7 +59,7 @@
  */
 @SysUISingleton
 class NotificationsControllerImpl @Inject constructor(
-    private val featureFlags: FeatureFlags,
+    private val notifPipelineFlags: NotifPipelineFlags,
     private val notificationListener: NotificationListener,
     private val entryManager: NotificationEntryManager,
     private val legacyRanker: NotificationRankingManager,
@@ -115,7 +115,7 @@
                     listContainer)
         }
 
-        if (featureFlags.isNewNotifPipelineRenderingEnabled) {
+        if (notifPipelineFlags.isNewPipelineEnabled()) {
             targetSdkResolver.initialize(notifPipeline.get())
             // TODO
         } else {
@@ -152,8 +152,14 @@
     }
 
     override fun resetUserExpandedStates() {
-        for (entry in entryManager.visibleNotifications) {
-            entry.resetUserExpansion()
+        if (notifPipelineFlags.isNewPipelineEnabled()) {
+            for (entry in notifPipeline.get().allNotifs) {
+                entry.resetUserExpansion()
+            }
+        } else {
+            for (entry in entryManager.visibleNotifications) {
+                entry.resetUserExpansion()
+            }
         }
     }
 
@@ -167,9 +173,12 @@
         }
     }
 
-    override fun getActiveNotificationsCount(): Int {
-        return entryManager.activeNotificationsCount
-    }
+    override fun getActiveNotificationsCount(): Int =
+        if (notifPipelineFlags.isNewPipelineEnabled()) {
+            notifPipeline.get().getShadeListCount()
+        } else {
+            entryManager.activeNotificationsCount
+        }
 
     companion object {
         // NOTE: The new pipeline is always active, even if the old pipeline is *rendering*.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
index 993e38d..bd1f609 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
@@ -34,11 +34,11 @@
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.statusbar.NotificationVisibility;
 import com.android.systemui.dagger.qualifiers.UiBackground;
-import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
 import com.android.systemui.statusbar.NotificationListener;
 import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.notification.NotifPipelineFlags;
 import com.android.systemui.statusbar.notification.NotificationEntryListener;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotifPipeline;
@@ -75,7 +75,7 @@
     // Dependencies:
     private final NotificationListenerService mNotificationListener;
     private final Executor mUiBgExecutor;
-    private final FeatureFlags mFeatureFlags;
+    private final NotifPipelineFlags mNotifPipelineFlags;
     private final NotificationVisibilityProvider mVisibilityProvider;
     private final NotificationEntryManager mEntryManager;
     private final NotifPipeline mNotifPipeline;
@@ -175,7 +175,7 @@
     };
 
     private List<NotificationEntry> getVisibleNotifications() {
-        if (mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
+        if (mNotifPipelineFlags.isNewPipelineEnabled()) {
             return mNotifPipeline.getFlatShadeList();
         } else {
             return mEntryManager.getVisibleNotifications();
@@ -218,7 +218,7 @@
      */
     public NotificationLogger(NotificationListener notificationListener,
             @UiBackground Executor uiBgExecutor,
-            FeatureFlags featureFlags,
+            NotifPipelineFlags notifPipelineFlags,
             NotificationVisibilityProvider visibilityProvider,
             NotificationEntryManager entryManager,
             NotifPipeline notifPipeline,
@@ -227,7 +227,7 @@
             NotificationPanelLogger notificationPanelLogger) {
         mNotificationListener = notificationListener;
         mUiBgExecutor = uiBgExecutor;
-        mFeatureFlags = featureFlags;
+        mNotifPipelineFlags = notifPipelineFlags;
         mVisibilityProvider = visibilityProvider;
         mEntryManager = entryManager;
         mNotifPipeline = notifPipeline;
@@ -238,7 +238,7 @@
         // Not expected to be destroyed, don't need to unsubscribe
         statusBarStateController.addCallback(this);
 
-        if (mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
+        if (mNotifPipelineFlags.isNewPipelineEnabled()) {
             registerNewPipelineListener();
         } else {
             registerLegacyListener();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index b0ee37b..9f10322 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -23,7 +23,6 @@
 import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_HEADSUP;
 import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_PUBLIC;
 
-import android.Manifest;
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ObjectAnimator;
@@ -50,7 +49,6 @@
 import android.os.Bundle;
 import android.os.RemoteException;
 import android.os.ServiceManager;
-import android.permission.PermissionManager;
 import android.provider.Settings;
 import android.service.notification.StatusBarNotification;
 import android.util.ArraySet;
@@ -3205,11 +3203,8 @@
         return getCurrentBottomRoundness() == 0.0f && getCurrentTopRoundness() == 0.0f;
     }
 
-    //TODO: this logic can't depend on layout if we are recycling!
     public boolean isMediaRow() {
-        return getExpandedContentView() != null
-                && getExpandedContentView().findViewById(
-                com.android.internal.R.id.media_actions) != null;
+        return mEntry.getSbn().getNotification().isMediaNotification();
     }
 
     public boolean isTopLevelChild() {
@@ -3368,6 +3363,8 @@
                 }
                 ipw.decreaseIndent();
                 ipw.println("}");
+            } else if (mPrivateLayout != null) {
+                mPrivateLayout.dumpSmartReplies(ipw);
             }
         });
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
index 1b4d369..727f0e5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
@@ -27,6 +27,7 @@
 import android.provider.Settings;
 import android.util.ArrayMap;
 import android.util.AttributeSet;
+import android.util.IndentingPrintWriter;
 import android.util.Log;
 import android.util.Pair;
 import android.view.LayoutInflater;
@@ -2005,6 +2006,22 @@
         pw.println();
     }
 
+    /** Add any existing SmartReplyView to the dump */
+    public void dumpSmartReplies(IndentingPrintWriter pw) {
+        if (mHeadsUpSmartReplyView != null) {
+            pw.println("HeadsUp SmartReplyView:");
+            pw.increaseIndent();
+            mHeadsUpSmartReplyView.dump(pw);
+            pw.decreaseIndent();
+        }
+        if (mExpandedSmartReplyView != null) {
+            pw.println("Expanded SmartReplyView:");
+            pw.increaseIndent();
+            mExpandedSmartReplyView.dump(pw);
+            pw.decreaseIndent();
+        }
+    }
+
     public RemoteInputView getExpandedRemoteInput() {
         return mExpandedRemoteInput;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index 9492996..f7a3e3c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -67,7 +67,6 @@
 import com.android.systemui.classifier.FalsingCollector;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
 import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.media.KeyguardMediaController;
 import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
@@ -85,6 +84,7 @@
 import com.android.systemui.statusbar.notification.DynamicPrivacyController;
 import com.android.systemui.statusbar.notification.ExpandAnimationParameters;
 import com.android.systemui.statusbar.notification.ForegroundServiceDismissalFeatureController;
+import com.android.systemui.statusbar.notification.NotifPipelineFlags;
 import com.android.systemui.statusbar.notification.NotificationActivityStarter;
 import com.android.systemui.statusbar.notification.NotificationEntryListener;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
@@ -159,7 +159,7 @@
     private final Resources mResources;
     private final NotificationSwipeHelper.Builder mNotificationSwipeHelperBuilder;
     private final ScrimController mScrimController;
-    private final FeatureFlags mFeatureFlags;
+    private final NotifPipelineFlags mNotifPipelineFlags;
     private final NotifPipeline mNotifPipeline;
     private final NotifCollection mNotifCollection;
     private final NotificationEntryManager mNotificationEntryManager;
@@ -642,7 +642,7 @@
             NotificationGroupManagerLegacy legacyGroupManager,
             GroupExpansionManager groupManager,
             @SilentHeader SectionHeaderController silentHeaderController,
-            FeatureFlags featureFlags,
+            NotifPipelineFlags notifPipelineFlags,
             NotifPipeline notifPipeline,
             NotifCollection notifCollection,
             NotificationEntryManager notificationEntryManager,
@@ -690,10 +690,10 @@
                 mStatusBar.requestNotificationUpdate("onGroupsChanged");
             }
         });
-        mLegacyGroupManager = featureFlags.isNewNotifPipelineRenderingEnabled()
+        mNotifPipelineFlags = notifPipelineFlags;
+        mLegacyGroupManager = mNotifPipelineFlags.isNewPipelineEnabled()
                 ? null : legacyGroupManager;
         mSilentHeaderController = silentHeaderController;
-        mFeatureFlags = featureFlags;
         mNotifPipeline = notifPipeline;
         mNotifCollection = notifCollection;
         mNotificationEntryManager = notificationEntryManager;
@@ -744,7 +744,7 @@
                 .setOnMenuEventListener(mMenuEventListener)
                 .build();
 
-        if (mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
+        if (mNotifPipelineFlags.isNewPipelineEnabled()) {
             mNotifPipeline.addCollectionListener(new NotifCollectionListener() {
                 @Override
                 public void onEntryUpdated(NotificationEntry entry) {
@@ -1309,7 +1309,7 @@
     }
 
     public void updateSectionBoundaries(String reason) {
-        if (mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
+        if (mNotifPipelineFlags.isNewPipelineEnabled()) {
             return;
         }
         mView.updateSectionBoundaries(reason);
@@ -1398,7 +1398,7 @@
      * @return if the shade has currently any active notifications.
      */
     public boolean hasActiveNotifications() {
-        if (mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
+        if (mNotifPipelineFlags.isNewPipelineEnabled()) {
             return !mNotifPipeline.getShadeList().isEmpty();
         } else {
             return mNotificationEntryManager.hasActiveNotifications();
@@ -1435,7 +1435,7 @@
 
     private void onAnimationEnd(List<ExpandableNotificationRow> viewsToRemove,
             @SelectedRows int selectedRows) {
-        if (mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
+        if (mNotifPipelineFlags.isNewPipelineEnabled()) {
             if (selectedRows == ROWS_ALL) {
                 mNotifCollection.dismissAllNotifications(
                         mLockscreenUserManager.getCurrentUserId());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
index eb7410c..1038e76 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
@@ -468,8 +468,8 @@
         final int height = (view instanceof ExpandableView)
                 ? ((ExpandableView) view).getActualHeight()
                 : view.getHeight();
-        final int rx = (int) ev.getX();
-        final int ry = (int) ev.getY();
+        final int rx = (int) ev.getRawX();
+        final int ry = (int) ev.getRawY();
         int[] temp = new int[2];
         view.getLocationOnScreen(temp);
         final int x = temp[0];
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
index fa32620..244103c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
@@ -31,7 +31,7 @@
 import com.android.systemui.qs.AutoAddTracker;
 import com.android.systemui.qs.QSTileHost;
 import com.android.systemui.qs.ReduceBrightColorsController;
-import com.android.systemui.qs.SecureSetting;
+import com.android.systemui.qs.SettingObserver;
 import com.android.systemui.qs.external.CustomTile;
 import com.android.systemui.statusbar.policy.CastController;
 import com.android.systemui.statusbar.policy.CastController.CastDevice;
@@ -383,8 +383,8 @@
     };
 
     @VisibleForTesting
-    protected SecureSetting getSecureSettingForKey(String key) {
-        for (SecureSetting s : mAutoAddSettingList) {
+    protected SettingObserver getSecureSettingForKey(String key) {
+        for (SettingObserver s : mAutoAddSettingList) {
             if (Objects.equals(key, s.getKey())) {
                 return s;
             }
@@ -398,7 +398,7 @@
      * When the setting changes to a value different from 0, if the tile has not been auto added
      * before, it will be added and the listener will be stopped.
      */
-    private class AutoAddSetting extends SecureSetting {
+    private class AutoAddSetting extends SettingObserver {
         private final String mSpec;
 
         AutoAddSetting(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
index 67f51cb..aa3b3e1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
@@ -20,6 +20,7 @@
 import android.content.Context;
 import android.content.res.Resources;
 import android.hardware.biometrics.BiometricSourceType;
+import android.hardware.fingerprint.FingerprintManager;
 import android.metrics.LogMaker;
 import android.os.Handler;
 import android.os.PowerManager;
@@ -46,9 +47,11 @@
 import com.android.systemui.keyguard.KeyguardViewMediator;
 import com.android.systemui.keyguard.ScreenLifecycle;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.NotificationMediaManager;
 import com.android.systemui.statusbar.NotificationShadeWindowController;
+import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 
 import java.io.FileDescriptor;
@@ -71,6 +74,7 @@
     private static final long BIOMETRIC_WAKELOCK_TIMEOUT_MS = 15 * 1000;
     private static final String BIOMETRIC_WAKE_LOCK_NAME = "wake-and-unlock:wakelock";
     private static final UiEventLogger UI_EVENT_LOGGER = new UiEventLoggerImpl();
+    private static final int FP_ATTEMPTS_BEFORE_SHOW_BOUNCER = 3;
 
     @IntDef(prefix = { "MODE_" }, value = {
             MODE_NONE,
@@ -167,6 +171,10 @@
 
     private final MetricsLogger mMetricsLogger;
     private final AuthController mAuthController;
+    private final StatusBarStateController mStatusBarStateController;
+
+    private long mLastFpFailureUptimeMillis;
+    private int mNumConsecutiveFpFailures;
 
     private static final class PendingAuthenticated {
         public final int userId;
@@ -209,7 +217,10 @@
         BIOMETRIC_IRIS_FAILURE(403),
 
         @UiEvent(doc = "A biometric event of type iris errored.")
-        BIOMETRIC_IRIS_ERROR(404);
+        BIOMETRIC_IRIS_ERROR(404),
+
+        @UiEvent(doc = "Bouncer was shown as a result of consecutive failed UDFPS attempts.")
+        BIOMETRIC_BOUNCER_SHOWN(916);
 
         private final int mId;
 
@@ -257,7 +268,8 @@
             NotificationMediaManager notificationMediaManager,
             WakefulnessLifecycle wakefulnessLifecycle,
             ScreenLifecycle screenLifecycle,
-            AuthController authController) {
+            AuthController authController,
+            StatusBarStateController statusBarStateController) {
         mContext = context;
         mPowerManager = powerManager;
         mShadeController = shadeController;
@@ -279,6 +291,7 @@
         mKeyguardBypassController.setUnlockController(this);
         mMetricsLogger = metricsLogger;
         mAuthController = authController;
+        mStatusBarStateController = statusBarStateController;
         dumpManager.registerDumpable(getClass().getName(), this);
     }
 
@@ -620,6 +633,22 @@
                 .setType(MetricsEvent.TYPE_FAILURE).setSubtype(toSubtype(biometricSourceType)));
         Optional.ofNullable(BiometricUiEvent.FAILURE_EVENT_BY_SOURCE_TYPE.get(biometricSourceType))
                 .ifPresent(UI_EVENT_LOGGER::log);
+
+        long currUptimeMillis = SystemClock.uptimeMillis();
+        if (currUptimeMillis - mLastFpFailureUptimeMillis < 2000) { // attempt within 2 seconds
+            mNumConsecutiveFpFailures += 1;
+        } else {
+            mNumConsecutiveFpFailures = 1;
+        }
+        mLastFpFailureUptimeMillis = currUptimeMillis;
+
+        if (biometricSourceType.equals(BiometricSourceType.FINGERPRINT)
+                && mUpdateMonitor.isUdfpsSupported()
+                && mNumConsecutiveFpFailures >= FP_ATTEMPTS_BEFORE_SHOW_BOUNCER) {
+            mKeyguardViewController.showBouncer(true);
+            UI_EVENT_LOGGER.log(BiometricUiEvent.BIOMETRIC_BOUNCER_SHOWN);
+            mNumConsecutiveFpFailures = 0;
+        }
         cleanup();
     }
 
@@ -631,6 +660,16 @@
                 .addTaggedData(MetricsEvent.FIELD_BIOMETRIC_AUTH_ERROR, msgId));
         Optional.ofNullable(BiometricUiEvent.ERROR_EVENT_BY_SOURCE_TYPE.get(biometricSourceType))
                 .ifPresent(UI_EVENT_LOGGER::log);
+
+        // if we're on the shade and we're locked out, immediately show the bouncer
+        if (biometricSourceType == BiometricSourceType.FINGERPRINT
+                && (msgId == FingerprintManager.FINGERPRINT_ERROR_LOCKOUT
+                || msgId == FingerprintManager.FINGERPRINT_ERROR_LOCKOUT_PERMANENT)
+                && mUpdateMonitor.isUdfpsSupported()
+                && (mStatusBarStateController.getState() == StatusBarState.SHADE
+                    || mStatusBarStateController.getState() == StatusBarState.SHADE_LOCKED)) {
+            mKeyguardViewController.showBouncer(true);
+        }
         cleanup();
     }
 
@@ -664,6 +703,8 @@
             mBiometricModeListener.onResetMode();
             mBiometricModeListener.notifyBiometricAuthModeChanged();
         }
+        mNumConsecutiveFpFailures = 0;
+        mLastFpFailureUptimeMillis = 0;
     }
 
     @VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
index 908cd34..ee51efb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
@@ -30,6 +30,7 @@
 import com.android.systemui.R;
 import com.android.systemui.demomode.DemoMode;
 import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
 import com.android.systemui.plugins.DarkIconDispatcher;
 import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
 import com.android.systemui.statusbar.StatusBarIconView;
@@ -255,7 +256,8 @@
     public void addMobileView(MobileIconState state) {
         Log.d(TAG, "addMobileView: ");
         StatusBarMobileView view = StatusBarMobileView.fromContext(
-                mContext, state.slot, mFeatureFlags.isCombinedStatusBarSignalIconsEnabled());
+                mContext, state.slot,
+                mFeatureFlags.isEnabled(Flags.COMBINED_STATUS_BAR_SIGNAL_ICONS));
 
         view.applyMobileState(state);
         view.setStaticDrawableColor(mColor);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
index 49e3fe7..14f7134 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
@@ -35,6 +35,7 @@
 import com.android.systemui.doze.DozeScreenState;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.DevicePostureController;
 import com.android.systemui.tuner.TunerService;
@@ -236,7 +237,7 @@
      */
     public boolean canControlUnlockedScreenOff() {
         return getAlwaysOn()
-                && mFeatureFlags.useNewLockscreenAnimations()
+                && mFeatureFlags.isEnabled(Flags.LOCKSCREEN_ANIMATIONS)
                 && !getDisplayNeedsBlanking();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index 353868b..9647486 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -21,6 +21,7 @@
 
 import android.content.Context;
 import android.content.res.ColorStateList;
+import android.hardware.biometrics.BiometricSourceType;
 import android.os.Handler;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -81,6 +82,13 @@
                 public void onStrongAuthStateChanged(int userId) {
                     mBouncerPromptReason = mCallback.getBouncerPromptReason();
                 }
+
+                @Override
+                public void onLockedOutStateChanged(BiometricSourceType type) {
+                    if (type == BiometricSourceType.FINGERPRINT) {
+                        mBouncerPromptReason = mCallback.getBouncerPromptReason();
+                    }
+                }
             };
     private final Runnable mRemoveViewRunnable = this::removeView;
     private final KeyguardBypassController mKeyguardBypassController;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
index 570b0ca..88ae0db 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
@@ -37,7 +37,6 @@
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.navigationbar.NavigationModeController;
 import com.android.systemui.plugins.DarkIconDispatcher;
-import com.android.systemui.shared.system.QuickStepContract;
 import com.android.systemui.statusbar.policy.BatteryController;
 
 import java.io.FileDescriptor;
@@ -251,7 +250,7 @@
 
     private void updateNavigation() {
         if (mNavigationBarController != null
-                && !QuickStepContract.isGesturalMode(mNavigationMode)) {
+                && mNavigationBarController.supportsIconTintForNavMode(mNavigationMode)) {
             mNavigationBarController.setIconsDark(mNavigationLight, animateChange());
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java
index 9021b74..415fb92 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java
@@ -28,6 +28,7 @@
 import com.android.systemui.Dumpable;
 import com.android.systemui.animation.Interpolators;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.shared.system.QuickStepContract;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.CommandQueue.Callbacks;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -230,6 +231,14 @@
     }
 
     /**
+     * Return whether to use the tint calculated in this class for nav icons.
+     */
+    public boolean supportsIconTintForNavMode(int navigationMode) {
+        // In gesture mode, we already do region sampling to update tint based on content beneath.
+        return !QuickStepContract.isGesturalMode(navigationMode);
+    }
+
+    /**
      * Interface to apply a specific dark intensity.
      */
     public interface DarkIntensityApplier {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitchController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitchController.java
index d69b31f..eb5db29 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitchController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitchController.java
@@ -24,6 +24,7 @@
 
 import com.android.systemui.R;
 import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
 import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.qs.DetailAdapter;
 import com.android.systemui.qs.FooterActionsView;
@@ -53,7 +54,7 @@
                 return;
             }
 
-            if (mFeatureFlags.useNewUserSwitcher()) {
+            if (mFeatureFlags.isEnabled(Flags.NEW_USER_SWITCHER)) {
                 mUserSwitchDialogController.showDialog(v);
             } else {
                 View center = mView.getChildCount() > 0 ? mView.getChildAt(0) : mView;
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 c4ec086..16aac4d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -126,6 +126,7 @@
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.doze.DozeLog;
 import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
 import com.android.systemui.fragments.FragmentHostManager.FragmentListener;
 import com.android.systemui.fragments.FragmentService;
 import com.android.systemui.idle.IdleHostView;
@@ -505,23 +506,11 @@
                     mPanelAlphaAnimator.getProperty(), Interpolators.ALPHA_IN);
     private final NotificationEntryManager mEntryManager;
 
-    private final CommunalSourceMonitor.Callback mCommunalSourceMonitorCallback =
-            new CommunalSourceMonitor.Callback() {
-                @Override
-                public void onSourceAvailable(WeakReference<CommunalSource> source) {
-                    setCommunalSource(source);
-                }
-            };
+    private final CommunalSourceMonitor.Callback mCommunalSourceMonitorCallback;
 
     private WeakReference<CommunalSource> mCommunalSource;
 
-    private final CommunalSource.Callback mCommunalSourceCallback =
-            new CommunalSource.Callback() {
-                @Override
-                public void onDisconnected() {
-                    setCommunalSource(null /*source*/);
-                }
-            };
+    private final CommunalSource.Callback mCommunalSourceCallback;
 
     private final CommandQueue mCommandQueue;
     private final NotificationLockscreenUserManager mLockscreenUserManager;
@@ -903,6 +892,15 @@
 
         mMaxKeyguardNotifications = resources.getInteger(R.integer.keyguard_max_notification_count);
         mKeyguardUnfoldTransition = unfoldComponent.map(c -> c.getKeyguardUnfoldTransition());
+
+        mCommunalSourceCallback = () -> {
+            mUiExecutor.execute(() -> setCommunalSource(null /*source*/));
+        };
+
+        mCommunalSourceMonitorCallback = (source) -> {
+            mUiExecutor.execute(() -> setCommunalSource(source));
+        };
+
         updateUserSwitcherFlags();
         onFinishInflate();
     }
@@ -4159,7 +4157,7 @@
                 com.android.internal.R.bool.config_keyguardUserSwitcher);
         mKeyguardQsUserSwitchEnabled =
                 mKeyguardUserSwitcherEnabled
-                        && mFeatureFlags.isKeyguardQsUserDetailsShortcutEnabled();
+                        && mFeatureFlags.isEnabled(Flags.QS_USER_DETAIL_SHORTCUT);
     }
 
     private void registerSettingsChangeListener() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SplitShadeHeaderController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SplitShadeHeaderController.kt
index c814622..fc549e2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SplitShadeHeaderController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SplitShadeHeaderController.kt
@@ -23,8 +23,10 @@
 import com.android.systemui.battery.BatteryMeterView
 import com.android.systemui.battery.BatteryMeterViewController
 import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
 import com.android.systemui.qs.carrier.QSCarrierGroupController
 import com.android.systemui.statusbar.phone.dagger.StatusBarComponent.StatusBarScope
+import com.android.systemui.statusbar.phone.dagger.StatusBarViewModule.SPLIT_SHADE_BATTERY_CONTROLLER
 import com.android.systemui.statusbar.phone.dagger.StatusBarViewModule.SPLIT_SHADE_HEADER
 import javax.inject.Inject
 import javax.inject.Named
@@ -35,7 +37,7 @@
     private val statusBarIconController: StatusBarIconController,
     qsCarrierGroupControllerBuilder: QSCarrierGroupController.Builder,
     featureFlags: FeatureFlags,
-    batteryMeterViewController: BatteryMeterViewController
+    @Named(SPLIT_SHADE_BATTERY_CONTROLLER) batteryMeterViewController: BatteryMeterViewController
 ) {
 
     companion object {
@@ -43,7 +45,7 @@
         private val SPLIT_HEADER_TRANSITION_ID = R.id.split_header_transition
     }
 
-    private val combinedHeaders = featureFlags.useCombinedQSHeaders()
+    private val combinedHeaders = featureFlags.isEnabled(Flags.COMBINED_QS_HEADERS)
     // TODO(b/194178072) Handle RSSI hiding when multi carrier
     private val iconManager: StatusBarIconController.IconManager
     private val qsCarrierGroupController: QSCarrierGroupController
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 2a54642..9e53378 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -148,8 +148,10 @@
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.emergency.EmergencyGesture;
 import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
 import com.android.systemui.fragments.ExtensionFragmentListener;
 import com.android.systemui.fragments.FragmentHostManager;
+import com.android.systemui.fragments.FragmentService;
 import com.android.systemui.keyguard.KeyguardService;
 import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
 import com.android.systemui.keyguard.KeyguardViewMediator;
@@ -490,7 +492,6 @@
     private final DozeParameters mDozeParameters;
     private final Lazy<BiometricUnlockController> mBiometricUnlockControllerLazy;
     private final StatusBarComponent.Factory mStatusBarComponentFactory;
-    private final StatusBarFragmentComponent.Factory mStatusBarFragmentComponentFactory;
     private final PluginManager mPluginManager;
     private final Optional<LegacySplitScreen> mSplitScreenOptional;
     private final StatusBarNotificationActivityStarter.Builder
@@ -507,6 +508,7 @@
     private final NotificationsController mNotificationsController;
     private final OngoingCallController mOngoingCallController;
     private final SystemStatusAnimationScheduler mAnimationScheduler;
+    private final StatusBarSignalPolicy mStatusBarSignalPolicy;
     private final StatusBarLocationPublisher mStatusBarLocationPublisher;
     private final StatusBarIconController mStatusBarIconController;
     private final StatusBarHideIconsForBouncerManager mStatusBarHideIconsForBouncerManager;
@@ -538,7 +540,7 @@
     protected final NotificationInterruptStateProvider mNotificationInterruptStateProvider;
     private final BrightnessSliderController.Factory mBrightnessSliderFactory;
     private final FeatureFlags mFeatureFlags;
-
+    private final FragmentService mFragmentService;
     private final WallpaperController mWallpaperController;
     private final KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
     private final MessageRouter mMessageRouter;
@@ -546,6 +548,8 @@
     private final UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
     private final TunerService mTunerService;
 
+    private StatusBarComponent mStatusBarComponent;
+
     // Flags for disabling the status bar
     // Two variables becaseu the first one evidently ran out of room for new flags.
     private int mDisabled1 = 0;
@@ -691,10 +695,12 @@
     public StatusBar(
             Context context,
             NotificationsController notificationsController,
+            FragmentService fragmentService,
             LightBarController lightBarController,
             AutoHideController autoHideController,
             StatusBarWindowController statusBarWindowController,
             KeyguardUpdateMonitor keyguardUpdateMonitor,
+            StatusBarSignalPolicy statusBarSignalPolicy,
             PulseExpansionHandler pulseExpansionHandler,
             NotificationWakeUpCoordinator notificationWakeUpCoordinator,
             KeyguardBypassController keyguardBypassController,
@@ -747,7 +753,6 @@
             CommandQueue commandQueue,
             CollapsedStatusBarFragmentLogger collapsedStatusBarFragmentLogger,
             StatusBarComponent.Factory statusBarComponentFactory,
-            StatusBarFragmentComponent.Factory statusBarFragmentComponentFactory,
             PluginManager pluginManager,
             Optional<LegacySplitScreen> splitScreenOptional,
             LightsOutNotifController lightsOutNotifController,
@@ -792,6 +797,7 @@
             NotifPipelineFlags notifPipelineFlags) {
         super(context);
         mNotificationsController = notificationsController;
+        mFragmentService = fragmentService;
         mLightBarController = lightBarController;
         mAutoHideController = autoHideController;
         mStatusBarWindowController = statusBarWindowController;
@@ -853,7 +859,6 @@
         mCommandQueue = commandQueue;
         mCollapsedStatusBarFragmentLogger = collapsedStatusBarFragmentLogger;
         mStatusBarComponentFactory = statusBarComponentFactory;
-        mStatusBarFragmentComponentFactory = statusBarFragmentComponentFactory;
         mPluginManager = pluginManager;
         mSplitScreenOptional = splitScreenOptional;
         mStatusBarNotificationActivityStarterBuilder = statusBarNotificationActivityStarterBuilder;
@@ -873,6 +878,7 @@
         mWallpaperController = wallpaperController;
         mOngoingCallController = ongoingCallController;
         mAnimationScheduler = animationScheduler;
+        mStatusBarSignalPolicy = statusBarSignalPolicy;
         mStatusBarLocationPublisher = locationPublisher;
         mStatusBarIconController = statusBarIconController;
         mStatusBarHideIconsForBouncerManager = statusBarHideIconsForBouncerManager;
@@ -927,6 +933,7 @@
             mBubblesOptional.get().setExpandListener(mBubbleExpandListener);
         }
 
+        mStatusBarSignalPolicy.init();
         mKeyguardIndicationController.init();
 
         mColorExtractor.addOnColorsChangedListener(mOnColorsChangedListener);
@@ -1184,24 +1191,7 @@
                 }).getFragmentManager()
                 .beginTransaction()
                 .replace(R.id.status_bar_container,
-                        new CollapsedStatusBarFragment(
-                                mStatusBarFragmentComponentFactory,
-                                mOngoingCallController,
-                                mAnimationScheduler,
-                                mStatusBarLocationPublisher,
-                                mNotificationIconAreaController,
-                                mPanelExpansionStateManager,
-                                mFeatureFlags,
-                                mStatusBarIconController,
-                                mStatusBarHideIconsForBouncerManager,
-                                mKeyguardStateController,
-                                mNetworkController,
-                                mStatusBarStateController,
-                                () -> Optional.of(this),
-                                mCommandQueue,
-                                mCollapsedStatusBarFragmentLogger,
-                                mOperatorNameViewControllerFactory
-                        ),
+                        mStatusBarComponent.createCollapsedStatusBarFragment(),
                         CollapsedStatusBarFragment.TAG)
                 .commit();
 
@@ -1460,7 +1450,6 @@
                 mDynamicPrivacyController,
                 mKeyguardStateController,
                 mKeyguardIndicationController,
-                mFeatureFlags,
                 this /* statusBar */,
                 mShadeController,
                 mLockscreenShadeTransitionController,
@@ -1558,32 +1547,34 @@
     }
 
     private void inflateStatusBarWindow() {
-        StatusBarComponent statusBarComponent = mStatusBarComponentFactory.create();
-        mNotificationShadeWindowView = statusBarComponent.getNotificationShadeWindowView();
-        mNotificationShadeWindowViewController = statusBarComponent
+        mStatusBarComponent = mStatusBarComponentFactory.create();
+        mFragmentService.addFragmentInstantiationProvider(mStatusBarComponent);
+
+        mNotificationShadeWindowView = mStatusBarComponent.getNotificationShadeWindowView();
+        mNotificationShadeWindowViewController = mStatusBarComponent
                 .getNotificationShadeWindowViewController();
         mNotificationShadeWindowController.setNotificationShadeView(mNotificationShadeWindowView);
         mNotificationShadeWindowViewController.setupExpandedStatusBar();
-        mNotificationPanelViewController = statusBarComponent.getNotificationPanelViewController();
-        statusBarComponent.getLockIconViewController().init();
-        mStackScrollerController = statusBarComponent.getNotificationStackScrollLayoutController();
+        mNotificationPanelViewController = mStatusBarComponent.getNotificationPanelViewController();
+        mStatusBarComponent.getLockIconViewController().init();
+        mStackScrollerController = mStatusBarComponent.getNotificationStackScrollLayoutController();
         mStackScroller = mStackScrollerController.getView();
 
-        mNotificationShelfController = statusBarComponent.getNotificationShelfController();
-        mAuthRippleController = statusBarComponent.getAuthRippleController();
+        mNotificationShelfController = mStatusBarComponent.getNotificationShelfController();
+        mAuthRippleController = mStatusBarComponent.getAuthRippleController();
         mAuthRippleController.init();
 
-        mHeadsUpManager.addListener(statusBarComponent.getStatusBarHeadsUpChangeListener());
+        mHeadsUpManager.addListener(mStatusBarComponent.getStatusBarHeadsUpChangeListener());
 
-        mHeadsUpManager.addListener(statusBarComponent.getStatusBarHeadsUpChangeListener());
+        mHeadsUpManager.addListener(mStatusBarComponent.getStatusBarHeadsUpChangeListener());
 
         // Listen for demo mode changes
-        mDemoModeController.addCallback(statusBarComponent.getStatusBarDemoMode());
+        mDemoModeController.addCallback(mStatusBarComponent.getStatusBarDemoMode());
 
         if (mCommandQueueCallbacks != null) {
             mCommandQueue.removeCallback(mCommandQueueCallbacks);
         }
-        mCommandQueueCallbacks = statusBarComponent.getStatusBarCommandQueueCallbacks();
+        mCommandQueueCallbacks = mStatusBarComponent.getStatusBarCommandQueueCallbacks();
         // Connect in to the status bar manager service
         mCommandQueue.addCallback(mCommandQueueCallbacks);
     }
@@ -2001,7 +1992,7 @@
         }
     }
 
-    public void maybeEscalateHeadsUp() {
+    private void maybeEscalateHeadsUp() {
         mHeadsUpManager.getAllEntries().forEach(entry -> {
             final StatusBarNotification sbn = entry.getSbn();
             final Notification notification = sbn.getNotification();
@@ -2012,6 +2003,7 @@
                 try {
                     EventLog.writeEvent(EventLogTags.SYSUI_HEADS_UP_ESCALATION,
                             sbn.getKey());
+                    wakeUpForFullScreenIntent();
                     notification.fullScreenIntent.send();
                     entry.notifyFullScreenIntentLaunched();
                 } catch (PendingIntent.CanceledException e) {
@@ -2021,6 +2013,17 @@
         mHeadsUpManager.releaseAllImmediately();
     }
 
+    void wakeUpForFullScreenIntent() {
+        if (isGoingToSleep() || mDozing) {
+            mPowerManager.wakeUp(
+                    SystemClock.uptimeMillis(),
+                    PowerManager.WAKE_REASON_APPLICATION,
+                    "com.android.systemui:full_screen_intent");
+            mWakeUpComingFromTouch = false;
+            mWakeUpTouchLocation = null;
+        }
+    }
+
     void makeExpandedVisible(boolean force) {
         if (SPEW) Log.d(TAG, "Make expanded visible: expanded visible=" + mExpandedVisible);
         if (!force && (mExpandedVisible || !mCommandQueue.panelsEnabled())) {
@@ -3550,7 +3553,7 @@
             DejankUtils.startDetectingBlockingIpcs(tag);
             updateRevealEffect(false /* wakingUp */);
             updateNotificationPanelTouchState();
-            notifyHeadsUpGoingToSleep();
+            maybeEscalateHeadsUp();
             dismissVolumeDialog();
             mWakeUpCoordinator.setFullyAwake(false);
             mBypassHeadsUpNotifier.setFullyAwake(false);
@@ -4095,10 +4098,6 @@
         }
     }
 
-    protected void notifyHeadsUpGoingToSleep() {
-        maybeEscalateHeadsUp();
-    }
-
     /**
      * @return Whether the security bouncer from Keyguard is showing.
      */
@@ -4284,7 +4283,7 @@
                 Log.v(TAG, "configuration changed: " + mContext.getResources().getConfiguration());
             }
 
-            if (!mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
+            if (!mNotifPipelineFlags.isNewPipelineEnabled()) {
                 mViewHierarchyManager.updateRowStates();
             }
             mScreenPinningRequest.onConfigurationChanged();
@@ -4368,7 +4367,7 @@
 
                 @Override
                 public void onDozeAmountChanged(float linear, float eased) {
-                    if (mFeatureFlags.useNewLockscreenAnimations()
+                    if (mFeatureFlags.isEnabled(Flags.LOCKSCREEN_ANIMATIONS)
                             && !(mLightRevealScrim.getRevealEffect() instanceof CircleReveal)
                             && !mBiometricUnlockController.isWakeAndUnlock()) {
                         mLightRevealScrim.setRevealAmount(1f - linear);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacks.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacks.java
index a77a097..ae3b7ee 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacks.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacks.java
@@ -30,11 +30,11 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.Resources;
-import android.media.AudioAttributes;
 import android.os.Bundle;
 import android.os.PowerManager;
 import android.os.SystemClock;
 import android.os.UserHandle;
+import android.os.VibrationAttributes;
 import android.os.VibrationEffect;
 import android.os.Vibrator;
 import android.util.Log;
@@ -106,10 +106,8 @@
     private final VibrationEffect mCameraLaunchGestureVibrationEffect;
 
 
-    private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder()
-            .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
-            .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
-            .build();
+    private static final VibrationAttributes HARDWARE_FEEDBACK_VIBRATION_ATTRIBUTES =
+            VibrationAttributes.createForUsage(VibrationAttributes.USAGE_HARDWARE_FEEDBACK);
 
     @Inject
     StatusBarCommandQueueCallbacks(
@@ -611,9 +609,9 @@
     }
 
     private void vibrateForCameraGesture() {
-        // Make sure to pass -1 for repeat so VibratorService doesn't stop us when going to sleep.
         mVibratorOptional.ifPresent(
-                v -> v.vibrate(mCameraLaunchGestureVibrationEffect, VIBRATION_ATTRIBUTES));
+                v -> v.vibrate(mCameraLaunchGestureVibrationEffect,
+                        HARDWARE_FEEDBACK_VIBRATION_ATTRIBUTES));
     }
 
     private static VibrationEffect getCameraGestureVibrationEffect(
@@ -627,6 +625,8 @@
                     .compose();
         }
         if (vibratorOptional.isPresent() && vibratorOptional.get().hasAmplitudeControl()) {
+            // Make sure to pass -1 for repeat so VibratorManagerService doesn't stop us when going
+            // to sleep.
             return VibrationEffect.createWaveform(
                     StatusBar.CAMERA_LAUNCH_GESTURE_VIBRATION_TIMINGS,
                     StatusBar.CAMERA_LAUNCH_GESTURE_VIBRATION_AMPLITUDES,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
index 48fe774..81fb903 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
@@ -38,6 +38,7 @@
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.demomode.DemoModeCommandReceiver;
 import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
 import com.android.systemui.plugins.DarkIconDispatcher;
 import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
 import com.android.systemui.statusbar.StatusBarIconView;
@@ -353,7 +354,8 @@
 
         private StatusBarMobileView onCreateStatusBarMobileView(String slot) {
             StatusBarMobileView view = StatusBarMobileView.fromContext(
-                            mContext, slot, mFeatureFlags.isCombinedStatusBarSignalIconsEnabled());
+                            mContext, slot,
+                    mFeatureFlags.isEnabled(Flags.COMBINED_STATUS_BAR_SIGNAL_ICONS));
             return view;
         }
 
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 7ab4a1e..0d23d66 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -441,6 +441,8 @@
      * dragging it and translation should be deferred {@see KeyguardBouncer#show(boolean, boolean)}
      */
     public void showBouncer(boolean scrimmed) {
+        resetAlternateAuth(false);
+
         if (mShowing && !mBouncer.isShowing()) {
             mBouncer.show(false /* resetSecuritySelection */, scrimmed);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
index c2e790f..863ce57 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
@@ -41,6 +41,8 @@
 import android.util.EventLog;
 import android.view.View;
 
+import androidx.annotation.VisibleForTesting;
+
 import com.android.internal.jank.InteractionJankMonitor;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.statusbar.NotificationVisibility;
@@ -52,7 +54,6 @@
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dagger.qualifiers.UiBackground;
-import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.CommandQueue;
@@ -60,6 +61,7 @@
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationPresenter;
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
+import com.android.systemui.statusbar.notification.NotifPipelineFlags;
 import com.android.systemui.statusbar.notification.NotificationActivityStarter;
 import com.android.systemui.statusbar.notification.NotificationEntryListener;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
@@ -117,7 +119,7 @@
     private final StatusBarRemoteInputCallback mStatusBarRemoteInputCallback;
     private final ActivityIntentHelper mActivityIntentHelper;
 
-    private final FeatureFlags mFeatureFlags;
+    private final NotifPipelineFlags mNotifPipelineFlags;
     private final MetricsLogger mMetricsLogger;
     private final StatusBarNotificationActivityStarterLogger mLogger;
 
@@ -156,12 +158,10 @@
             LockPatternUtils lockPatternUtils,
             StatusBarRemoteInputCallback remoteInputCallback,
             ActivityIntentHelper activityIntentHelper,
-
-            FeatureFlags featureFlags,
+            NotifPipelineFlags notifPipelineFlags,
             MetricsLogger metricsLogger,
             StatusBarNotificationActivityStarterLogger logger,
             OnUserInteractionCallback onUserInteractionCallback,
-
             StatusBar statusBar,
             NotificationPresenter presenter,
             NotificationPanelViewController panel,
@@ -193,7 +193,7 @@
         mStatusBarRemoteInputCallback = remoteInputCallback;
         mActivityIntentHelper = activityIntentHelper;
 
-        mFeatureFlags = featureFlags;
+        mNotifPipelineFlags = notifPipelineFlags;
         mMetricsLogger = metricsLogger;
         mLogger = logger;
         mOnUserInteractionCallback = onUserInteractionCallback;
@@ -205,7 +205,7 @@
         mActivityLaunchAnimator = activityLaunchAnimator;
         mNotificationAnimationProvider = notificationAnimationProvider;
 
-        if (!mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
+        if (!mNotifPipelineFlags.isNewPipelineEnabled()) {
             mEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
                 @Override
                 public void onPendingEntryAdded(NotificationEntry entry) {
@@ -590,7 +590,8 @@
         }
     }
 
-    private void handleFullScreenIntent(NotificationEntry entry) {
+    @VisibleForTesting
+    void handleFullScreenIntent(NotificationEntry entry) {
         if (mNotificationInterruptStateProvider.shouldLaunchFullScreenIntentWhenAdded(entry)) {
             if (shouldSuppressFullScreenIntent(entry)) {
                 mLogger.logFullScreenIntentSuppressedByDnD(entry.getKey());
@@ -614,6 +615,7 @@
                 try {
                     EventLog.writeEvent(EventLogTags.SYSUI_FULLSCREEN_NOTIFICATION,
                             entry.getKey());
+                    mStatusBar.wakeUpForFullScreenIntent();
                     fullscreenIntent.send();
                     entry.notifyFullScreenIntentLaunched();
                     mMetricsLogger.count("note_fullscreen", 1);
@@ -659,7 +661,7 @@
     // --------------------- NotificationEntryManager/NotifPipeline methods ------------------------
 
     private int getVisibleNotificationsCount() {
-        if (mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
+        if (mNotifPipelineFlags.isNewPipelineEnabled()) {
             return mNotifPipeline.getShadeListCount();
         } else {
             return mEntryManager.getActiveNotificationsCount();
@@ -696,13 +698,11 @@
         private final NotificationInterruptStateProvider mNotificationInterruptStateProvider;
         private final LockPatternUtils mLockPatternUtils;
         private final StatusBarRemoteInputCallback mRemoteInputCallback;
-        private final ActivityIntentHelper mActivityIntentHelper;
-
-        private final FeatureFlags mFeatureFlags;
+        private final ActivityIntentHelper mActivityIntentHelper;;
         private final MetricsLogger mMetricsLogger;
         private final StatusBarNotificationActivityStarterLogger mLogger;
         private final OnUserInteractionCallback mOnUserInteractionCallback;
-
+        private final NotifPipelineFlags mNotifPipelineFlags;
         private StatusBar mStatusBar;
         private NotificationPresenter mNotificationPresenter;
         private NotificationPanelViewController mNotificationPanelViewController;
@@ -736,8 +736,7 @@
                 LockPatternUtils lockPatternUtils,
                 StatusBarRemoteInputCallback remoteInputCallback,
                 ActivityIntentHelper activityIntentHelper,
-
-                FeatureFlags featureFlags,
+                NotifPipelineFlags notifPipelineFlags,
                 MetricsLogger metricsLogger,
                 StatusBarNotificationActivityStarterLogger logger,
                 OnUserInteractionCallback onUserInteractionCallback) {
@@ -767,8 +766,7 @@
             mLockPatternUtils = lockPatternUtils;
             mRemoteInputCallback = remoteInputCallback;
             mActivityIntentHelper = activityIntentHelper;
-
-            mFeatureFlags = featureFlags;
+            mNotifPipelineFlags = notifPipelineFlags;
             mMetricsLogger = metricsLogger;
             mLogger = logger;
             mOnUserInteractionCallback = onUserInteractionCallback;
@@ -832,7 +830,7 @@
                     mLockPatternUtils,
                     mRemoteInputCallback,
                     mActivityIntentHelper,
-                    mFeatureFlags,
+                    mNotifPipelineFlags,
                     mMetricsLogger,
                     mLogger,
                     mOnUserInteractionCallback,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
index 58a018c..9682c60 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
@@ -41,7 +41,6 @@
 import com.android.systemui.ForegroundServiceNotificationListener;
 import com.android.systemui.InitController;
 import com.android.systemui.R;
-import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
 import com.android.systemui.statusbar.CommandQueue;
@@ -100,7 +99,6 @@
     private final DozeScrimController mDozeScrimController;
     private final ScrimController mScrimController;
     private final KeyguardIndicationController mKeyguardIndicationController;
-    private final FeatureFlags mFeatureFlags;
     private final StatusBar mStatusBar;
     private final ShadeController mShadeController;
     private final LockscreenShadeTransitionController mShadeTransitionController;
@@ -129,7 +127,6 @@
             DynamicPrivacyController dynamicPrivacyController,
             KeyguardStateController keyguardStateController,
             KeyguardIndicationController keyguardIndicationController,
-            FeatureFlags featureFlags,
             StatusBar statusBar,
             ShadeController shadeController,
             LockscreenShadeTransitionController shadeTransitionController,
@@ -153,7 +150,6 @@
         mHeadsUpManager = headsUp;
         mDynamicPrivacyController = dynamicPrivacyController;
         mKeyguardIndicationController = keyguardIndicationController;
-        mFeatureFlags = featureFlags;
         // TODO: use KeyguardStateController#isOccluded to remove this dependency
         mStatusBar = statusBar;
         mShadeController = shadeController;
@@ -199,7 +195,7 @@
                     stackScrollerController.getNotificationListContainer());
             mNotifShadeEventSource.setShadeEmptiedCallback(this::maybeClosePanelForShadeEmptied);
             mNotifShadeEventSource.setNotifRemovedByUserCallback(this::maybeEndAmbientPulse);
-            if (!mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
+            if (!mNotifPipelineFlags.isNewPipelineEnabled()) {
                 mEntryManager.setUpWithPresenter(this);
                 mEntryManager.addNotificationLifetimeExtender(mHeadsUpManager);
                 mEntryManager.addNotificationLifetimeExtender(mGutsManager);
@@ -236,7 +232,7 @@
     @Override
     public void onDensityOrFontScaleChanged() {
         // TODO(b/145659174): Remove legacy pipeline code
-        if (mFeatureFlags.isNewNotifPipelineRenderingEnabled()) return;
+        if (mNotifPipelineFlags.isNewPipelineEnabled()) return;
         MessagingMessage.dropCache();
         MessagingGroup.dropCache();
         if (!mKeyguardUpdateMonitor.isSwitchingUser()) {
@@ -249,7 +245,7 @@
     @Override
     public void onUiModeChanged() {
         // TODO(b/145659174): Remove legacy pipeline code
-        if (mFeatureFlags.isNewNotifPipelineRenderingEnabled()) return;
+        if (mNotifPipelineFlags.isNewPipelineEnabled()) return;
         if (!mKeyguardUpdateMonitor.isSwitchingUser()) {
             updateNotificationsOnUiModeChanged();
         } else {
@@ -264,7 +260,7 @@
 
     private void updateNotificationsOnUiModeChanged() {
         // TODO(b/145659174): Remove legacy pipeline code
-        if (mFeatureFlags.isNewNotifPipelineRenderingEnabled()) return;
+        if (mNotifPipelineFlags.isNewPipelineEnabled()) return;
         List<NotificationEntry> userNotifications =
                 mEntryManager.getActiveNotificationsForCurrentUser();
         for (int i = 0; i < userNotifications.size(); i++) {
@@ -278,7 +274,7 @@
 
     private void updateNotificationsOnDensityOrFontScaleChanged() {
         // TODO(b/145659174): Remove legacy pipeline code
-        if (mFeatureFlags.isNewNotifPipelineRenderingEnabled()) return;
+        if (mNotifPipelineFlags.isNewPipelineEnabled()) return;
         List<NotificationEntry> userNotifications =
                 mEntryManager.getActiveNotificationsForCurrentUser();
         for (int i = 0; i < userNotifications.size(); i++) {
@@ -332,7 +328,7 @@
         // End old BaseStatusBar.userSwitched
         if (MULTIUSER_DEBUG) mNotificationPanel.setHeaderDebugInfo("USER " + newUserId);
         mCommandQueue.animateCollapsePanels();
-        if (!mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
+        if (!mNotifPipelineFlags.isNewPipelineEnabled()) {
             if (mReinflateNotificationsOnUserSwitched) {
                 updateNotificationsOnDensityOrFontScaleChanged();
                 mReinflateNotificationsOnUserSwitched = false;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
index 9c69f51..b0206f0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
@@ -27,6 +27,7 @@
 import com.android.systemui.R;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
 import com.android.systemui.statusbar.connectivity.IconState;
 import com.android.systemui.statusbar.connectivity.MobileDataIndicators;
 import com.android.systemui.statusbar.connectivity.NetworkController;
@@ -72,17 +73,15 @@
     private boolean mHideWifi;
     private boolean mHideEthernet;
     private boolean mActivityEnabled;
-    private boolean mForceHideWifi;
 
     // Track as little state as possible, and only for padding purposes
     private boolean mIsAirplaneMode = false;
     private boolean mIsWifiEnabled = false;
-    private boolean mWifiVisible = false;
 
-    private ArrayList<MobileIconState> mMobileStates = new ArrayList<MobileIconState>();
-    private ArrayList<CallIndicatorIconState> mCallIndicatorStates =
-            new ArrayList<CallIndicatorIconState>();
+    private ArrayList<MobileIconState> mMobileStates = new ArrayList<>();
+    private ArrayList<CallIndicatorIconState> mCallIndicatorStates = new ArrayList<>();
     private WifiIconState mWifiIconState = new WifiIconState();
+    private boolean mInitialized;
 
     @Inject
     public StatusBarSignalPolicy(
@@ -112,9 +111,15 @@
         mSlotCallStrength =
                 mContext.getString(com.android.internal.R.string.status_bar_call_strength);
         mActivityEnabled = mContext.getResources().getBoolean(R.bool.config_showActivity);
+    }
 
-
-        tunerService.addTunable(this, StatusBarIconController.ICON_HIDE_LIST);
+    /** Call to initilaize and register this classw with the system. */
+    public void init() {
+        if (mInitialized) {
+            return;
+        }
+        mInitialized = true;
+        mTunerService.addTunable(this, StatusBarIconController.ICON_HIDE_LIST);
         mNetworkController.addCallback(this);
         mSecurityController.addCallback(this);
     }
@@ -162,7 +167,7 @@
             mHideAirplane = hideAirplane;
             mHideMobile = hideMobile;
             mHideEthernet = hideEthernet;
-            mHideWifi = hideWifi || mForceHideWifi;
+            mHideWifi = hideWifi;
             // Re-register to get new callbacks.
             mNetworkController.removeCallback(this);
             mNetworkController.addCallback(this);
@@ -375,7 +380,7 @@
     @Override
     public void setConnectivityStatus(boolean noDefaultNetwork, boolean noValidatedNetwork,
             boolean noNetworksAvailable) {
-        if (!mFeatureFlags.isCombinedStatusBarSignalIconsEnabled()) {
+        if (!mFeatureFlags.isEnabled(Flags.COMBINED_STATUS_BAR_SIGNAL_ICONS)) {
             return;
         }
         if (DEBUG) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
index cf4aaba..ed52a81 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
@@ -36,6 +36,8 @@
 import android.view.WindowManager;
 import android.view.WindowManager.LayoutParams;
 
+import androidx.annotation.Nullable;
+
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.animation.DialogListener;
@@ -218,6 +220,19 @@
         }
     }
 
+    /**
+     * Dismiss this dialog. If it was launched from another dialog using
+     * {@link com.android.systemui.animation.DialogLaunchAnimator#showFromView} with a
+     * non-{@code null} {@code parentHostDialog} parameter, also dismisses the stack of dialogs,
+     * animating back to the original touchSurface.
+     */
+    public void dismissStack() {
+        for (DialogListener listener : new LinkedHashSet<>(mDialogListeners)) {
+            listener.prepareForStackDismiss();
+        }
+        dismiss();
+    }
+
     @Override
     public void hide() {
         super.hide();
@@ -290,13 +305,32 @@
      * the screen off / close system dialogs broadcast.
      * <p>
      * <strong>Note:</strong> Don't call dialog.setOnDismissListener() after
-     * calling this because it causes a leak of BroadcastReceiver.
+     * calling this because it causes a leak of BroadcastReceiver. Instead, call the version that
+     * takes an extra Runnable as a parameter.
      *
      * @param dialog The dialog to be associated with the listener.
      */
     public static void registerDismissListener(Dialog dialog) {
+        registerDismissListener(dialog, null);
+    }
+
+
+    /**
+     * Registers a listener that dismisses the given dialog when it receives
+     * the screen off / close system dialogs broadcast.
+     * <p>
+     * <strong>Note:</strong> Don't call dialog.setOnDismissListener() after
+     * calling this because it causes a leak of BroadcastReceiver.
+     *
+     * @param dialog The dialog to be associated with the listener.
+     * @param dismissAction An action to run when the dialog is dismissed.
+     */
+    public static void registerDismissListener(Dialog dialog, @Nullable Runnable dismissAction) {
         DismissReceiver dismissReceiver = new DismissReceiver(dialog);
-        dialog.setOnDismissListener(d -> dismissReceiver.unregister());
+        dialog.setOnDismissListener(d -> {
+            dismissReceiver.unregister();
+            if (dismissAction != null) dismissAction.run();
+        });
         dismissReceiver.register();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarComponent.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarComponent.java
index e06605e..375641f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarComponent.java
@@ -29,6 +29,7 @@
 import com.android.systemui.statusbar.phone.StatusBarCommandQueueCallbacks;
 import com.android.systemui.statusbar.phone.StatusBarDemoMode;
 import com.android.systemui.statusbar.phone.StatusBarHeadsUpChangeListener;
+import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment;
 
 import java.lang.annotation.Documented;
 import java.lang.annotation.Retention;
@@ -38,7 +39,13 @@
 import dagger.Subcomponent;
 
 /**
- * Dagger subcomponent tied to the lifecycle of StatusBar views.
+ * Dagger subcomponent for classes (semi-)related to the status bar. The component is created once
+ * inside {@link com.android.systemui.statusbar.phone.StatusBar} and never re-created.
+ *
+ * TODO(b/197137564): This should likely be re-factored a bit. It includes classes that aren't
+ * directly related to status bar functionality, like multiple notification classes. And, the fact
+ * that it has many getter methods indicates that we need to access many of these classes from
+ * outside the component. Should more items be moved *into* this component to avoid so many getters?
  */
 @Subcomponent(modules = {StatusBarViewModule.class})
 @StatusBarComponent.StatusBarScope
@@ -121,4 +128,10 @@
      */
     @StatusBarScope
     SplitShadeHeaderController getSplitShadeHeaderController();
+
+    /**
+     * Creates a new {@link CollapsedStatusBarFragment} each time it's called. See
+     * {@link StatusBarViewModule#createCollapsedStatusBarFragment}.
+     */
+    CollapsedStatusBarFragment createCollapsedStatusBarFragment();
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
index 1c3229f..b3f59b4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
@@ -39,6 +39,7 @@
 import com.android.systemui.demomode.DemoModeController;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.fragments.FragmentService;
 import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
 import com.android.systemui.keyguard.KeyguardViewMediator;
 import com.android.systemui.keyguard.ScreenLifecycle;
@@ -97,10 +98,10 @@
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
 import com.android.systemui.statusbar.phone.StatusBarLocationPublisher;
 import com.android.systemui.statusbar.phone.StatusBarNotificationActivityStarter;
+import com.android.systemui.statusbar.phone.StatusBarSignalPolicy;
 import com.android.systemui.statusbar.phone.StatusBarTouchableRegionManager;
 import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController;
 import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragmentLogger;
-import com.android.systemui.statusbar.phone.fragment.dagger.StatusBarFragmentComponent;
 import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController;
 import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
 import com.android.systemui.statusbar.policy.BatteryController;
@@ -143,10 +144,12 @@
     static StatusBar provideStatusBar(
             Context context,
             NotificationsController notificationsController,
+            FragmentService fragmentService,
             LightBarController lightBarController,
             AutoHideController autoHideController,
             StatusBarWindowController statusBarWindowController,
             KeyguardUpdateMonitor keyguardUpdateMonitor,
+            StatusBarSignalPolicy statusBarSignalPolicy,
             PulseExpansionHandler pulseExpansionHandler,
             NotificationWakeUpCoordinator notificationWakeUpCoordinator,
             KeyguardBypassController keyguardBypassController,
@@ -199,7 +202,6 @@
             CommandQueue commandQueue,
             CollapsedStatusBarFragmentLogger collapsedStatusBarFragmentLogger,
             StatusBarComponent.Factory statusBarComponentFactory,
-            StatusBarFragmentComponent.Factory statusBarFragmentComponentFactory,
             PluginManager pluginManager,
             Optional<LegacySplitScreen> splitScreenOptional,
             LightsOutNotifController lightsOutNotifController,
@@ -245,10 +247,12 @@
         return new StatusBar(
                 context,
                 notificationsController,
+                fragmentService,
                 lightBarController,
                 autoHideController,
                 statusBarWindowController,
                 keyguardUpdateMonitor,
+                statusBarSignalPolicy,
                 pulseExpansionHandler,
                 notificationWakeUpCoordinator,
                 keyguardBypassController,
@@ -301,7 +305,6 @@
                 commandQueue,
                 collapsedStatusBarFragmentLogger,
                 statusBarComponentFactory,
-                statusBarFragmentComponentFactory,
                 pluginManager,
                 splitScreenOptional,
                 lightsOutNotifController,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java
index 2765fe3..8f11819 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java
@@ -17,6 +17,8 @@
 package com.android.systemui.statusbar.phone.dagger;
 
 import android.annotation.Nullable;
+import android.content.ContentResolver;
+import android.os.Handler;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewStub;
@@ -24,19 +26,46 @@
 import com.android.keyguard.LockIconView;
 import com.android.systemui.R;
 import com.android.systemui.battery.BatteryMeterView;
+import com.android.systemui.battery.BatteryMeterViewController;
 import com.android.systemui.biometrics.AuthRippleView;
+import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.NotificationShelf;
 import com.android.systemui.statusbar.NotificationShelfController;
+import com.android.systemui.statusbar.OperatorNameViewController;
+import com.android.systemui.statusbar.connectivity.NetworkController;
+import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
 import com.android.systemui.statusbar.notification.row.dagger.NotificationShelfComponent;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
+import com.android.systemui.statusbar.phone.NotificationIconAreaController;
 import com.android.systemui.statusbar.phone.NotificationPanelView;
+import com.android.systemui.statusbar.phone.NotificationPanelViewController;
 import com.android.systemui.statusbar.phone.NotificationShadeWindowView;
 import com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer;
+import com.android.systemui.statusbar.phone.StatusBar;
+import com.android.systemui.statusbar.phone.StatusBarHideIconsForBouncerManager;
+import com.android.systemui.statusbar.phone.StatusBarIconController;
+import com.android.systemui.statusbar.phone.StatusBarLocationPublisher;
 import com.android.systemui.statusbar.phone.TapAgainView;
+import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment;
+import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragmentLogger;
+import com.android.systemui.statusbar.phone.fragment.dagger.StatusBarFragmentComponent;
+import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController;
+import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
+import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.tuner.TunerService;
+
+import java.util.Optional;
 
 import javax.inject.Named;
 
+import dagger.Lazy;
 import dagger.Module;
 import dagger.Provides;
 
@@ -44,6 +73,8 @@
 public abstract class StatusBarViewModule {
 
     public static final String SPLIT_SHADE_HEADER = "split_shade_header";
+    private static final String SPLIT_SHADE_BATTERY_VIEW = "split_shade_battery_view";
+    public static final String SPLIT_SHADE_BATTERY_CONTROLLER = "split_shade_battery_controller";
 
     /** */
     @Provides
@@ -132,7 +163,7 @@
             NotificationShadeWindowView notificationShadeWindowView,
             FeatureFlags featureFlags) {
         ViewStub stub = notificationShadeWindowView.findViewById(R.id.qs_header_stub);
-        int layoutId = featureFlags.useCombinedQSHeaders()
+        int layoutId = featureFlags.isEnabled(Flags.COMBINED_QS_HEADERS)
                 ? R.layout.combined_qs_header
                 : R.layout.split_shade_header;
         stub.setLayoutResource(layoutId);
@@ -143,10 +174,34 @@
     /** */
     @Provides
     @StatusBarComponent.StatusBarScope
+    @Named(SPLIT_SHADE_BATTERY_VIEW)
     static BatteryMeterView getBatteryMeterView(@Named(SPLIT_SHADE_HEADER) View view) {
         return view.findViewById(R.id.batteryRemainingIcon);
     }
 
+    @Provides
+    @StatusBarComponent.StatusBarScope
+    @Named(SPLIT_SHADE_BATTERY_CONTROLLER)
+    static BatteryMeterViewController getBatteryMeterViewController(
+            @Named(SPLIT_SHADE_BATTERY_VIEW) BatteryMeterView batteryMeterView,
+            ConfigurationController configurationController,
+            TunerService tunerService,
+            BroadcastDispatcher broadcastDispatcher,
+            @Main Handler mainHandler,
+            ContentResolver contentResolver,
+            BatteryController batteryController
+    ) {
+        return new BatteryMeterViewController(
+                batteryMeterView,
+                configurationController,
+                tunerService,
+                broadcastDispatcher,
+                mainHandler,
+                contentResolver,
+                batteryController);
+
+    }
+
     /** */
     @Provides
     @StatusBarComponent.StatusBarScope
@@ -161,4 +216,54 @@
             NotificationShadeWindowView notificationShadeWindowView) {
         return notificationShadeWindowView.findViewById(R.id.notification_container_parent);
     }
+
+    /**
+     * Creates a new {@link CollapsedStatusBarFragment}.
+     *
+     * **IMPORTANT**: This method intentionally does not have
+     * {@link StatusBarComponent.StatusBarScope}, which means a new fragment *will* be created each
+     * time this method is called. This is intentional because we need fragments to re-created in
+     * certain lifecycle scenarios.
+     *
+     * **IMPORTANT**: This method also intentionally does not have a {@link Provides} annotation. If
+     * you need to get access to a {@link CollapsedStatusBarFragment}, go through
+     * {@link StatusBarFragmentComponent} instead.
+     */
+    public static CollapsedStatusBarFragment createCollapsedStatusBarFragment(
+            StatusBarFragmentComponent.Factory statusBarFragmentComponentFactory,
+            OngoingCallController ongoingCallController,
+            SystemStatusAnimationScheduler animationScheduler,
+            StatusBarLocationPublisher locationPublisher,
+            NotificationIconAreaController notificationIconAreaController,
+            PanelExpansionStateManager panelExpansionStateManager,
+            FeatureFlags featureFlags,
+            StatusBarIconController statusBarIconController,
+            StatusBarHideIconsForBouncerManager statusBarHideIconsForBouncerManager,
+            KeyguardStateController keyguardStateController,
+            NotificationPanelViewController notificationPanelViewController,
+            NetworkController networkController,
+            StatusBarStateController statusBarStateController,
+            Lazy<Optional<StatusBar>> statusBarOptionalLazy,
+            CommandQueue commandQueue,
+            CollapsedStatusBarFragmentLogger collapsedStatusBarFragmentLogger,
+            OperatorNameViewController.Factory operatorNameViewControllerFactory
+    ) {
+        return new CollapsedStatusBarFragment(statusBarFragmentComponentFactory,
+                ongoingCallController,
+                animationScheduler,
+                locationPublisher,
+                notificationIconAreaController,
+                panelExpansionStateManager,
+                featureFlags,
+                statusBarIconController,
+                statusBarHideIconsForBouncerManager,
+                keyguardStateController,
+                notificationPanelViewController,
+                networkController,
+                statusBarStateController,
+                statusBarOptionalLazy,
+                commandQueue,
+                collapsedStatusBarFragmentLogger,
+                operatorNameViewControllerFactory);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
index 2880e4d..2e3893a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
@@ -53,6 +53,7 @@
 import com.android.systemui.statusbar.events.SystemStatusAnimationCallback;
 import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
 import com.android.systemui.statusbar.phone.NotificationIconAreaController;
+import com.android.systemui.statusbar.phone.NotificationPanelViewController;
 import com.android.systemui.statusbar.phone.PhoneStatusBarView;
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.phone.StatusBarHideIconsForBouncerManager;
@@ -94,6 +95,7 @@
     private PhoneStatusBarView mStatusBar;
     private final StatusBarStateController mStatusBarStateController;
     private final KeyguardStateController mKeyguardStateController;
+    private final NotificationPanelViewController mNotificationPanelViewController;
     private final NetworkController mNetworkController;
     private LinearLayout mSystemIconArea;
     private View mClockView;
@@ -146,6 +148,7 @@
             StatusBarIconController statusBarIconController,
             StatusBarHideIconsForBouncerManager statusBarHideIconsForBouncerManager,
             KeyguardStateController keyguardStateController,
+            NotificationPanelViewController notificationPanelViewController,
             NetworkController networkController,
             StatusBarStateController statusBarStateController,
             Lazy<Optional<StatusBar>> statusBarOptionalLazy,
@@ -163,6 +166,7 @@
         mStatusBarIconController = statusBarIconController;
         mStatusBarHideIconsForBouncerManager = statusBarHideIconsForBouncerManager;
         mKeyguardStateController = keyguardStateController;
+        mNotificationPanelViewController = notificationPanelViewController;
         mNetworkController = networkController;
         mStatusBarStateController = statusBarStateController;
         mStatusBarOptionalLazy = statusBarOptionalLazy;
@@ -354,8 +358,7 @@
         // The shelf will be hidden when dozing with a custom clock, we must show notification
         // icons in this occasion.
         if (mStatusBarStateController.isDozing()
-                && mStatusBarOptionalLazy.get().map(
-                        sb -> sb.getPanelController().hasCustomClock()).orElse(false)) {
+                && mNotificationPanelViewController.hasCustomClock()) {
             state |= DISABLE_CLOCK | DISABLE_SYSTEM_INFO;
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
index 1225813..c7f7258 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
@@ -33,7 +33,6 @@
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.plugins.ActivityStarter
-import com.android.systemui.flags.FeatureFlags
 import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.statusbar.gesture.SwipeStatusBarAwayGestureHandler
 import com.android.systemui.statusbar.notification.collection.NotificationEntry
@@ -44,7 +43,7 @@
 import com.android.systemui.util.time.SystemClock
 import java.io.FileDescriptor
 import java.io.PrintWriter
-import java.util.Optional
+import java.util.*
 import java.util.concurrent.Executor
 import javax.inject.Inject
 
@@ -54,7 +53,7 @@
 @SysUISingleton
 class OngoingCallController @Inject constructor(
     private val notifCollection: CommonNotifCollection,
-    private val featureFlags: FeatureFlags,
+    private val ongoingCallFlags: OngoingCallFlags,
     private val systemClock: SystemClock,
     private val activityStarter: ActivityStarter,
     @Main private val mainExecutor: Executor,
@@ -65,7 +64,6 @@
     private val swipeStatusBarAwayGestureHandler: Optional<SwipeStatusBarAwayGestureHandler>,
     private val statusBarStateController: StatusBarStateController,
 ) : CallbackController<OngoingCallListener>, Dumpable {
-
     private var isFullscreen: Boolean = false
     /** Non-null if there's an active call notification. */
     private var callNotificationInfo: CallNotificationInfo? = null
@@ -126,7 +124,7 @@
 
     fun init() {
         dumpManager.registerDumpable(this)
-        if (featureFlags.isOngoingCallStatusBarChipEnabled) {
+        if (ongoingCallFlags.isStatusBarChipEnabled()) {
             notifCollection.addCollectionListener(notifListener)
             statusBarStateController.addCallback(statusBarStateListener)
         }
@@ -218,7 +216,7 @@
 
     private fun updateChipClickListener() {
         if (callNotificationInfo == null) { return }
-        if (isFullscreen && !featureFlags.isOngoingCallInImmersiveChipTapEnabled) {
+        if (isFullscreen && !ongoingCallFlags.isInImmersiveChipTapEnabled()) {
             chipView?.setOnClickListener(null)
         } else {
             val currentChipView = chipView
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallFlags.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallFlags.kt
new file mode 100644
index 0000000..fcfcb8f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallFlags.kt
@@ -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.statusbar.phone.ongoingcall
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
+import javax.inject.Inject
+
+@SysUISingleton
+class OngoingCallFlags @Inject constructor(private val featureFlags: FeatureFlags) {
+
+    fun isStatusBarChipEnabled(): Boolean =
+            featureFlags.isEnabled(Flags.ONGOING_CALL_STATUS_BAR_CHIP)
+
+    fun isInImmersiveEnabled(): Boolean = isStatusBarChipEnabled()
+            && featureFlags.isEnabled(Flags.ONGOING_CALL_IN_IMMERSIVE)
+
+    fun isInImmersiveChipTapEnabled(): Boolean = isInImmersiveEnabled()
+            && featureFlags.isEnabled(Flags.ONGOING_CALL_IN_IMMERSIVE_CHIP_TAP)
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java
index 793a9e1..a857815 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java
@@ -37,6 +37,7 @@
 import com.android.systemui.communal.CommunalStateController;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
 import com.android.systemui.keyguard.ScreenLifecycle;
 import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -173,7 +174,7 @@
             }
 
             // Tapping anywhere in the view will open QS user panel
-            if (mFeatureFlags.useNewUserSwitcher()) {
+            if (mFeatureFlags.isEnabled(Flags.NEW_USER_SWITCHER)) {
                 mUserSwitchDialogController.showDialog(mView);
             } else {
                 openQsUserPanel();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
index 4e33529..85add6c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
@@ -1,7 +1,8 @@
 package com.android.systemui.statusbar.policy;
 
+import static java.lang.Float.NaN;
+
 import android.annotation.ColorInt;
-import android.annotation.NonNull;
 import android.app.Notification;
 import android.app.PendingIntent;
 import android.app.RemoteInput;
@@ -14,10 +15,12 @@
 import android.graphics.drawable.GradientDrawable;
 import android.graphics.drawable.InsetDrawable;
 import android.graphics.drawable.RippleDrawable;
+import android.os.SystemClock;
 import android.text.Layout;
 import android.text.TextPaint;
 import android.text.method.TransformationMethod;
 import android.util.AttributeSet;
+import android.util.IndentingPrintWriter;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -25,6 +28,8 @@
 import android.widget.Button;
 import android.widget.TextView;
 
+import androidx.annotation.NonNull;
+
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ContrastColorUtil;
 import com.android.systemui.R;
@@ -89,6 +94,13 @@
     private int mMaxNumActions;
     private int mMinNumSystemGeneratedReplies;
 
+    // DEBUG variables tracked for the dump()
+    private long mLastDrawChildTime;
+    private long mLastDispatchDrawTime;
+    private long mLastMeasureTime;
+    private int mTotalSqueezeRemeasureAttempts;
+    private boolean mDidHideSystemReplies;
+
     public SmartReplyView(Context context, AttributeSet attrs) {
         super(context, attrs);
 
@@ -217,6 +229,7 @@
 
         // Mark all buttons as hidden and un-squeezed.
         resetButtonsLayoutParams();
+        mTotalSqueezeRemeasureAttempts = 0;
 
         if (!mCandidateButtonQueueForSqueezing.isEmpty()) {
             Log.wtf(TAG, "Single line button queue leaked between onMeasure calls");
@@ -329,6 +342,7 @@
             }
         }
 
+        mDidHideSystemReplies = false;
         if (mSmartRepliesGeneratedByAssistant) {
             if (!gotEnoughSmartReplies(smartReplies)) {
                 // We don't have enough smart replies - hide all of them.
@@ -339,6 +353,7 @@
                 // Reset our measures back to when we had only added actions (before adding
                 // replies).
                 accumulatedMeasures = actionsMeasures;
+                mDidHideSystemReplies = true;
             }
         }
 
@@ -356,6 +371,7 @@
                                      accumulatedMeasures.mMeasuredWidth),
                             widthMeasureSpec),
                 resolveSize(buttonHeight, heightMeasureSpec));
+        mLastMeasureTime = SystemClock.elapsedRealtime();
     }
 
     // TODO: this should be replaced, and instead, setMinSystemGenerated... should be invoked
@@ -371,6 +387,53 @@
         }
     }
 
+    /** Dump internal state for debugging */
+    public void dump(IndentingPrintWriter pw) {
+        pw.println(this);
+        pw.increaseIndent();
+        pw.print("mMaxSqueezeRemeasureAttempts=");
+        pw.println(mMaxSqueezeRemeasureAttempts);
+        pw.print("mTotalSqueezeRemeasureAttempts=");
+        pw.println(mTotalSqueezeRemeasureAttempts);
+        pw.print("mMaxNumActions=");
+        pw.println(mMaxNumActions);
+        pw.print("mSmartRepliesGeneratedByAssistant=");
+        pw.println(mSmartRepliesGeneratedByAssistant);
+        pw.print("mMinNumSystemGeneratedReplies=");
+        pw.println(mMinNumSystemGeneratedReplies);
+        pw.print("mHeightUpperLimit=");
+        pw.println(mHeightUpperLimit);
+        pw.print("mDidHideSystemReplies=");
+        pw.println(mDidHideSystemReplies);
+        long now = SystemClock.elapsedRealtime();
+        pw.print("lastMeasureAge (s)=");
+        pw.println(mLastMeasureTime == 0 ? NaN : (now - mLastMeasureTime) / 1000.0f);
+        pw.print("lastDrawChildAge (s)=");
+        pw.println(mLastDrawChildTime == 0 ? NaN : (now - mLastDrawChildTime) / 1000.0f);
+        pw.print("lastDispatchDrawAge (s)=");
+        pw.println(mLastDispatchDrawTime == 0 ? NaN : (now - mLastDispatchDrawTime) / 1000.0f);
+        int numChildren = getChildCount();
+        pw.print("children: num=");
+        pw.println(numChildren);
+        pw.increaseIndent();
+        for (int i = 0; i < numChildren; i++) {
+            View child = getChildAt(i);
+            LayoutParams lp = (LayoutParams) child.getLayoutParams();
+            pw.print("[");
+            pw.print(i);
+            pw.print("] type=");
+            pw.print(lp.mButtonType);
+            pw.print(" squeezeStatus=");
+            pw.print(lp.squeezeStatus);
+            pw.print(" show=");
+            pw.print(lp.show);
+            pw.print(" view=");
+            pw.println(child);
+        }
+        pw.decreaseIndent();
+        pw.decreaseIndent();
+    }
+
     /**
      * Fields we keep track of inside onMeasure() to correctly measure the SmartReplyView depending
      * on which suggestions are added.
@@ -393,8 +456,11 @@
      * Returns whether our notification contains at least N smart replies (or 0) where N is
      * determined by {@link SmartReplyConstants}.
      */
-    // TODO: we probably sholdn't make this deliberation in the View
     private boolean gotEnoughSmartReplies(List<View> smartReplies) {
+        if (mMinNumSystemGeneratedReplies <= 1) {
+            // Count is irrelevant, do not bother.
+            return true;
+        }
         int numShownReplies = 0;
         for (View smartReplyButton : smartReplies) {
             final LayoutParams lp = (LayoutParams) smartReplyButton.getLayoutParams();
@@ -474,6 +540,7 @@
             final boolean moveLeft = initialLeftTextWidth > initialRightTextWidth;
             final int maxSqueezeRemeasureAttempts = mMaxSqueezeRemeasureAttempts;
             for (int i = 0; i < maxSqueezeRemeasureAttempts; i++) {
+                mTotalSqueezeRemeasureAttempts++;
                 final int newPosition =
                         moveLeft ? mBreakIterator.previous() : mBreakIterator.next();
                 if (newPosition == BreakIterator.DONE) {
@@ -613,7 +680,17 @@
     @Override
     protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
         final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-        return lp.show && super.drawChild(canvas, child, drawingTime);
+        if (!lp.show) {
+            return false;
+        }
+        mLastDrawChildTime = SystemClock.elapsedRealtime();
+        return super.drawChild(canvas, child, drawingTime);
+    }
+
+    @Override
+    protected void dispatchDraw(Canvas canvas) {
+        super.dispatchDraw(canvas);
+        mLastDispatchDrawTime = SystemClock.elapsedRealtime();
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index 0443d94..364c931 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -55,6 +55,8 @@
 import android.view.WindowManagerGlobal;
 import android.widget.BaseAdapter;
 
+import androidx.annotation.Nullable;
+
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.jank.InteractionJankMonitor;
 import com.android.internal.logging.UiEventLogger;
@@ -77,6 +79,7 @@
 import com.android.systemui.plugins.qs.DetailAdapter;
 import com.android.systemui.qs.QSUserSwitcherEvent;
 import com.android.systemui.qs.tiles.UserDetailView;
+import com.android.systemui.qs.user.UserSwitchDialogController.DialogShower;
 import com.android.systemui.settings.UserTracker;
 import com.android.systemui.statusbar.phone.NotificationShadeWindowView;
 import com.android.systemui.statusbar.phone.SystemUIDialog;
@@ -460,7 +463,7 @@
     }
 
     @VisibleForTesting
-    void onUserListItemClicked(UserRecord record) {
+    void onUserListItemClicked(UserRecord record, DialogShower dialogShower) {
         int id;
         if (record.isGuest && record.info == null) {
             // No guest user. Create one.
@@ -472,7 +475,7 @@
             mUiEventLogger.log(QSUserSwitcherEvent.QS_USER_GUEST_ADD);
             id = guestId;
         } else if (record.isAddUser) {
-            showAddUserDialog();
+            showAddUserDialog(dialogShower);
             return;
         } else {
             id = record.info.id;
@@ -481,7 +484,7 @@
         int currUserId = mUserTracker.getUserId();
         if (currUserId == id) {
             if (record.isGuest) {
-                showExitGuestDialog(id);
+                showExitGuestDialog(id, dialogShower);
             }
             return;
         }
@@ -490,11 +493,15 @@
             // If switching from guest, we want to bring up the guest exit dialog instead of switching
             UserInfo currUserInfo = mUserManager.getUserInfo(currUserId);
             if (currUserInfo != null && currUserInfo.isGuest()) {
-                showExitGuestDialog(currUserId, record.resolveId());
+                showExitGuestDialog(currUserId, record.resolveId(), dialogShower);
                 return;
             }
         }
-
+        if (dialogShower != null) {
+            // If we haven't morphed into another dialog, it means we have just switched users.
+            // Then, dismiss the dialog.
+            dialogShower.dismiss();
+        }
         switchToUserId(id);
     }
 
@@ -511,7 +518,7 @@
         }
     }
 
-    protected void showExitGuestDialog(int id) {
+    private void showExitGuestDialog(int id, DialogShower dialogShower) {
         int newId = UserHandle.USER_SYSTEM;
         if (mResumeUserOnGuestLogout && mLastNonGuestUser != UserHandle.USER_SYSTEM) {
             UserInfo info = mUserManager.getUserInfo(mLastNonGuestUser);
@@ -519,23 +526,31 @@
                 newId = info.id;
             }
         }
-        showExitGuestDialog(id, newId);
+        showExitGuestDialog(id, newId, dialogShower);
     }
 
-    protected void showExitGuestDialog(int id, int targetId) {
+    private void showExitGuestDialog(int id, int targetId, DialogShower dialogShower) {
         if (mExitGuestDialog != null && mExitGuestDialog.isShowing()) {
             mExitGuestDialog.cancel();
         }
         mExitGuestDialog = new ExitGuestDialog(mContext, id, targetId);
-        mExitGuestDialog.show();
+        if (dialogShower != null) {
+            dialogShower.showDialog(mExitGuestDialog);
+        } else {
+            mExitGuestDialog.show();
+        }
     }
 
-    public void showAddUserDialog() {
+    private void showAddUserDialog(DialogShower dialogShower) {
         if (mAddUserDialog != null && mAddUserDialog.isShowing()) {
             mAddUserDialog.cancel();
         }
         mAddUserDialog = new AddUserDialog(mContext);
-        mAddUserDialog.show();
+        if (dialogShower != null) {
+            dialogShower.showDialog(mAddUserDialog);
+        } else {
+            mAddUserDialog.show();
+        }
     }
 
     private void listenForCallState() {
@@ -868,9 +883,17 @@
 
         /**
          * It handles click events on user list items.
+         *
+         * If the user switcher is hosted in a dialog, passing a non-null {@link DialogShower}
+         * will allow animation to and from the parent dialog.
+         *
          */
+        public void onUserListItemClicked(UserRecord record, @Nullable DialogShower dialogShower) {
+            mController.onUserListItemClicked(record, dialogShower);
+        }
+
         public void onUserListItemClicked(UserRecord record) {
-            mController.onUserListItemClicked(record);
+            onUserListItemClicked(record, null);
         }
 
         public String getName(Context context, UserRecord item) {
@@ -1156,7 +1179,7 @@
                 cancel();
             } else {
                 mUiEventLogger.log(QSUserSwitcherEvent.QS_USER_GUEST_REMOVE);
-                dismiss();
+                dismissStack();
                 removeGuestUser(mGuestId, mTargetId);
             }
         }
@@ -1187,7 +1210,7 @@
             if (which == BUTTON_NEGATIVE) {
                 cancel();
             } else {
-                dismiss();
+                dismissStack();
                 if (ActivityManager.isUserAMonkey()) {
                     return;
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
index 5acce7f..b5ee62d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
@@ -45,9 +45,10 @@
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dump.DumpManager;
-import com.android.systemui.qs.GlobalSetting;
+import com.android.systemui.qs.SettingObserver;
 import com.android.systemui.settings.CurrentUserTracker;
 import com.android.systemui.util.Utils;
+import com.android.systemui.util.settings.GlobalSettings;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -66,8 +67,8 @@
     private final ArrayList<Callback> mCallbacks = new ArrayList<>();
     private final Object mCallbacksLock = new Object();
     private final Context mContext;
-    private final GlobalSetting mModeSetting;
-    private final GlobalSetting mConfigSetting;
+    private final SettingObserver mModeSetting;
+    private final SettingObserver mConfigSetting;
     private final NotificationManager mNoMan;
     private final AlarmManager mAlarmManager;
     private final SetupObserver mSetupObserver;
@@ -85,19 +86,20 @@
             Context context,
             @Main Handler handler,
             BroadcastDispatcher broadcastDispatcher,
-            DumpManager dumpManager) {
+            DumpManager dumpManager,
+            GlobalSettings globalSettings) {
         super(broadcastDispatcher);
         mContext = context;
-        mModeSetting = new GlobalSetting(mContext, handler, Global.ZEN_MODE) {
+        mModeSetting = new SettingObserver(globalSettings, handler, Global.ZEN_MODE) {
             @Override
-            protected void handleValueChanged(int value) {
+            protected void handleValueChanged(int value, boolean observedChange) {
                 updateZenMode(value);
                 fireZenChanged(value);
             }
         };
-        mConfigSetting = new GlobalSetting(mContext, handler, Global.ZEN_MODE_CONFIG_ETAG) {
+        mConfigSetting = new SettingObserver(globalSettings, handler, Global.ZEN_MODE_CONFIG_ETAG) {
             @Override
-            protected void handleValueChanged(int value) {
+            protected void handleValueChanged(int value, boolean observedChange) {
                 updateZenModeConfig();
             }
         };
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
index 50a0b80..39544fb 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
@@ -61,6 +61,7 @@
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.monet.ColorScheme;
 import com.android.systemui.settings.UserTracker;
@@ -311,7 +312,7 @@
             WakefulnessLifecycle wakefulnessLifecycle) {
         super(context);
 
-        mIsMonetEnabled = featureFlags.isMonetEnabled();
+        mIsMonetEnabled = featureFlags.isEnabled(Flags.MONET);
         mDeviceProvisionedController = deviceProvisionedController;
         mBroadcastDispatcher = broadcastDispatcher;
         mUserManager = userManager;
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
index 4aad9b6..e8f6de7 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
@@ -60,12 +60,12 @@
 import com.android.systemui.Dumpable;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dump.DumpManager;
-import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.model.SysUiState;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.shared.system.QuickStepContract;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationShadeWindowController;
+import com.android.systemui.statusbar.notification.NotifPipelineFlags;
 import com.android.systemui.statusbar.notification.NotificationChannelHelper;
 import com.android.systemui.statusbar.notification.NotificationEntryListener;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
@@ -141,7 +141,7 @@
             NotificationEntryManager entryManager,
             NotifPipeline notifPipeline,
             SysUiState sysUiState,
-            FeatureFlags featureFlags,
+            NotifPipelineFlags notifPipelineFlags,
             DumpManager dumpManager,
             Executor sysuiMainExecutor) {
         if (bubblesOptional.isPresent()) {
@@ -150,7 +150,7 @@
                     configurationController, statusBarService, notificationManager,
                     visibilityProvider,
                     interruptionStateProvider, zenModeController, notifUserManager,
-                    groupManager, entryManager, notifPipeline, sysUiState, featureFlags,
+                    groupManager, entryManager, notifPipeline, sysUiState, notifPipelineFlags,
                     dumpManager, sysuiMainExecutor);
         } else {
             return null;
@@ -174,7 +174,7 @@
             NotificationEntryManager entryManager,
             NotifPipeline notifPipeline,
             SysUiState sysUiState,
-            FeatureFlags featureFlags,
+            NotifPipelineFlags notifPipelineFlags,
             DumpManager dumpManager,
             Executor sysuiMainExecutor) {
         mContext = context;
@@ -194,7 +194,7 @@
                 ServiceManager.getService(Context.STATUS_BAR_SERVICE))
                 : statusBarService;
 
-        if (featureFlags.isNewNotifPipelineRenderingEnabled()) {
+        if (notifPipelineFlags.isNewPipelineEnabled()) {
             setupNotifPipeline();
         } else {
             setupNEM();
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
index 66c70ed..63ca94c 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
@@ -65,6 +65,7 @@
 import com.android.wm.shell.onehanded.OneHandedUiEventLogger;
 import com.android.wm.shell.pip.Pip;
 import com.android.wm.shell.protolog.ShellProtoLogImpl;
+import com.android.wm.shell.sizecompatui.SizeCompatUI;
 import com.android.wm.shell.splitscreen.SplitScreen;
 
 import java.io.FileDescriptor;
@@ -112,6 +113,7 @@
     private final Optional<OneHanded> mOneHandedOptional;
     private final Optional<HideDisplayCutout> mHideDisplayCutoutOptional;
     private final Optional<ShellCommandHandler> mShellCommandHandler;
+    private final Optional<SizeCompatUI> mSizeCompatUIOptional;
 
     private final CommandQueue mCommandQueue;
     private final ConfigurationController mConfigurationController;
@@ -128,6 +130,7 @@
     private KeyguardUpdateMonitorCallback mSplitScreenKeyguardCallback;
     private KeyguardUpdateMonitorCallback mPipKeyguardCallback;
     private KeyguardUpdateMonitorCallback mOneHandedKeyguardCallback;
+    private KeyguardUpdateMonitorCallback mSizeCompatUIKeyguardCallback;
     private WakefulnessLifecycle.Observer mWakefulnessObserver;
 
     @Inject
@@ -138,6 +141,7 @@
             Optional<OneHanded> oneHandedOptional,
             Optional<HideDisplayCutout> hideDisplayCutoutOptional,
             Optional<ShellCommandHandler> shellCommandHandler,
+            Optional<SizeCompatUI> sizeCompatUIOptional,
             CommandQueue commandQueue,
             ConfigurationController configurationController,
             KeyguardUpdateMonitor keyguardUpdateMonitor,
@@ -162,6 +166,7 @@
         mWakefulnessLifecycle = wakefulnessLifecycle;
         mProtoTracer = protoTracer;
         mShellCommandHandler = shellCommandHandler;
+        mSizeCompatUIOptional = sizeCompatUIOptional;
         mSysUiMainExecutor = sysUiMainExecutor;
     }
 
@@ -176,6 +181,7 @@
         mSplitScreenOptional.ifPresent(this::initSplitScreen);
         mOneHandedOptional.ifPresent(this::initOneHanded);
         mHideDisplayCutoutOptional.ifPresent(this::initHideDisplayCutout);
+        mSizeCompatUIOptional.ifPresent(this::initSizeCompatUi);
     }
 
     @VisibleForTesting
@@ -254,6 +260,18 @@
             }
         };
         mKeyguardUpdateMonitor.registerCallback(mSplitScreenKeyguardCallback);
+
+        mWakefulnessLifecycle.addObserver(new WakefulnessLifecycle.Observer() {
+            @Override
+            public void onFinishedWakingUp() {
+                splitScreen.onFinishedWakingUp();
+            }
+
+            @Override
+            public void onFinishedGoingToSleep() {
+                splitScreen.onFinishedGoingToSleep();
+            }
+        });
     }
 
     @VisibleForTesting
@@ -367,6 +385,17 @@
         });
     }
 
+    @VisibleForTesting
+    void initSizeCompatUi(SizeCompatUI sizeCompatUI) {
+        mSizeCompatUIKeyguardCallback = new KeyguardUpdateMonitorCallback() {
+            @Override
+            public void onKeyguardOccludedChanged(boolean occluded) {
+                sizeCompatUI.onKeyguardOccludedChanged(occluded);
+            }
+        };
+        mKeyguardUpdateMonitor.registerCallback(mSizeCompatUIKeyguardCallback);
+    }
+
     @Override
     public void writeToProto(SystemUiTraceProto proto) {
         if (proto.wmShell == null) {
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
index 5e0f427..e967033 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
@@ -18,14 +18,19 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.content.res.Resources;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.provider.Settings;
 import android.testing.AndroidTestingRunner;
 import android.view.View;
 import android.widget.FrameLayout;
@@ -50,6 +55,9 @@
 import com.android.systemui.statusbar.phone.NotificationIconAreaController;
 import com.android.systemui.statusbar.phone.NotificationIconContainer;
 import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.settings.SecureSettings;
+import com.android.systemui.util.time.FakeSystemClock;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -104,11 +112,14 @@
     private AnimatableClockView mLargeClockView;
     @Mock
     private FrameLayout mLargeClockFrame;
+    @Mock
+    private SecureSettings mSecureSettings;
 
     private final View mFakeSmartspaceView = new View(mContext);
 
     private KeyguardClockSwitchController mController;
     private View mSliceView;
+    private FakeExecutor mExecutor;
 
     @Before
     public void setup() {
@@ -129,6 +140,7 @@
 
         when(mView.isAttachedToWindow()).thenReturn(true);
         when(mSmartspaceController.buildAndConnectView(any())).thenReturn(mFakeSmartspaceView);
+        mExecutor = new FakeExecutor(new FakeSystemClock());
         mController = new KeyguardClockSwitchController(
                 mView,
                 mStatusBarStateController,
@@ -143,6 +155,8 @@
                 mSmartspaceController,
                 mKeyguardUnlockAnimationController,
                 mSmartSpaceTransitionController,
+                mSecureSettings,
+                mExecutor,
                 mResources
         );
 
@@ -194,7 +208,6 @@
         verifyAttachment(times(1));
 
         listenerArgumentCaptor.getValue().onViewDetachedFromWindow(mView);
-        verify(mView).onViewDetached();
         verify(mColorExtractor).removeOnColorsChangedListener(
                 any(ColorExtractor.OnColorsChangedListener.class));
     }
@@ -235,6 +248,25 @@
         verify(mSmartspaceController).requestSmartspaceUpdate();
     }
 
+    @Test
+    public void testChangeToDoubleLineClockSetsSmallClock() {
+        when(mSecureSettings.getInt(Settings.Secure.LOCKSCREEN_USE_DOUBLE_LINE_CLOCK, 1))
+                .thenReturn(0);
+        ArgumentCaptor<ContentObserver> observerCaptor =
+                ArgumentCaptor.forClass(ContentObserver.class);
+        mController.init();
+        verify(mSecureSettings).registerContentObserver(any(Uri.class),
+                anyBoolean(), observerCaptor.capture());
+        ContentObserver observer = observerCaptor.getValue();
+        mExecutor.runAllReady();
+
+        // When a settings change has occurred to the small clock, make sure the view is adjusted
+        reset(mView);
+        observer.onChange(true);
+        mExecutor.runAllReady();
+        verify(mView).switchToClock(KeyguardClockSwitch.SMALL);
+    }
+
     private void verifyAttachment(VerificationMode times) {
         verify(mClockManager, times).addOnClockChangedListener(
                 any(ClockManager.ClockChangedListener.class));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/IWindowMagnificationConnectionTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/IWindowMagnificationConnectionTest.java
index 77286b1..326d902 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/IWindowMagnificationConnectionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/IWindowMagnificationConnectionTest.java
@@ -64,7 +64,7 @@
     @Mock
     private IWindowMagnificationConnectionCallback mConnectionCallback;
     @Mock
-    private WindowMagnificationAnimationController mWindowMagnificationAnimationController;
+    private WindowMagnificationController mWindowMagnificationController;
     @Mock
     private ModeSwitchesController mModeSwitchesController;
     @Mock
@@ -89,7 +89,7 @@
         mWindowMagnification = new WindowMagnification(getContext(),
                 getContext().getMainThreadHandler(), mCommandQueue,
                 mModeSwitchesController, mSysUiState, mOverviewProxyService);
-        mWindowMagnification.mAnimationControllerSupplier = new FakeAnimationControllerSupplier(
+        mWindowMagnification.mMagnificationControllerSupplier = new FakeControllerSupplier(
                 mContext.getSystemService(DisplayManager.class));
 
         mWindowMagnification.requestWindowMagnificationConnection(true);
@@ -103,7 +103,7 @@
                 Float.NaN, mAnimationCallback);
         waitForIdleSync();
 
-        verify(mWindowMagnificationAnimationController).enableWindowMagnification(eq(3.0f),
+        verify(mWindowMagnificationController).enableWindowMagnification(eq(3.0f),
                 eq(Float.NaN), eq(Float.NaN), eq(mAnimationCallback));
     }
 
@@ -113,7 +113,7 @@
                 mAnimationCallback);
         waitForIdleSync();
 
-        verify(mWindowMagnificationAnimationController).deleteWindowMagnification(
+        verify(mWindowMagnificationController).deleteWindowMagnification(
                 mAnimationCallback);
     }
 
@@ -122,7 +122,7 @@
         mIWindowMagnificationConnection.setScale(TEST_DISPLAY, 3.0f);
         waitForIdleSync();
 
-        verify(mWindowMagnificationAnimationController).setScale(3.0f);
+        verify(mWindowMagnificationController).setScale(3.0f);
     }
 
     @Test
@@ -130,7 +130,7 @@
         mIWindowMagnificationConnection.moveWindowMagnifier(TEST_DISPLAY, 100f, 200f);
         waitForIdleSync();
 
-        verify(mWindowMagnificationAnimationController).moveWindowMagnifier(100f, 200f);
+        verify(mWindowMagnificationController).moveWindowMagnifier(100f, 200f);
     }
 
     @Test
@@ -151,16 +151,16 @@
         verify(mModeSwitchesController).removeButton(TEST_DISPLAY);
     }
 
-    private class FakeAnimationControllerSupplier extends
-            DisplayIdIndexSupplier<WindowMagnificationAnimationController> {
+    private class FakeControllerSupplier extends
+            DisplayIdIndexSupplier<WindowMagnificationController> {
 
-        FakeAnimationControllerSupplier(DisplayManager displayManager) {
+        FakeControllerSupplier(DisplayManager displayManager) {
             super(displayManager);
         }
 
         @Override
-        protected WindowMagnificationAnimationController createInstance(Display display) {
-            return mWindowMagnificationAnimationController;
+        protected WindowMagnificationController createInstance(Display display) {
+            return mWindowMagnificationController;
         }
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java
index 148c6ef..854fc33 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java
@@ -100,12 +100,13 @@
         mInstrumentation = InstrumentationRegistry.getInstrumentation();
         mWaitingAnimationPeriod = 2 * ANIMATION_DURATION_MS;
         mWaitIntermediateAnimationPeriod = ANIMATION_DURATION_MS / 2;
+        mWindowMagnificationAnimationController = new WindowMagnificationAnimationController(
+                mContext, newValueAnimator());
         mController = new SpyWindowMagnificationController(mContext, mHandler,
+                mWindowMagnificationAnimationController,
                 mSfVsyncFrameProvider, null, new SurfaceControl.Transaction(),
                 mWindowMagnifierCallback, mSysUiState);
         mSpyController = mController.getSpyController();
-        mWindowMagnificationAnimationController = new WindowMagnificationAnimationController(
-                mContext, mController, newValueAnimator());
     }
 
     @After
@@ -383,17 +384,6 @@
     }
 
     @Test
-    public void setScale_enabled_expectedScale() {
-        enableWindowMagnificationWithoutAnimation();
-
-        mInstrumentation.runOnMainSync(
-                () -> mWindowMagnificationAnimationController.setScale(DEFAULT_SCALE + 1));
-
-        verify(mSpyController).setScale(DEFAULT_SCALE + 1);
-        verifyFinalSpec(DEFAULT_SCALE + 1, DEFAULT_CENTER_X, DEFAULT_CENTER_Y);
-    }
-
-    @Test
     public void deleteWindowMagnification_enabled_expectedValuesAndInvokeCallback()
             throws RemoteException {
         enableWindowMagnificationWithoutAnimation();
@@ -508,26 +498,12 @@
         enableWindowMagnificationWithoutAnimation();
 
         mInstrumentation.runOnMainSync(
-                () -> mWindowMagnificationAnimationController.moveWindowMagnifier(100f, 200f));
+                () -> mController.moveWindowMagnifier(100f, 200f));
 
         verify(mSpyController).moveWindowMagnifier(100f, 200f);
         verifyFinalSpec(DEFAULT_SCALE, DEFAULT_CENTER_X + 100f, DEFAULT_CENTER_Y + 100f);
     }
 
-    @Test
-    public void onConfigurationChanged_passThrough() {
-        mWindowMagnificationAnimationController.onConfigurationChanged(100);
-
-        verify(mSpyController).onConfigurationChanged(100);
-    }
-
-    @Test
-    public void updateSysUiStateFlag_passThrough() {
-        mWindowMagnificationAnimationController.updateSysUiStateFlag();
-
-        verify(mSpyController).updateSysUIStateFlag();
-    }
-
     private void verifyFinalSpec(float expectedScale, float expectedCenterX,
             float expectedCenterY) {
         assertEquals(expectedScale, mController.getScale(), 0f);
@@ -581,11 +557,12 @@
         private WindowMagnificationController mSpyController;
 
         SpyWindowMagnificationController(Context context, Handler handler,
+                WindowMagnificationAnimationController animationController,
                 SfVsyncFrameCallbackProvider sfVsyncFrameProvider,
                 MirrorWindowControl mirrorWindowControl, SurfaceControl.Transaction transaction,
                 WindowMagnifierCallback callback, SysUiState sysUiState) {
-            super(context, handler, sfVsyncFrameProvider, mirrorWindowControl, transaction,
-                    callback, sysUiState);
+            super(context, handler, animationController, sfVsyncFrameProvider, mirrorWindowControl,
+                    transaction, callback, sysUiState);
             mSpyController = Mockito.mock(WindowMagnificationController.class);
         }
 
@@ -622,12 +599,6 @@
             super.updateSysUIStateFlag();
             mSpyController.updateSysUIStateFlag();
         }
-
-        @Override
-        void onConfigurationChanged(int configDiff) {
-            super.onConfigurationChanged(configDiff);
-            mSpyController.onConfigurationChanged(configDiff);
-        }
     }
 
     private static ValueAnimator newValueAnimator() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
index 70457cf..9a30465 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
@@ -89,6 +89,8 @@
     @Mock
     private Handler mHandler;
     @Mock
+    private WindowMagnificationAnimationController mWindowMagnificationAnimationController;
+    @Mock
     private SfVsyncFrameCallbackProvider mSfVsyncFrameProvider;
     @Mock
     private MirrorWindowControl mMirrorWindowControl;
@@ -128,7 +130,7 @@
 
         mResources = getContext().getOrCreateTestableResources().getResources();
         mWindowMagnificationController = new WindowMagnificationController(mContext,
-                mHandler, mSfVsyncFrameProvider,
+                mHandler, mWindowMagnificationAnimationController, mSfVsyncFrameProvider,
                 mMirrorWindowControl, mTransaction, mWindowMagnifierCallback, mSysUiState);
 
         verify(mMirrorWindowControl).setWindowDelegate(
@@ -174,7 +176,7 @@
         mWindowManager.setWindowBounds(new Rect(0, 0, screenSize, screenSize));
         //We need to initialize new one because the window size is determined when initialization.
         final WindowMagnificationController controller = new WindowMagnificationController(mContext,
-                mHandler, mSfVsyncFrameProvider,
+                mHandler, mWindowMagnificationAnimationController, mSfVsyncFrameProvider,
                 mMirrorWindowControl, mTransaction, mWindowMagnifierCallback, mSysUiState);
 
         mInstrumentation.runOnMainSync(() -> {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java
index fb1716a..c898150 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java
@@ -167,30 +167,29 @@
 
     @Test
     public void overviewProxyIsConnected_controllerIsAvailable_updateSysUiStateFlag() {
-        final WindowMagnificationAnimationController mController = mock(
-                WindowMagnificationAnimationController.class);
-        mWindowMagnification.mAnimationControllerSupplier = new FakeAnimationControllerSupplier(
+        final WindowMagnificationController mController = mock(WindowMagnificationController.class);
+        mWindowMagnification.mMagnificationControllerSupplier = new FakeControllerSupplier(
                 mContext.getSystemService(DisplayManager.class), mController);
-        mWindowMagnification.mAnimationControllerSupplier.get(TEST_DISPLAY);
+        mWindowMagnification.mMagnificationControllerSupplier.get(TEST_DISPLAY);
 
         mOverviewProxyListener.onConnectionChanged(true);
 
-        verify(mController).updateSysUiStateFlag();
+        verify(mController).updateSysUIStateFlag();
     }
 
-    private static class FakeAnimationControllerSupplier extends
-            DisplayIdIndexSupplier<WindowMagnificationAnimationController> {
+    private static class FakeControllerSupplier extends
+            DisplayIdIndexSupplier<WindowMagnificationController> {
 
-        private final WindowMagnificationAnimationController mController;
+        private final WindowMagnificationController mController;
 
-        FakeAnimationControllerSupplier(DisplayManager displayManager,
-                WindowMagnificationAnimationController controller) {
+        FakeControllerSupplier(DisplayManager displayManager,
+                WindowMagnificationController controller) {
             super(displayManager);
             mController = controller;
         }
 
         @Override
-        protected WindowMagnificationAnimationController createInstance(Display display) {
+        protected WindowMagnificationController createInstance(Display display) {
             return mController;
         }
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/DialogLaunchAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/DialogLaunchAnimatorTest.kt
index d4c3840..9bd33eb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/DialogLaunchAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/DialogLaunchAnimatorTest.kt
@@ -16,6 +16,7 @@
 import junit.framework.Assert.assertEquals
 import junit.framework.Assert.assertFalse
 import junit.framework.Assert.assertTrue
+import org.junit.After
 import org.junit.Test
 import org.junit.runner.RunWith
 
@@ -28,24 +29,22 @@
     private val dialogLaunchAnimator =
         DialogLaunchAnimator(context, launchAnimator, hostDialogprovider)
 
+    private val attachedViews = mutableSetOf<View>()
+
+    @After
+    fun tearDown() {
+        runOnMainThreadAndWaitForIdleSync {
+            attachedViews.forEach {
+                ViewUtils.detachView(it)
+            }
+        }
+    }
+
     @Test
     fun testShowDialogFromView() {
         // Show the dialog. showFromView() must be called on the main thread with a dialog created
         // on the main thread too.
-        val (dialog, hostDialog) = runOnMainThreadAndWaitForIdleSync {
-            val touchSurfaceRoot = LinearLayout(context)
-            val touchSurface = View(context)
-            touchSurfaceRoot.addView(touchSurface)
-
-            // We need to attach the root to the window manager otherwise the exit animation will
-            // be skipped
-            ViewUtils.attachView(touchSurfaceRoot)
-
-            val dialog = TestDialog(context)
-            val hostDialog =
-                dialogLaunchAnimator.showFromView(dialog, touchSurface) as TestHostDialog
-            dialog to hostDialog
-        }
+        val (dialog, hostDialog) = createDialogAndHostDialog()
 
         // Only the host dialog is actually showing.
         assertTrue(hostDialog.isShowing)
@@ -100,6 +99,51 @@
         assertTrue(dialog.onStopCalled)
     }
 
+    @Test
+    fun testStackedDialogsDismissesAll() {
+        val (_, hostDialogFirst) = createDialogAndHostDialog()
+        val (dialogSecond, hostDialogSecond) = createDialogAndHostDialogFromDialog(hostDialogFirst)
+
+        runOnMainThreadAndWaitForIdleSync {
+            dialogLaunchAnimator.disableAllCurrentDialogsExitAnimations()
+            dialogSecond.dismissStack()
+        }
+
+        assertTrue(hostDialogSecond.wasDismissed)
+        assertTrue(hostDialogFirst.wasDismissed)
+    }
+
+    private fun createDialogAndHostDialog(): Pair<TestDialog, TestHostDialog> {
+        return runOnMainThreadAndWaitForIdleSync {
+            val touchSurfaceRoot = LinearLayout(context)
+            val touchSurface = View(context)
+            touchSurfaceRoot.addView(touchSurface)
+
+            // We need to attach the root to the window manager otherwise the exit animation will
+            // be skipped
+            ViewUtils.attachView(touchSurfaceRoot)
+            attachedViews.add(touchSurfaceRoot)
+
+            val dialog = TestDialog(context)
+            val hostDialog =
+                    dialogLaunchAnimator.showFromView(dialog, touchSurface) as TestHostDialog
+            dialog to hostDialog
+        }
+    }
+
+    private fun createDialogAndHostDialogFromDialog(
+        hostParent: Dialog
+    ): Pair<TestDialog, TestHostDialog> {
+        return runOnMainThreadAndWaitForIdleSync {
+            val dialog = TestDialog(context)
+            val hostDialog = dialogLaunchAnimator.showFromDialog(
+                    dialog,
+                    hostParent
+            ) as TestHostDialog
+            dialog to hostDialog
+        }
+    }
+
     private fun <T : Any> runOnMainThreadAndWaitForIdleSync(f: () -> T): T {
         lateinit var result: T
         context.mainExecutor.execute {
@@ -198,6 +242,11 @@
             notifyListeners { onShow() }
         }
 
+        fun dismissStack() {
+            notifyListeners { prepareForStackDismiss() }
+            dismiss()
+        }
+
         private fun notifyListeners(notify: DialogListener.() -> Unit) {
             for (listener in HashSet(listeners)) {
                 listener.notify()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/GhostedViewLaunchAnimatorControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/GhostedViewLaunchAnimatorControllerTest.kt
index 58e0cb2..3696ec5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/GhostedViewLaunchAnimatorControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/GhostedViewLaunchAnimatorControllerTest.kt
@@ -16,22 +16,53 @@
 
 package com.android.systemui.animation
 
+import android.graphics.drawable.Drawable
 import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
-import android.widget.LinearLayout
+import android.view.View
+import android.view.ViewGroup
+import android.view.ViewParent
 import androidx.test.filters.SmallTest
+import com.android.internal.jank.InteractionJankMonitor
 import com.android.systemui.SysuiTestCase
+import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.any
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.Mock
+import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations
 
 @SmallTest
 @RunWith(AndroidTestingRunner::class)
 @TestableLooper.RunWithLooper
 class GhostedViewLaunchAnimatorControllerTest : SysuiTestCase() {
+    @Mock lateinit var interactionJankMonitor: InteractionJankMonitor
+    @Mock lateinit var view: View
+    @Mock lateinit var rootView: ViewGroup
+    @Mock lateinit var viewParent: ViewParent
+    @Mock lateinit var drawable: Drawable
+    lateinit var controller: GhostedViewLaunchAnimatorController
+
+    @Before
+    fun setup() {
+        MockitoAnnotations.initMocks(this)
+        whenever(view.rootView).thenReturn(rootView)
+        whenever(view.background).thenReturn(drawable)
+        whenever(view.height).thenReturn(0)
+        whenever(view.width).thenReturn(0)
+        whenever(view.parent).thenReturn(viewParent)
+        whenever(view.visibility).thenReturn(View.VISIBLE)
+        whenever(view.invalidate()).then { /* NO-OP */ }
+        whenever(view.getLocationOnScreen(any())).then { /* NO-OP */ }
+        whenever(interactionJankMonitor.begin(any(), anyInt())).thenReturn(true)
+        whenever(interactionJankMonitor.end(anyInt())).thenReturn(true)
+        controller = GhostedViewLaunchAnimatorController(view, 0, interactionJankMonitor)
+    }
+
     @Test
     fun animatingOrphanViewDoesNotCrash() {
-        val ghostedView = LinearLayout(mContext)
-        val controller = GhostedViewLaunchAnimatorController(ghostedView)
         val state = LaunchAnimator.State(top = 0, bottom = 0, left = 0, right = 0)
 
         controller.onIntentStarted(willAnimate = true)
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 9e42ff3..241b02d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -16,8 +16,6 @@
 
 package com.android.systemui.biometrics;
 
-import static android.media.AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY;
-
 import static junit.framework.Assert.assertEquals;
 
 import static org.mockito.ArgumentMatchers.any;
@@ -44,6 +42,7 @@
 import android.os.Handler;
 import android.os.PowerManager;
 import android.os.RemoteException;
+import android.os.VibrationAttributes;
 import android.os.Vibrator;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper.RunWithLooper;
@@ -648,11 +647,11 @@
                 anyString(),
                 any(),
                 eq("udfps-onStart-tick"),
-                eq(UdfpsController.VIBRATION_SONIFICATION_ATTRIBUTES));
+                eq(UdfpsController.VIBRATION_ATTRIBUTES));
 
         // THEN make sure vibration attributes has so that it always will play the haptic,
         // even in battery saver mode
-        assertEquals(USAGE_ASSISTANCE_ACCESSIBILITY,
-                UdfpsController.VIBRATION_SONIFICATION_ATTRIBUTES.getUsage());
+        assertEquals(VibrationAttributes.USAGE_COMMUNICATION_REQUEST,
+                UdfpsController.VIBRATION_ATTRIBUTES.getUsage());
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
index 0e86964..1cf21ac 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
@@ -351,9 +351,8 @@
         mSystemClock.advanceTime(205);
         mController.onTouchOutsideView();
 
-        // THEN show the bouncer and reset alt auth
+        // THEN show the bouncer
         verify(mStatusBarKeyguardViewManager).showBouncer(eq(true));
-        verify(mStatusBarKeyguardViewManager).resetAlternateAuth(anyBoolean());
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/communal/CommunalSourcePrimerTest.java b/packages/SystemUI/tests/src/com/android/systemui/communal/CommunalSourcePrimerTest.java
new file mode 100644
index 0000000..659b1a3
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/communal/CommunalSourcePrimerTest.java
@@ -0,0 +1,169 @@
+/*
+ * 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.communal;
+
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.testing.AndroidTestingRunner;
+
+import androidx.concurrent.futures.CallbackToFutureAdapter;
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.time.FakeSystemClock;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+import java.util.Optional;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class CommunalSourcePrimerTest extends SysuiTestCase {
+    private static final String TEST_COMPONENT_NAME = "com.google.tests/.CommunalService";
+    private static final int MAX_RETRIES = 5;
+    private static final int RETRY_DELAY_MS = 1000;
+
+    @Mock
+    private Context mContext;
+
+    @Mock
+    private Resources mResources;
+
+    private FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock());
+
+    @Mock
+    private CommunalSource mSource;
+
+    @Mock
+    private CommunalSourceMonitor mCommunalSourceMonitor;
+
+    @Mock
+    private CommunalSource.Connector mConnector;
+
+    @Mock
+    private CommunalSource.Observer mObserver;
+
+    private CommunalSourcePrimer mPrimer;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+        when(mResources.getInteger(R.integer.config_communalSourceMaxReconnectAttempts))
+                .thenReturn(MAX_RETRIES);
+        when(mResources.getInteger(R.integer.config_communalSourceReconnectBaseDelay))
+                .thenReturn(RETRY_DELAY_MS);
+        when(mResources.getString(R.string.config_communalSourceComponent))
+                .thenReturn(TEST_COMPONENT_NAME);
+
+        mPrimer = new CommunalSourcePrimer(mContext, mResources, mFakeExecutor,
+                mCommunalSourceMonitor, Optional.of(mConnector), Optional.of(mObserver));
+    }
+
+    @Test
+    public void testConnect() {
+        when(mConnector.connect()).thenReturn(
+                CallbackToFutureAdapter.getFuture(completer -> {
+                    completer.set(Optional.of(mSource));
+                    return "test";
+                }));
+
+        mPrimer.onBootCompleted();
+        mFakeExecutor.runAllReady();
+        verify(mCommunalSourceMonitor).setSource(mSource);
+    }
+
+    @Test
+    public void testRetryOnBindFailure() throws Exception {
+        when(mConnector.connect()).thenReturn(
+                CallbackToFutureAdapter.getFuture(completer -> {
+                    completer.set(Optional.empty());
+                    return "test";
+                }));
+
+        mPrimer.onBootCompleted();
+        mFakeExecutor.runAllReady();
+
+        // Verify attempts happen. Note that we account for the retries plus initial attempt, which
+        // is not scheduled.
+        for (int attemptCount = 0; attemptCount < MAX_RETRIES + 1; attemptCount++) {
+            verify(mConnector, times(1)).connect();
+            clearInvocations(mConnector);
+            mFakeExecutor.advanceClockToNext();
+            mFakeExecutor.runAllReady();
+        }
+
+        verify(mCommunalSourceMonitor, never()).setSource(Mockito.notNull());
+    }
+
+    @Test
+    public void testAttemptOnPackageChange() {
+        when(mConnector.connect()).thenReturn(
+                CallbackToFutureAdapter.getFuture(completer -> {
+                    completer.set(Optional.empty());
+                    return "test";
+                }));
+
+        mPrimer.onBootCompleted();
+        mFakeExecutor.runAllReady();
+
+        final ArgumentCaptor<CommunalSource.Observer.Callback> callbackCaptor =
+                ArgumentCaptor.forClass(CommunalSource.Observer.Callback.class);
+        verify(mObserver).addCallback(callbackCaptor.capture());
+
+        clearInvocations(mConnector);
+        callbackCaptor.getValue().onSourceChanged();
+
+        verify(mConnector, times(1)).connect();
+    }
+
+    @Test
+    public void testDisconnect() {
+        final ArgumentCaptor<CommunalSource.Callback> callbackCaptor =
+                ArgumentCaptor.forClass(CommunalSource.Callback.class);
+
+        when(mConnector.connect()).thenReturn(
+                CallbackToFutureAdapter.getFuture(completer -> {
+                    completer.set(Optional.of(mSource));
+                    return "test";
+                }));
+
+        mPrimer.onBootCompleted();
+        mFakeExecutor.runAllReady();
+        verify(mCommunalSourceMonitor).setSource(mSource);
+        verify(mSource).addCallback(callbackCaptor.capture());
+
+        clearInvocations(mConnector);
+        callbackCaptor.getValue().onDisconnected();
+        mFakeExecutor.runAllReady();
+
+        verify(mConnector).connect();
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java
index f525fee..f207b9e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java
@@ -17,6 +17,7 @@
 package com.android.systemui.doze;
 
 import static com.android.systemui.doze.DozeLog.REASON_SENSOR_TAP;
+import static com.android.systemui.doze.DozeLog.REASON_SENSOR_UDFPS_LONG_PRESS;
 import static com.android.systemui.plugins.SensorManagerPlugin.Sensor.TYPE_WAKE_LOCK_SCREEN;
 
 import static org.junit.Assert.assertEquals;
@@ -37,6 +38,7 @@
 import android.database.ContentObserver;
 import android.hardware.Sensor;
 import android.hardware.display.AmbientDisplayConfiguration;
+import android.os.UserHandle;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.testing.TestableLooper.RunWithLooper;
@@ -57,6 +59,8 @@
 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;
 
@@ -94,6 +98,13 @@
     private DevicePostureController mDevicePostureController;
     @Mock
     private ProximitySensor mProximitySensor;
+
+    // Capture listeners so that they can be used to send events
+    @Captor
+    private ArgumentCaptor<AuthController.Callback> mAuthControllerCallbackCaptor =
+            ArgumentCaptor.forClass(AuthController.Callback.class);
+    private AuthController.Callback mAuthControllerCallback;
+
     private FakeSettings mFakeSettings = new FakeSettings();
     private SensorManagerPlugin.SensorEventListener mWakeLockScreenListener;
     private TestableLooper mTestableLooper;
@@ -105,14 +116,18 @@
         MockitoAnnotations.initMocks(this);
         mTestableLooper = TestableLooper.get(this);
         when(mAmbientDisplayConfiguration.tapSensorTypeMapping())
-                .thenReturn(new String[]{"tapSEnsor"});
+                .thenReturn(new String[]{"tapSensor"});
         when(mAmbientDisplayConfiguration.getWakeLockScreenDebounce()).thenReturn(5000L);
         when(mAmbientDisplayConfiguration.alwaysOnEnabled(anyInt())).thenReturn(true);
+        when(mAmbientDisplayConfiguration.enabled(UserHandle.USER_CURRENT)).thenReturn(true);
         doAnswer(invocation -> {
             ((Runnable) invocation.getArgument(0)).run();
             return null;
         }).when(mWakeLock).wrap(any(Runnable.class));
         mDozeSensors = new TestableDozeSensors();
+
+        verify(mAuthController).addCallback(mAuthControllerCallbackCaptor.capture());
+        mAuthControllerCallback = mAuthControllerCallbackCaptor.getValue();
     }
 
     @Test
@@ -375,6 +390,47 @@
                         "some other name"));
     }
 
+    @Test
+    public void testUdfpsEnrollmentChanged() throws Exception {
+        // GIVEN a UDFPS_LONG_PRESS trigger sensor that's not configured
+        Sensor mockSensor = mock(Sensor.class);
+        TriggerSensor triggerSensor = mDozeSensors.createDozeSensor(
+                mockSensor,
+                REASON_SENSOR_UDFPS_LONG_PRESS,
+                /* configured */ false);
+        mDozeSensors.addSensor(triggerSensor);
+        when(mSensorManager.requestTriggerSensor(eq(triggerSensor), eq(mockSensor)))
+                .thenReturn(true);
+
+        // WHEN listening state is set to TRUE
+        mDozeSensors.setListening(true, true);
+
+        // THEN mRegistered is still false b/c !mConfigured
+        assertFalse(triggerSensor.mConfigured);
+        assertFalse(triggerSensor.mRegistered);
+
+        // WHEN enrollment changes to TRUE
+        when(mAuthController.isUdfpsEnrolled(anyInt())).thenReturn(true);
+        mAuthControllerCallback.onEnrollmentsChanged();
+
+        // THEN mConfigured = TRUE
+        assertTrue(triggerSensor.mConfigured);
+
+        // THEN mRegistered = TRUE
+        assertTrue(triggerSensor.mRegistered);
+    }
+
+    @Test
+    public void testGesturesAllInitiallyRespectSettings() {
+        DozeSensors dozeSensors = new DozeSensors(getContext(), mSensorManager, mDozeParameters,
+                mAmbientDisplayConfiguration, mWakeLock, mCallback, mProxCallback, mDozeLog,
+                mProximitySensor, mFakeSettings, mAuthController,
+                mDevicePostureController);
+
+        for (TriggerSensor sensor : dozeSensors.mTriggerSensors) {
+            assertFalse(sensor.mIgnoresSetting);
+        }
+    }
 
     private class TestableDozeSensors extends DozeSensors {
         TestableDozeSensors() {
@@ -407,6 +463,22 @@
                     requiresTouchScreen);
         }
 
+        public TriggerSensor createDozeSensor(
+                Sensor sensor,
+                int pulseReason,
+                boolean configured
+        ) {
+            return new TriggerSensor(/* sensor */ sensor,
+                    /* setting name */ "test_setting",
+                    /* settingDefault */ true,
+                    /* configured */ configured,
+                    /* pulseReason*/ pulseReason,
+                    /* reportsTouchCoordinate*/ false,
+                    /* requiresTouchscreen */ false,
+                    /* ignoresSetting */ false,
+                    /* requiresTouchScreen */false);
+        }
+
         /**
          * create a doze sensor that supports postures and is enabled
          */
@@ -422,6 +494,15 @@
                     /* requiresProx */false,
                     posture);
         }
+
+        public void addSensor(TriggerSensor sensor) {
+            TriggerSensor[] newArray = new TriggerSensor[mTriggerSensors.length + 1];
+            for (int i = 0; i < mTriggerSensors.length; i++) {
+                newArray[i] = mTriggerSensors[i];
+            }
+            newArray[mTriggerSensors.length] = sensor;
+            mTriggerSensors = newArray;
+        }
     }
 
     public static void setSensorType(Sensor sensor, int type, String strType) throws Exception {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsReleaseTest.java
similarity index 73%
rename from packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagManagerTest.java
rename to packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsReleaseTest.java
index 6347638..475dde2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsReleaseTest.java
@@ -25,7 +25,6 @@
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.verifyZeroInteractions;
 
 import android.content.Context;
 
@@ -33,7 +32,6 @@
 
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.dump.DumpManager;
-import com.android.systemui.util.settings.SecureSettings;
 
 import org.junit.After;
 import org.junit.Before;
@@ -50,17 +48,16 @@
  * overriding, and should never return any value other than the one provided as the default.
  */
 @SmallTest
-public class FeatureFlagManagerTest extends SysuiTestCase {
-    FeatureFlagManager mFeatureFlagManager;
+public class FeatureFlagsReleaseTest extends SysuiTestCase {
+    FeatureFlagsRelease mFeatureFlagsRelease;
 
-    @Mock private Context mContext;
     @Mock private DumpManager mDumpManager;
 
     @Before
     public void setup() {
         MockitoAnnotations.initMocks(this);
 
-        mFeatureFlagManager = new FeatureFlagManager(mDumpManager);
+        mFeatureFlagsRelease = new FeatureFlagsRelease(mDumpManager);
     }
 
     @After
@@ -71,23 +68,10 @@
     }
 
     @Test
-    public void testIsEnabled() {
-        mFeatureFlagManager.setEnabled(1, true);
-        // Again, nothing changes.
-        assertThat(mFeatureFlagManager.isEnabled(1, false)).isFalse();
-    }
-
-    @Test
     public void testDump() {
-        // Even if a flag is set before
-        mFeatureFlagManager.setEnabled(1, true);
-
         // WHEN the flags have been accessed
-        assertFalse(mFeatureFlagManager.isEnabled(1, false));
-        assertTrue(mFeatureFlagManager.isEnabled(2, true));
-
-        // Even if a flag is set after
-        mFeatureFlagManager.setEnabled(2, false);
+        assertFalse(mFeatureFlagsRelease.isEnabled(1, false));
+        assertTrue(mFeatureFlagsRelease.isEnabled(2, true));
 
         // THEN the dump contains the flags and the default values
         String dump = dumpToString();
@@ -98,7 +82,7 @@
     private String dumpToString() {
         StringWriter sw = new StringWriter();
         PrintWriter pw = new PrintWriter(sw);
-        mFeatureFlagManager.dump(mock(FileDescriptor.class), pw, new String[0]);
+        mFeatureFlagsRelease.dump(mock(FileDescriptor.class), pw, new String[0]);
         pw.flush();
         String dump = sw.toString();
         return dump;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/fragments/FragmentServiceTest.kt b/packages/SystemUI/tests/src/com/android/systemui/fragments/FragmentServiceTest.kt
new file mode 100644
index 0000000..77c837b
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/fragments/FragmentServiceTest.kt
@@ -0,0 +1,82 @@
+package com.android.systemui.fragments
+
+import android.app.Fragment
+import android.os.Looper
+import android.test.suitebuilder.annotation.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.qs.QSFragment
+import com.android.systemui.util.mockito.mock
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+
+@SmallTest
+class FragmentServiceTest : SysuiTestCase() {
+    private val fragmentCreator = TestFragmentCreator()
+    private val fragmentCreatorFactory = FragmentService.FragmentCreator.Factory { fragmentCreator }
+
+    private lateinit var fragmentService: FragmentService
+
+    @Before
+    fun setUp() {
+        if (Looper.myLooper() == null) {
+            Looper.prepare()
+        }
+
+        fragmentService = FragmentService(fragmentCreatorFactory, mock(), DumpManager())
+    }
+
+    @Test
+    fun constructor_addsFragmentCreatorMethodsToMap() {
+        val map = fragmentService.injectionMap
+        assertThat(map).hasSize(2)
+        assertThat(map.keys).contains(QSFragment::class.java.name)
+        assertThat(map.keys).contains(TestFragmentInCreator::class.java.name)
+    }
+
+    @Test
+    fun addFragmentInstantiationProvider_objectHasNoFragmentMethods_nothingAdded() {
+        fragmentService.addFragmentInstantiationProvider(Object())
+
+        assertThat(fragmentService.injectionMap).hasSize(2)
+    }
+
+    @Test
+    fun addFragmentInstantiationProvider_objectHasFragmentMethods_methodsAdded() {
+        fragmentService.addFragmentInstantiationProvider(
+            @Suppress("unused")
+            object : Any() {
+                fun createTestFragment2() = TestFragment2()
+                fun createTestFragment3() = TestFragment3()
+            }
+        )
+
+        val map = fragmentService.injectionMap
+        assertThat(map).hasSize(4)
+        assertThat(map.keys).contains(TestFragment2::class.java.name)
+        assertThat(map.keys).contains(TestFragment3::class.java.name)
+    }
+
+    @Test
+    fun addFragmentInstantiationProvider_objectFragmentMethodsAlreadyProvided_nothingAdded() {
+        fragmentService.addFragmentInstantiationProvider(
+            @Suppress("unused")
+            object : Any() {
+                fun createTestFragment() = TestFragmentInCreator()
+            }
+        )
+
+        assertThat(fragmentService.injectionMap).hasSize(2)
+    }
+
+    class TestFragmentCreator : FragmentService.FragmentCreator {
+        override fun createQSFragment(): QSFragment = mock()
+        @Suppress("unused")
+        fun createTestFragment(): TestFragmentInCreator = TestFragmentInCreator()
+    }
+
+    class TestFragmentInCreator : Fragment()
+    class TestFragment2 : Fragment()
+    class TestFragment3 : Fragment()
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
index 6d8645e..b774daf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
@@ -41,6 +41,7 @@
 
 import androidx.test.filters.SmallTest;
 
+import com.android.internal.jank.InteractionJankMonitor;
 import com.android.internal.policy.IKeyguardDrawnCallback;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.keyguard.KeyguardDisplayManager;
@@ -64,9 +65,6 @@
 import com.android.systemui.util.concurrency.FakeExecutor;
 import com.android.systemui.util.time.FakeSystemClock;
 
-import java.util.Optional;
-import java.util.function.Function;
-
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -75,6 +73,9 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.util.Optional;
+import java.util.function.Function;
+
 @RunWith(AndroidTestingRunner.class)
 @TestableLooper.RunWithLooper
 @SmallTest
@@ -103,6 +104,7 @@
     private @Mock KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
     private @Mock UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
     private @Mock IKeyguardDrawnCallback mKeyguardDrawnCallback;
+    private @Mock InteractionJankMonitor mInteractionJankMonitor;
     private DeviceConfigProxy mDeviceConfig = new DeviceConfigProxyFake();
     private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock());
 
@@ -121,6 +123,8 @@
             .thenReturn(mUnfoldAnimationOptional);
         when(mUnfoldAnimationOptional.isPresent()).thenReturn(true);
         when(mUnfoldAnimationOptional.get()).thenReturn(mUnfoldAnimation);
+        when(mInteractionJankMonitor.begin(any(), anyInt())).thenReturn(true);
+        when(mInteractionJankMonitor.end(anyInt())).thenReturn(true);
 
         mViewMediator = new KeyguardViewMediator(
                 mContext,
@@ -144,7 +148,8 @@
                 mKeyguardStateController,
                 () -> mKeyguardUnlockAnimationController,
                 mUnlockedScreenOffAnimationController,
-                () -> mNotificationShadeDepthController);
+                () -> mNotificationShadeDepthController,
+                mInteractionJankMonitor);
         mViewMediator.start();
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt
index 175ec87f..a6e567e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt
@@ -104,37 +104,54 @@
     fun testPlayerOrdering() {
         // Test values: key, data, last active time
         val playingLocal = Triple("playing local",
-            DATA.copy(active = true, isPlaying = true, isLocalSession = true, resumption = false),
+            DATA.copy(active = true, isPlaying = true,
+                    playbackLocation = MediaData.PLAYBACK_LOCAL, resumption = false),
             4500L)
 
-        val playingRemote = Triple("playing remote",
-            DATA.copy(active = true, isPlaying = true, isLocalSession = false, resumption = false),
+        val playingCast = Triple("playing cast",
+            DATA.copy(active = true, isPlaying = true,
+                    playbackLocation = MediaData.PLAYBACK_CAST_LOCAL, resumption = false),
             5000L)
 
         val pausedLocal = Triple("paused local",
-            DATA.copy(active = true, isPlaying = false, isLocalSession = true, resumption = false),
+            DATA.copy(active = true, isPlaying = false,
+                    playbackLocation = MediaData.PLAYBACK_LOCAL, resumption = false),
             1000L)
 
-        val pausedRemote = Triple("paused remote",
-            DATA.copy(active = true, isPlaying = false, isLocalSession = false, resumption = false),
+        val pausedCast = Triple("paused cast",
+            DATA.copy(active = true, isPlaying = false,
+                    playbackLocation = MediaData.PLAYBACK_CAST_LOCAL, resumption = false),
             2000L)
 
+        val playingRcn = Triple("playing RCN",
+            DATA.copy(active = true, isPlaying = true,
+                    playbackLocation = MediaData.PLAYBACK_CAST_REMOTE, resumption = false),
+            5000L)
+
+        val pausedRcn = Triple("paused RCN",
+                DATA.copy(active = true, isPlaying = false,
+                        playbackLocation = MediaData.PLAYBACK_CAST_REMOTE, resumption = false),
+                5000L)
+
         val resume1 = Triple("resume 1",
-            DATA.copy(active = false, isPlaying = false, isLocalSession = true, resumption = true),
+            DATA.copy(active = false, isPlaying = false,
+                    playbackLocation = MediaData.PLAYBACK_LOCAL, resumption = true),
             500L)
 
         val resume2 = Triple("resume 2",
-            DATA.copy(active = false, isPlaying = false, isLocalSession = true, resumption = true),
+            DATA.copy(active = false, isPlaying = false,
+                    playbackLocation = MediaData.PLAYBACK_LOCAL, resumption = true),
             1000L)
 
         // Expected ordering for media players:
         // Actively playing local sessions
-        // Actively playing remote sessions
-        // Paused sessions, by last active
+        // Actively playing cast sessions
+        // Paused local and cast sessions, by last active
+        // RCNs
         // Resume controls, by last active
 
-        val expected = listOf(playingLocal, playingRemote, pausedRemote, pausedLocal, resume2,
-            resume1)
+        val expected = listOf(playingLocal, playingCast, pausedCast, pausedLocal, playingRcn,
+                pausedRcn, resume2, resume1)
 
         expected.forEach {
             clock.setCurrentTimeMillis(it.third)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataCombineLatestTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataCombineLatestTest.java
index 66b6470..f870da3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataCombineLatestTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataCombineLatestTest.java
@@ -74,8 +74,8 @@
         mManager.addListener(mListener);
 
         mMediaData = new MediaData(USER_ID, true, BG_COLOR, APP, null, ARTIST, TITLE, null,
-                new ArrayList<>(), new ArrayList<>(), PACKAGE, null, null, null, true, null, true,
-                false, KEY, false, false, false, 0L);
+                new ArrayList<>(), new ArrayList<>(), PACKAGE, null, null, null, true, null,
+                MediaData.PLAYBACK_LOCAL, false, KEY, false, false, false, 0L);
         mDeviceData = new MediaDeviceData(true, null, DEVICE_NAME);
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
index 2b2fc51..f44cc38 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
@@ -1,5 +1,6 @@
 package com.android.systemui.media
 
+import android.app.Notification
 import android.app.Notification.MediaStyle
 import android.app.PendingIntent
 import android.app.smartspace.SmartspaceAction
@@ -229,6 +230,30 @@
     }
 
     @Test
+    fun testOnNotificationAdded_isRcn_markedRemote() {
+        val bundle = Bundle().apply {
+            putString(Notification.EXTRA_SUBSTITUTE_APP_NAME, "Remote Cast Notification")
+        }
+        val rcn = SbnBuilder().run {
+            setPkg("com.android.systemui") // System package
+            modifyNotification(context).also {
+                it.setSmallIcon(android.R.drawable.ic_media_pause)
+                it.setStyle(MediaStyle().apply { setMediaSession(session.sessionToken) })
+                it.addExtras(bundle)
+            }
+            build()
+        }
+
+        mediaDataManager.onNotificationAdded(KEY, rcn)
+        assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
+        assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
+        verify(listener).onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor), eq(true),
+                eq(false))
+        assertThat(mediaDataCaptor.value!!.playbackLocation).isEqualTo(
+                MediaData.PLAYBACK_CAST_REMOTE)
+    }
+
+    @Test
     fun testOnNotificationRemoved_callsListener() {
         mediaDataManager.onNotificationAdded(KEY, mediaNotification)
         mediaDataManager.onMediaDataLoaded(KEY, oldKey = null, data = mock(MediaData::class.java))
@@ -306,7 +331,8 @@
         verify(listener).onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor), eq(true),
                 eq(false))
         val data = mediaDataCaptor.value
-        val dataRemoteWithResume = data.copy(resumeAction = Runnable {}, isLocalSession = false)
+        val dataRemoteWithResume = data.copy(resumeAction = Runnable {},
+                playbackLocation = MediaData.PLAYBACK_CAST_LOCAL)
         mediaDataManager.onMediaDataLoaded(KEY, null, dataRemoteWithResume)
 
         // WHEN the notification is removed
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaPlayerDataTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaPlayerDataTest.kt
index 8dc9eff..421f9be 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaPlayerDataTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaPlayerDataTest.kt
@@ -42,7 +42,8 @@
     val mockito = MockitoJUnit.rule()
 
     companion object {
-        val LOCAL = true
+        val LOCAL = MediaData.PLAYBACK_LOCAL
+        val REMOTE = MediaData.PLAYBACK_CAST_LOCAL
         val RESUMPTION = true
         val PLAYING = true
         val UNDETERMINED = null
@@ -58,7 +59,7 @@
         val dataIsPlaying = createMediaData("app1", PLAYING, LOCAL, !RESUMPTION)
 
         val playerIsRemote = mock(MediaControlPanel::class.java)
-        val dataIsRemote = createMediaData("app2", PLAYING, !LOCAL, !RESUMPTION)
+        val dataIsRemote = createMediaData("app2", PLAYING, REMOTE, !RESUMPTION)
 
         MediaPlayerData.addMediaPlayer("2", dataIsRemote, playerIsRemote, systemClock)
         MediaPlayerData.addMediaPlayer("1", dataIsPlaying, playerIsPlaying, systemClock)
@@ -100,13 +101,13 @@
         val dataIsPlaying = createMediaData("app1", PLAYING, LOCAL, !RESUMPTION)
 
         val playerIsPlayingAndRemote = mock(MediaControlPanel::class.java)
-        val dataIsPlayingAndRemote = createMediaData("app2", PLAYING, !LOCAL, !RESUMPTION)
+        val dataIsPlayingAndRemote = createMediaData("app2", PLAYING, REMOTE, !RESUMPTION)
 
         val playerIsStoppedAndLocal = mock(MediaControlPanel::class.java)
         val dataIsStoppedAndLocal = createMediaData("app3", !PLAYING, LOCAL, !RESUMPTION)
 
         val playerIsStoppedAndRemote = mock(MediaControlPanel::class.java)
-        val dataIsStoppedAndRemote = createMediaData("app4", !PLAYING, !LOCAL, !RESUMPTION)
+        val dataIsStoppedAndRemote = createMediaData("app4", !PLAYING, REMOTE, !RESUMPTION)
 
         val playerCanResume = mock(MediaControlPanel::class.java)
         val dataCanResume = createMediaData("app5", !PLAYING, LOCAL, RESUMPTION)
@@ -127,8 +128,8 @@
         val players = MediaPlayerData.players()
         assertThat(players).hasSize(6)
         assertThat(players).containsExactly(playerIsPlaying, playerIsPlayingAndRemote,
-            playerIsStoppedAndRemote, playerIsStoppedAndLocal, playerCanResume,
-            playerUndetermined).inOrder()
+            playerIsStoppedAndRemote, playerIsStoppedAndLocal, playerUndetermined,
+            playerCanResume).inOrder()
     }
 
     @Test
@@ -160,9 +161,10 @@
     private fun createMediaData(
         app: String,
         isPlaying: Boolean?,
-        isLocalSession: Boolean,
+        location: Int,
         resumption: Boolean
     ) =
-        MediaData(0, false, 0, app, null, null, null, null, emptyList(), emptyList<Int>(), "",
-            null, null, null, true, null, isLocalSession, resumption, null, false, isPlaying)
+        MediaData(0, false, 0, app, null, null, null, null, emptyList(), emptyList<Int>(),
+            "package:" + app, null, null, null, true, null, location, resumption, "key:" + app,
+            false, isPlaying)
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaResumeListenerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaResumeListenerTest.kt
index a17a03d..30ee2e4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaResumeListenerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaResumeListenerTest.kt
@@ -211,10 +211,20 @@
     }
 
     @Test
-    fun testOnLoad_remotePlayback_doesNotCheck() {
-        // When media data is loaded that has not been checked yet, and is not local
-        val dataRemote = data.copy(isLocalSession = false)
-        resumeListener.onMediaDataLoaded(KEY, null, dataRemote)
+    fun testOnLoad_localCast_doesNotCheck() {
+        // When media data is loaded that has not been checked yet, and is a local cast
+        val dataCast = data.copy(playbackLocation = MediaData.PLAYBACK_CAST_LOCAL)
+        resumeListener.onMediaDataLoaded(KEY, null, dataCast)
+
+        // Then we do not take action
+        verify(mediaDataManager, never()).setResumeAction(any(), any())
+    }
+
+    @Test
+    fun testOnload_remoteCast_doesNotCheck() {
+        // When media data is loaded that has not been checked yet, and is a remote cast
+        val dataRcn = data.copy(playbackLocation = MediaData.PLAYBACK_CAST_REMOTE)
+        resumeListener.onMediaDataLoaded(KEY, null, dataRcn)
 
         // Then we do not take action
         verify(mediaDataManager, never()).setResumeAction(any(), any())
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java
index f7e60ca..09ec4ca 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java
@@ -469,7 +469,7 @@
         when(entry.getSbn()).thenReturn(sbn);
         when(sbn.getNotification()).thenReturn(notification);
         when(sbn.getPackageName()).thenReturn(TEST_PACKAGE_NAME);
-        when(notification.hasMediaSession()).thenReturn(true);
+        when(notification.isMediaNotification()).thenReturn(true);
         when(notification.getLargeIcon()).thenReturn(null);
 
         assertThat(mMediaOutputController.getNotificationIcon()).isNull();
@@ -489,7 +489,7 @@
         when(entry.getSbn()).thenReturn(sbn);
         when(sbn.getNotification()).thenReturn(notification);
         when(sbn.getPackageName()).thenReturn(TEST_PACKAGE_NAME);
-        when(notification.hasMediaSession()).thenReturn(true);
+        when(notification.isMediaNotification()).thenReturn(true);
         when(notification.getLargeIcon()).thenReturn(icon);
 
         assertThat(mMediaOutputController.getNotificationIcon() instanceof IconCompat).isTrue();
@@ -509,7 +509,7 @@
         when(entry.getSbn()).thenReturn(sbn);
         when(sbn.getNotification()).thenReturn(notification);
         when(sbn.getPackageName()).thenReturn(TEST_PACKAGE_NAME);
-        when(notification.hasMediaSession()).thenReturn(false);
+        when(notification.isMediaNotification()).thenReturn(false);
         when(notification.getLargeIcon()).thenReturn(icon);
 
         assertThat(mMediaOutputController.getNotificationIcon()).isNull();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavBarHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavBarHelperTest.java
new file mode 100644
index 0000000..734faec
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavBarHelperTest.java
@@ -0,0 +1,178 @@
+/*
+ * 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.navigationbar;
+
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.ComponentName;
+import android.view.accessibility.AccessibilityManager;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.accessibility.AccessibilityButtonModeObserver;
+import com.android.systemui.assist.AssistManager;
+import com.android.systemui.dump.DumpManager;
+import com.android.systemui.recents.OverviewProxyService;
+import com.android.systemui.settings.UserTracker;
+import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import dagger.Lazy;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class NavBarHelperTest extends SysuiTestCase {
+
+    @Mock
+    AccessibilityManager mAccessibilityManager;
+    @Mock
+    AccessibilityManagerWrapper mAccessibilityManagerWrapper;
+    @Mock
+    AccessibilityButtonModeObserver mAccessibilityButtonModeObserver;
+    @Mock
+    OverviewProxyService mOverviewProxyService;
+    @Mock
+    Lazy<AssistManager> mAssistManagerLazy;
+    @Mock
+    AssistManager mAssistManager;
+    @Mock
+    NavigationModeController mNavigationModeController;
+    @Mock
+    UserTracker mUserTracker;
+    @Mock
+    ComponentName mAssistantComponent;
+    @Mock
+    DumpManager mDumpManager;
+    @Mock
+    NavBarHelper.NavbarTaskbarStateUpdater mNavbarTaskbarStateUpdater;
+
+    private NavBarHelper mNavBarHelper;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+        when(mAssistManagerLazy.get()).thenReturn(mAssistManager);
+        when(mAssistManager.getAssistInfoForUser(anyInt())).thenReturn(mAssistantComponent);
+        when(mUserTracker.getUserId()).thenReturn(1);
+
+        mNavBarHelper = new NavBarHelper(mAccessibilityManager,
+                mAccessibilityManagerWrapper, mAccessibilityButtonModeObserver,
+                mOverviewProxyService, mAssistManagerLazy, mNavigationModeController,
+                mUserTracker, mDumpManager);
+
+    }
+
+    @Test
+    public void registerListenersInCtor() {
+        verify(mAccessibilityButtonModeObserver, times(1)).addListener(mNavBarHelper);
+        verify(mNavigationModeController, times(1)).addListener(mNavBarHelper);
+        verify(mOverviewProxyService, times(1)).addCallback(mNavBarHelper);
+    }
+
+    @Test
+    public void registerAssistantContentObserver() {
+        mNavBarHelper.init(mContext);
+        verify(mAssistManager, times(1)).getAssistInfoForUser(anyInt());
+    }
+
+    @Test
+    public void callbacksFiredWhenRegistering() {
+        mNavBarHelper.init(mContext);
+        mNavBarHelper.registerNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
+        verify(mNavbarTaskbarStateUpdater, times(1))
+                .updateAccessibilityServicesState();
+        verify(mNavbarTaskbarStateUpdater, times(1))
+                .updateAssistantAvailable(anyBoolean());
+    }
+
+    @Test
+    public void assistantCallbacksFiredAfterConnecting() {
+        mNavBarHelper.init(mContext);
+        // 1st set of callbacks get called when registering
+        mNavBarHelper.registerNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
+
+        mNavBarHelper.onConnectionChanged(false);
+        // assert no more callbacks fired
+        verify(mNavbarTaskbarStateUpdater, times(1))
+                .updateAccessibilityServicesState();
+        verify(mNavbarTaskbarStateUpdater, times(1))
+                .updateAssistantAvailable(anyBoolean());
+
+        mNavBarHelper.onConnectionChanged(true);
+        // assert no more callbacks fired
+        verify(mNavbarTaskbarStateUpdater, times(1))
+                .updateAccessibilityServicesState();
+        verify(mNavbarTaskbarStateUpdater, times(2))
+                .updateAssistantAvailable(anyBoolean());
+    }
+
+    @Test
+    public void a11yCallbacksFiredAfterModeChange() {
+        mNavBarHelper.init(mContext);
+        // 1st set of callbacks get called when registering
+        mNavBarHelper.registerNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
+
+        mNavBarHelper.onAccessibilityButtonModeChanged(0);
+        verify(mNavbarTaskbarStateUpdater, times(2))
+                .updateAccessibilityServicesState();
+        verify(mNavbarTaskbarStateUpdater, times(1))
+                .updateAssistantAvailable(anyBoolean());
+    }
+
+    @Test
+    public void assistantCallbacksFiredAfterNavModeChange() {
+        mNavBarHelper.init(mContext);
+        // 1st set of callbacks get called when registering
+        mNavBarHelper.registerNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
+
+        mNavBarHelper.onNavigationModeChanged(0);
+        verify(mNavbarTaskbarStateUpdater, times(1))
+                .updateAccessibilityServicesState();
+        verify(mNavbarTaskbarStateUpdater, times(2))
+                .updateAssistantAvailable(anyBoolean());
+    }
+
+    @Test
+    public void removeListenerNoCallbacksFired() {
+        mNavBarHelper.init(mContext);
+        // 1st set of callbacks get called when registering
+        mNavBarHelper.registerNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
+
+        // Remove listener
+        mNavBarHelper.removeNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
+
+        // Would have fired 2nd callback if not removed
+        mNavBarHelper.onAccessibilityButtonModeChanged(0);
+
+        // assert no more callbacks fired
+        verify(mNavbarTaskbarStateUpdater, times(1))
+                .updateAccessibilityServicesState();
+        verify(mNavbarTaskbarStateUpdater, times(1))
+                .updateAssistantAvailable(anyBoolean());
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java
index 4fc329f..9d2541c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java
@@ -45,6 +45,7 @@
 import com.android.systemui.recents.OverviewProxyService;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.phone.AutoHideController;
+import com.android.systemui.statusbar.phone.LightBarController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 
 import org.junit.After;
@@ -82,11 +83,12 @@
                         mCommandQueue,
                         Dependency.get(Dependency.MAIN_HANDLER),
                         mock(ConfigurationController.class),
-                        mock(NavigationBarA11yHelper.class),
+                        mock(NavBarHelper.class),
                         mock(TaskbarDelegate.class),
                         mNavigationBarFactory,
                         mock(DumpManager.class),
-                        mock(AutoHideController.class)));
+                        mock(AutoHideController.class),
+                        mock(LightBarController.class)));
         initializeNavigationBars();
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
index 223ffbd..e038b6e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
@@ -23,17 +23,20 @@
 import static android.inputmethodservice.InputMethodService.IME_VISIBLE;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS;
+import static android.view.WindowInsets.Type.ime;
 
 import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.HOME_BUTTON_LONG_PRESS_DURATION_MS;
 import static com.android.systemui.navigationbar.NavigationBar.NavBarActionEvent.NAVBAR_ASSIST_LONGPRESS;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
@@ -57,6 +60,7 @@
 import android.view.DisplayInfo;
 import android.view.MotionEvent;
 import android.view.View;
+import android.view.WindowInsets;
 import android.view.WindowManager;
 import android.view.WindowMetrics;
 import android.view.accessibility.AccessibilityManager;
@@ -83,6 +87,7 @@
 import com.android.systemui.statusbar.NotificationShadeDepthController;
 import com.android.systemui.statusbar.phone.AutoHideController;
 import com.android.systemui.statusbar.phone.LightBarController;
+import com.android.systemui.statusbar.phone.NotificationShadeWindowView;
 import com.android.systemui.statusbar.phone.ShadeController;
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
@@ -131,7 +136,7 @@
     @Mock
     EdgeBackGestureHandler mEdgeBackGestureHandler;
     @Mock
-    NavigationBarA11yHelper mNavigationBarA11yHelper;
+    NavBarHelper mNavBarHelper;
     @Mock
     private LightBarController mLightBarController;
     @Mock
@@ -148,6 +153,8 @@
     private InputMethodManager mInputMethodManager;
     @Mock
     private AssistManager mAssistManager;
+    @Mock
+    private StatusBar mStatusBar;
 
     @Rule
     public final LeakCheckedTest.SysuiLeakCheck mLeakCheck = new LeakCheckedTest.SysuiLeakCheck();
@@ -220,6 +227,7 @@
                 new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_SYSTEMUI)
                     .setLong(HOME_BUTTON_LONG_PRESS_DURATION_MS, 100)
                     .build());
+        when(mNavBarHelper.getLongPressHomeEnabled()).thenReturn(true);
         mNavigationBar.onViewAttachedToWindow(mNavigationBar.createView(null));
 
         mNavigationBar.onHomeTouch(mNavigationBar.getView(), MotionEvent.obtain(
@@ -255,6 +263,11 @@
         // Create default & external NavBar fragment.
         NavigationBar defaultNavBar = mNavigationBar;
         NavigationBar externalNavBar = mExternalDisplayNavigationBar;
+        NotificationShadeWindowView mockShadeWindowView = mock(NotificationShadeWindowView.class);
+        WindowInsets windowInsets = new WindowInsets.Builder().setVisible(ime(), false).build();
+        doReturn(windowInsets).when(mockShadeWindowView).getRootWindowInsets();
+        doReturn(mockShadeWindowView).when(mStatusBar).getNotificationShadeWindowView();
+        doReturn(true).when(mockShadeWindowView).isAttachedToWindow();
         doNothing().when(defaultNavBar).checkNavBarModes();
         doNothing().when(externalNavBar).checkNavBarModes();
         defaultNavBar.createView(null);
@@ -281,17 +294,51 @@
     }
 
     @Test
+    public void testSetImeWindowStatusWhenKeyguardLockingAndImeInsetsChange() {
+        NotificationShadeWindowView mockShadeWindowView = mock(NotificationShadeWindowView.class);
+        doReturn(mockShadeWindowView).when(mStatusBar).getNotificationShadeWindowView();
+        doReturn(true).when(mockShadeWindowView).isAttachedToWindow();
+        doNothing().when(mNavigationBar).checkNavBarModes();
+        mNavigationBar.createView(null);
+        WindowInsets windowInsets = new WindowInsets.Builder().setVisible(ime(), false).build();
+        doReturn(windowInsets).when(mockShadeWindowView).getRootWindowInsets();
+
+        // Verify navbar altered back icon when an app is showing IME
+        mNavigationBar.setImeWindowStatus(DEFAULT_DISPLAY, null, IME_VISIBLE,
+                BACK_DISPOSITION_DEFAULT, true);
+        assertTrue((mNavigationBar.getNavigationIconHints() & NAVIGATION_HINT_BACK_ALT) != 0);
+        assertTrue((mNavigationBar.getNavigationIconHints() & NAVIGATION_HINT_IME_SHOWN) != 0);
+
+        // Verify navbar didn't alter and showing back icon when the keyguard is showing without
+        // requesting IME insets visible.
+        doReturn(true).when(mStatusBar).isKeyguardShowing();
+        mNavigationBar.setImeWindowStatus(DEFAULT_DISPLAY, null, IME_VISIBLE,
+                BACK_DISPOSITION_DEFAULT, true);
+        assertFalse((mNavigationBar.getNavigationIconHints() & NAVIGATION_HINT_BACK_ALT) != 0);
+        assertFalse((mNavigationBar.getNavigationIconHints() & NAVIGATION_HINT_IME_SHOWN) != 0);
+
+        // Verify navbar altered and showing back icon when the keyguard is showing and
+        // requesting IME insets visible.
+        windowInsets = new WindowInsets.Builder().setVisible(ime(), true).build();
+        doReturn(windowInsets).when(mockShadeWindowView).getRootWindowInsets();
+        mNavigationBar.setImeWindowStatus(DEFAULT_DISPLAY, null, IME_VISIBLE,
+                BACK_DISPOSITION_DEFAULT, true);
+        assertTrue((mNavigationBar.getNavigationIconHints() & NAVIGATION_HINT_BACK_ALT) != 0);
+        assertTrue((mNavigationBar.getNavigationIconHints() & NAVIGATION_HINT_IME_SHOWN) != 0);
+    }
+
+    @Test
     public void testA11yEventAfterDetach() {
         View v = mNavigationBar.createView(null);
         mNavigationBar.onViewAttachedToWindow(v);
-        verify(mNavigationBarA11yHelper).registerA11yEventListener(any(
-                NavigationBarA11yHelper.NavA11yEventListener.class));
+        verify(mNavBarHelper).registerNavTaskStateUpdater(any(
+                NavBarHelper.NavbarTaskbarStateUpdater.class));
         mNavigationBar.onViewDetachedFromWindow(v);
-        verify(mNavigationBarA11yHelper).removeA11yEventListener(any(
-                NavigationBarA11yHelper.NavA11yEventListener.class));
+        verify(mNavBarHelper).removeNavTaskStateUpdater(any(
+                NavBarHelper.NavbarTaskbarStateUpdater.class));
 
         // Should be safe even though the internal view is now null.
-        mNavigationBar.updateAccessibilityServicesState();
+        mNavigationBar.updateAcessibilityStateFlags();
     }
 
     private NavigationBar createNavBar(Context context) {
@@ -313,7 +360,7 @@
                 Optional.of(mock(Pip.class)),
                 Optional.of(mock(LegacySplitScreen.class)),
                 Optional.of(mock(Recents.class)),
-                () -> Optional.of(mock(StatusBar.class)),
+                () -> Optional.of(mStatusBar),
                 mock(ShadeController.class),
                 mock(NotificationRemoteInputManager.class),
                 mock(NotificationShadeDepthController.class),
@@ -321,7 +368,7 @@
                 mHandler,
                 mock(NavigationBarOverlayController.class),
                 mUiEventLogger,
-                mNavigationBarA11yHelper,
+                mNavBarHelper,
                 mock(UserTracker.class),
                 mLightBarController,
                 mLightBarcontrollerFactory,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/FooterActionsControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/FooterActionsControllerTest.kt
index d2bba36..26f04fc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/FooterActionsControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/FooterActionsControllerTest.kt
@@ -1,6 +1,8 @@
 package com.android.systemui.qs
 
+import android.os.Handler
 import android.os.UserManager
+import android.provider.Settings
 import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
 import android.testing.ViewUtils
@@ -16,10 +18,12 @@
 import com.android.systemui.globalactions.GlobalActionsDialogLite
 import com.android.systemui.plugins.ActivityStarter
 import com.android.systemui.qs.FooterActionsController.ExpansionState
+import com.android.systemui.settings.UserTracker
 import com.android.systemui.statusbar.phone.MultiUserSwitchController
 import com.android.systemui.statusbar.policy.DeviceProvisionedController
 import com.android.systemui.statusbar.policy.UserInfoController
 import com.android.systemui.tuner.TunerService
+import com.android.systemui.util.settings.FakeSettings
 import com.android.systemui.utils.leaks.FakeTunerService
 import com.android.systemui.utils.leaks.LeakCheckedTest
 import com.google.common.truth.Truth.assertThat
@@ -42,6 +46,8 @@
     @Mock
     private lateinit var userManager: UserManager
     @Mock
+    private lateinit var userTracker: UserTracker
+    @Mock
     private lateinit var activityStarter: ActivityStarter
     @Mock
     private lateinit var deviceProvisionedController: DeviceProvisionedController
@@ -62,11 +68,13 @@
     private lateinit var view: FooterActionsView
     private val falsingManager: FalsingManagerFake = FalsingManagerFake()
     private lateinit var testableLooper: TestableLooper
+    private lateinit var fakeSettings: FakeSettings
 
     @Before
     fun setUp() {
         MockitoAnnotations.initMocks(this)
         testableLooper = TestableLooper.get(this)
+        fakeSettings = FakeSettings()
         injectLeakCheckedDependencies(*LeakCheckedTest.ALL_SUPPORTED_CLASSES)
         val fakeTunerService = Dependency.get(TunerService::class.java) as FakeTunerService
 
@@ -74,10 +82,11 @@
                 .inflate(R.layout.footer_actions, null) as FooterActionsView
 
         controller = FooterActionsController(view, qsPanelController, activityStarter,
-                userManager, userInfoController, multiUserSwitchController,
+                userManager, userTracker, userInfoController, multiUserSwitchController,
                 deviceProvisionedController, falsingManager, metricsLogger, fakeTunerService,
                 globalActionsDialog, uiEventLogger, showPMLiteButton = true,
-                buttonsVisibleState = ExpansionState.EXPANDED)
+                buttonsVisibleState = ExpansionState.EXPANDED, fakeSettings,
+                Handler(testableLooper.looper))
         controller.init()
         ViewUtils.attachView(view)
         // View looper is the testable looper associated with the test
@@ -122,4 +131,24 @@
 
         assertThat(multiUserSwitch.visibility).isEqualTo(View.VISIBLE)
     }
+
+    @Test
+    fun testMultiUserSwitchUpdatedWhenSettingChanged() {
+        // When expanded, listening is true
+        controller.setListening(true)
+        testableLooper.processAllMessages()
+
+        val multiUserSwitch = view.requireViewById<View>(R.id.multi_user_switch)
+        assertThat(multiUserSwitch.visibility).isNotEqualTo(View.VISIBLE)
+
+        // The setting is only used as an indicator for whether the view should refresh. The actual
+        // value of the setting is ignored; isMultiUserEnabled is the source of truth
+        whenever(multiUserSwitchController.isMultiUserEnabled).thenReturn(true)
+
+        // Changing the value of USER_SWITCHER_ENABLED should cause the view to update
+        fakeSettings.putIntForUser(Settings.Global.USER_SWITCHER_ENABLED, 1, userTracker.userId)
+        testableLooper.processAllMessages()
+
+        assertThat(multiUserSwitch.visibility).isEqualTo(View.VISIBLE)
+    }
 }
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
index 047ff037..c1562c1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
@@ -54,6 +54,7 @@
 import com.android.systemui.settings.UserTracker;
 import com.android.systemui.shared.plugins.PluginManager;
 import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.connectivity.StatusBarFlags;
 import com.android.systemui.statusbar.phone.AutoTileManager;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.phone.StatusBar;
@@ -101,6 +102,8 @@
     private TileServiceRequestController mTileServiceRequestController;
     @Mock
     private FeatureFlags mFeatureFlags;
+    @Mock
+    private StatusBarFlags mStatusBarFlags;
 
     public QSFragmentTest() {
         super(QSFragment.class);
@@ -146,7 +149,7 @@
                 mock(BroadcastDispatcher.class), Optional.of(mock(StatusBar.class)),
                 mock(QSLogger.class), mock(UiEventLogger.class), mock(UserTracker.class),
                 mock(SecureSettings.class), mock(CustomTileStatePersister.class),
-                mTileServiceRequestControllerBuilder, mFeatureFlags);
+                mTileServiceRequestControllerBuilder, mFeatureFlags, mStatusBarFlags);
         qs.setHost(host);
 
         qs.setListening(true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSSquishinessControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QSSquishinessControllerTest.kt
index f41d7b1..e2a0626 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSSquishinessControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSSquishinessControllerTest.kt
@@ -1,7 +1,6 @@
 package com.android.systemui.qs
 
 import android.testing.AndroidTestingRunner
-import android.view.ViewGroup
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import org.junit.Before
@@ -9,7 +8,6 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.Mock
-import org.mockito.Mockito.`when`
 import org.mockito.Mockito.never
 import org.mockito.Mockito.verify
 import org.mockito.junit.MockitoJUnit
@@ -18,13 +16,9 @@
 @SmallTest
 class QSSquishinessControllerTest : SysuiTestCase() {
 
-    @Mock private lateinit var qqsFooterActionsView: FooterActionsView
-    @Mock private lateinit var qqsFooterActionsViewLP: ViewGroup.MarginLayoutParams
     @Mock private lateinit var qsAnimator: QSAnimator
     @Mock private lateinit var qsPanelController: QSPanelController
     @Mock private lateinit var quickQsPanelController: QuickQSPanelController
-    @Mock private lateinit var tileLayout: TileLayout
-    @Mock private lateinit var pagedTileLayout: PagedTileLayout
 
     @JvmField @Rule val mockitoRule = MockitoJUnit.rule()
 
@@ -32,11 +26,8 @@
 
     @Before
     fun setup() {
-        qsSquishinessController = QSSquishinessController(qqsFooterActionsView, qsAnimator,
+        qsSquishinessController = QSSquishinessController(qsAnimator,
                 qsPanelController, quickQsPanelController)
-        `when`(quickQsPanelController.tileLayout).thenReturn(tileLayout)
-        `when`(qsPanelController.tileLayout).thenReturn(pagedTileLayout)
-        `when`(qqsFooterActionsView.layoutParams).thenReturn(qqsFooterActionsViewLP)
     }
 
     @Test
@@ -51,7 +42,7 @@
     @Test
     fun setSquishiness_updatesTiles() {
         qsSquishinessController.squishiness = 0.5f
-        verify(tileLayout).setSquishinessFraction(0.5f)
-        verify(pagedTileLayout).setSquishinessFraction(0.5f)
+        verify(qsPanelController).setSquishinessFraction(0.5f)
+        verify(quickQsPanelController).setSquishinessFraction(0.5f)
     }
 }
\ No newline at end of file
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 ce36935..913b1d7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
@@ -63,6 +63,7 @@
 import com.android.systemui.qs.tileimpl.QSTileImpl;
 import com.android.systemui.settings.UserTracker;
 import com.android.systemui.shared.plugins.PluginManager;
+import com.android.systemui.statusbar.connectivity.StatusBarFlags;
 import com.android.systemui.statusbar.phone.AutoTileManager;
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
@@ -129,6 +130,8 @@
     private TileServiceRequestController mTileServiceRequestController;
     @Mock
     private FeatureFlags mFeatureFlags;
+    @Mock
+    private StatusBarFlags mStatusBarFlags;
 
     private Handler mHandler;
     private TestableLooper mLooper;
@@ -149,9 +152,9 @@
                 mLooper.getLooper(), mPluginManager, mTunerService, mAutoTiles, mDumpManager,
                 mBroadcastDispatcher, mStatusBar, mQSLogger, mUiEventLogger, mUserTracker,
                 mSecureSettings, mCustomTileStatePersister, mTileServiceRequestControllerBuilder,
-                mFeatureFlags);
+                mFeatureFlags, mStatusBarFlags);
         setUpTileFactory();
-        when(mFeatureFlags.isProviderModelSettingEnabled(mContext)).thenReturn(false);
+        when(mStatusBarFlags.isProviderModelSettingEnabled()).thenReturn(false);
     }
 
     private void setUpTileFactory() {
@@ -179,13 +182,13 @@
 
     @Test
     public void testLoadTileSpecs_emptySetting() {
-        List<String> tiles = QSTileHost.loadTileSpecs(mContext, "", mFeatureFlags);
+        List<String> tiles = QSTileHost.loadTileSpecs(mContext, "", mStatusBarFlags);
         assertFalse(tiles.isEmpty());
     }
 
     @Test
     public void testLoadTileSpecs_nullSetting() {
-        List<String> tiles = QSTileHost.loadTileSpecs(mContext, null, mFeatureFlags);
+        List<String> tiles = QSTileHost.loadTileSpecs(mContext, null, mStatusBarFlags);
         assertFalse(tiles.isEmpty());
     }
 
@@ -200,7 +203,7 @@
 
     @Test
     public void testRemoveWifiAndCellularWithoutInternet() {
-        when(mFeatureFlags.isProviderModelSettingEnabled(mContext)).thenReturn(true);
+        when(mStatusBarFlags.isProviderModelSettingEnabled()).thenReturn(true);
         mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "wifi, spec1, cell, spec2");
 
         assertEquals("internet", mQSTileHost.mTileSpecs.get(0));
@@ -210,7 +213,7 @@
 
     @Test
     public void testRemoveWifiAndCellularWithInternet() {
-        when(mFeatureFlags.isProviderModelSettingEnabled(mContext)).thenReturn(true);
+        when(mStatusBarFlags.isProviderModelSettingEnabled()).thenReturn(true);
         mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "wifi, spec1, cell, spec2, internet");
 
         assertEquals("spec1", mQSTileHost.mTileSpecs.get(0));
@@ -220,7 +223,7 @@
 
     @Test
     public void testRemoveWifiWithoutInternet() {
-        when(mFeatureFlags.isProviderModelSettingEnabled(mContext)).thenReturn(true);
+        when(mStatusBarFlags.isProviderModelSettingEnabled()).thenReturn(true);
         mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "spec1, wifi, spec2");
 
         assertEquals("spec1", mQSTileHost.mTileSpecs.get(0));
@@ -230,7 +233,7 @@
 
     @Test
     public void testRemoveCellWithInternet() {
-        when(mFeatureFlags.isProviderModelSettingEnabled(mContext)).thenReturn(true);
+        when(mStatusBarFlags.isProviderModelSettingEnabled()).thenReturn(true);
         mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "spec1, spec2, cell, internet");
 
         assertEquals("spec1", mQSTileHost.mTileSpecs.get(0));
@@ -240,7 +243,7 @@
 
     @Test
     public void testNoWifiNoCellularNoInternet() {
-        when(mFeatureFlags.isProviderModelSettingEnabled(mContext)).thenReturn(true);
+        when(mStatusBarFlags.isProviderModelSettingEnabled()).thenReturn(true);
         mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "spec1,spec2");
 
         assertEquals("spec1", mQSTileHost.mTileSpecs.get(0));
@@ -380,7 +383,7 @@
 
     @Test
     public void testLoadTileSpec_repeated() {
-        List<String> specs = QSTileHost.loadTileSpecs(mContext, "spec1,spec1,spec2", mFeatureFlags);
+        List<String> specs = QSTileHost.loadTileSpecs(mContext, "spec1,spec1,spec2", mStatusBarFlags);
 
         assertEquals(2, specs.size());
         assertEquals("spec1", specs.get(0));
@@ -391,7 +394,7 @@
     public void testLoadTileSpec_repeatedInDefault() {
         mContext.getOrCreateTestableResources()
                 .addOverride(R.string.quick_settings_tiles_default, "spec1,spec1");
-        List<String> specs = QSTileHost.loadTileSpecs(mContext, "default", mFeatureFlags);
+        List<String> specs = QSTileHost.loadTileSpecs(mContext, "default", mStatusBarFlags);
 
         // Remove spurious tiles, like dbg:mem
         specs.removeIf(spec -> !"spec1".equals(spec));
@@ -402,7 +405,7 @@
     public void testLoadTileSpec_repeatedDefaultAndSetting() {
         mContext.getOrCreateTestableResources()
                 .addOverride(R.string.quick_settings_tiles_default, "spec1");
-        List<String> specs = QSTileHost.loadTileSpecs(mContext, "default,spec1", mFeatureFlags);
+        List<String> specs = QSTileHost.loadTileSpecs(mContext, "default,spec1", mStatusBarFlags);
 
         // Remove spurious tiles, like dbg:mem
         specs.removeIf(spec -> !"spec1".equals(spec));
@@ -442,11 +445,12 @@
                 UiEventLogger uiEventLogger, UserTracker userTracker,
                 SecureSettings secureSettings, CustomTileStatePersister customTileStatePersister,
                 TileServiceRequestController.Builder tileServiceRequestControllerBuilder,
-                FeatureFlags featureFlags) {
+                FeatureFlags featureFlags, StatusBarFlags statusBarFlags) {
             super(context, iconController, defaultFactory, mainHandler, bgLooper, pluginManager,
                     tunerService, autoTiles, dumpManager, broadcastDispatcher,
                     Optional.of(statusBar), qsLogger, uiEventLogger, userTracker, secureSettings,
-                    customTileStatePersister, tileServiceRequestControllerBuilder, featureFlags);
+                    customTileStatePersister, tileServiceRequestControllerBuilder, featureFlags,
+                    statusBarFlags);
         }
 
         @Override
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 3625874..815c818 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt
@@ -27,6 +27,7 @@
 import com.android.systemui.colorextraction.SysuiColorExtractor
 import com.android.systemui.demomode.DemoModeController
 import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
 import com.android.systemui.plugins.ActivityStarter
 import com.android.systemui.privacy.OngoingPrivacyChip
 import com.android.systemui.privacy.PrivacyDialogController
@@ -248,7 +249,7 @@
 
     @Test
     fun testRSSISlot_notCombined() {
-        `when`(featureFlags.isCombinedStatusBarSignalIconsEnabled).thenReturn(false)
+        `when`(featureFlags.isEnabled(Flags.COMBINED_STATUS_BAR_SIGNAL_ICONS)).thenReturn(false)
         controller.init()
 
         val captor = argumentCaptor<List<String>>()
@@ -261,7 +262,7 @@
 
     @Test
     fun testRSSISlot_combined() {
-        `when`(featureFlags.isCombinedStatusBarSignalIconsEnabled).thenReturn(true)
+        `when`(featureFlags.isEnabled(Flags.COMBINED_STATUS_BAR_SIGNAL_ICONS)).thenReturn(true)
         controller.init()
 
         val captor = argumentCaptor<List<String>>()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/SecureSettingTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/SettingObserverTest.kt
similarity index 96%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/SecureSettingTest.kt
rename to packages/SystemUI/tests/src/com/android/systemui/qs/SettingObserverTest.kt
index 6af8402..4be6890 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/SecureSettingTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/SettingObserverTest.kt
@@ -35,7 +35,7 @@
 @SmallTest
 @RunWith(AndroidTestingRunner::class)
 @TestableLooper.RunWithLooper
-class SecureSettingTest : SysuiTestCase() {
+class SettingObserverTest : SysuiTestCase() {
 
     companion object {
         private const val TEST_SETTING = "setting"
@@ -46,7 +46,7 @@
     }
 
     private lateinit var testableLooper: TestableLooper
-    private lateinit var setting: SecureSetting
+    private lateinit var setting: SettingObserver
     private lateinit var secureSettings: SecureSettings
 
     private lateinit var callback: Callback
@@ -56,7 +56,7 @@
         testableLooper = TestableLooper.get(this)
         secureSettings = FakeSettings()
 
-        setting = object : SecureSetting(
+        setting = object : SettingObserver(
                 secureSettings,
                 Handler(testableLooper.looper),
                 TEST_SETTING,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java
index 05db1eb..c3a488f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java
@@ -53,12 +53,12 @@
 import com.android.internal.logging.InstanceId;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
-import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.plugins.qs.DetailAdapter;
 import com.android.systemui.plugins.qs.QSIconView;
 import com.android.systemui.plugins.qs.QSTile;
 import com.android.systemui.qs.QSTileHost;
 import com.android.systemui.settings.UserTracker;
+import com.android.systemui.statusbar.connectivity.StatusBarFlags;
 import com.android.systemui.util.concurrency.FakeExecutor;
 import com.android.systemui.util.time.FakeSystemClock;
 
@@ -110,7 +110,7 @@
     @Mock
     private UserTracker mUserTracker;
     @Mock
-    private FeatureFlags mFeatureFlags;
+    private StatusBarFlags mStatusBarFlags;
     @Captor
     private ArgumentCaptor<List<TileQueryHelper.TileInfo>> mCaptor;
 
@@ -136,12 +136,12 @@
                     }
                 }
         ).when(mQSTileHost).createTile(anyString());
-        when(mFeatureFlags.isProviderModelSettingEnabled(mContext)).thenReturn(false);
+        when(mStatusBarFlags.isProviderModelSettingEnabled()).thenReturn(false);
         FakeSystemClock clock = new FakeSystemClock();
         mMainExecutor = new FakeExecutor(clock);
         mBgExecutor = new FakeExecutor(clock);
         mTileQueryHelper = new TileQueryHelper(
-                mContext, mUserTracker, mMainExecutor, mBgExecutor, mFeatureFlags);
+                mContext, mUserTracker, mMainExecutor, mBgExecutor, mStatusBarFlags);
         mTileQueryHelper.setListener(mListener);
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
index e756b7d..29b3b86 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
@@ -51,6 +51,7 @@
 import com.android.systemui.qs.tileimpl.QSFactoryImpl;
 import com.android.systemui.settings.UserTracker;
 import com.android.systemui.shared.plugins.PluginManager;
+import com.android.systemui.statusbar.connectivity.StatusBarFlags;
 import com.android.systemui.statusbar.phone.AutoTileManager;
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
@@ -107,6 +108,8 @@
     private TileServiceRequestController mTileServiceRequestController;
     @Mock
     private FeatureFlags mFeatureFlags;
+    @Mock
+    private StatusBarFlags mStatusBarFlags;
 
     @Before
     public void setUp() throws Exception {
@@ -134,7 +137,8 @@
                 mSecureSettings,
                 mock(CustomTileStatePersister.class),
                 mTileServiceRequestControllerBuilder,
-                mFeatureFlags);
+                mFeatureFlags,
+                mStatusBarFlags);
         mTileService = new TestTileServices(host, Looper.getMainLooper(), mBroadcastDispatcher,
                 mUserTracker);
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ColorInversionTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ColorInversionTileTest.java
new file mode 100644
index 0000000..bf682a8
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ColorInversionTileTest.java
@@ -0,0 +1,116 @@
+/*
+ * 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.qs.tiles;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Intent;
+import android.os.Handler;
+import android.provider.Settings;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import androidx.test.filters.SmallTest;
+
+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.QSTileHost;
+import com.android.systemui.qs.logging.QSLogger;
+import com.android.systemui.settings.UserTracker;
+import com.android.systemui.util.settings.FakeSettings;
+import com.android.systemui.util.settings.SecureSettings;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+@SmallTest
+public class ColorInversionTileTest extends SysuiTestCase {
+
+    @Mock
+    private QSTileHost mHost;
+    @Mock
+    private MetricsLogger mMetricsLogger;
+    @Mock
+    private StatusBarStateController mStatusBarStateController;
+    @Mock
+    private ActivityStarter mActivityStarter;
+    @Mock
+    private QSLogger mQSLogger;
+    @Mock
+    private UiEventLogger mUiEventLogger;
+    @Mock
+    private UserTracker mUserTracker;
+
+    private TestableLooper mTestableLooper;
+    private SecureSettings mSecureSettings;
+    private ColorInversionTile mTile;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+
+        mSecureSettings = new FakeSettings();
+        mTestableLooper = TestableLooper.get(this);
+
+        when(mHost.getContext()).thenReturn(mContext);
+        when(mHost.getUiEventLogger()).thenReturn(mUiEventLogger);
+
+        mTile = new ColorInversionTile(
+                mHost,
+                mTestableLooper.getLooper(),
+                new Handler(mTestableLooper.getLooper()),
+                new FalsingManagerFake(),
+                mMetricsLogger,
+                mStatusBarStateController,
+                mActivityStarter,
+                mQSLogger,
+                mUserTracker,
+                mSecureSettings
+        );
+
+        mTile.initialize();
+        mTestableLooper.processAllMessages();
+    }
+
+    @Test
+    public void longClick_expectedAction() {
+        final ArgumentCaptor<Intent> IntentCaptor = ArgumentCaptor.forClass(Intent.class);
+
+        mTile.longClick(/* view= */ null);
+        mTestableLooper.processAllMessages();
+
+        verify(mActivityStarter).postStartActivityDismissingKeyguard(IntentCaptor.capture(),
+                anyInt(), any());
+        assertThat(IntentCaptor.getValue().getAction()).isEqualTo(
+                Settings.ACTION_COLOR_INVERSION_SETTINGS);
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DndTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DndTileTest.kt
index f99703e..3ea2cc5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DndTileTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DndTileTest.kt
@@ -16,22 +16,28 @@
 
 package com.android.systemui.qs.tiles
 
+import android.app.Dialog
 import android.content.ContextWrapper
 import android.content.SharedPreferences
 import android.os.Handler
 import android.provider.Settings
+import android.provider.Settings.Global.ZEN_MODE_OFF
 import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
+import android.view.View
 import androidx.test.filters.SmallTest
 import com.android.internal.logging.MetricsLogger
 import com.android.internal.logging.UiEventLogger
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.animation.DialogLaunchAnimator
 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
 import com.android.systemui.qs.logging.QSLogger
 import com.android.systemui.statusbar.policy.ZenModeController
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.eq
 import com.android.systemui.util.settings.FakeSettings
 import com.android.systemui.util.settings.SecureSettings
 import com.google.common.truth.Truth.assertThat
@@ -40,9 +46,12 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.Mock
-import org.mockito.Mockito
+import org.mockito.Mockito.anyBoolean
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
 import org.mockito.MockitoAnnotations
 import java.io.File
+import org.mockito.Mockito.`when` as whenever
 
 @SmallTest
 @RunWith(AndroidTestingRunner::class)
@@ -70,6 +79,10 @@
     private lateinit var zenModeController: ZenModeController
     @Mock
     private lateinit var sharedPreferences: SharedPreferences
+    @Mock
+    private lateinit var dialogLaunchAnimator: DialogLaunchAnimator
+    @Mock
+    private lateinit var hostDialog: Dialog
 
     private lateinit var secureSettings: SecureSettings
     private lateinit var testableLooper: TestableLooper
@@ -81,15 +94,17 @@
         testableLooper = TestableLooper.get(this)
         secureSettings = FakeSettings()
 
-        Mockito.`when`(qsHost.userId).thenReturn(DEFAULT_USER)
-        Mockito.`when`(qsHost.uiEventLogger).thenReturn(uiEventLogger)
+        whenever(qsHost.userId).thenReturn(DEFAULT_USER)
+        whenever(qsHost.uiEventLogger).thenReturn(uiEventLogger)
+        whenever(dialogLaunchAnimator.showFromView(any(), any(), anyBoolean()))
+                .thenReturn(hostDialog)
 
         val wrappedContext = object : ContextWrapper(context) {
             override fun getSharedPreferences(file: File?, mode: Int): SharedPreferences {
                 return sharedPreferences
             }
         }
-        Mockito.`when`(qsHost.context).thenReturn(wrappedContext)
+        whenever(qsHost.context).thenReturn(wrappedContext)
 
         tile = DndTile(
             qsHost,
@@ -102,7 +117,8 @@
             qsLogger,
             zenModeController,
             sharedPreferences,
-            secureSettings
+            secureSettings,
+            dialogLaunchAnimator
         )
     }
 
@@ -147,4 +163,32 @@
 
         assertThat(tile.state.forceExpandIcon).isTrue()
     }
+
+    @Test
+    fun testLaunchDialogFromViewWhenPrompt() {
+        whenever(zenModeController.zen).thenReturn(ZEN_MODE_OFF)
+
+        secureSettings.putIntForUser(KEY, Settings.Secure.ZEN_DURATION_PROMPT, DEFAULT_USER)
+        testableLooper.processAllMessages()
+
+        val view = View(context)
+        tile.handleClick(view)
+        testableLooper.processAllMessages()
+
+        verify(dialogLaunchAnimator).showFromView(any(), eq(view), anyBoolean())
+    }
+
+    @Test
+    fun testNoLaunchDialogWhenNotPrompt() {
+        whenever(zenModeController.zen).thenReturn(ZEN_MODE_OFF)
+
+        secureSettings.putIntForUser(KEY, 60, DEFAULT_USER)
+        testableLooper.processAllMessages()
+
+        val view = View(context)
+        tile.handleClick(view)
+        testableLooper.processAllMessages()
+
+        verify(dialogLaunchAnimator, never()).showFromView(any(), any(), anyBoolean())
+    }
 }
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/OneHandedModeTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/OneHandedModeTileTest.java
new file mode 100644
index 0000000..8031875
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/OneHandedModeTileTest.java
@@ -0,0 +1,112 @@
+/*
+ * 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.qs.tiles;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.os.Handler;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+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.QSTileHost;
+import com.android.systemui.qs.logging.QSLogger;
+import com.android.systemui.settings.UserTracker;
+import com.android.systemui.util.settings.SecureSettings;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+@SmallTest
+public class OneHandedModeTileTest extends SysuiTestCase {
+
+    private final String mOneHandedTitle = "One-handed mode";
+
+    @Mock
+    private ActivityStarter mActivityStarter;
+    @Mock
+    private QSTileHost mHost;
+    @Mock
+    private MetricsLogger mMetricsLogger;
+    @Mock
+    private StatusBarStateController mStatusBarStateController;
+    @Mock
+    private QSLogger mQSLogger;
+    @Mock
+    private UserTracker mUserTracker;
+    @Mock
+    private SecureSettings mSecureSettings;
+
+    private TestableLooper mTestableLooper;
+    private OneHandedModeTile mTile;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        mTestableLooper = TestableLooper.get(this);
+
+        when(mHost.getContext()).thenReturn(mContext);
+
+        mTile = spy(new OneHandedModeTile(
+                mHost,
+                mTestableLooper.getLooper(),
+                new Handler(mTestableLooper.getLooper()),
+                new FalsingManagerFake(),
+                mMetricsLogger,
+                mStatusBarStateController,
+                mActivityStarter,
+                mQSLogger,
+                mUserTracker,
+                mSecureSettings));
+
+        mTestableLooper.processAllMessages();
+        mTile.initialize();
+    }
+
+    @Test
+    public void testIsAvailable_unsupportOneHandedProperty_shouldReturnsFalse() {
+        when(mTile.isSupportOneHandedMode()).thenReturn(false);
+
+        assertThat(mTile.isAvailable()).isFalse();
+    }
+
+    @Test
+    public void testIsAvailable_supportOneHandedProperty_shouldReturnsTrue() {
+        when(mTile.isSupportOneHandedMode()).thenReturn(true);
+
+        assertThat(mTile.isAvailable()).isTrue();
+    }
+
+    @Test
+    public void testGetTileLabel_shouldReturnOneHandedModeTitle() {
+        assertThat(mTile.getTileLabel()).isEqualTo(mOneHandedTitle);
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/user/UserDialogTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/user/UserDialogTest.kt
deleted file mode 100644
index d5fe588..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/user/UserDialogTest.kt
+++ /dev/null
@@ -1,62 +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.qs.user
-
-import android.testing.AndroidTestingRunner
-import android.testing.TestableLooper
-import android.view.View
-import android.view.ViewGroup
-import androidx.test.filters.SmallTest
-import com.android.systemui.SysuiTestCase
-import com.google.common.truth.Truth.assertThat
-import org.junit.After
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@SmallTest
-@RunWith(AndroidTestingRunner::class)
-@TestableLooper.RunWithLooper
-class UserDialogTest : SysuiTestCase() {
-
-    private lateinit var dialog: UserDialog
-
-    @Before
-    fun setUp() {
-        dialog = UserDialog(mContext)
-    }
-
-    @After
-    fun tearDown() {
-        dialog.dismiss()
-    }
-
-    @Test
-    fun doneButtonExists() {
-        assertThat(dialog.doneButton).isInstanceOf(View::class.java)
-    }
-
-    @Test
-    fun settingsButtonExists() {
-        assertThat(dialog.settingsButton).isInstanceOf(View::class.java)
-    }
-
-    @Test
-    fun gridExistsAndIsViewGroup() {
-        assertThat(dialog.grid).isInstanceOf(ViewGroup::class.java)
-    }
-}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/user/UserSwitchDialogControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/user/UserSwitchDialogControllerTest.kt
index 7e900c8..3c4a557 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/user/UserSwitchDialogControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/user/UserSwitchDialogControllerTest.kt
@@ -16,6 +16,8 @@
 
 package com.android.systemui.qs.user
 
+import android.app.Dialog
+import android.content.DialogInterface
 import android.content.Intent
 import android.provider.Settings
 import android.testing.AndroidTestingRunner
@@ -27,7 +29,8 @@
 import com.android.systemui.plugins.FalsingManager
 import com.android.systemui.qs.PseudoGridView
 import com.android.systemui.qs.tiles.UserDetailView
-import com.android.systemui.statusbar.policy.UserSwitcherController
+import com.android.systemui.statusbar.phone.SystemUIDialog
+import com.android.systemui.util.mockito.any
 import com.android.systemui.util.mockito.argumentCaptor
 import com.android.systemui.util.mockito.capture
 import com.android.systemui.util.mockito.eq
@@ -39,40 +42,33 @@
 import org.mockito.Captor
 import org.mockito.Mock
 import org.mockito.Mockito.`when`
-import org.mockito.Mockito.any
+import org.mockito.Mockito.anyBoolean
 import org.mockito.Mockito.anyInt
 import org.mockito.Mockito.argThat
-import org.mockito.Mockito.inOrder
-import org.mockito.Mockito.mock
 import org.mockito.Mockito.never
 import org.mockito.Mockito.verify
 import org.mockito.MockitoAnnotations
-import java.util.function.Consumer
 
 @SmallTest
 @RunWith(AndroidTestingRunner::class)
 class UserSwitchDialogControllerTest : SysuiTestCase() {
 
     @Mock
-    private lateinit var dialog: UserDialog
+    private lateinit var dialog: SystemUIDialog
     @Mock
     private lateinit var falsingManager: FalsingManager
     @Mock
-    private lateinit var settingsView: View
-    @Mock
-    private lateinit var doneView: View
-    @Mock
     private lateinit var activityStarter: ActivityStarter
     @Mock
     private lateinit var userDetailViewAdapter: UserDetailView.Adapter
     @Mock
     private lateinit var launchView: View
     @Mock
-    private lateinit var gridView: PseudoGridView
-    @Mock
     private lateinit var dialogLaunchAnimator: DialogLaunchAnimator
+    @Mock
+    private lateinit var hostDialog: Dialog
     @Captor
-    private lateinit var clickCaptor: ArgumentCaptor<View.OnClickListener>
+    private lateinit var clickCaptor: ArgumentCaptor<DialogInterface.OnClickListener>
 
     private lateinit var controller: UserSwitchDialogController
 
@@ -80,11 +76,10 @@
     fun setUp() {
         MockitoAnnotations.initMocks(this)
 
-        `when`(dialog.settingsButton).thenReturn(settingsView)
-        `when`(dialog.doneButton).thenReturn(doneView)
-        `when`(dialog.grid).thenReturn(gridView)
-
         `when`(launchView.context).thenReturn(mContext)
+        `when`(dialog.context).thenReturn(mContext)
+        `when`(dialogLaunchAnimator.showFromView(any(), any(), anyBoolean()))
+                .thenReturn(hostDialog)
 
         controller = UserSwitchDialogController(
                 { userDetailViewAdapter },
@@ -102,30 +97,6 @@
     }
 
     @Test
-    fun createCalledBeforeDoneButton() {
-        controller.showDialog(launchView)
-        val inOrder = inOrder(dialog)
-        inOrder.verify(dialog).create()
-        inOrder.verify(dialog).doneButton
-    }
-
-    @Test
-    fun createCalledBeforeSettingsButton() {
-        controller.showDialog(launchView)
-        val inOrder = inOrder(dialog)
-        inOrder.verify(dialog).create()
-        inOrder.verify(dialog).settingsButton
-    }
-
-    @Test
-    fun createCalledBeforeGrid() {
-        controller.showDialog(launchView)
-        val inOrder = inOrder(dialog)
-        inOrder.verify(dialog).create()
-        inOrder.verify(dialog).grid
-    }
-
-    @Test
     fun dialog_showForAllUsers() {
         controller.showDialog(launchView)
         verify(dialog).setShowForAllUsers(true)
@@ -140,63 +111,56 @@
     @Test
     fun adapterAndGridLinked() {
         controller.showDialog(launchView)
-        verify(userDetailViewAdapter).linkToViewGroup(gridView)
+        verify(userDetailViewAdapter).linkToViewGroup(any<PseudoGridView>())
     }
 
     @Test
-    fun clickDoneButton_dismiss() {
+    fun doneButtonSetWithNullHandler() {
         controller.showDialog(launchView)
 
-        verify(doneView).setOnClickListener(capture(clickCaptor))
-
-        clickCaptor.value.onClick(doneView)
-
-        verify(activityStarter, never()).postStartActivityDismissingKeyguard(any(), anyInt())
-        verify(dialog).dismiss()
+        verify(dialog).setPositiveButton(anyInt(), eq(null))
     }
 
     @Test
-    fun clickSettingsButton_noFalsing_opensSettingsAndDismisses() {
+    fun clickSettingsButton_noFalsing_opensSettings() {
         `when`(falsingManager.isFalseTap(anyInt())).thenReturn(false)
 
         controller.showDialog(launchView)
 
-        verify(settingsView).setOnClickListener(capture(clickCaptor))
+        verify(dialog).setNeutralButton(anyInt(), capture(clickCaptor))
 
-        clickCaptor.value.onClick(settingsView)
+        clickCaptor.value.onClick(dialog, DialogInterface.BUTTON_NEUTRAL)
 
         verify(activityStarter)
                 .postStartActivityDismissingKeyguard(
                         argThat(IntentMatcher(Settings.ACTION_USER_SETTINGS)),
                         eq(0)
                 )
-        verify(dialog).dismiss()
     }
 
     @Test
-    fun clickSettingsButton_Falsing_notOpensSettingsAndDismisses() {
+    fun clickSettingsButton_Falsing_notOpensSettings() {
         `when`(falsingManager.isFalseTap(anyInt())).thenReturn(true)
 
         controller.showDialog(launchView)
 
-        verify(settingsView).setOnClickListener(capture(clickCaptor))
+        verify(dialog).setNeutralButton(anyInt(), capture(clickCaptor))
 
-        clickCaptor.value.onClick(settingsView)
+        clickCaptor.value.onClick(dialog, DialogInterface.BUTTON_NEUTRAL)
 
         verify(activityStarter, never()).postStartActivityDismissingKeyguard(any(), anyInt())
-        verify(dialog).dismiss()
     }
 
     @Test
-    fun callbackFromDetailView_dismissesDialog() {
-        val captor = argumentCaptor<Consumer<UserSwitcherController.UserRecord>>()
+    fun callbackFromDialogShower_dismissesDialog() {
+        val captor = argumentCaptor<UserSwitchDialogController.DialogShower>()
 
         controller.showDialog(launchView)
-        verify(userDetailViewAdapter).injectCallback(capture(captor))
+        verify(userDetailViewAdapter).injectDialogShower(capture(captor))
 
-        captor.value.accept(mock(UserSwitcherController.UserRecord::class.java))
+        captor.value.dismiss()
 
-        verify(dialog).dismiss()
+        verify(hostDialog).dismiss()
     }
 
     private class IntentMatcher(private val action: String) : ArgumentMatcher<Intent> {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
index 8e4b98f..bd9f91f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
@@ -39,11 +39,11 @@
 
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.dump.DumpManager;
-import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.NotificationRemoteInputManager.LegacyRemoteInputLifetimeExtender.RemoteInputActiveExtender;
 import com.android.systemui.statusbar.NotificationRemoteInputManager.LegacyRemoteInputLifetimeExtender.RemoteInputHistoryExtender;
 import com.android.systemui.statusbar.NotificationRemoteInputManager.LegacyRemoteInputLifetimeExtender.SmartReplyHistoryExtender;
+import com.android.systemui.statusbar.notification.NotifPipelineFlags;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
@@ -99,7 +99,7 @@
         MockitoAnnotations.initMocks(this);
 
         mRemoteInputManager = new TestableNotificationRemoteInputManager(mContext,
-                mock(FeatureFlags.class),
+                mock(NotifPipelineFlags.class),
                 mLockscreenUserManager,
                 mSmartReplyController,
                 mVisibilityProvider,
@@ -190,7 +190,7 @@
 
         TestableNotificationRemoteInputManager(
                 Context context,
-                FeatureFlags featureFlags,
+                NotifPipelineFlags notifPipelineFlags,
                 NotificationLockscreenUserManager lockscreenUserManager,
                 SmartReplyController smartReplyController,
                 NotificationVisibilityProvider visibilityProvider,
@@ -205,7 +205,7 @@
                 DumpManager dumpManager) {
             super(
                     context,
-                    featureFlags,
+                    notifPipelineFlags,
                     lockscreenUserManager,
                     smartReplyController,
                     visibilityProvider,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
index 7210d9c..3972f14 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
@@ -105,8 +105,8 @@
         when(mVisualStabilityManager.areGroupChangesAllowed()).thenReturn(true);
         when(mVisualStabilityManager.isReorderingAllowed()).thenReturn(true);
 
-        when(mFeatureFlags.isNewNotifPipelineRenderingEnabled()).thenReturn(false);
         when(mNotifPipelineFlags.checkLegacyPipelineEnabled()).thenReturn(true);
+        when(mNotifPipelineFlags.isNewPipelineEnabled()).thenReturn(false);
 
         mHelper = new NotificationTestHelper(mContext, mDependency, TestableLooper.get(this));
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
index 8b28fd5..e0689f3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
@@ -39,8 +39,8 @@
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.dump.DumpManager;
-import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.notification.NotifPipelineFlags;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
@@ -97,7 +97,7 @@
                 mSmartReplyController);
 
         mRemoteInputManager = new NotificationRemoteInputManager(mContext,
-                mock(FeatureFlags.class),
+                mock(NotifPipelineFlags.class),
                 mock(NotificationLockscreenUserManager.class),
                 mSmartReplyController,
                 mVisibilityProvider,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/charging/WiredChargingRippleControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/charging/WiredChargingRippleControllerTest.kt
index f2671b76..ecc2a1b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/charging/WiredChargingRippleControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/charging/WiredChargingRippleControllerTest.kt
@@ -23,6 +23,7 @@
 import com.android.internal.logging.UiEventLogger
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
 import com.android.systemui.statusbar.commandline.CommandRegistry
 import com.android.systemui.statusbar.policy.BatteryController
 import com.android.systemui.statusbar.policy.ConfigurationController
@@ -57,7 +58,7 @@
     @Before
     fun setUp() {
         MockitoAnnotations.initMocks(this)
-        `when`(featureFlags.isChargingRippleEnabled).thenReturn(true)
+        `when`(featureFlags.isEnabled(Flags.CHARGING_RIPPLE)).thenReturn(true)
         controller = WiredChargingRippleController(
                 commandRegistry, batteryController, configurationController,
                 featureFlags, context, windowManager, systemClock, uiEventLogger)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerBaseTest.java
index 344d6f4..ee6324b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerBaseTest.java
@@ -60,7 +60,6 @@
 
 import androidx.test.InstrumentationRegistry;
 
-import com.android.dx.mockito.inline.extended.ExtendedMockito;
 import com.android.settingslib.R;
 import com.android.settingslib.graph.SignalDrawable;
 import com.android.settingslib.mobile.MobileMappings.Config;
@@ -72,6 +71,7 @@
 import com.android.systemui.demomode.DemoModeController;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
 import com.android.systemui.telephony.TelephonyListenerManager;
@@ -87,7 +87,6 @@
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mockito;
 import org.mockito.MockitoSession;
-import org.mockito.quality.Strictness;
 
 import java.io.PrintWriter;
 import java.io.StringWriter;
@@ -127,6 +126,7 @@
     protected CarrierConfigTracker mCarrierConfigTracker;
     protected FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock());
     protected FeatureFlags mFeatureFlags;
+    protected StatusBarFlags mStatusBarFlags;
 
     protected int mSubId;
 
@@ -156,11 +156,10 @@
 
     @Before
     public void setUp() throws Exception {
-        mMockingSession = ExtendedMockito.mockitoSession().strictness(Strictness.LENIENT)
-                .mockStatic(FeatureFlags.class).startMocking();
         mFeatureFlags = mock(FeatureFlags.class);
-        when(mFeatureFlags.isCombinedStatusBarSignalIconsEnabled()).thenReturn(false);
-        when(mFeatureFlags.isProviderModelSettingEnabled(mContext)).thenReturn(true);
+        mStatusBarFlags = mock(StatusBarFlags.class);
+        when(mFeatureFlags.isEnabled(Flags.COMBINED_STATUS_BAR_SIGNAL_ICONS)).thenReturn(false);
+        when(mStatusBarFlags.isProviderModelSettingEnabled()).thenReturn(true);
 
 
         mInstrumentation = InstrumentationRegistry.getInstrumentation();
@@ -239,6 +238,7 @@
                 mDemoModeController,
                 mCarrierConfigTracker,
                 mFeatureFlags,
+                mStatusBarFlags,
                 mock(DumpManager.class)
         );
         setupNetworkController();
@@ -308,7 +308,7 @@
                         mock(AccessPointControllerImpl.class),
                         mock(DataUsageController.class), mMockSubDefaults,
                         mock(DeviceProvisionedController.class), mMockBd, mDemoModeController,
-                        mCarrierConfigTracker, mFeatureFlags,
+                        mCarrierConfigTracker, mFeatureFlags, mStatusBarFlags,
                         mock(DumpManager.class));
 
         setupNetworkController();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerDataTest.java
index 12f8282..0ed4243 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerDataTest.java
@@ -130,7 +130,8 @@
                 mock(AccessPointControllerImpl.class),
                 mock(DataUsageController.class), mMockSubDefaults,
                 mock(DeviceProvisionedController.class), mMockBd, mDemoModeController,
-                mock(CarrierConfigTracker.class), mFeatureFlags, mock(DumpManager.class));
+                mock(CarrierConfigTracker.class), mFeatureFlags, mStatusBarFlags,
+                mock(DumpManager.class));
         setupNetworkController();
 
         setupDefaultSignal();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerSignalTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerSignalTest.java
index 73eddd1..64da141 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerSignalTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerSignalTest.java
@@ -70,7 +70,7 @@
                 mock(AccessPointControllerImpl.class), mock(DataUsageController.class),
                 mMockSubDefaults, mock(DeviceProvisionedController.class), mMockBd,
                 mDemoModeController, mock(CarrierConfigTracker.class), mFeatureFlags,
-                mock(DumpManager.class));
+                mStatusBarFlags, mock(DumpManager.class));
         setupNetworkController();
 
         verifyLastMobileDataIndicators(false, -1, 0);
@@ -91,7 +91,7 @@
                 mock(AccessPointControllerImpl.class), mock(DataUsageController.class),
                 mMockSubDefaults, mock(DeviceProvisionedController.class), mMockBd,
                 mDemoModeController, mock(CarrierConfigTracker.class), mFeatureFlags,
-                mock(DumpManager.class));
+                mStatusBarFlags, mock(DumpManager.class));
         mNetworkController.registerListeners();
 
         // Wait for the main looper to execute the previous command
@@ -160,7 +160,7 @@
                 mock(AccessPointControllerImpl.class), mock(DataUsageController.class),
                 mMockSubDefaults, mock(DeviceProvisionedController.class), mMockBd,
                 mDemoModeController, mock(CarrierConfigTracker.class), mFeatureFlags,
-                mock(DumpManager.class));
+                mStatusBarFlags, mock(DumpManager.class));
         setupNetworkController();
 
         // No Subscriptions.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt
index ff91978..de627de 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt
@@ -42,6 +42,7 @@
 import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener
 import com.android.systemui.settings.UserTracker
 import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
 import com.android.systemui.statusbar.policy.ConfigurationController
 import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener
 import com.android.systemui.statusbar.policy.DeviceProvisionedController
@@ -144,7 +145,7 @@
     fun setUp() {
         MockitoAnnotations.initMocks(this)
 
-        `when`(featureFlags.isSmartspaceEnabled).thenReturn(true)
+        `when`(featureFlags.isEnabled(Flags.SMARTSPACE)).thenReturn(true)
 
         `when`(secureSettings.getUriFor(PRIVATE_LOCKSCREEN_SETTING))
                 .thenReturn(fakePrivateLockscreenSettingUri)
@@ -185,7 +186,7 @@
     @Test(expected = RuntimeException::class)
     fun testThrowsIfFlagIsDisabled() {
         // GIVEN the feature flag is disabled
-        `when`(featureFlags.isSmartspaceEnabled).thenReturn(false)
+        `when`(featureFlags.isEnabled(Flags.SMARTSPACE)).thenReturn(false)
 
         // WHEN we try to build the view
         controller.buildAndConnectView(fakeParent)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
index f8effa1..f62de51 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
@@ -66,7 +66,6 @@
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.dump.DumpManager;
-import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.statusbar.NotificationLifetimeExtender;
 import com.android.systemui.statusbar.NotificationListener;
 import com.android.systemui.statusbar.NotificationMediaManager;
@@ -132,7 +131,7 @@
     @Mock private DeviceProvisionedController mDeviceProvisionedController;
     @Mock private RowInflaterTask mAsyncInflationTask;
     @Mock private NotificationEntryManagerLogger mLogger;
-    @Mock private FeatureFlags mFeatureFlags;
+    @Mock private NotifPipelineFlags mNotifPipelineFlags;
     @Mock private LeakDetector mLeakDetector;
     @Mock private NotificationMediaManager mNotificationMediaManager;
     @Mock private NotificationRowBinder mNotificationRowBinder;
@@ -192,11 +191,11 @@
         mEntry = createNotification();
         mSbn = mEntry.getSbn();
 
-        when(mFeatureFlags.isNewNotifPipelineRenderingEnabled()).thenReturn(false);
+        when(mNotifPipelineFlags.isNewPipelineEnabled()).thenReturn(false);
         mEntryManager = new NotificationEntryManager(
                 mLogger,
                 mGroupManager,
-                mFeatureFlags,
+                mNotifPipelineFlags,
                 () -> mNotificationRowBinder,
                 () -> mRemoteInputManager,
                 mLeakDetector,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
index cf90cef6..8e6bcb01 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
@@ -70,8 +70,8 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.dump.LogBufferEulogizer;
-import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.statusbar.RankingBuilder;
+import com.android.systemui.statusbar.notification.NotifPipelineFlags;
 import com.android.systemui.statusbar.notification.collection.NoManSimulator.NotifEvent;
 import com.android.systemui.statusbar.notification.collection.NotifCollection.CancellationReason;
 import com.android.systemui.statusbar.notification.collection.coalescer.CoalescedEvent;
@@ -107,7 +107,7 @@
 public class NotifCollectionTest extends SysuiTestCase {
 
     @Mock private IStatusBarService mStatusBarService;
-    @Mock private FeatureFlags mFeatureFlags;
+    @Mock private NotifPipelineFlags mNotifPipelineFlags;
     @Mock private NotifCollectionLogger mLogger;
     @Mock private LogBufferEulogizer mEulogizer;
     @Mock private Handler mMainHandler;
@@ -144,7 +144,7 @@
         MockitoAnnotations.initMocks(this);
         allowTestableLooperAsMainThread();
 
-        when(mFeatureFlags.isNewNotifPipelineRenderingEnabled()).thenReturn(true);
+        when(mNotifPipelineFlags.isNewPipelineEnabled()).thenReturn(true);
 
         when(mEulogizer.record(any(Exception.class))).thenAnswer(i -> i.getArguments()[0]);
 
@@ -153,7 +153,7 @@
         mCollection = new NotifCollection(
                 mStatusBarService,
                 mClock,
-                mFeatureFlags,
+                mNotifPipelineFlags,
                 mLogger,
                 mMainHandler,
                 mEulogizer,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/CommunalCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/CommunalCoordinatorTest.java
index 01e4cce0..f4452bc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/CommunalCoordinatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/CommunalCoordinatorTest.java
@@ -17,6 +17,7 @@
 package com.android.systemui.statusbar.notification.collection.coordinator;
 
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 
 import android.test.suitebuilder.annotation.SmallTest;
@@ -29,6 +30,8 @@
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Pluggable;
+import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.time.FakeSystemClock;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -39,6 +42,8 @@
 
 @SmallTest
 public class CommunalCoordinatorTest extends SysuiTestCase {
+    private final FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock());
+
     @Mock
     CommunalStateController mCommunalStateController;
     @Mock
@@ -57,7 +62,7 @@
     @Before
     public void setup() {
         MockitoAnnotations.initMocks(this);
-        mCoordinator = new CommunalCoordinator(mNotificationEntryManager,
+        mCoordinator = new CommunalCoordinator(mExecutor, mNotificationEntryManager,
                 mNotificationLockscreenUserManager, mCommunalStateController);
     }
 
@@ -84,6 +89,12 @@
         // Verify that notifications are filtered out when communal is showing and that the filter
         // pipeline is notified.
         stateCallback.onCommunalViewShowingChanged();
+        // Make sure callback depends on executor to run.
+        verify(mFilterListener, never()).onPluggableInvalidated(any());
+        verify(mNotificationEntryManager, never()).updateNotifications(any());
+
+        mExecutor.runAllReady();
+
         verify(mFilterListener).onPluggableInvalidated(any());
         verify(mNotificationEntryManager).updateNotifications(any());
         assert (filter.shouldFilterOut(mNotificationEntry, 0));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerLegacyTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerLegacyTest.java
index 4cf530e..395aec3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerLegacyTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerLegacyTest.java
@@ -41,10 +41,10 @@
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.statusbar.NotificationVisibility;
 import com.android.systemui.SysuiTestCase;
-import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.statusbar.NotificationListener;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.StatusBarStateControllerImpl;
+import com.android.systemui.statusbar.notification.NotifPipelineFlags;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotifPipeline;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -81,7 +81,7 @@
     @Mock private NotificationLogger.ExpansionStateLogger mExpansionStateLogger;
 
     // Dependency mocks:
-    @Mock private FeatureFlags mFeatureFlags;
+    @Mock private NotifPipelineFlags mNotifPipelineFlags;
     @Mock private NotificationVisibilityProvider mVisibilityProvider;
     @Mock private NotificationEntryManager mEntryManager;
     @Mock private NotifPipeline mNotifPipeline;
@@ -111,7 +111,7 @@
         mLogger = new TestableNotificationLogger(
                 mListener,
                 mUiBgExecutor,
-                mFeatureFlags,
+                mNotifPipelineFlags,
                 mVisibilityProvider,
                 mEntryManager,
                 mNotifPipeline,
@@ -253,7 +253,7 @@
 
         TestableNotificationLogger(NotificationListener notificationListener,
                 Executor uiBgExecutor,
-                FeatureFlags featureFlags,
+                NotifPipelineFlags notifPipelineFlags,
                 NotificationVisibilityProvider visibilityProvider,
                 NotificationEntryManager entryManager,
                 NotifPipeline notifPipeline,
@@ -263,7 +263,7 @@
             super(
                     notificationListener,
                     uiBgExecutor,
-                    featureFlags,
+                    notifPipelineFlags,
                     visibilityProvider,
                     entryManager,
                     notifPipeline,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
index ba198ef..3a9b297 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
@@ -41,10 +41,10 @@
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.statusbar.NotificationVisibility;
 import com.android.systemui.SysuiTestCase;
-import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.statusbar.NotificationListener;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.StatusBarStateControllerImpl;
+import com.android.systemui.statusbar.notification.NotifPipelineFlags;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotifPipeline;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -81,7 +81,7 @@
     @Mock private NotificationLogger.ExpansionStateLogger mExpansionStateLogger;
 
     // Dependency mocks:
-    @Mock private FeatureFlags mFeatureFlags;
+    @Mock private NotifPipelineFlags mNotifPipelineFlags;
     @Mock private NotificationVisibilityProvider mVisibilityProvider;
     @Mock private NotificationEntryManager mEntryManager;
     @Mock private NotifPipeline mNotifPipeline;
@@ -97,7 +97,7 @@
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
-        when(mFeatureFlags.isNewNotifPipelineRenderingEnabled()).thenReturn(true);
+        when(mNotifPipelineFlags.isNewPipelineEnabled()).thenReturn(true);
 
         mEntry = new NotificationEntryBuilder()
                 .setPkg(TEST_PACKAGE_NAME)
@@ -112,7 +112,7 @@
         mLogger = new TestableNotificationLogger(
                 mListener,
                 mUiBgExecutor,
-                mFeatureFlags,
+                mNotifPipelineFlags,
                 mVisibilityProvider,
                 mEntryManager,
                 mNotifPipeline,
@@ -254,7 +254,7 @@
 
         TestableNotificationLogger(NotificationListener notificationListener,
                 Executor uiBgExecutor,
-                FeatureFlags featureFlags,
+                NotifPipelineFlags notifPipelineFlags,
                 NotificationVisibilityProvider visibilityProvider,
                 NotificationEntryManager entryManager,
                 NotifPipeline notifPipeline,
@@ -264,7 +264,7 @@
             super(
                     notificationListener,
                     uiBgExecutor,
-                    featureFlags,
+                    notifPipelineFlags,
                     visibilityProvider,
                     entryManager,
                     notifPipeline,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
index 4521610..eeda9dd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
@@ -48,7 +48,6 @@
 import com.android.systemui.classifier.FalsingCollectorFake;
 import com.android.systemui.classifier.FalsingManagerFake;
 import com.android.systemui.dump.DumpManager;
-import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.media.MediaFeatureFlag;
 import com.android.systemui.media.dialog.MediaOutputDialogFactory;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -143,7 +142,6 @@
 
     @Mock private NotificationGroupManagerLegacy mGroupMembershipManager;
     @Mock private NotificationGroupManagerLegacy mGroupExpansionManager;
-    @Mock private FeatureFlags mFeatureFlags;
     @Mock private NotifPipelineFlags mNotifPipelineFlags;
     @Mock private LeakDetector mLeakDetector;
 
@@ -182,12 +180,12 @@
                 .build();
 
         when(mNotifPipelineFlags.checkLegacyPipelineEnabled()).thenReturn(true);
-        when(mFeatureFlags.isNewNotifPipelineRenderingEnabled()).thenReturn(false);
+        when(mNotifPipelineFlags.isNewPipelineEnabled()).thenReturn(false);
 
         mEntryManager = new NotificationEntryManager(
                 mock(NotificationEntryManagerLogger.class),
                 mGroupMembershipManager,
-                mFeatureFlags,
+                mNotifPipelineFlags,
                 () -> mRowBinder,
                 () -> mRemoteInputManager,
                 mLeakDetector,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
index f26bb75..7194c66 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
@@ -46,7 +46,6 @@
 import com.android.systemui.classifier.FalsingCollectorFake;
 import com.android.systemui.classifier.FalsingManagerFake;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
-import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.media.KeyguardMediaController;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.OnMenuEventListener;
@@ -59,6 +58,7 @@
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.notification.DynamicPrivacyController;
 import com.android.systemui.statusbar.notification.ForegroundServiceDismissalFeatureController;
+import com.android.systemui.statusbar.notification.NotifPipelineFlags;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotifCollection;
 import com.android.systemui.statusbar.notification.collection.NotifPipeline;
@@ -121,7 +121,7 @@
     @Mock private ScrimController mScrimController;
     @Mock private NotificationGroupManagerLegacy mLegacyGroupManager;
     @Mock private SectionHeaderController mSilentHeaderController;
-    @Mock private FeatureFlags mFeatureFlags;
+    @Mock private NotifPipelineFlags mNotifPipelineFlags;
     @Mock private NotifPipeline mNotifPipeline;
     @Mock private NotifCollection mNotifCollection;
     @Mock private NotificationEntryManager mEntryManager;
@@ -146,7 +146,7 @@
         MockitoAnnotations.initMocks(this);
 
         when(mNotificationSwipeHelperBuilder.build()).thenReturn(mNotificationSwipeHelper);
-        when(mFeatureFlags.isNewNotifPipelineRenderingEnabled()).thenReturn(false);
+        when(mNotifPipelineFlags.isNewPipelineEnabled()).thenReturn(false);
         when(mFgServicesSectionController.createView(mLayoutInflater))
                 .thenReturn(mForegroundServiceDungeonView);
 
@@ -176,7 +176,7 @@
                 mLegacyGroupManager,
                 mLegacyGroupManager,
                 mSilentHeaderController,
-                mFeatureFlags,
+                mNotifPipelineFlags,
                 mNotifPipeline,
                 mNotifCollection,
                 mEntryManager,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java
index 0faf5d4..a0e91fc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java
@@ -438,8 +438,8 @@
         assertEquals("returns false when view is null", false,
                 NotificationSwipeHelper.isTouchInView(mEvent, null));
 
-        doReturn(5f).when(mEvent).getX();
-        doReturn(10f).when(mEvent).getY();
+        doReturn(5f).when(mEvent).getRawX();
+        doReturn(10f).when(mEvent).getRawY();
 
         doReturn(20).when(mView).getWidth();
         doReturn(20).when(mView).getHeight();
@@ -455,7 +455,7 @@
         assertTrue("Touch is within the view",
                 mSwipeHelper.isTouchInView(mEvent, mView));
 
-        doReturn(50f).when(mEvent).getX();
+        doReturn(50f).when(mEvent).getRawX();
 
         assertFalse("Touch is not within the view",
                 mSwipeHelper.isTouchInView(mEvent, mView));
@@ -466,8 +466,8 @@
         assertEquals("returns false when view is null", false,
                 NotificationSwipeHelper.isTouchInView(mEvent, null));
 
-        doReturn(5f).when(mEvent).getX();
-        doReturn(10f).when(mEvent).getY();
+        doReturn(5f).when(mEvent).getRawX();
+        doReturn(10f).when(mEvent).getRawY();
 
         doReturn(20).when(mNotificationRow).getWidth();
         doReturn(20).when(mNotificationRow).getActualHeight();
@@ -483,7 +483,7 @@
         assertTrue("Touch is within the view",
                 mSwipeHelper.isTouchInView(mEvent, mNotificationRow));
 
-        doReturn(50f).when(mEvent).getX();
+        doReturn(50f).when(mEvent).getRawX();
 
         assertFalse("Touch is not within the view",
                 mSwipeHelper.isTouchInView(mEvent, mNotificationRow));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
index 3f5d220..2289936 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
@@ -51,7 +51,7 @@
 import com.android.systemui.qs.AutoAddTracker;
 import com.android.systemui.qs.QSTileHost;
 import com.android.systemui.qs.ReduceBrightColorsController;
-import com.android.systemui.qs.SecureSetting;
+import com.android.systemui.qs.SettingObserver;
 import com.android.systemui.statusbar.policy.CastController;
 import com.android.systemui.statusbar.policy.CastController.CastDevice;
 import com.android.systemui.statusbar.policy.DataSaverController;
@@ -249,7 +249,7 @@
 
         verify(mWalletController, times(2)).getWalletPosition();
 
-        SecureSetting setting = mAutoTileManager.getSecureSettingForKey(TEST_SETTING);
+        SettingObserver setting = mAutoTileManager.getSecureSettingForKey(TEST_SETTING);
         assertEquals(USER + 1, setting.getCurrentUser());
         assertTrue(setting.isListening());
     }
@@ -299,7 +299,7 @@
 
         verify(mWalletController, times(2)).getWalletPosition();
 
-        SecureSetting setting = mAutoTileManager.getSecureSettingForKey(TEST_SETTING);
+        SettingObserver setting = mAutoTileManager.getSecureSettingForKey(TEST_SETTING);
         assertEquals(USER + 1, setting.getCurrentUser());
         assertFalse(setting.isListening());
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
index 25fd801..07debe6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
@@ -45,6 +45,7 @@
 import com.android.systemui.keyguard.KeyguardViewMediator;
 import com.android.systemui.keyguard.ScreenLifecycle;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.NotificationMediaManager;
 import com.android.systemui.statusbar.NotificationShadeWindowController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -101,6 +102,8 @@
     private WakefulnessLifecycle mWakefulnessLifecycle;
     @Mock
     private ScreenLifecycle mScreenLifecycle;
+    @Mock
+    private StatusBarStateController mStatusBarStateController;
     private BiometricUnlockController mBiometricUnlockController;
 
     @Before
@@ -123,7 +126,7 @@
                 mUpdateMonitor, res.getResources(), mKeyguardBypassController, mDozeParameters,
                 mMetricsLogger, mDumpManager, mPowerManager,
                 mNotificationMediaManager, mWakefulnessLifecycle, mScreenLifecycle,
-                mAuthController);
+                mAuthController, mStatusBarStateController);
         mBiometricUnlockController.setKeyguardViewController(mStatusBarKeyguardViewManager);
         mBiometricUnlockController.setBiometricModeListener(mBiometricModeListener);
     }
@@ -378,6 +381,23 @@
     }
 
     @Test
+    public void onUdfpsConsecutivelyFailedThreeTimes_showBouncer() {
+        // GIVEN UDFPS is supported
+        when(mUpdateMonitor.isUdfpsSupported()).thenReturn(true);
+
+        // WHEN udfps fails twice - then don't show the bouncer
+        mBiometricUnlockController.onBiometricAuthFailed(BiometricSourceType.FINGERPRINT);
+        mBiometricUnlockController.onBiometricAuthFailed(BiometricSourceType.FINGERPRINT);
+        verify(mStatusBarKeyguardViewManager, never()).showBouncer(anyBoolean());
+
+        // WHEN udfps fails the third time
+        mBiometricUnlockController.onBiometricAuthFailed(BiometricSourceType.FINGERPRINT);
+
+        // THEN show the bouncer
+        verify(mStatusBarKeyguardViewManager).showBouncer(true);
+    }
+
+    @Test
     public void onFinishedGoingToSleep_authenticatesWhenPending() {
         when(mUpdateMonitor.isGoingToSleep()).thenReturn(true);
         mBiometricUnlockController.onFinishedGoingToSleep(-1);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java
index 7a0b366..391a64e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java
@@ -39,6 +39,7 @@
 import com.android.systemui.doze.DozeScreenState;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.tuner.TunerService;
 
@@ -126,7 +127,7 @@
     public void testControlUnlockedScreenOffAnimation_dozeAfterScreenOff_false() {
         when(mAmbientDisplayConfiguration.alwaysOnEnabled(anyInt())).thenReturn(true);
         mDozeParameters.onTuningChanged(Settings.Secure.DOZE_ALWAYS_ON, "1");
-        when(mFeatureFlags.useNewLockscreenAnimations()).thenReturn(true);
+        when(mFeatureFlags.isEnabled(Flags.LOCKSCREEN_ANIMATIONS)).thenReturn(true);
         when(mUnlockedScreenOffAnimationController.shouldPlayUnlockedScreenOffAnimation())
                 .thenReturn(true);
         assertTrue(mDozeParameters.shouldControlUnlockedScreenOff());
@@ -143,7 +144,7 @@
     public void testControlUnlockedScreenOffAnimationDisabled_dozeAfterScreenOff() {
         when(mAmbientDisplayConfiguration.alwaysOnEnabled(anyInt())).thenReturn(true);
         mDozeParameters.onTuningChanged(Settings.Secure.DOZE_ALWAYS_ON, "1");
-        when(mFeatureFlags.useNewLockscreenAnimations()).thenReturn(false);
+        when(mFeatureFlags.isEnabled(Flags.LOCKSCREEN_ANIMATIONS)).thenReturn(false);
 
         assertFalse(mDozeParameters.shouldControlUnlockedScreenOff());
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java
index 81ddc67..270c64d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java
@@ -358,6 +358,7 @@
     private NotificationsQuickSettingsContainer mNotificationContainerParent;
     private List<View.OnAttachStateChangeListener> mOnAttachStateChangeListeners;
     private FalsingManagerFake mFalsingManager = new FalsingManagerFake();
+    private FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock());
 
     @Before
     public void setup() {
@@ -511,7 +512,7 @@
                 mQuickAccessWalletController,
                 mQrCodeScannerController,
                 mRecordingController,
-                new FakeExecutor(new FakeSystemClock()),
+                mExecutor,
                 mSecureSettings,
                 mSplitShadeHeaderController,
                 mUnlockedScreenOffAnimationController,
@@ -936,6 +937,7 @@
                 ArgumentCaptor.forClass(WeakReference.class);
 
         monitorCallback.getValue().onSourceAvailable(new WeakReference<>(mCommunalSource));
+        mExecutor.runAllReady();
         verify(mCommunalHostViewController).show(sourceCapture.capture());
         assertThat(sourceCapture.getValue().get()).isEqualTo(mCommunalSource);
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SplitShadeHeaderControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SplitShadeHeaderControllerTest.kt
index 4f68a3d..0df7549 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SplitShadeHeaderControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SplitShadeHeaderControllerTest.kt
@@ -9,6 +9,7 @@
 import com.android.systemui.battery.BatteryMeterView
 import com.android.systemui.battery.BatteryMeterViewController
 import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
 import com.android.systemui.qs.carrier.QSCarrierGroupController
 import com.google.common.truth.Truth.assertThat
 import org.junit.Before
@@ -54,7 +55,7 @@
             null
         }
         whenever(view.visibility).thenAnswer { _ -> viewVisibility }
-        whenever(featureFlags.useCombinedQSHeaders()).thenReturn(false)
+        whenever(featureFlags.isEnabled(Flags.COMBINED_QS_HEADERS)).thenReturn(false)
         splitShadeHeaderController = SplitShadeHeaderController(view, statusBarIconController,
         qsCarrierGroupControllerBuilder, featureFlags, batteryMeterViewController)
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
index 6f174cb..c5bdfed 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
@@ -374,6 +374,21 @@
     }
 
     @Test
+    public void testHideAltAuth_onShowBouncer() {
+        // GIVEN alt auth is showing
+        mStatusBarKeyguardViewManager.setAlternateAuthInterceptor(mAlternateAuthInterceptor);
+        when(mBouncer.isShowing()).thenReturn(false);
+        when(mAlternateAuthInterceptor.isShowingAlternateAuthBouncer()).thenReturn(true);
+        reset(mAlternateAuthInterceptor);
+
+        // WHEN showBouncer is called
+        mStatusBarKeyguardViewManager.showBouncer(true);
+
+        // THEN alt bouncer should be hidden
+        verify(mAlternateAuthInterceptor).hideAlternateAuthBouncer();
+    }
+
+    @Test
     public void testUpdateResources_delegatesToBouncer() {
         mStatusBarKeyguardViewManager.updateResources();
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
index 7791fd0..07ec0e2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
@@ -35,6 +35,7 @@
 
 import android.app.KeyguardManager;
 import android.app.Notification;
+import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.content.Intent;
 import android.os.Handler;
@@ -54,7 +55,6 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.animation.ActivityLaunchAnimator;
 import com.android.systemui.assist.AssistManager;
-import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.CommandQueue;
@@ -63,6 +63,7 @@
 import com.android.systemui.statusbar.NotificationPresenter;
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
 import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.notification.NotifPipelineFlags;
 import com.android.systemui.statusbar.notification.NotificationActivityStarter;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.NotificationLaunchAnimatorControllerProvider;
@@ -116,13 +117,15 @@
     @Mock
     private KeyguardStateController mKeyguardStateController;
     @Mock
+    private NotificationInterruptStateProvider mNotificationInterruptStateProvider;
+    @Mock
     private Handler mHandler;
     @Mock
     private BubblesManager mBubblesManager;
     @Mock
     private ShadeControllerImpl mShadeController;
     @Mock
-    private FeatureFlags mFeatureFlags;
+    private NotifPipelineFlags mNotifPipelineFlags;
     @Mock
     private NotifPipeline mNotifPipeline;
     @Mock
@@ -137,7 +140,7 @@
     @Mock
     private OnUserInteractionCallback mOnUserInteractionCallback;
     @Mock
-    private NotificationActivityStarter mNotificationActivityStarter;
+    private StatusBarNotificationActivityStarter mNotificationActivityStarter;
     @Mock
     private ActivityLaunchAnimator mActivityLaunchAnimator;
     private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock());
@@ -180,7 +183,7 @@
         mActiveNotifications.add(mBubbleNotificationRow.getEntry());
         when(mEntryManager.getVisibleNotifications()).thenReturn(mActiveNotifications);
         when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE);
-        when(mFeatureFlags.isNewNotifPipelineRenderingEnabled()).thenReturn(false);
+        when(mNotifPipelineFlags.isNewPipelineEnabled()).thenReturn(false);
         when(mOnUserInteractionCallback.getGroupSummaryToDismiss(mNotificationRow.getEntry()))
                 .thenReturn(null);
         when(mVisibilityProvider.obtain(anyString(), anyBoolean())).thenAnswer(
@@ -219,12 +222,12 @@
                         mock(NotificationLockscreenUserManager.class),
                         mShadeController,
                         mKeyguardStateController,
-                        mock(NotificationInterruptStateProvider.class),
+                        mNotificationInterruptStateProvider,
                         mock(LockPatternUtils.class),
                         mock(StatusBarRemoteInputCallback.class),
                         mActivityIntentHelper,
 
-                        mFeatureFlags,
+                        mNotifPipelineFlags,
                         mock(MetricsLogger.class),
                         mock(StatusBarNotificationActivityStarterLogger.class),
                         mOnUserInteractionCallback)
@@ -375,4 +378,27 @@
         // Notification should not be cancelled.
         verify(mEntryManager, never()).performRemoveNotification(eq(sbn), any(), anyInt());
     }
+
+    @Test
+    public void testOnFullScreenIntentWhenDozing_wakeUpDevice() {
+        // GIVEN entry that can has a full screen intent that can show
+        Notification.Builder nb = new Notification.Builder(mContext, "a")
+                .setContentTitle("foo")
+                .setSmallIcon(android.R.drawable.sym_def_app_icon)
+                .setFullScreenIntent(mock(PendingIntent.class), true);
+        StatusBarNotification sbn = new StatusBarNotification("pkg", "pkg", 0,
+                "tag" + System.currentTimeMillis(), 0, 0,
+                nb.build(), new UserHandle(0), null, 0);
+        NotificationEntry entry = mock(NotificationEntry.class);
+        when(entry.getImportance()).thenReturn(NotificationManager.IMPORTANCE_HIGH);
+        when(entry.getSbn()).thenReturn(sbn);
+        when(mNotificationInterruptStateProvider.shouldLaunchFullScreenIntentWhenAdded(eq(entry)))
+                .thenReturn(true);
+
+        // WHEN
+        mNotificationActivityStarter.handleFullScreenIntent(entry);
+
+        // THEN display should try wake up for the full screen intent
+        verify(mStatusBar).wakeUpForFullScreenIntent();
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
index ffef55b..7d9e6b4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
@@ -37,7 +37,6 @@
 import com.android.systemui.ForegroundServiceNotificationListener;
 import com.android.systemui.InitController;
 import com.android.systemui.SysuiTestCase;
-import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.KeyguardIndicationController;
@@ -113,7 +112,6 @@
                 mock(NotificationShadeWindowController.class), mock(DynamicPrivacyController.class),
                 mock(KeyguardStateController.class),
                 mock(KeyguardIndicationController.class),
-                mock(FeatureFlags.class),
                 mStatusBar,
                 mock(ShadeControllerImpl.class), mock(LockscreenShadeTransitionController.class),
                 mCommandQueue,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index 6cc6490..1df576e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -86,6 +86,7 @@
 import com.android.systemui.demomode.DemoModeController;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.fragments.FragmentService;
 import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
 import com.android.systemui.keyguard.KeyguardViewMediator;
 import com.android.systemui.keyguard.ScreenLifecycle;
@@ -135,7 +136,6 @@
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
 import com.android.systemui.statusbar.phone.dagger.StatusBarComponent;
 import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragmentLogger;
-import com.android.systemui.statusbar.phone.fragment.dagger.StatusBarFragmentComponent;
 import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController;
 import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
 import com.android.systemui.statusbar.policy.BatteryController;
@@ -210,6 +210,7 @@
     @Mock private AmbientDisplayConfiguration mAmbientDisplayConfiguration;
     @Mock private NotificationLogger.ExpansionStateLogger mExpansionStateLogger;
     @Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+    @Mock private StatusBarSignalPolicy mStatusBarSignalPolicy;
     @Mock private NotificationShadeWindowView mNotificationShadeWindowView;
     @Mock private BroadcastDispatcher mBroadcastDispatcher;
     @Mock private AssistManager mAssistManager;
@@ -246,8 +247,6 @@
     @Mock private CollapsedStatusBarFragmentLogger mCollapsedStatusBarFragmentLogger;
     @Mock private StatusBarComponent.Factory mStatusBarComponentFactory;
     @Mock private StatusBarComponent mStatusBarComponent;
-    @Mock private StatusBarFragmentComponent.Factory mStatusBarFragmentComponentFactory;
-    @Mock private StatusBarFragmentComponent mStatusBarFragmentComponent;
     @Mock private PluginManager mPluginManager;
     @Mock private LegacySplitScreen mLegacySplitScreen;
     @Mock private LightsOutNotifController mLightsOutNotifController;
@@ -314,7 +313,7 @@
         NotificationLogger notificationLogger = new NotificationLogger(
                 mNotificationListener,
                 mUiBgExecutor,
-                mFeatureFlags,
+                mNotifPipelineFlags,
                 mVisibilityProvider,
                 mock(NotificationEntryManager.class),
                 mock(NotifPipeline.class),
@@ -362,8 +361,6 @@
         when(mBiometricUnlockControllerLazy.get()).thenReturn(mBiometricUnlockController);
 
         when(mStatusBarComponentFactory.create()).thenReturn(mStatusBarComponent);
-        when(mStatusBarFragmentComponentFactory.create(any()))
-                .thenReturn(mStatusBarFragmentComponent);
         when(mStatusBarComponent.getNotificationShadeWindowViewController()).thenReturn(
                 mNotificationShadeWindowViewController);
 
@@ -378,10 +375,12 @@
         mStatusBar = new StatusBar(
                 mContext,
                 mNotificationsController,
+                mock(FragmentService.class),
                 mLightBarController,
                 mAutoHideController,
                 mStatusBarWindowController,
                 mKeyguardUpdateMonitor,
+                mStatusBarSignalPolicy,
                 mPulseExpansionHandler,
                 mNotificationWakeUpCoordinator,
                 mKeyguardBypassController,
@@ -433,7 +432,6 @@
                 mCommandQueue,
                 mCollapsedStatusBarFragmentLogger,
                 mStatusBarComponentFactory,
-                mStatusBarFragmentComponentFactory,
                 mPluginManager,
                 Optional.of(mLegacySplitScreen),
                 mLightsOutNotifController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
index 0ee4e7a..609d69c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
@@ -294,6 +294,7 @@
                 new StatusBarHideIconsForBouncerManager(
                         mCommandQueue, new FakeExecutor(new FakeSystemClock()), new DumpManager()),
                 mKeyguardStateController,
+                mock(NotificationPanelViewController.class),
                 mNetworkController,
                 mStatusBarStateController,
                 () -> Optional.of(mStatusBar),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt
index b385b7d..0920cac 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt
@@ -35,7 +35,6 @@
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.plugins.ActivityStarter
-import com.android.systemui.flags.FeatureFlags
 import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.statusbar.gesture.SwipeStatusBarAwayGestureHandler
 import com.android.systemui.statusbar.notification.collection.NotificationEntry
@@ -62,7 +61,7 @@
 import org.mockito.Mockito.times
 import org.mockito.Mockito.verify
 import org.mockito.MockitoAnnotations
-import java.util.Optional
+import java.util.*
 
 private const val CALL_UID = 900
 
@@ -84,7 +83,7 @@
     private lateinit var controller: OngoingCallController
     private lateinit var notifCollectionListener: NotifCollectionListener
 
-    @Mock private lateinit var mockFeatureFlags: FeatureFlags
+    @Mock private lateinit var mockOngoingCallFlags: OngoingCallFlags
     @Mock private lateinit var mockSwipeStatusBarAwayGestureHandler: SwipeStatusBarAwayGestureHandler
     @Mock private lateinit var mockOngoingCallListener: OngoingCallListener
     @Mock private lateinit var mockActivityStarter: ActivityStarter
@@ -102,12 +101,12 @@
         }
 
         MockitoAnnotations.initMocks(this)
-        `when`(mockFeatureFlags.isOngoingCallStatusBarChipEnabled).thenReturn(true)
+        `when`(mockOngoingCallFlags.isStatusBarChipEnabled()).thenReturn(true)
         val notificationCollection = mock(CommonNotifCollection::class.java)
 
         controller = OngoingCallController(
                 notificationCollection,
-                mockFeatureFlags,
+                mockOngoingCallFlags,
                 clock,
                 mockActivityStarter,
                 mainExecutor,
@@ -449,7 +448,7 @@
 
     @Test
     fun fullscreenIsTrue_thenCallNotificationAdded_chipNotClickable() {
-        `when`(mockFeatureFlags.isOngoingCallInImmersiveChipTapEnabled).thenReturn(false)
+        `when`(mockOngoingCallFlags.isInImmersiveChipTapEnabled()).thenReturn(false)
 
         getStateListener().onFullscreenStateChanged(/* isFullscreen= */ true)
         notifCollectionListener.onEntryUpdated(createOngoingCallNotifEntry())
@@ -459,7 +458,7 @@
 
     @Test
     fun callNotificationAdded_thenFullscreenIsTrue_chipNotClickable() {
-        `when`(mockFeatureFlags.isOngoingCallInImmersiveChipTapEnabled).thenReturn(false)
+        `when`(mockOngoingCallFlags.isInImmersiveChipTapEnabled()).thenReturn(false)
 
         notifCollectionListener.onEntryUpdated(createOngoingCallNotifEntry())
         getStateListener().onFullscreenStateChanged(/* isFullscreen= */ true)
@@ -469,7 +468,7 @@
 
     @Test
     fun fullscreenChangesToFalse_chipClickable() {
-        `when`(mockFeatureFlags.isOngoingCallInImmersiveChipTapEnabled).thenReturn(false)
+        `when`(mockOngoingCallFlags.isInImmersiveChipTapEnabled()).thenReturn(false)
 
         notifCollectionListener.onEntryUpdated(createOngoingCallNotifEntry())
         // First, update to true
@@ -482,7 +481,7 @@
 
     @Test
     fun fullscreenIsTrue_butChipClickInImmersiveEnabled_chipClickable() {
-        `when`(mockFeatureFlags.isOngoingCallInImmersiveChipTapEnabled).thenReturn(true)
+        `when`(mockOngoingCallFlags.isInImmersiveChipTapEnabled()).thenReturn(true)
 
         notifCollectionListener.onEntryUpdated(createOngoingCallNotifEntry())
         getStateListener().onFullscreenStateChanged(/* isFullscreen= */ true)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt
index 379c595..de2012a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt
@@ -31,6 +31,7 @@
 import android.os.UserManager
 import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
+import android.view.ThreadedRenderer
 import androidx.test.filters.SmallTest
 import com.android.internal.jank.InteractionJankMonitor
 import com.android.internal.logging.testing.UiEventLoggerFake
@@ -44,13 +45,16 @@
 import com.android.systemui.plugins.ActivityStarter
 import com.android.systemui.plugins.FalsingManager
 import com.android.systemui.qs.QSUserSwitcherEvent
+import com.android.systemui.qs.user.UserSwitchDialogController
 import com.android.systemui.settings.UserTracker
+import com.android.systemui.statusbar.phone.NotificationShadeWindowView
 import com.android.systemui.telephony.TelephonyListenerManager
 import com.android.systemui.util.concurrency.FakeExecutor
 import com.android.systemui.util.settings.SecureSettings
 import com.android.systemui.util.time.FakeSystemClock
 import org.junit.Assert.assertEquals
 import org.junit.Assert.assertNotNull
+import org.junit.Assert.assertFalse
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -60,6 +64,8 @@
 import org.mockito.Mockito.`when`
 import org.mockito.Mockito.any
 import org.mockito.Mockito.anyString
+import org.mockito.Mockito.doNothing
+import org.mockito.Mockito.doReturn
 import org.mockito.Mockito.mock
 import org.mockito.Mockito.verify
 import org.mockito.MockitoAnnotations
@@ -85,6 +91,9 @@
     @Mock private lateinit var dumpManager: DumpManager
     @Mock private lateinit var interactionJankMonitor: InteractionJankMonitor
     @Mock private lateinit var latencyTracker: LatencyTracker
+    @Mock private lateinit var dialogShower: UserSwitchDialogController.DialogShower
+    @Mock private lateinit var notificationShadeWindowView: NotificationShadeWindowView
+    @Mock private lateinit var threadedRenderer: ThreadedRenderer
     private lateinit var testableLooper: TestableLooper
     private lateinit var uiBgExecutor: FakeExecutor
     private lateinit var uiEventLogger: UiEventLoggerFake
@@ -98,6 +107,8 @@
     private val guestId = 1234
     private val guestInfo = UserInfo(guestId, "Guest", null,
             UserInfo.FLAG_FULL or UserInfo.FLAG_GUEST, UserManager.USER_TYPE_FULL_GUEST)
+    private val secondaryUser =
+            UserInfo(10, "Secondary", null, 0, UserManager.USER_TYPE_FULL_SECONDARY)
 
     @Before
     fun setUp() {
@@ -114,6 +125,7 @@
                 mock(FingerprintManager::class.java))
 
         `when`(userManager.canAddMoreUsers()).thenReturn(true)
+        `when`(notificationShadeWindowView.context).thenReturn(context)
 
         userSwitcherController = UserSwitcherController(
                 context,
@@ -138,7 +150,37 @@
                 dumpManager)
         userSwitcherController.mPauseRefreshUsers = true
 
+        // Since userSwitcherController involves InteractionJankMonitor.
+        // Let's fulfill the dependencies.
+        val mockedContext = mock(Context::class.java)
+        doReturn(mockedContext).`when`(notificationShadeWindowView).context
+        doReturn(true).`when`(notificationShadeWindowView).isAttachedToWindow
+        doNothing().`when`(threadedRenderer).addObserver(any())
+        doNothing().`when`(threadedRenderer).removeObserver(any())
+        doReturn(threadedRenderer).`when`(notificationShadeWindowView).threadedRenderer
+        userSwitcherController.init(notificationShadeWindowView)
+
         picture = UserIcons.convertToBitmap(context.getDrawable(R.drawable.ic_avatar_user))
+        userSwitcherController.init(notificationShadeWindowView)
+    }
+
+    @Test
+    fun testSwitchUser_parentDialogDismissed() {
+        val otherUserRecord = UserSwitcherController.UserRecord(
+                secondaryUser,
+                picture,
+                false /* guest */,
+                false /* current */,
+                false /* isAddUser */,
+                false /* isRestricted */,
+                true /* isSwitchToEnabled */)
+        `when`(userTracker.userId).thenReturn(ownerId)
+        `when`(userTracker.userInfo).thenReturn(ownerInfo)
+
+        userSwitcherController.onUserListItemClicked(otherUserRecord, dialogShower)
+        testableLooper.processAllMessages()
+
+        verify(dialogShower).dismiss()
     }
 
     @Test
@@ -156,7 +198,7 @@
 
         `when`(userManager.createGuest(any(), anyString())).thenReturn(guestInfo)
 
-        userSwitcherController.onUserListItemClicked(emptyGuestUserRecord)
+        userSwitcherController.onUserListItemClicked(emptyGuestUserRecord, null)
         testableLooper.processAllMessages()
         verify(interactionJankMonitor).begin(any())
         verify(latencyTracker).onActionStart(LatencyTracker.ACTION_USER_SWITCH)
@@ -166,6 +208,26 @@
     }
 
     @Test
+    fun testAddGuest_parentDialogDismissed() {
+        val emptyGuestUserRecord = UserSwitcherController.UserRecord(
+                null,
+                null,
+                true /* guest */,
+                false /* current */,
+                false /* isAddUser */,
+                false /* isRestricted */,
+                true /* isSwitchToEnabled */)
+        `when`(userTracker.userId).thenReturn(ownerId)
+        `when`(userTracker.userInfo).thenReturn(ownerInfo)
+
+        `when`(userManager.createGuest(any(), anyString())).thenReturn(guestInfo)
+
+        userSwitcherController.onUserListItemClicked(emptyGuestUserRecord, dialogShower)
+        testableLooper.processAllMessages()
+        verify(dialogShower).dismiss()
+    }
+
+    @Test
     fun testRemoveGuest_removeButtonPressed_isLogged() {
         val currentGuestUserRecord = UserSwitcherController.UserRecord(
                 guestInfo,
@@ -178,7 +240,7 @@
         `when`(userTracker.userId).thenReturn(guestInfo.id)
         `when`(userTracker.userInfo).thenReturn(guestInfo)
 
-        userSwitcherController.onUserListItemClicked(currentGuestUserRecord)
+        userSwitcherController.onUserListItemClicked(currentGuestUserRecord, null)
         assertNotNull(userSwitcherController.mExitGuestDialog)
         userSwitcherController.mExitGuestDialog
                 .getButton(DialogInterface.BUTTON_POSITIVE).performClick()
@@ -188,6 +250,46 @@
     }
 
     @Test
+    fun testRemoveGuest_removeButtonPressed_dialogDismissed() {
+        val currentGuestUserRecord = UserSwitcherController.UserRecord(
+                guestInfo,
+                picture,
+                true /* guest */,
+                true /* current */,
+                false /* isAddUser */,
+                false /* isRestricted */,
+                true /* isSwitchToEnabled */)
+        `when`(userTracker.userId).thenReturn(guestInfo.id)
+        `when`(userTracker.userInfo).thenReturn(guestInfo)
+
+        userSwitcherController.onUserListItemClicked(currentGuestUserRecord, null)
+        assertNotNull(userSwitcherController.mExitGuestDialog)
+        userSwitcherController.mExitGuestDialog
+                .getButton(DialogInterface.BUTTON_POSITIVE).performClick()
+        testableLooper.processAllMessages()
+        assertFalse(userSwitcherController.mExitGuestDialog.isShowing)
+    }
+
+    @Test
+    fun testRemoveGuest_dialogShowerUsed() {
+        val currentGuestUserRecord = UserSwitcherController.UserRecord(
+                guestInfo,
+                picture,
+                true /* guest */,
+                true /* current */,
+                false /* isAddUser */,
+                false /* isRestricted */,
+                true /* isSwitchToEnabled */)
+        `when`(userTracker.userId).thenReturn(guestInfo.id)
+        `when`(userTracker.userInfo).thenReturn(guestInfo)
+
+        userSwitcherController.onUserListItemClicked(currentGuestUserRecord, dialogShower)
+        assertNotNull(userSwitcherController.mExitGuestDialog)
+        testableLooper.processAllMessages()
+        verify(dialogShower).showDialog(userSwitcherController.mExitGuestDialog)
+    }
+
+    @Test
     fun testRemoveGuest_cancelButtonPressed_isNotLogged() {
         val currentGuestUserRecord = UserSwitcherController.UserRecord(
                 guestInfo,
@@ -200,7 +302,7 @@
         `when`(userTracker.userId).thenReturn(guestId)
         `when`(userTracker.userInfo).thenReturn(guestInfo)
 
-        userSwitcherController.onUserListItemClicked(currentGuestUserRecord)
+        userSwitcherController.onUserListItemClicked(currentGuestUserRecord, null)
         assertNotNull(userSwitcherController.mExitGuestDialog)
         userSwitcherController.mExitGuestDialog
                 .getButton(DialogInterface.BUTTON_NEGATIVE).performClick()
@@ -226,7 +328,7 @@
                 eq(GuestResumeSessionReceiver.SETTING_GUEST_HAS_LOGGED_IN), anyInt(), anyInt()))
                 .thenReturn(1)
 
-        userSwitcherController.onUserListItemClicked(currentGuestUserRecord)
+        userSwitcherController.onUserListItemClicked(currentGuestUserRecord, null)
 
         // Simulate a user switch event
         val intent = Intent(Intent.ACTION_USER_SWITCHED).putExtra(Intent.EXTRA_USER_HANDLE, guestId)
@@ -260,7 +362,7 @@
                 eq(GuestResumeSessionReceiver.SETTING_GUEST_HAS_LOGGED_IN), anyInt(), anyInt()))
                 .thenReturn(1)
 
-        userSwitcherController.onUserListItemClicked(currentGuestUserRecord)
+        userSwitcherController.onUserListItemClicked(currentGuestUserRecord, null)
 
         // Simulate a user switch event
         val intent = Intent(Intent.ACTION_USER_SWITCHED).putExtra(Intent.EXTRA_USER_HANDLE, guestId)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ZenModeControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ZenModeControllerImplTest.java
index 336f2b1..3fe1a9f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ZenModeControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ZenModeControllerImplTest.java
@@ -36,6 +36,7 @@
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.statusbar.policy.ZenModeController.Callback;
+import com.android.systemui.util.settings.FakeSettings;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -70,7 +71,8 @@
                 mContext,
                 Handler.createAsync(Looper.myLooper()),
                 mBroadcastDispatcher,
-                mDumpManager);
+                mDumpManager,
+                new FakeSettings());
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
index 3ff5666..ccb4f67 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
@@ -53,6 +53,7 @@
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.settings.UserTracker;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
@@ -114,7 +115,7 @@
     @Before
     public void setup() {
         MockitoAnnotations.initMocks(this);
-        when(mFeatureFlags.isMonetEnabled()).thenReturn(true);
+        when(mFeatureFlags.isEnabled(Flags.MONET)).thenReturn(true);
         when(mWakefulnessLifecycle.getWakefulness()).thenReturn(WAKEFULNESS_AWAKE);
         when(mDeviceProvisionedController.isCurrentUserSetup()).thenReturn(true);
         mThemeOverlayController = new ThemeOverlayController(null /* context */,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
index c900ad5..a8e92f5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -76,7 +76,6 @@
 import com.android.systemui.biometrics.AuthController;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
 import com.android.systemui.dump.DumpManager;
-import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.keyguard.KeyguardViewMediator;
 import com.android.systemui.model.SysUiState;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -85,6 +84,7 @@
 import com.android.systemui.statusbar.NotificationRemoveInterceptor;
 import com.android.systemui.statusbar.RankingBuilder;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
+import com.android.systemui.statusbar.notification.NotifPipelineFlags;
 import com.android.systemui.statusbar.notification.NotificationEntryListener;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.NotificationFilter;
@@ -221,7 +221,7 @@
     @Mock
     private NotifPipeline mNotifPipeline;
     @Mock
-    private FeatureFlags mFeatureFlagsOldPipeline;
+    private NotifPipelineFlags mNotifPipelineFlags;
     @Mock
     private DumpManager mDumpManager;
     @Mock
@@ -326,7 +326,7 @@
                         mock(Handler.class)
                 );
 
-        when(mFeatureFlagsOldPipeline.isNewNotifPipelineRenderingEnabled()).thenReturn(false);
+        when(mNotifPipelineFlags.isNewPipelineEnabled()).thenReturn(false);
         when(mShellTaskOrganizer.getExecutor()).thenReturn(syncExecutor);
         mBubbleController = new TestableBubbleController(
                 mContext,
@@ -365,7 +365,7 @@
                 mNotificationEntryManager,
                 mNotifPipeline,
                 mSysUiState,
-                mFeatureFlagsOldPipeline,
+                mNotifPipelineFlags,
                 mDumpManager,
                 syncExecutor);
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java
index 5ab2113..8027390 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java
@@ -64,7 +64,6 @@
 import com.android.systemui.biometrics.AuthController;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
 import com.android.systemui.dump.DumpManager;
-import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.keyguard.KeyguardViewMediator;
 import com.android.systemui.model.SysUiState;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -72,6 +71,7 @@
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.RankingBuilder;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
+import com.android.systemui.statusbar.notification.NotifPipelineFlags;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.NotificationFilter;
 import com.android.systemui.statusbar.notification.collection.NotifPipeline;
@@ -199,7 +199,7 @@
     @Mock
     private NotifPipeline mNotifPipeline;
     @Mock
-    private FeatureFlags mFeatureFlagsNewPipeline;
+    private NotifPipelineFlags mNotifPipelineFlags;
     @Mock
     private DumpManager mDumpManager;
     @Mock
@@ -291,7 +291,7 @@
                         mock(HeadsUpManager.class),
                         mock(Handler.class)
                 );
-        when(mFeatureFlagsNewPipeline.isNewNotifPipelineRenderingEnabled()).thenReturn(true);
+        when(mNotifPipelineFlags.isNewPipelineEnabled()).thenReturn(true);
         when(mShellTaskOrganizer.getExecutor()).thenReturn(syncExecutor);
         mBubbleController = new TestableBubbleController(
                 mContext,
@@ -330,7 +330,7 @@
                 mNotificationEntryManager,
                 mNotifPipeline,
                 mSysUiState,
-                mFeatureFlagsNewPipeline,
+                mNotifPipelineFlags,
                 mDumpManager,
                 syncExecutor);
         mBubblesManager.addNotifCallback(mNotifCallback);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
index 8480702..ae7afce 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
@@ -41,6 +41,7 @@
 import com.android.wm.shell.onehanded.OneHandedEventCallback;
 import com.android.wm.shell.onehanded.OneHandedTransitionCallback;
 import com.android.wm.shell.pip.Pip;
+import com.android.wm.shell.sizecompatui.SizeCompatUI;
 import com.android.wm.shell.splitscreen.SplitScreen;
 
 import org.junit.Before;
@@ -76,6 +77,7 @@
     @Mock WakefulnessLifecycle mWakefulnessLifecycle;
     @Mock ProtoTracer mProtoTracer;
     @Mock ShellCommandHandler mShellCommandHandler;
+    @Mock SizeCompatUI mSizeCompatUI;
     @Mock ShellExecutor mSysUiMainExecutor;
 
     @Before
@@ -84,10 +86,10 @@
 
         mWMShell = new WMShell(mContext, Optional.of(mPip), Optional.of(mLegacySplitScreen),
                 Optional.of(mSplitScreen), Optional.of(mOneHanded), Optional.of(mHideDisplayCutout),
-                Optional.of(mShellCommandHandler), mCommandQueue, mConfigurationController,
-                mKeyguardUpdateMonitor, mNavigationModeController,
-                mScreenLifecycle, mSysUiState, mProtoTracer, mWakefulnessLifecycle,
-                mSysUiMainExecutor);
+                Optional.of(mShellCommandHandler), Optional.of(mSizeCompatUI),
+                mCommandQueue, mConfigurationController, mKeyguardUpdateMonitor,
+                mNavigationModeController, mScreenLifecycle, mSysUiState, mProtoTracer,
+                mWakefulnessLifecycle, mSysUiMainExecutor);
     }
 
     @Test
@@ -129,4 +131,11 @@
         verify(mConfigurationController).addCallback(
                 any(ConfigurationController.ConfigurationListener.class));
     }
+
+    @Test
+    public void initSizeCompatUI_registersCallbacks() {
+        mWMShell.initSizeCompatUi(mSizeCompatUI);
+
+        verify(mKeyguardUpdateMonitor).registerCallback(any(KeyguardUpdateMonitorCallback.class));
+    }
 }
diff --git a/packages/overlays/Android.mk b/packages/overlays/Android.mk
index 928892c..69641e6 100644
--- a/packages/overlays/Android.mk
+++ b/packages/overlays/Android.mk
@@ -31,7 +31,6 @@
 	NavigationBarModeGesturalOverlayNarrowBack \
 	NavigationBarModeGesturalOverlayWideBack \
 	NavigationBarModeGesturalOverlayExtraWideBack \
-        OneHandedModeGesturalOverlay \
 	preinstalled-packages-platform-overlays.xml
 
 include $(BUILD_PHONY_PACKAGE)
diff --git a/packages/overlays/OneHandedModeGesturalOverlay/AndroidManifest.xml b/packages/overlays/OneHandedModeGesturalOverlay/AndroidManifest.xml
deleted file mode 100644
index e4867df..0000000
--- a/packages/overlays/OneHandedModeGesturalOverlay/AndroidManifest.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!--
-/**
- * Copyright (c) 2020, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-        package="com.android.internal.systemui.onehanded.gestural"
-        android:versionCode="1"
-        android:versionName="1.0">
-    <overlay android:targetPackage="android"
-        android:category="com.android.internal.one_handed_mode"
-        android:priority="2"/>
-    <!-- To override dimen in NavigationBarModeGesturalOverlay, priority should be higher -->
-
-    <application android:label="@string/one_handed_mode_title" android:hasCode="false"/>
-</manifest>
diff --git a/packages/overlays/OneHandedModeGesturalOverlay/res/values/strings.xml b/packages/overlays/OneHandedModeGesturalOverlay/res/values/strings.xml
deleted file mode 100644
index 9e8c779..0000000
--- a/packages/overlays/OneHandedModeGesturalOverlay/res/values/strings.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/**
- * Copyright (c) 2020, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
--->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <!-- Name of overlay [CHAR LIMIT=64] -->
-    <string name="one_handed_mode_title" translatable="false">One Handed Mode</string>
-</resources>
diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
index 67bb726..f1599e4 100644
--- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
@@ -39,6 +39,7 @@
 import android.accessibilityservice.AccessibilityTrace;
 import android.accessibilityservice.IAccessibilityServiceClient;
 import android.accessibilityservice.IAccessibilityServiceConnection;
+import android.accessibilityservice.MagnificationConfig;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.PendingIntent;
@@ -1101,8 +1102,12 @@
             try {
                 MagnificationProcessor magnificationProcessor =
                         mSystemSupport.getMagnificationProcessor();
-                return magnificationProcessor
-                        .setScaleAndCenter(displayId, scale, centerX, centerY, animate, mId);
+                final MagnificationConfig config = new MagnificationConfig.Builder()
+                        .setScale(scale)
+                        .setCenterX(centerX)
+                        .setCenterY(centerY).build();
+                return magnificationProcessor.setMagnificationConfig(displayId, config, animate,
+                        mId);
             } finally {
                 Binder.restoreCallingIdentity(identity);
             }
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index d0b298f..f3a5d35 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -3708,6 +3708,7 @@
                 }
                 updateMagnificationLocked(userState);
                 updateWindowsForAccessibilityCallbackLocked(userState);
+                notifyClearAccessibilityCacheLocked();
             }
         }
 
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
index 6473bf5..327f087 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
@@ -84,6 +84,8 @@
 
     @GuardedBy("mLock")
     private int mActivatedMode = ACCESSIBILITY_MAGNIFICATION_MODE_NONE;
+    @GuardedBy("mLock")
+    private int mLastActivatedMode = ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN;
     // Track the active user to reset the magnification and get the associated user settings.
     private @UserIdInt int mUserId = UserHandle.USER_SYSTEM;
     @GuardedBy("mLock")
@@ -239,6 +241,7 @@
 
             synchronized (mLock) {
                 mActivatedMode = ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW;
+                mLastActivatedMode = mActivatedMode;
             }
             logMagnificationModeWithImeOnIfNeeded();
             disableFullScreenMagnificationIfNeeded(displayId);
@@ -276,6 +279,7 @@
 
             synchronized (mLock) {
                 mActivatedMode = ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN;
+                mLastActivatedMode = mActivatedMode;
             }
             logMagnificationModeWithImeOnIfNeeded();
         } else {
@@ -298,6 +302,16 @@
     }
 
     /**
+     * Returns the last activated magnification mode. If there is no activated magnifier before, it
+     * returns fullscreen mode by default.
+     */
+    public int getLastActivatedMode() {
+        synchronized (mLock) {
+            return mLastActivatedMode;
+        }
+    }
+
+    /**
      * Wrapper method of logging the magnification activated mode and its duration of the usage
      * when the magnification is disabled.
      *
@@ -336,6 +350,7 @@
         synchronized (mLock) {
             fullMagnificationController = mFullScreenMagnificationController;
             windowMagnificationManager = mWindowMagnificationMgr;
+            mLastActivatedMode = ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN;
         }
 
         mScaleProvider.onUserChanged(userId);
@@ -462,7 +477,15 @@
         return mTempPoint;
     }
 
-    private boolean isActivated(int displayId, int mode) {
+    /**
+     * Return {@code true} if the specified magnification mode on the given display is activated
+     * or not.
+     *
+     * @param displayId The logical displayId.
+     * @param mode It's either ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN or
+     * ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW.
+     */
+    public boolean isActivated(int displayId, int mode) {
         boolean isActivated = false;
         if (mode == ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN) {
             synchronized (mLock) {
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationProcessor.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationProcessor.java
index efc6d51..2324a5a 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationProcessor.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationProcessor.java
@@ -16,6 +16,13 @@
 
 package com.android.server.accessibility.magnification;
 
+import static android.accessibilityservice.MagnificationConfig.DEFAULT_MODE;
+import static android.accessibilityservice.MagnificationConfig.FULLSCREEN_MODE;
+import static android.accessibilityservice.MagnificationConfig.WINDOW_MODE;
+import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN;
+import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW;
+
+import android.accessibilityservice.MagnificationConfig;
 import android.annotation.NonNull;
 import android.graphics.Region;
 
@@ -23,6 +30,22 @@
  * Processor class for AccessibilityService connection to control magnification on the specified
  * display. This wraps the function of magnification controller.
  *
+ * <p>
+ * If the magnification config uses {@link DEFAULT_MODE}. This processor will control the current
+ * activated magnifier on the display. If there is no magnifier activated, it controls
+ * full-screen magnifier by default.
+ * </p>
+ *
+ * <p>
+ * If the magnification config uses {@link FULLSCREEN_MODE}. This processor will control
+ * full-screen magnifier on the display.
+ * </p>
+ *
+ * <p>
+ * If the magnification config uses {@link WINDOW_MODE}. This processor will control
+ * the activated window magnifier on the display.
+ * </p>
+ *
  * @see MagnificationController
  * @see FullScreenMagnificationController
  */
@@ -35,53 +58,166 @@
     }
 
     /**
-     * {@link FullScreenMagnificationController#getScale(int)}
+     * Gets the magnification config of the display.
+     *
+     * @param displayId The logical display id
+     * @return the magnification config
+     */
+    public @NonNull MagnificationConfig getMagnificationConfig(int displayId) {
+        final int mode = getControllingMode(displayId);
+        MagnificationConfig.Builder builder = new MagnificationConfig.Builder();
+        if (mode == FULLSCREEN_MODE) {
+            final FullScreenMagnificationController fullScreenMagnificationController =
+                    mController.getFullScreenMagnificationController();
+            builder.setMode(mode)
+                    .setScale(fullScreenMagnificationController.getScale(displayId))
+                    .setCenterX(fullScreenMagnificationController.getCenterX(displayId))
+                    .setCenterY(fullScreenMagnificationController.getCenterY(displayId));
+        } else if (mode == WINDOW_MODE) {
+            final WindowMagnificationManager windowMagnificationManager =
+                    mController.getWindowMagnificationMgr();
+            builder.setMode(mode)
+                    .setScale(windowMagnificationManager.getScale(displayId))
+                    .setCenterX(windowMagnificationManager.getCenterX(displayId))
+                    .setCenterY(windowMagnificationManager.getCenterY(displayId));
+        }
+        return builder.build();
+    }
+
+    /**
+     * Sets the magnification config of the display. If animation is disabled, the transition
+     * is immediate.
+     *
+     * @param displayId The logical display id
+     * @param config    The magnification config
+     * @param animate   {@code true} to animate from the current config or
+     *                  {@code false} to set the config immediately
+     * @param id        The ID of the service requesting the change
+     * @return {@code true} if the magnification spec changed, {@code false} if the spec did not
+     * change
+     */
+    public boolean setMagnificationConfig(int displayId, @NonNull MagnificationConfig config,
+            boolean animate, int id) {
+        int configMode = config.getMode();
+        if (configMode == DEFAULT_MODE) {
+            configMode = getControllingMode(displayId);
+        }
+        if (configMode == FULLSCREEN_MODE) {
+            return setScaleAndCenterForFullScreenMagnification(displayId, config.getScale(),
+                    config.getCenterX(), config.getCenterY(),
+                    animate, id);
+        } else if (configMode == WINDOW_MODE) {
+            return mController.getWindowMagnificationMgr().enableWindowMagnification(displayId,
+                    config.getScale(), config.getCenterX(), config.getCenterY());
+        }
+        return false;
+    }
+
+    /**
+     * Returns the magnification scale. If an animation is in progress,
+     * this reflects the end state of the animation.
+     *
+     * @param displayId The logical display id.
+     * @return the scale
      */
     public float getScale(int displayId) {
-        return mController.getFullScreenMagnificationController().getScale(displayId);
+        int mode = getControllingMode(displayId);
+        if (mode == FULLSCREEN_MODE) {
+            return mController.getFullScreenMagnificationController().getScale(displayId);
+        } else if (mode == WINDOW_MODE) {
+            return mController.getWindowMagnificationMgr().getScale(displayId);
+        }
+        return 0;
     }
 
     /**
-     * {@link FullScreenMagnificationController#getCenterX(int)}
+     * Returns the magnification center in X coordinate of the controlling magnification mode.
+     * If the service can control magnification but fullscreen magnifier is not registered, it will
+     * register the magnifier for this call then unregister the magnifier finally to make the
+     * magnification center correct.
+     *
+     * @param displayId The logical display id
+     * @param canControlMagnification Whether the service can control magnification
+     * @return the X coordinate
      */
     public float getCenterX(int displayId, boolean canControlMagnification) {
-        boolean registeredJustForThisCall = registerMagnificationIfNeeded(displayId,
-                canControlMagnification);
-        try {
-            return mController.getFullScreenMagnificationController().getCenterX(displayId);
-        } finally {
-            if (registeredJustForThisCall) {
-                unregister(displayId);
+        int mode = getControllingMode(displayId);
+        if (mode == FULLSCREEN_MODE) {
+            boolean registeredJustForThisCall = registerDisplayMagnificationIfNeeded(displayId,
+                    canControlMagnification);
+            try {
+                return mController.getFullScreenMagnificationController().getCenterX(displayId);
+            } finally {
+                if (registeredJustForThisCall) {
+                    unregister(displayId);
+                }
             }
+        } else if (mode == WINDOW_MODE) {
+            return mController.getWindowMagnificationMgr().getCenterX(displayId);
         }
+        return 0;
     }
 
     /**
-     * {@link FullScreenMagnificationController#getCenterY(int)}
+     * Returns the magnification center in Y coordinate of the controlling magnification mode.
+     * If the service can control magnification but fullscreen magnifier is not registered, it will
+     * register the magnifier for this call then unregister the magnifier finally to make the
+     * magnification center correct.
+     *
+     * @param displayId The logical display id
+     * @param canControlMagnification Whether the service can control magnification
+     * @return the Y coordinate
      */
     public float getCenterY(int displayId, boolean canControlMagnification) {
-        boolean registeredJustForThisCall = registerMagnificationIfNeeded(displayId,
-                canControlMagnification);
-        try {
-            return mController.getFullScreenMagnificationController().getCenterY(displayId);
-        } finally {
-            if (registeredJustForThisCall) {
-                unregister(displayId);
+        int mode = getControllingMode(displayId);
+        if (mode == FULLSCREEN_MODE) {
+            boolean registeredJustForThisCall = registerDisplayMagnificationIfNeeded(displayId,
+                    canControlMagnification);
+            try {
+                return mController.getFullScreenMagnificationController().getCenterY(displayId);
+            } finally {
+                if (registeredJustForThisCall) {
+                    unregister(displayId);
+                }
             }
+        } else if (mode == WINDOW_MODE) {
+            return mController.getWindowMagnificationMgr().getCenterY(displayId);
         }
+        return 0;
     }
 
     /**
-     * {@link FullScreenMagnificationController#getMagnificationRegion(int, Region)}
+     * Return the magnification bounds of the current controlling magnification on the given
+     * display. If the magnifier is not enabled, it returns an empty region.
+     * If the service can control magnification but fullscreen magnifier is not registered, it will
+     * register the magnifier for this call then unregister the magnifier finally to make
+     * the magnification region correct.
+     *
+     * @param displayId The logical display id
+     * @param outRegion the region to populate
+     * @param canControlMagnification Whether the service can control magnification
+     * @return outRegion the magnification bounds of full-screen magnifier or the magnification
+     * source bounds of window magnifier
      */
     public Region getMagnificationRegion(int displayId, @NonNull Region outRegion,
             boolean canControlMagnification) {
-        boolean registeredJustForThisCall = registerMagnificationIfNeeded(displayId,
+        int mode = getControllingMode(displayId);
+        if (mode == FULLSCREEN_MODE) {
+            getFullscreenMagnificationRegion(displayId, outRegion, canControlMagnification);
+        } else if (mode == WINDOW_MODE) {
+            mController.getWindowMagnificationMgr().getMagnificationSourceBounds(displayId,
+                    outRegion);
+        }
+        return outRegion;
+    }
+
+    private void getFullscreenMagnificationRegion(int displayId, @NonNull Region outRegion,
+            boolean canControlMagnification) {
+        boolean registeredJustForThisCall = registerDisplayMagnificationIfNeeded(displayId,
                 canControlMagnification);
         try {
             mController.getFullScreenMagnificationController().getMagnificationRegion(displayId,
                     outRegion);
-            return outRegion;
         } finally {
             if (registeredJustForThisCall) {
                 unregister(displayId);
@@ -89,67 +225,105 @@
         }
     }
 
-    /**
-     * {@link FullScreenMagnificationController#setScaleAndCenter(int, float, float, float, boolean,
-     * int)}
-     */
-    public boolean setScaleAndCenter(int displayId, float scale, float centerX, float centerY,
+    private boolean setScaleAndCenterForFullScreenMagnification(int displayId, float scale,
+            float centerX, float centerY,
             boolean animate, int id) {
         if (!isRegistered(displayId)) {
             register(displayId);
         }
-        return mController.getFullScreenMagnificationController().setScaleAndCenter(displayId,
+        return mController.getFullScreenMagnificationController().setScaleAndCenter(
+                displayId,
                 scale,
                 centerX, centerY, animate, id);
     }
 
     /**
-     * {@link FullScreenMagnificationController#reset(int, boolean)}
+     * Resets the magnification on the given display. The reset mode could be full-screen or
+     * window if it is activated.
+     *
+     * @param displayId The logical display id.
+     * @param animate   {@code true} to animate the transition, {@code false}
+     *                  to transition immediately
+     * @return {@code true} if the magnification spec changed, {@code false} if
+     * the spec did not change
      */
     public boolean reset(int displayId, boolean animate) {
-        return mController.getFullScreenMagnificationController().reset(displayId, animate);
+        int mode = getControllingMode(displayId);
+        if (mode == FULLSCREEN_MODE) {
+            return mController.getFullScreenMagnificationController().reset(displayId, animate);
+        } else if (mode == WINDOW_MODE) {
+            return mController.getWindowMagnificationMgr().reset(displayId);
+        }
+        return false;
     }
 
     /**
      * {@link FullScreenMagnificationController#resetIfNeeded(int, boolean)}
      */
+    // TODO: support window magnification
     public void resetAllIfNeeded(int connectionId) {
         mController.getFullScreenMagnificationController().resetAllIfNeeded(connectionId);
     }
 
     /**
+     * {@link FullScreenMagnificationController#isMagnifying(int)}
+     * {@link WindowMagnificationManager#isWindowMagnifierEnabled(int)}
+     */
+    public boolean isMagnifying(int displayId) {
+        int mode = getControllingMode(displayId);
+        if (mode == FULLSCREEN_MODE) {
+            return mController.getFullScreenMagnificationController().isMagnifying(displayId);
+        } else if (mode == WINDOW_MODE) {
+            return mController.getWindowMagnificationMgr().isWindowMagnifierEnabled(displayId);
+        }
+        return false;
+    }
+
+    /**
+     * Returns the current controlling magnification mode on the given display.
+     * If there is no magnifier activated, it fallbacks to the last activated mode.
+     * And the last activated mode is {@link FULLSCREEN_MODE} by default.
+     *
+     * @param displayId The logical display id
+     */
+    public int getControllingMode(int displayId) {
+        if (mController.isActivated(displayId,
+                ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW)) {
+            return WINDOW_MODE;
+        } else if (mController.isActivated(displayId,
+                ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN)) {
+            return FULLSCREEN_MODE;
+        } else {
+            return (mController.getLastActivatedMode() == ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW)
+                    ? WINDOW_MODE
+                    : FULLSCREEN_MODE;
+        }
+    }
+
+    private boolean registerDisplayMagnificationIfNeeded(int displayId,
+            boolean canControlMagnification) {
+        if (!isRegistered(displayId) && canControlMagnification) {
+            register(displayId);
+            return true;
+        }
+        return false;
+    }
+
+    private boolean isRegistered(int displayId) {
+        return mController.getFullScreenMagnificationController().isRegistered(displayId);
+    }
+
+    /**
      * {@link FullScreenMagnificationController#register(int)}
      */
-    public void register(int displayId) {
+    private void register(int displayId) {
         mController.getFullScreenMagnificationController().register(displayId);
     }
 
     /**
      * {@link FullScreenMagnificationController#unregister(int)} (int)}
      */
-    public void unregister(int displayId) {
+    private void unregister(int displayId) {
         mController.getFullScreenMagnificationController().unregister(displayId);
     }
-
-    /**
-     * {@link FullScreenMagnificationController#isMagnifying(int)}
-     */
-    public boolean isMagnifying(int displayId) {
-        return mController.getFullScreenMagnificationController().isMagnifying(displayId);
-    }
-
-    /**
-     * {@link FullScreenMagnificationController#isRegistered(int)}
-     */
-    public boolean isRegistered(int displayId) {
-        return mController.getFullScreenMagnificationController().isRegistered(displayId);
-    }
-
-    private boolean registerMagnificationIfNeeded(int displayId, boolean canControlMagnification) {
-        if (!isRegistered(displayId) && canControlMagnification) {
-            register(displayId);
-            return true;
-        }
-        return false;
-    }
 }
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
index e1ec273..d34b4a9 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
@@ -27,6 +27,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.graphics.Rect;
+import android.graphics.Region;
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.RemoteException;
@@ -271,9 +272,12 @@
      *                or {@link Float#NaN} to leave unchanged.
      * @param centerY The screen-relative Y coordinate around which to center,
      *                or {@link Float#NaN} to leave unchanged.
+     * @return {@code true} if the magnification is enabled successfully.
      */
-    void enableWindowMagnification(int displayId, float scale, float centerX, float centerY) {
-        enableWindowMagnification(displayId, scale, centerX, centerY, STUB_ANIMATION_CALLBACK);
+    public boolean enableWindowMagnification(int displayId, float scale, float centerX,
+            float centerY) {
+        return enableWindowMagnification(displayId, scale, centerX, centerY,
+                STUB_ANIMATION_CALLBACK);
     }
 
     /**
@@ -287,25 +291,29 @@
      * @param centerY The screen-relative Y coordinate around which to center,
      *                or {@link Float#NaN} to leave unchanged.
      * @param animationCallback Called when the animation result is valid.
+     * @return {@code true} if the magnification is enabled successfully.
      */
-    void enableWindowMagnification(int displayId, float scale, float centerX, float centerY,
-            @Nullable MagnificationAnimationCallback animationCallback) {
+    public boolean enableWindowMagnification(int displayId, float scale, float centerX,
+            float centerY, @Nullable MagnificationAnimationCallback animationCallback) {
         final boolean enabled;
+        boolean previousEnabled;
         synchronized (mLock) {
             if (mConnectionWrapper == null) {
-                return;
+                return false;
             }
             WindowMagnifier magnifier = mWindowMagnifiers.get(displayId);
             if (magnifier == null) {
                 magnifier = createWindowMagnifier(displayId);
             }
+            previousEnabled = magnifier.mEnabled;
             enabled = magnifier.enableWindowMagnificationInternal(scale, centerX, centerY,
                     animationCallback);
         }
 
-        if (enabled) {
+        if (enabled && !previousEnabled) {
             mCallback.onWindowMagnificationActivationState(displayId, true);
         }
+        return enabled;
     }
 
     /**
@@ -464,7 +472,7 @@
      * @param displayId The logical display id
      * @return the X coordinate. {@link Float#NaN} if the window magnification is not enabled.
      */
-    float getCenterX(int displayId) {
+    public float getCenterX(int displayId) {
         synchronized (mLock) {
             WindowMagnifier magnifier = mWindowMagnifiers.get(displayId);
             if (magnifier == null) {
@@ -480,7 +488,7 @@
      * @param displayId The logical display id
      * @return the Y coordinate. {@link Float#NaN} if the window magnification is not enabled.
      */
-    float getCenterY(int displayId) {
+    public float getCenterY(int displayId) {
         synchronized (mLock) {
             WindowMagnifier magnifier = mWindowMagnifiers.get(displayId);
             if (magnifier == null) {
@@ -491,6 +499,42 @@
     }
 
     /**
+     * Populates magnified bounds on the screen. And the populated magnified bounds would be
+     * empty If window magnifier is not activated.
+     *
+     * @param displayId The logical display id.
+     * @param outRegion the region to populate
+     */
+    public void getMagnificationSourceBounds(int displayId, @NonNull Region outRegion) {
+        synchronized (mLock) {
+            WindowMagnifier magnifier = mWindowMagnifiers.get(displayId);
+            if (magnifier == null) {
+                outRegion.setEmpty();
+            } else {
+                outRegion.set(magnifier.mSourceBounds);
+            }
+        }
+    }
+
+    /**
+     * Resets the magnification scale and center.
+     *
+     * @param displayId The logical display id.
+     * @return {@code true} if the magnification spec changed, {@code false} if
+     * the spec did not change
+     */
+    public boolean reset(int displayId) {
+        synchronized (mLock) {
+            WindowMagnifier magnifier = mWindowMagnifiers.get(displayId);
+            if (magnifier == null) {
+                return false;
+            }
+            magnifier.reset();
+            return true;
+        }
+    }
+
+    /**
      * Creates the windowMagnifier based on the specified display and stores it.
      *
      * @param displayId logical display id.
@@ -626,8 +670,9 @@
         @GuardedBy("mLock")
         boolean enableWindowMagnificationInternal(float scale, float centerX, float centerY,
                 @Nullable MagnificationAnimationCallback animationCallback) {
-            if (mEnabled) {
-                return false;
+            // Handle defaults. The scale may be NAN when just updating magnification center.
+            if (Float.isNaN(scale)) {
+                scale = getScale();
             }
             final float normScale = MagnificationScaleProvider.constrainScale(scale);
             if (mWindowMagnificationManager.enableWindowMagnificationInternal(mDisplayId, normScale,
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index 5e2449d..422749e 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -210,7 +210,7 @@
         final IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
         context.registerReceiver(mBroadcastReceiver, filter, null, FgThread.getHandler(),
-                Context.RECEIVER_NOT_EXPORTED);
+                Context.RECEIVER_EXPORTED);
 
         mAugmentedAutofillResolver = new FrameworkResourcesServiceNameResolver(getContext(),
                 com.android.internal.R.string.config_defaultAugmentedAutofillService);
diff --git a/services/core/java/com/android/server/BluetoothAirplaneModeListener.java b/services/core/java/com/android/server/BluetoothAirplaneModeListener.java
index 197321f..263ff18 100644
--- a/services/core/java/com/android/server/BluetoothAirplaneModeListener.java
+++ b/services/core/java/com/android/server/BluetoothAirplaneModeListener.java
@@ -35,6 +35,7 @@
  * when Bluetooth is on and Bluetooth is in one of the following situations:
  *   1. Bluetooth A2DP is connected.
  *   2. Bluetooth Hearing Aid profile is connected.
+ *   3. Bluetooth LE Audio is connected
  */
 class BluetoothAirplaneModeListener {
     private static final String TAG = "BluetoothAirplaneModeListener";
@@ -132,7 +133,7 @@
             return false;
         }
         if (!mAirplaneHelper.isBluetoothOn() || !mAirplaneHelper.isAirplaneModeOn()
-                || !mAirplaneHelper.isA2dpOrHearingAidConnected()) {
+                || !mAirplaneHelper.isMediaProfileConnected()) {
             return false;
         }
         return true;
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index f62935a..8860a81 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -35,6 +35,7 @@
 import android.bluetooth.BluetoothA2dp;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothHearingAid;
+import android.bluetooth.BluetoothLeAudio;
 import android.bluetooth.BluetoothProfile;
 import android.bluetooth.BluetoothProtoEnums;
 import android.bluetooth.IBluetooth;
@@ -456,12 +457,13 @@
                     }
                 }
             } else if (BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED.equals(action)
-                    || BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED.equals(action)) {
+                    || BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED.equals(action)
+                    || BluetoothLeAudio.ACTION_LE_AUDIO_CONNECTION_STATE_CHANGED.equals(action)) {
                 final int state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
                         BluetoothProfile.STATE_CONNECTED);
                 if (mHandler.hasMessages(MESSAGE_INIT_FLAGS_CHANGED)
                         && state == BluetoothProfile.STATE_DISCONNECTED
-                        && !mBluetoothModeChangeHelper.isA2dpOrHearingAidConnected()) {
+                        && !mBluetoothModeChangeHelper.isMediaProfileConnected()) {
                     Slog.i(TAG, "Device disconnected, reactivating pending flag changes");
                     onInitFlagsChanged();
                 }
@@ -2291,7 +2293,7 @@
                         Slog.d(TAG, "MESSAGE_INIT_FLAGS_CHANGED");
                     }
                     mHandler.removeMessages(MESSAGE_INIT_FLAGS_CHANGED);
-                    if (mBluetoothModeChangeHelper.isA2dpOrHearingAidConnected()) {
+                    if (mBluetoothModeChangeHelper.isMediaProfileConnected()) {
                         Slog.i(TAG, "Delaying MESSAGE_INIT_FLAGS_CHANGED by "
                                 + DELAY_FOR_RETRY_INIT_FLAG_CHECK_MS
                                 + " ms due to existing connections");
diff --git a/services/core/java/com/android/server/BluetoothModeChangeHelper.java b/services/core/java/com/android/server/BluetoothModeChangeHelper.java
index 3642e4d..e5854c9 100644
--- a/services/core/java/com/android/server/BluetoothModeChangeHelper.java
+++ b/services/core/java/com/android/server/BluetoothModeChangeHelper.java
@@ -20,6 +20,7 @@
 import android.bluetooth.BluetoothA2dp;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothHearingAid;
+import android.bluetooth.BluetoothLeAudio;
 import android.bluetooth.BluetoothProfile;
 import android.bluetooth.BluetoothProfile.ServiceListener;
 import android.content.Context;
@@ -37,6 +38,7 @@
 public class BluetoothModeChangeHelper {
     private volatile BluetoothA2dp mA2dp;
     private volatile BluetoothHearingAid mHearingAid;
+    private volatile BluetoothLeAudio mLeAudio;
     private final BluetoothAdapter mAdapter;
     private final Context mContext;
 
@@ -47,6 +49,7 @@
         mAdapter.getProfileProxy(mContext, mProfileServiceListener, BluetoothProfile.A2DP);
         mAdapter.getProfileProxy(mContext, mProfileServiceListener,
                 BluetoothProfile.HEARING_AID);
+        mAdapter.getProfileProxy(mContext, mProfileServiceListener, BluetoothProfile.LE_AUDIO);
     }
 
     private final ServiceListener mProfileServiceListener = new ServiceListener() {
@@ -60,6 +63,9 @@
                 case BluetoothProfile.HEARING_AID:
                     mHearingAid = (BluetoothHearingAid) proxy;
                     break;
+                case BluetoothProfile.LE_AUDIO:
+                    mLeAudio = (BluetoothLeAudio) proxy;
+                    break;
                 default:
                     break;
             }
@@ -75,6 +81,9 @@
                 case BluetoothProfile.HEARING_AID:
                     mHearingAid = null;
                     break;
+                case BluetoothProfile.LE_AUDIO:
+                    mLeAudio = null;
+                    break;
                 default:
                     break;
             }
@@ -82,8 +91,8 @@
     };
 
     @VisibleForTesting
-    public boolean isA2dpOrHearingAidConnected() {
-        return isA2dpConnected() || isHearingAidConnected();
+    public boolean isMediaProfileConnected() {
+        return isA2dpConnected() || isHearingAidConnected() || isLeAudioConnected();
     }
 
     @VisibleForTesting
@@ -142,4 +151,12 @@
         }
         return hearingAid.getConnectedDevices().size() > 0;
     }
+
+    private boolean isLeAudioConnected() {
+        final BluetoothLeAudio leAudio = mLeAudio;
+        if (leAudio == null) {
+            return false;
+        }
+        return leAudio.getConnectedDevices().size() > 0;
+    }
 }
diff --git a/services/core/java/com/android/server/MasterClearReceiver.java b/services/core/java/com/android/server/MasterClearReceiver.java
index b2f5396..513d86e7 100644
--- a/services/core/java/com/android/server/MasterClearReceiver.java
+++ b/services/core/java/com/android/server/MasterClearReceiver.java
@@ -181,7 +181,7 @@
         public WipeDataTask(Context context, Thread chainedTask) {
             mContext = context;
             mChainedTask = chainedTask;
-            mProgressDialog = new ProgressDialog(context);
+            mProgressDialog = new ProgressDialog(context, R.style.Theme_DeviceDefault_System);
         }
 
         @Override
diff --git a/services/core/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java
index c9608a5..3e02084 100644
--- a/services/core/java/com/android/server/NsdService.java
+++ b/services/core/java/com/android/server/NsdService.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2021 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -20,24 +20,27 @@
 import android.content.Context;
 import android.content.Intent;
 import android.database.ContentObserver;
-import android.net.NetworkStack;
 import android.net.Uri;
 import android.net.nsd.INsdManager;
+import android.net.nsd.INsdManagerCallback;
+import android.net.nsd.INsdServiceConnector;
 import android.net.nsd.NsdManager;
 import android.net.nsd.NsdServiceInfo;
 import android.os.Handler;
 import android.os.HandlerThread;
+import android.os.IBinder;
 import android.os.Message;
-import android.os.Messenger;
+import android.os.RemoteException;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.util.Base64;
+import android.util.Log;
+import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseIntArray;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.AsyncChannel;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.State;
 import com.android.internal.util.StateMachine;
@@ -72,12 +75,11 @@
     /**
      * Clients receiving asynchronous messages
      */
-    private final HashMap<Messenger, ClientInfo> mClients = new HashMap<>();
+    private final HashMap<NsdServiceConnector, ClientInfo> mClients = new HashMap<>();
 
     /* A map from unique id to client info */
     private final SparseArray<ClientInfo> mIdToClientInfoMap= new SparseArray<>();
 
-    private final AsyncChannel mReplyChannel = new AsyncChannel();
     private final long mCleanupDelayMs;
 
     private static final int INVALID_ID = 0;
@@ -149,65 +151,66 @@
         class DefaultState extends State {
             @Override
             public boolean processMessage(Message msg) {
-                ClientInfo cInfo = null;
+                final ClientInfo cInfo;
+                final int clientId = msg.arg2;
                 switch (msg.what) {
-                    case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
-                        if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
-                            AsyncChannel c = (AsyncChannel) msg.obj;
-                            if (DBG) Slog.d(TAG, "New client listening to asynchronous messages");
-                            c.sendMessage(AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED);
-                            cInfo = new ClientInfo(c, msg.replyTo);
-                            mClients.put(msg.replyTo, cInfo);
-                        } else {
-                            Slog.e(TAG, "Client connection failure, error=" + msg.arg1);
+                    case NsdManager.REGISTER_CLIENT:
+                        final Pair<NsdServiceConnector, INsdManagerCallback> arg =
+                                (Pair<NsdServiceConnector, INsdManagerCallback>) msg.obj;
+                        final INsdManagerCallback cb = arg.second;
+                        try {
+                            cb.asBinder().linkToDeath(arg.first, 0);
+                            cInfo = new ClientInfo(cb);
+                            mClients.put(arg.first, cInfo);
+                        } catch (RemoteException e) {
+                            Log.w(TAG, "Client " + clientId + " has already died");
                         }
                         break;
-                    case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
-                        switch (msg.arg1) {
-                            case AsyncChannel.STATUS_SEND_UNSUCCESSFUL:
-                                Slog.e(TAG, "Send failed, client connection lost");
-                                break;
-                            case AsyncChannel.STATUS_REMOTE_DISCONNECTION:
-                                if (DBG) Slog.d(TAG, "Client disconnected");
-                                break;
-                            default:
-                                if (DBG) Slog.d(TAG, "Client connection lost with reason: " + msg.arg1);
-                                break;
-                        }
-
-                        cInfo = mClients.get(msg.replyTo);
+                    case NsdManager.UNREGISTER_CLIENT:
+                        final NsdServiceConnector connector = (NsdServiceConnector) msg.obj;
+                        cInfo = mClients.remove(connector);
                         if (cInfo != null) {
                             cInfo.expungeAllRequests();
-                            mClients.remove(msg.replyTo);
                             if (cInfo.isLegacy()) {
                                 mLegacyClientCount -= 1;
                             }
                         }
                         maybeScheduleStop();
                         break;
-                    case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION:
-                        AsyncChannel ac = new AsyncChannel();
-                        ac.connect(mContext, getHandler(), msg.replyTo);
-                        break;
                     case NsdManager.DISCOVER_SERVICES:
-                        replyToMessage(msg, NsdManager.DISCOVER_SERVICES_FAILED,
-                                NsdManager.FAILURE_INTERNAL_ERROR);
+                        cInfo = getClientInfoForReply(msg);
+                        if (cInfo != null) {
+                            cInfo.onDiscoverServicesFailed(
+                                    clientId, NsdManager.FAILURE_INTERNAL_ERROR);
+                        }
                        break;
                     case NsdManager.STOP_DISCOVERY:
-                       replyToMessage(msg, NsdManager.STOP_DISCOVERY_FAILED,
-                               NsdManager.FAILURE_INTERNAL_ERROR);
+                        cInfo = getClientInfoForReply(msg);
+                        if (cInfo != null) {
+                            cInfo.onStopDiscoveryFailed(
+                                    clientId, NsdManager.FAILURE_INTERNAL_ERROR);
+                        }
                         break;
                     case NsdManager.REGISTER_SERVICE:
-                        replyToMessage(msg, NsdManager.REGISTER_SERVICE_FAILED,
-                                NsdManager.FAILURE_INTERNAL_ERROR);
+                        cInfo = getClientInfoForReply(msg);
+                        if (cInfo != null) {
+                            cInfo.onRegisterServiceFailed(
+                                    clientId, NsdManager.FAILURE_INTERNAL_ERROR);
+                        }
                         break;
                     case NsdManager.UNREGISTER_SERVICE:
-                        replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_FAILED,
-                                NsdManager.FAILURE_INTERNAL_ERROR);
+                        cInfo = getClientInfoForReply(msg);
+                        if (cInfo != null) {
+                            cInfo.onUnregisterServiceFailed(
+                                    clientId, NsdManager.FAILURE_INTERNAL_ERROR);
+                        }
                         break;
                     case NsdManager.RESOLVE_SERVICE:
-                        replyToMessage(msg, NsdManager.RESOLVE_SERVICE_FAILED,
-                                NsdManager.FAILURE_INTERNAL_ERROR);
+                        cInfo = getClientInfoForReply(msg);
+                        if (cInfo != null) {
+                            cInfo.onResolveServiceFailed(
+                                    clientId, NsdManager.FAILURE_INTERNAL_ERROR);
+                        }
                         break;
                     case NsdManager.DAEMON_CLEANUP:
                         mDaemon.maybeStop();
@@ -215,7 +218,7 @@
                     // This event should be only sent by the legacy (target SDK < S) clients.
                     // Mark the sending client as legacy.
                     case NsdManager.DAEMON_STARTUP:
-                        cInfo = mClients.get(msg.replyTo);
+                        cInfo = getClientInfoForReply(msg);
                         if (cInfo != null) {
                             cancelStop();
                             cInfo.setLegacy();
@@ -230,6 +233,11 @@
                 }
                 return HANDLED;
             }
+
+            private ClientInfo getClientInfoForReply(Message msg) {
+                final ListenerArgs args = (ListenerArgs) msg.obj;
+                return mClients.get(args.connector);
+            }
         }
 
         class DisabledState extends State {
@@ -289,122 +297,119 @@
 
             @Override
             public boolean processMessage(Message msg) {
-                ClientInfo clientInfo;
-                NsdServiceInfo servInfo;
-                int id;
+                final ClientInfo clientInfo;
+                final int id;
+                final int clientId = msg.arg2;
+                final ListenerArgs args;
                 switch (msg.what) {
-                    case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
-                        return NOT_HANDLED;
-                    case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
-                        return NOT_HANDLED;
                     case NsdManager.DISABLE:
                         //TODO: cleanup clients
                         transitionTo(mDisabledState);
                         break;
                     case NsdManager.DISCOVER_SERVICES:
                         if (DBG) Slog.d(TAG, "Discover services");
-                        servInfo = (NsdServiceInfo) msg.obj;
-                        clientInfo = mClients.get(msg.replyTo);
+                        args = (ListenerArgs) msg.obj;
+                        clientInfo = mClients.get(args.connector);
 
                         if (requestLimitReached(clientInfo)) {
-                            replyToMessage(msg, NsdManager.DISCOVER_SERVICES_FAILED,
-                                    NsdManager.FAILURE_MAX_LIMIT);
+                            clientInfo.onDiscoverServicesFailed(
+                                    clientId, NsdManager.FAILURE_MAX_LIMIT);
                             break;
                         }
 
                         maybeStartDaemon();
                         id = getUniqueId();
-                        if (discoverServices(id, servInfo.getServiceType())) {
+                        if (discoverServices(id, args.serviceInfo.getServiceType())) {
                             if (DBG) {
                                 Slog.d(TAG, "Discover " + msg.arg2 + " " + id +
-                                        servInfo.getServiceType());
+                                        args.serviceInfo.getServiceType());
                             }
-                            storeRequestMap(msg.arg2, id, clientInfo, msg.what);
-                            replyToMessage(msg, NsdManager.DISCOVER_SERVICES_STARTED, servInfo);
+                            storeRequestMap(clientId, id, clientInfo, msg.what);
+                            clientInfo.onDiscoverServicesStarted(clientId, args.serviceInfo);
                         } else {
                             stopServiceDiscovery(id);
-                            replyToMessage(msg, NsdManager.DISCOVER_SERVICES_FAILED,
+                            clientInfo.onDiscoverServicesFailed(clientId,
                                     NsdManager.FAILURE_INTERNAL_ERROR);
                         }
                         break;
                     case NsdManager.STOP_DISCOVERY:
                         if (DBG) Slog.d(TAG, "Stop service discovery");
-                        clientInfo = mClients.get(msg.replyTo);
+                        args = (ListenerArgs) msg.obj;
+                        clientInfo = mClients.get(args.connector);
 
                         try {
-                            id = clientInfo.mClientIds.get(msg.arg2);
+                            id = clientInfo.mClientIds.get(clientId);
                         } catch (NullPointerException e) {
-                            replyToMessage(msg, NsdManager.STOP_DISCOVERY_FAILED,
-                                    NsdManager.FAILURE_INTERNAL_ERROR);
+                            clientInfo.onStopDiscoveryFailed(
+                                    clientId, NsdManager.FAILURE_INTERNAL_ERROR);
                             break;
                         }
-                        removeRequestMap(msg.arg2, id, clientInfo);
+                        removeRequestMap(clientId, id, clientInfo);
                         if (stopServiceDiscovery(id)) {
-                            replyToMessage(msg, NsdManager.STOP_DISCOVERY_SUCCEEDED);
+                            clientInfo.onStopDiscoverySucceeded(clientId);
                         } else {
-                            replyToMessage(msg, NsdManager.STOP_DISCOVERY_FAILED,
-                                    NsdManager.FAILURE_INTERNAL_ERROR);
+                            clientInfo.onStopDiscoveryFailed(
+                                    clientId, NsdManager.FAILURE_INTERNAL_ERROR);
                         }
                         break;
                     case NsdManager.REGISTER_SERVICE:
                         if (DBG) Slog.d(TAG, "Register service");
-                        clientInfo = mClients.get(msg.replyTo);
+                        args = (ListenerArgs) msg.obj;
+                        clientInfo = mClients.get(args.connector);
                         if (requestLimitReached(clientInfo)) {
-                            replyToMessage(msg, NsdManager.REGISTER_SERVICE_FAILED,
-                                    NsdManager.FAILURE_MAX_LIMIT);
+                            clientInfo.onRegisterServiceFailed(
+                                    clientId, NsdManager.FAILURE_MAX_LIMIT);
                             break;
                         }
 
                         maybeStartDaemon();
                         id = getUniqueId();
-                        if (registerService(id, (NsdServiceInfo) msg.obj)) {
-                            if (DBG) Slog.d(TAG, "Register " + msg.arg2 + " " + id);
-                            storeRequestMap(msg.arg2, id, clientInfo, msg.what);
+                        if (registerService(id, args.serviceInfo)) {
+                            if (DBG) Slog.d(TAG, "Register " + clientId + " " + id);
+                            storeRequestMap(clientId, id, clientInfo, msg.what);
                             // Return success after mDns reports success
                         } else {
                             unregisterService(id);
-                            replyToMessage(msg, NsdManager.REGISTER_SERVICE_FAILED,
-                                    NsdManager.FAILURE_INTERNAL_ERROR);
+                            clientInfo.onRegisterServiceFailed(
+                                    clientId, NsdManager.FAILURE_INTERNAL_ERROR);
                         }
                         break;
                     case NsdManager.UNREGISTER_SERVICE:
                         if (DBG) Slog.d(TAG, "unregister service");
-                        clientInfo = mClients.get(msg.replyTo);
-                        try {
-                            id = clientInfo.mClientIds.get(msg.arg2);
-                        } catch (NullPointerException e) {
-                            replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_FAILED,
-                                    NsdManager.FAILURE_INTERNAL_ERROR);
+                        args = (ListenerArgs) msg.obj;
+                        clientInfo = mClients.get(args.connector);
+                        if (clientInfo == null) {
+                            Slog.e(TAG, "Unknown connector in unregistration");
                             break;
                         }
-                        removeRequestMap(msg.arg2, id, clientInfo);
+                        id = clientInfo.mClientIds.get(clientId);
+                        removeRequestMap(clientId, id, clientInfo);
                         if (unregisterService(id)) {
-                            replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_SUCCEEDED);
+                            clientInfo.onUnregisterServiceSucceeded(clientId);
                         } else {
-                            replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_FAILED,
-                                    NsdManager.FAILURE_INTERNAL_ERROR);
+                            clientInfo.onUnregisterServiceFailed(
+                                    clientId, NsdManager.FAILURE_INTERNAL_ERROR);
                         }
                         break;
                     case NsdManager.RESOLVE_SERVICE:
                         if (DBG) Slog.d(TAG, "Resolve service");
-                        servInfo = (NsdServiceInfo) msg.obj;
-                        clientInfo = mClients.get(msg.replyTo);
-
+                        args = (ListenerArgs) msg.obj;
+                        clientInfo = mClients.get(args.connector);
 
                         if (clientInfo.mResolvedService != null) {
-                            replyToMessage(msg, NsdManager.RESOLVE_SERVICE_FAILED,
-                                    NsdManager.FAILURE_ALREADY_ACTIVE);
+                            clientInfo.onResolveServiceFailed(
+                                    clientId, NsdManager.FAILURE_ALREADY_ACTIVE);
                             break;
                         }
 
                         maybeStartDaemon();
                         id = getUniqueId();
-                        if (resolveService(id, servInfo)) {
+                        if (resolveService(id, args.serviceInfo)) {
                             clientInfo.mResolvedService = new NsdServiceInfo();
-                            storeRequestMap(msg.arg2, id, clientInfo, msg.what);
+                            storeRequestMap(clientId, id, clientInfo, msg.what);
                         } else {
-                            replyToMessage(msg, NsdManager.RESOLVE_SERVICE_FAILED,
-                                    NsdManager.FAILURE_INTERNAL_ERROR);
+                            clientInfo.onResolveServiceFailed(
+                                    clientId, NsdManager.FAILURE_INTERNAL_ERROR);
                         }
                         break;
                     case NsdManager.NATIVE_DAEMON_EVENT:
@@ -449,30 +454,27 @@
                     case NativeResponseCode.SERVICE_FOUND:
                         /* NNN uniqueId serviceName regType domain */
                         servInfo = new NsdServiceInfo(cooked[2], cooked[3]);
-                        clientInfo.mChannel.sendMessage(NsdManager.SERVICE_FOUND, 0,
-                                clientId, servInfo);
+                        clientInfo.onServiceFound(clientId, servInfo);
                         break;
                     case NativeResponseCode.SERVICE_LOST:
                         /* NNN uniqueId serviceName regType domain */
                         servInfo = new NsdServiceInfo(cooked[2], cooked[3]);
-                        clientInfo.mChannel.sendMessage(NsdManager.SERVICE_LOST, 0,
-                                clientId, servInfo);
+                        clientInfo.onServiceLost(clientId, servInfo);
                         break;
                     case NativeResponseCode.SERVICE_DISCOVERY_FAILED:
                         /* NNN uniqueId errorCode */
-                        clientInfo.mChannel.sendMessage(NsdManager.DISCOVER_SERVICES_FAILED,
-                                NsdManager.FAILURE_INTERNAL_ERROR, clientId);
+                        clientInfo.onDiscoverServicesFailed(
+                                clientId, NsdManager.FAILURE_INTERNAL_ERROR);
                         break;
                     case NativeResponseCode.SERVICE_REGISTERED:
                         /* NNN regId serviceName regType */
                         servInfo = new NsdServiceInfo(cooked[2], null);
-                        clientInfo.mChannel.sendMessage(NsdManager.REGISTER_SERVICE_SUCCEEDED,
-                                id, clientId, servInfo);
+                        clientInfo.onRegisterServiceSucceeded(clientId, servInfo);
                         break;
                     case NativeResponseCode.SERVICE_REGISTRATION_FAILED:
                         /* NNN regId errorCode */
-                        clientInfo.mChannel.sendMessage(NsdManager.REGISTER_SERVICE_FAILED,
-                               NsdManager.FAILURE_INTERNAL_ERROR, clientId);
+                        clientInfo.onRegisterServiceFailed(
+                                clientId, NsdManager.FAILURE_INTERNAL_ERROR);
                         break;
                     case NativeResponseCode.SERVICE_UPDATED:
                         /* NNN regId */
@@ -511,8 +513,8 @@
                         if (getAddrInfo(id2, cooked[3])) {
                             storeRequestMap(clientId, id2, clientInfo, NsdManager.RESOLVE_SERVICE);
                         } else {
-                            clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED,
-                                    NsdManager.FAILURE_INTERNAL_ERROR, clientId);
+                            clientInfo.onResolveServiceFailed(
+                                    clientId, NsdManager.FAILURE_INTERNAL_ERROR);
                             clientInfo.mResolvedService = null;
                         }
                         break;
@@ -521,26 +523,26 @@
                         stopResolveService(id);
                         removeRequestMap(clientId, id, clientInfo);
                         clientInfo.mResolvedService = null;
-                        clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED,
-                                NsdManager.FAILURE_INTERNAL_ERROR, clientId);
+                        clientInfo.onResolveServiceFailed(
+                                clientId, NsdManager.FAILURE_INTERNAL_ERROR);
                         break;
                     case NativeResponseCode.SERVICE_GET_ADDR_FAILED:
                         /* NNN resolveId errorCode */
                         stopGetAddrInfo(id);
                         removeRequestMap(clientId, id, clientInfo);
                         clientInfo.mResolvedService = null;
-                        clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED,
-                                NsdManager.FAILURE_INTERNAL_ERROR, clientId);
+                        clientInfo.onResolveServiceFailed(
+                                clientId, NsdManager.FAILURE_INTERNAL_ERROR);
                         break;
                     case NativeResponseCode.SERVICE_GET_ADDR_SUCCESS:
                         /* NNN resolveId hostname ttl addr */
                         try {
                             clientInfo.mResolvedService.setHost(InetAddress.getByName(cooked[4]));
-                            clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_SUCCEEDED,
-                                   0, clientId, clientInfo.mResolvedService);
+                            clientInfo.onResolveServiceSucceeded(
+                                    clientId, clientInfo.mResolvedService);
                         } catch (java.net.UnknownHostException e) {
-                            clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED,
-                                    NsdManager.FAILURE_INTERNAL_ERROR, clientId);
+                            clientInfo.onResolveServiceFailed(
+                                    clientId, NsdManager.FAILURE_INTERNAL_ERROR);
                         }
                         stopGetAddrInfo(id);
                         removeRequestMap(clientId, id, clientInfo);
@@ -601,15 +603,71 @@
         return service;
     }
 
-    public Messenger getMessenger() {
+    @Override
+    public INsdServiceConnector connect(INsdManagerCallback cb) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INTERNET, "NsdService");
-        return new Messenger(mNsdStateMachine.getHandler());
+        final INsdServiceConnector connector = new NsdServiceConnector();
+        mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage(
+                NsdManager.REGISTER_CLIENT, new Pair<>(connector, cb)));
+        return connector;
     }
 
-    public void setEnabled(boolean isEnabled) {
-        NetworkStack.checkNetworkStackPermission(mContext);
-        mNsdSettings.putEnabledStatus(isEnabled);
-        notifyEnabled(isEnabled);
+    private static class ListenerArgs {
+        public final NsdServiceConnector connector;
+        public final NsdServiceInfo serviceInfo;
+        ListenerArgs(NsdServiceConnector connector, NsdServiceInfo serviceInfo) {
+            this.connector = connector;
+            this.serviceInfo = serviceInfo;
+        }
+    }
+
+    private class NsdServiceConnector extends INsdServiceConnector.Stub
+            implements IBinder.DeathRecipient  {
+        @Override
+        public void registerService(int listenerKey, NsdServiceInfo serviceInfo) {
+            mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage(
+                    NsdManager.REGISTER_SERVICE, 0, listenerKey,
+                    new ListenerArgs(this, serviceInfo)));
+        }
+
+        @Override
+        public void unregisterService(int listenerKey) {
+            mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage(
+                    NsdManager.UNREGISTER_SERVICE, 0, listenerKey,
+                    new ListenerArgs(this, null)));
+        }
+
+        @Override
+        public void discoverServices(int listenerKey, NsdServiceInfo serviceInfo) {
+            mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage(
+                    NsdManager.DISCOVER_SERVICES, 0, listenerKey,
+                    new ListenerArgs(this, serviceInfo)));
+        }
+
+        @Override
+        public void stopDiscovery(int listenerKey) {
+            mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage(
+                    NsdManager.STOP_DISCOVERY, 0, listenerKey, new ListenerArgs(this, null)));
+        }
+
+        @Override
+        public void resolveService(int listenerKey, NsdServiceInfo serviceInfo) {
+            mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage(
+                    NsdManager.RESOLVE_SERVICE, 0, listenerKey,
+                    new ListenerArgs(this, serviceInfo)));
+        }
+
+        @Override
+        public void startDaemon() {
+            mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage(
+                    NsdManager.DAEMON_STARTUP, new ListenerArgs(this, null)));
+        }
+
+        @Override
+        public void binderDied() {
+            mNsdStateMachine.sendMessage(
+                    mNsdStateMachine.obtainMessage(NsdManager.UNREGISTER_CLIENT, this));
+        }
     }
 
     private void notifyEnabled(boolean isEnabled) {
@@ -832,43 +890,11 @@
         mNsdStateMachine.dump(fd, pw, args);
     }
 
-    /* arg2 on the source message has an id that needs to be retained in replies
-     * see NsdManager for details */
-    private Message obtainMessage(Message srcMsg) {
-        Message msg = Message.obtain();
-        msg.arg2 = srcMsg.arg2;
-        return msg;
-    }
-
-    private void replyToMessage(Message msg, int what) {
-        if (msg.replyTo == null) return;
-        Message dstMsg = obtainMessage(msg);
-        dstMsg.what = what;
-        mReplyChannel.replyToMessage(msg, dstMsg);
-    }
-
-    private void replyToMessage(Message msg, int what, int arg1) {
-        if (msg.replyTo == null) return;
-        Message dstMsg = obtainMessage(msg);
-        dstMsg.what = what;
-        dstMsg.arg1 = arg1;
-        mReplyChannel.replyToMessage(msg, dstMsg);
-    }
-
-    private void replyToMessage(Message msg, int what, Object obj) {
-        if (msg.replyTo == null) return;
-        Message dstMsg = obtainMessage(msg);
-        dstMsg.what = what;
-        dstMsg.obj = obj;
-        mReplyChannel.replyToMessage(msg, dstMsg);
-    }
-
     /* Information tracked per client */
     private class ClientInfo {
 
         private static final int MAX_LIMIT = 10;
-        private final AsyncChannel mChannel;
-        private final Messenger mMessenger;
+        private final INsdManagerCallback mCb;
         /* Remembers a resolved service until getaddrinfo completes */
         private NsdServiceInfo mResolvedService;
 
@@ -881,17 +907,14 @@
         // The target SDK of this client < Build.VERSION_CODES.S
         private boolean mIsLegacy = false;
 
-        private ClientInfo(AsyncChannel c, Messenger m) {
-            mChannel = c;
-            mMessenger = m;
-            if (DBG) Slog.d(TAG, "New client, channel: " + c + " messenger: " + m);
+        private ClientInfo(INsdManagerCallback cb) {
+            mCb = cb;
+            if (DBG) Slog.d(TAG, "New client");
         }
 
         @Override
         public String toString() {
             StringBuilder sb = new StringBuilder();
-            sb.append("mChannel ").append(mChannel).append("\n");
-            sb.append("mMessenger ").append(mMessenger).append("\n");
             sb.append("mResolvedService ").append(mResolvedService).append("\n");
             sb.append("mIsLegacy ").append(mIsLegacy).append("\n");
             for(int i = 0; i< mClientIds.size(); i++) {
@@ -949,6 +972,102 @@
             }
             return mClientIds.keyAt(idx);
         }
+
+        void onDiscoverServicesStarted(int listenerKey, NsdServiceInfo info) {
+            try {
+                mCb.onDiscoverServicesStarted(listenerKey, info);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error calling onDiscoverServicesStarted", e);
+            }
+        }
+
+        void onDiscoverServicesFailed(int listenerKey, int error) {
+            try {
+                mCb.onDiscoverServicesFailed(listenerKey, error);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error calling onDiscoverServicesFailed", e);
+            }
+        }
+
+        void onServiceFound(int listenerKey, NsdServiceInfo info) {
+            try {
+                mCb.onServiceFound(listenerKey, info);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error calling onServiceFound(", e);
+            }
+        }
+
+        void onServiceLost(int listenerKey, NsdServiceInfo info) {
+            try {
+                mCb.onServiceLost(listenerKey, info);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error calling onServiceLost(", e);
+            }
+        }
+
+        void onStopDiscoveryFailed(int listenerKey, int error) {
+            try {
+                mCb.onStopDiscoveryFailed(listenerKey, error);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error calling onStopDiscoveryFailed", e);
+            }
+        }
+
+        void onStopDiscoverySucceeded(int listenerKey) {
+            try {
+                mCb.onStopDiscoverySucceeded(listenerKey);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error calling onStopDiscoverySucceeded", e);
+            }
+        }
+
+        void onRegisterServiceFailed(int listenerKey, int error) {
+            try {
+                mCb.onRegisterServiceFailed(listenerKey, error);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error calling onRegisterServiceFailed", e);
+            }
+        }
+
+        void onRegisterServiceSucceeded(int listenerKey, NsdServiceInfo info) {
+            try {
+                mCb.onRegisterServiceSucceeded(listenerKey, info);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error calling onRegisterServiceSucceeded", e);
+            }
+        }
+
+        void onUnregisterServiceFailed(int listenerKey, int error) {
+            try {
+                mCb.onUnregisterServiceFailed(listenerKey, error);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error calling onUnregisterServiceFailed", e);
+            }
+        }
+
+        void onUnregisterServiceSucceeded(int listenerKey) {
+            try {
+                mCb.onUnregisterServiceSucceeded(listenerKey);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error calling onUnregisterServiceSucceeded", e);
+            }
+        }
+
+        void onResolveServiceFailed(int listenerKey, int error) {
+            try {
+                mCb.onResolveServiceFailed(listenerKey, error);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error calling onResolveServiceFailed", e);
+            }
+        }
+
+        void onResolveServiceSucceeded(int listenerKey, NsdServiceInfo info) {
+            try {
+                mCb.onResolveServiceSucceeded(listenerKey, info);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error calling onResolveServiceSucceeded", e);
+            }
+        }
     }
 
     /**
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index b019789..ac20a08 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -685,6 +685,7 @@
             final UUID errorId = mTraceErrorLogger.generateErrorId();
             if (mTraceErrorLogger.isAddErrorIdEnabled()) {
                 mTraceErrorLogger.addErrorIdToTrace("system_server", errorId);
+                mTraceErrorLogger.addSubjectToTrace(subject, errorId);
             }
 
             // Log the atom as early as possible since it is used as a mechanism to trigger
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index bf744cf..6decdb9 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -87,7 +87,6 @@
 import android.app.ActivityThread;
 import android.app.AppGlobals;
 import android.app.AppOpsManager;
-import android.app.ForegroundServiceDidNotStartInTimeException;
 import android.app.ForegroundServiceStartNotAllowedException;
 import android.app.IApplicationThread;
 import android.app.IForegroundServiceObserver;
@@ -95,6 +94,7 @@
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
+import android.app.RemoteServiceException.ForegroundServiceDidNotStartInTimeException;
 import android.app.Service;
 import android.app.ServiceStartArgs;
 import android.app.admin.DevicePolicyEventLogger;
@@ -861,7 +861,7 @@
                 final ServiceState stracker = r.getTracker();
                 if (stracker != null) {
                     stracker.setForeground(true, mAm.mProcessStats.getMemFactorLocked(),
-                            r.lastActivity);
+                            SystemClock.uptimeMillis()); // Use current time, not lastActivity.
                 }
             }
             mAm.mAppOpsService.startOperation(AppOpsManager.getToken(mAm.mAppOpsService),
@@ -1137,7 +1137,8 @@
         synchronized (mAm.mProcessStats.mLock) {
             final ServiceState stracker = r.getTracker();
             if (stracker != null) {
-                stracker.setStarted(true, mAm.mProcessStats.getMemFactorLocked(), r.lastActivity);
+                stracker.setStarted(true, mAm.mProcessStats.getMemFactorLocked(),
+                        SystemClock.uptimeMillis()); // Use current time, not lastActivity.
             }
         }
         r.callStart = false;
@@ -1293,7 +1294,7 @@
     }
 
     void killMisbehavingService(ServiceRecord r,
-            int appUid, int appPid, String localPackageName) {
+            int appUid, int appPid, String localPackageName, int exceptionTypeId) {
         synchronized (mAm) {
             if (!r.destroying) {
                 // This service is still alive, stop it.
@@ -1307,8 +1308,8 @@
                     stopServiceLocked(found, false);
                 }
             }
-            mAm.crashApplication(appUid, appPid, localPackageName, -1,
-                    "Bad notification for startForeground", true /*force*/);
+            mAm.crashApplicationWithType(appUid, appPid, localPackageName, -1,
+                    "Bad notification for startForeground", true /*force*/, exceptionTypeId);
         }
     }
 
@@ -1974,7 +1975,8 @@
                                 final ServiceState stracker = r.getTracker();
                                 if (stracker != null) {
                                     stracker.setForeground(true,
-                                            mAm.mProcessStats.getMemFactorLocked(), r.lastActivity);
+                                            mAm.mProcessStats.getMemFactorLocked(),
+                                            SystemClock.uptimeMillis());
                                 }
                             }
                         } else {
@@ -2843,7 +2845,7 @@
                         final ServiceState stracker = s.getTracker();
                         if (stracker != null) {
                             stracker.setBound(true, mAm.mProcessStats.getMemFactorLocked(),
-                                    s.lastActivity);
+                                    SystemClock.uptimeMillis());
                         }
                     }
                 }
@@ -3509,14 +3511,14 @@
             timeoutNeeded = false;
         }
 
-        long now = SystemClock.uptimeMillis();
         ProcessServiceRecord psr;
         if (r.executeNesting == 0) {
             r.executeFg = fg;
             synchronized (mAm.mProcessStats.mLock) {
                 final ServiceState stracker = r.getTracker();
                 if (stracker != null) {
-                    stracker.setExecuting(true, mAm.mProcessStats.getMemFactorLocked(), now);
+                    stracker.setExecuting(true, mAm.mProcessStats.getMemFactorLocked(),
+                            SystemClock.uptimeMillis());
                 }
             }
             if (r.app != null) {
@@ -3547,7 +3549,7 @@
         }
         r.executeFg |= fg;
         r.executeNesting++;
-        r.executingStart = now;
+        r.executingStart = SystemClock.uptimeMillis();
         return oomAdjusted;
     }
 
@@ -3734,7 +3736,8 @@
             if (oldPosInRestarting == -1) {
                 r.createdFromFg = false;
                 synchronized (mAm.mProcessStats.mLock) {
-                    r.makeRestarting(mAm.mProcessStats.getMemFactorLocked(), now);
+                    r.makeRestarting(mAm.mProcessStats.getMemFactorLocked(),
+                            SystemClock.uptimeMillis());
                 }
             }
             boolean added = false;
@@ -4500,7 +4503,6 @@
             }
         }
 
-        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) {
@@ -4511,7 +4513,8 @@
             synchronized (mAm.mProcessStats.mLock) {
                 ServiceState stracker = r.getTracker();
                 if (stracker != null) {
-                    stracker.setForeground(false, mAm.mProcessStats.getMemFactorLocked(), now);
+                    stracker.setForeground(false, mAm.mProcessStats.getMemFactorLocked(),
+                            SystemClock.uptimeMillis());
                 }
             }
             mAm.mAppOpsService.finishOperation(AppOpsManager.getToken(mAm.mAppOpsService),
@@ -4573,7 +4576,8 @@
             synchronized (mAm.mProcessStats.mLock) {
                 ServiceState stracker = r.getTracker();
                 if (stracker != null) {
-                    stracker.setForeground(false, mAm.mProcessStats.getMemFactorLocked(), now);
+                    stracker.setForeground(false, mAm.mProcessStats.getMemFactorLocked(),
+                            SystemClock.uptimeMillis());
                 }
             }
             mAm.mAppOpsService.finishOperation(
@@ -4650,6 +4654,7 @@
         synchronized (mAm.mProcessStats.mLock) {
             final int memFactor = mAm.mProcessStats.getMemFactorLocked();
             if (r.tracker != null) {
+                final long now = SystemClock.uptimeMillis();
                 r.tracker.setStarted(false, memFactor, now);
                 r.tracker.setBound(false, memFactor, now);
                 if (r.executeNesting == 0) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 5188a72..02a16fc 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -186,7 +186,6 @@
 import android.app.ProcessMemoryState;
 import android.app.ProfilerInfo;
 import android.app.PropertyInvalidatedCache;
-import android.app.RemoteServiceException;
 import android.app.SyncNotedAppOp;
 import android.app.WaitResult;
 import android.app.backup.BackupManager.OperationType;
@@ -643,10 +642,11 @@
 
     final BroadcastQueue mFgBroadcastQueue;
     final BroadcastQueue mBgBroadcastQueue;
-    final BroadcastQueue mOffloadBroadcastQueue;
+    final BroadcastQueue mBgOffloadBroadcastQueue;
+    final BroadcastQueue mFgOffloadBroadcastQueue;
     // Convenient for easy iteration over the queues. Foreground is first
     // so that dispatch of foreground broadcasts gets precedence.
-    final BroadcastQueue[] mBroadcastQueues = new BroadcastQueue[3];
+    final BroadcastQueue[] mBroadcastQueues = new BroadcastQueue[4];
 
     @GuardedBy("this")
     BroadcastStats mLastBroadcastStats;
@@ -657,12 +657,20 @@
     TraceErrorLogger mTraceErrorLogger;
 
     BroadcastQueue broadcastQueueForIntent(Intent intent) {
-        if (isOnOffloadQueue(intent.getFlags())) {
+        if (isOnFgOffloadQueue(intent.getFlags())) {
             if (DEBUG_BROADCAST_BACKGROUND) {
                 Slog.i(TAG_BROADCAST,
-                        "Broadcast intent " + intent + " on offload queue");
+                        "Broadcast intent " + intent + " on foreground offload queue");
             }
-            return mOffloadBroadcastQueue;
+            return mFgOffloadBroadcastQueue;
+        }
+
+        if (isOnBgOffloadQueue(intent.getFlags())) {
+            if (DEBUG_BROADCAST_BACKGROUND) {
+                Slog.i(TAG_BROADCAST,
+                        "Broadcast intent " + intent + " on background offload queue");
+            }
+            return mBgOffloadBroadcastQueue;
         }
 
         final boolean isFg = (intent.getFlags() & Intent.FLAG_RECEIVER_FOREGROUND) != 0;
@@ -2264,7 +2272,8 @@
         mPendingStartActivityUids = new PendingStartActivityUids(mContext);
         mUseFifoUiScheduling = false;
         mEnableOffloadQueue = false;
-        mFgBroadcastQueue = mBgBroadcastQueue = mOffloadBroadcastQueue = null;
+        mFgBroadcastQueue = mBgBroadcastQueue = mBgOffloadBroadcastQueue =
+                mFgOffloadBroadcastQueue = null;
         mComponentAliasResolver = new ComponentAliasResolver(this);
     }
 
@@ -2325,11 +2334,14 @@
                 "foreground", foreConstants, false);
         mBgBroadcastQueue = new BroadcastQueue(this, mHandler,
                 "background", backConstants, true);
-        mOffloadBroadcastQueue = new BroadcastQueue(this, mHandler,
-                "offload", offloadConstants, true);
+        mBgOffloadBroadcastQueue = new BroadcastQueue(this, mHandler,
+                "offload_bg", offloadConstants, true);
+        mFgOffloadBroadcastQueue = new BroadcastQueue(this, mHandler,
+                "offload_fg", foreConstants, true);
         mBroadcastQueues[0] = mFgBroadcastQueue;
         mBroadcastQueues[1] = mBgBroadcastQueue;
-        mBroadcastQueues[2] = mOffloadBroadcastQueue;
+        mBroadcastQueues[2] = mBgOffloadBroadcastQueue;
+        mBroadcastQueues[3] = mFgOffloadBroadcastQueue;
 
         mServices = new ActiveServices(this);
         mCpHelper = new ContentProviderHelper(this, true);
@@ -3034,13 +3046,6 @@
     }
 
     @Override
-    public void crashApplication(int uid, int initialPid, String packageName, int userId,
-            String message, boolean force) {
-        crashApplicationWithType(uid, initialPid, packageName, userId, message, force,
-                RemoteServiceException.TYPE_ID);
-    }
-
-    @Override
     public void crashApplicationWithType(int uid, int initialPid, String packageName, int userId,
             String message, boolean force, int exceptionTypeId) {
         if (checkCallingPermission(android.Manifest.permission.FORCE_STOP_PACKAGES)
@@ -12560,13 +12565,15 @@
     boolean isPendingBroadcastProcessLocked(int pid) {
         return mFgBroadcastQueue.isPendingBroadcastProcessLocked(pid)
                 || mBgBroadcastQueue.isPendingBroadcastProcessLocked(pid)
-                || mOffloadBroadcastQueue.isPendingBroadcastProcessLocked(pid);
+                || mBgOffloadBroadcastQueue.isPendingBroadcastProcessLocked(pid)
+                || mFgOffloadBroadcastQueue.isPendingBroadcastProcessLocked(pid);
     }
 
     boolean isPendingBroadcastProcessLocked(ProcessRecord app) {
         return mFgBroadcastQueue.isPendingBroadcastProcessLocked(app)
                 || mBgBroadcastQueue.isPendingBroadcastProcessLocked(app)
-                || mOffloadBroadcastQueue.isPendingBroadcastProcessLocked(app);
+                || mBgOffloadBroadcastQueue.isPendingBroadcastProcessLocked(app)
+                || mFgOffloadBroadcastQueue.isPendingBroadcastProcessLocked(app);
     }
 
     void skipPendingBroadcastLocked(int pid) {
@@ -12683,30 +12690,38 @@
                         "Receiver can't specify both RECEIVER_EXPORTED and RECEIVER_NOT_EXPORTED"
                                 + "flag");
             }
-            if (CompatChanges.isChangeEnabled(DYNAMIC_RECEIVER_EXPLICIT_EXPORT_REQUIRED,
-                    callingUid)
-                    && !explicitExportStateDefined) {
-                if (ENFORCE_DYNAMIC_RECEIVER_EXPLICIT_EXPORT) {
-                    throw new SecurityException(
-                            callerPackage + ": Targeting T+ (version "
-                                    + Build.VERSION_CODES.TIRAMISU
-                                    + " and above) requires that one of RECEIVER_EXPORTED or "
-                                    + "RECEIVER_NOT_EXPORTED be specified when registering a "
-                                    + "receiver");
-                } else {
-                    Slog.wtf(TAG,
-                            callerPackage + ": Targeting T+ (version "
-                                    + Build.VERSION_CODES.TIRAMISU
-                                    + " and above) requires that one of RECEIVER_EXPORTED or "
-                                    + "RECEIVER_NOT_EXPORTED be specified when registering a "
-                                    + "receiver");
-                    // Assume default behavior-- flag check is not enforced
+
+            // Don't enforce the flag check if we're EITHER registering for only protected
+            // broadcasts, or the receiver is null (a sticky broadcast). Sticky broadcasts should
+            // not be used generally, so we will be marking them as exported by default
+            final boolean requireExplicitFlagForDynamicReceivers = CompatChanges.isChangeEnabled(
+                    DYNAMIC_RECEIVER_EXPLICIT_EXPORT_REQUIRED, callingUid);
+            if (!onlyProtectedBroadcasts) {
+                if (receiver == null && !explicitExportStateDefined) {
+                    // sticky broadcast, no flag specified (flag isn't required)
+                    flags |= Context.RECEIVER_EXPORTED;
+                } else if (requireExplicitFlagForDynamicReceivers && !explicitExportStateDefined) {
+                    if (ENFORCE_DYNAMIC_RECEIVER_EXPLICIT_EXPORT) {
+                        throw new SecurityException(
+                                callerPackage + ": Targeting T+ (version "
+                                        + Build.VERSION_CODES.TIRAMISU
+                                        + " and above) requires that one of RECEIVER_EXPORTED or "
+                                        + "RECEIVER_NOT_EXPORTED be specified when registering a "
+                                        + "receiver");
+                    } else {
+                        Slog.wtf(TAG,
+                                callerPackage + ": Targeting T+ (version "
+                                        + Build.VERSION_CODES.TIRAMISU
+                                        + " and above) requires that one of RECEIVER_EXPORTED or "
+                                        + "RECEIVER_NOT_EXPORTED be specified when registering a "
+                                        + "receiver");
+                        // Assume default behavior-- flag check is not enforced
+                        flags |= Context.RECEIVER_EXPORTED;
+                    }
+                } else if (!requireExplicitFlagForDynamicReceivers) {
+                    // Change is not enabled, thus not targeting T+. Assume exported.
                     flags |= Context.RECEIVER_EXPORTED;
                 }
-            } else if (!CompatChanges.isChangeEnabled(DYNAMIC_RECEIVER_EXPLICIT_EXPORT_REQUIRED,
-                    callingUid)) {
-                // Change is not enabled, thus not targeting T+. Assume exported.
-                flags |= Context.RECEIVER_EXPORTED;
             }
         }
 
@@ -12724,7 +12739,7 @@
                         (intent.getFlags() & Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS) == 0) {
                     continue;
                 }
-                // If intent has scheme "content", it will need to acccess
+                // If intent has scheme "content", it will need to access
                 // provider that needs to lock mProviderMap in ActivityThread
                 // and also it may need to wait application response, so we
                 // cannot lock ActivityManagerService here.
@@ -14015,8 +14030,10 @@
             BroadcastQueue queue;
 
             synchronized(this) {
-                if (isOnOffloadQueue(flags)) {
-                    queue = mOffloadBroadcastQueue;
+                if (isOnFgOffloadQueue(flags)) {
+                    queue = mFgOffloadBroadcastQueue;
+                } else if (isOnBgOffloadQueue(flags)) {
+                    queue = mBgOffloadBroadcastQueue;
                 } else {
                     queue = (flags & Intent.FLAG_RECEIVER_FOREGROUND) != 0
                             ? mFgBroadcastQueue : mBgBroadcastQueue;
@@ -14751,10 +14768,10 @@
     }
 
     @GuardedBy(anyOf = {"this", "mProcLock"})
-    final void setProcessTrackerStateLOSP(ProcessRecord proc, int memFactor, long now) {
+    final void setProcessTrackerStateLOSP(ProcessRecord proc, int memFactor) {
         if (proc.getThread() != null) {
             proc.mProfile.setProcessTrackerState(
-                    proc.mState.getReportedProcState(), memFactor, now);
+                    proc.mState.getReportedProcState(), memFactor);
         }
     }
 
@@ -15400,6 +15417,16 @@
     }
 
     @Override
+    public String getSwitchingFromUserMessage() {
+        return mUserController.getSwitchingFromSystemUserMessage();
+    }
+
+    @Override
+    public String getSwitchingToUserMessage() {
+        return mUserController.getSwitchingToSystemUserMessage();
+    }
+
+    @Override
     public void setStopUserOnSwitch(@StopUserOnSwitch int value) {
         mUserController.setStopUserOnSwitch(value);
     }
@@ -16310,7 +16337,7 @@
                         Binder.getCallingUid(), Binder.getCallingPid(), UserHandle.USER_ALL);
                 if ((changes & ActivityInfo.CONFIG_LOCALE) != 0) {
                     intent = new Intent(Intent.ACTION_LOCALE_CHANGED);
-                    intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND
+                    intent.addFlags(Intent.FLAG_RECEIVER_OFFLOAD_FOREGROUND
                             | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND
                             | Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
                     if (initLocale || !mProcessesReady) {
@@ -17487,7 +17514,11 @@
         }
     }
 
-    private boolean isOnOffloadQueue(int flags) {
+    private boolean isOnFgOffloadQueue(int flags) {
+        return ((flags & Intent.FLAG_RECEIVER_OFFLOAD_FOREGROUND) != 0);
+    }
+
+    private boolean isOnBgOffloadQueue(int flags) {
         return (mEnableOffloadQueue && ((flags & Intent.FLAG_RECEIVER_OFFLOAD) != 0));
     }
 
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 5b33a71..c062365 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -46,6 +46,7 @@
 import android.app.IUidObserver;
 import android.app.KeyguardManager;
 import android.app.ProfilerInfo;
+import android.app.RemoteServiceException.CrashedByAdbException;
 import android.app.UserSwitchObserver;
 import android.app.WaitResult;
 import android.app.usage.AppStandbyInfo;
@@ -1173,7 +1174,8 @@
         } catch (NumberFormatException e) {
             packageName = arg;
         }
-        mInterface.crashApplication(-1, pid, packageName, userId, "shell-induced crash", false);
+        mInterface.crashApplicationWithType(-1, pid, packageName, userId, "shell-induced crash",
+                false, CrashedByAdbException.TYPE_ID);
         return 0;
     }
 
diff --git a/services/core/java/com/android/server/am/AppProfiler.java b/services/core/java/com/android/server/am/AppProfiler.java
index d44d729..221de8d 100644
--- a/services/core/java/com/android/server/am/AppProfiler.java
+++ b/services/core/java/com/android/server/am/AppProfiler.java
@@ -953,7 +953,6 @@
 
     @GuardedBy({"mService", "mProcLock"})
     boolean updateLowMemStateLSP(int numCached, int numEmpty, int numTrimming) {
-        final long now = SystemClock.uptimeMillis();
         int memFactor;
         if (mLowMemDetector != null && mLowMemDetector.isAvailable()) {
             memFactor = mLowMemDetector.getMemFactor();
@@ -1008,7 +1007,9 @@
         mLastNumProcesses = mService.mProcessList.getLruSizeLOSP();
         boolean allChanged;
         int trackerMemFactor;
+        final long now;
         synchronized (mService.mProcessStats.mLock) {
+            now = SystemClock.uptimeMillis();
             allChanged = mService.mProcessStats.setMemFactorLocked(memFactor,
                     mService.mAtmInternal == null || !mService.mAtmInternal.isSleeping(), now);
             trackerMemFactor = mService.mProcessStats.getMemFactorLocked();
@@ -1044,7 +1045,7 @@
                 final int curProcState = state.getCurProcState();
                 IApplicationThread thread;
                 if (allChanged || state.hasProcStateChanged()) {
-                    mService.setProcessTrackerStateLOSP(app, trackerMemFactor, now);
+                    mService.setProcessTrackerStateLOSP(app, trackerMemFactor);
                     state.setProcStateChanged(false);
                 }
                 trimMemoryUiHiddenIfNecessaryLSP(app);
@@ -1113,7 +1114,7 @@
                 final IApplicationThread thread;
                 final ProcessStateRecord state = app.mState;
                 if (allChanged || state.hasProcStateChanged()) {
-                    mService.setProcessTrackerStateLOSP(app, trackerMemFactor, now);
+                    mService.setProcessTrackerStateLOSP(app, trackerMemFactor);
                     state.setProcStateChanged(false);
                 }
                 trimMemoryUiHiddenIfNecessaryLSP(app);
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index fd6f099..592abbb 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -20,7 +20,13 @@
 import static android.os.Process.ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE;
 import static android.text.TextUtils.formatSimple;
 
-import static com.android.server.am.ActivityManagerDebugConfig.*;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST_DEFERRAL;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST_LIGHT;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_MU;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PERMISSIONS_REVIEW;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_BROADCAST;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_MU;
 
 import android.annotation.Nullable;
 import android.app.ActivityManager;
@@ -29,6 +35,7 @@
 import android.app.BroadcastOptions;
 import android.app.IApplicationThread;
 import android.app.PendingIntent;
+import android.app.RemoteServiceException.CannotDeliverBroadcastException;
 import android.app.usage.UsageEvents.Event;
 import android.content.ComponentName;
 import android.content.ContentResolver;
@@ -607,7 +614,8 @@
                     synchronized (mService) {
                         Slog.w(TAG, "Can't deliver broadcast to " + app.processName
                                 + " (pid " + app.getPid() + "). Crashing it.");
-                        app.scheduleCrashLocked("can't deliver broadcast");
+                        app.scheduleCrashLocked("can't deliver broadcast",
+                                CannotDeliverBroadcastException.TYPE_ID);
                     }
                     throw ex;
                 }
@@ -781,7 +789,7 @@
 
         // Ensure that broadcasts are only sent to other apps if they are explicitly marked as
         // exported, or are System level broadcasts
-        if (!skip && !filter.exported && Process.SYSTEM_UID != r.callingUid
+        if (!skip && !filter.exported && !Process.isCoreUid(r.callingUid)
                 && filter.receiverList.uid != r.callingUid) {
 
             Slog.w(TAG, "Exported Denial: sending "
@@ -792,7 +800,7 @@
                     + " due to receiver " + filter.receiverList.app
                     + " (uid " + filter.receiverList.uid + ")"
                     + " not specifying RECEIVER_EXPORTED");
-            skip = true;
+            // skip = true;
         }
 
         if (skip) {
diff --git a/services/core/java/com/android/server/am/ConnectionRecord.java b/services/core/java/com/android/server/am/ConnectionRecord.java
index b434328..b6757c8 100644
--- a/services/core/java/com/android/server/am/ConnectionRecord.java
+++ b/services/core/java/com/android/server/am/ConnectionRecord.java
@@ -23,6 +23,7 @@
 import android.app.PendingIntent;
 import android.content.ComponentName;
 import android.content.Context;
+import android.os.SystemClock;
 import android.util.Slog;
 import android.util.proto.ProtoOutputStream;
 import android.util.proto.ProtoUtils;
@@ -158,10 +159,10 @@
         }
     }
 
-    public void trackProcState(int procState, int seq, long now) {
+    public void trackProcState(int procState, int seq) {
         if (association != null) {
             synchronized (mProcStatsLock) {
-                association.trackProcState(procState, seq, now);
+                association.trackProcState(procState, seq, SystemClock.uptimeMillis());
             }
         }
     }
diff --git a/services/core/java/com/android/server/am/ContentProviderConnection.java b/services/core/java/com/android/server/am/ContentProviderConnection.java
index 3b9d47d..825b938 100644
--- a/services/core/java/com/android/server/am/ContentProviderConnection.java
+++ b/services/core/java/com/android/server/am/ContentProviderConnection.java
@@ -98,10 +98,13 @@
         }
     }
 
-    public void trackProcState(int procState, int seq, long now) {
+    /**
+     * Track the given proc state change.
+     */
+    public void trackProcState(int procState, int seq) {
         if (association != null) {
             synchronized (mProcStatsLock) {
-                association.trackProcState(procState, seq, now);
+                association.trackProcState(procState, seq, SystemClock.uptimeMillis());
             }
         }
     }
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index dc9ecfe..47e24b1 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -874,13 +874,14 @@
         updateUidsLSP(activeUids, nowElapsed);
 
         synchronized (mService.mProcessStats.mLock) {
-            if (mService.mProcessStats.shouldWriteNowLocked(now)) {
+            final long nowUptime = SystemClock.uptimeMillis();
+            if (mService.mProcessStats.shouldWriteNowLocked(nowUptime)) {
                 mService.mHandler.post(new ActivityManagerService.ProcStatsRunnable(mService,
                         mService.mProcessStats));
             }
 
             // Run this after making sure all procstates are updated.
-            mService.mProcessStats.updateTrackingAssociationsLocked(mAdjSeq, now);
+            mService.mProcessStats.updateTrackingAssociationsLocked(mAdjSeq, nowUptime);
         }
 
         if (DEBUG_OOM_ADJ) {
@@ -1978,7 +1979,7 @@
                                         newAdj = ProcessList.PERSISTENT_SERVICE_ADJ;
                                         schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
                                         procState = ActivityManager.PROCESS_STATE_PERSISTENT;
-                                        cr.trackProcState(procState, mAdjSeq, now);
+                                        cr.trackProcState(procState, mAdjSeq);
                                         trackedProcState = true;
                                     }
                                 } else if ((cr.flags & Context.BIND_NOT_PERCEPTIBLE) != 0
@@ -2085,7 +2086,7 @@
                         }
 
                         if (!trackedProcState) {
-                            cr.trackProcState(clientProcState, mAdjSeq, now);
+                            cr.trackProcState(clientProcState, mAdjSeq);
                         }
 
                         if (procState > clientProcState) {
@@ -2233,7 +2234,7 @@
                     }
                 }
 
-                conn.trackProcState(clientProcState, mAdjSeq, now);
+                conn.trackProcState(clientProcState, mAdjSeq);
                 if (procState > clientProcState) {
                     procState = clientProcState;
                     state.setCurRawProcState(procState);
@@ -2695,7 +2696,7 @@
             if (!doingAll) {
                 synchronized (mService.mProcessStats.mLock) {
                     mService.setProcessTrackerStateLOSP(app,
-                            mService.mProcessStats.getMemFactorLocked(), now);
+                            mService.mProcessStats.getMemFactorLocked());
                 }
             } else {
                 state.setProcStateChanged(true);
diff --git a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
index 4220506..18ad1f5 100644
--- a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
+++ b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
@@ -286,6 +286,7 @@
                     && mService.mTraceErrorLogger.isAddErrorIdEnabled()) {
                 errorId = mService.mTraceErrorLogger.generateErrorId();
                 mService.mTraceErrorLogger.addErrorIdToTrace(mApp.processName, errorId);
+                mService.mTraceErrorLogger.addSubjectToTrace(annotation, errorId);
             } else {
                 errorId = null;
             }
diff --git a/services/core/java/com/android/server/am/ProcessProfileRecord.java b/services/core/java/com/android/server/am/ProcessProfileRecord.java
index 47573f3..50970b5 100644
--- a/services/core/java/com/android/server/am/ProcessProfileRecord.java
+++ b/services/core/java/com/android/server/am/ProcessProfileRecord.java
@@ -518,12 +518,13 @@
         }
     }
 
-    void setProcessTrackerState(int procState, int memFactor, long now) {
+    void setProcessTrackerState(int procState, int memFactor) {
         synchronized (mService.mProcessStats.mLock) {
             final ProcessState tracker = mBaseProcessTracker;
             if (tracker != null) {
                 if (procState != PROCESS_STATE_NONEXISTENT) {
                     final PackageList pkgList = mApp.getPkgList();
+                    final long now = SystemClock.uptimeMillis();
                     synchronized (pkgList) {
                         tracker.setState(procState, memFactor, now,
                                 pkgList.getPackageListLocked());
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 8c55626..eba02f10 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -26,7 +26,6 @@
 import android.app.ApplicationExitInfo.Reason;
 import android.app.ApplicationExitInfo.SubReason;
 import android.app.IApplicationThread;
-import android.app.RemoteServiceException;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.ProcessInfo;
 import android.content.pm.VersionedPackage;
@@ -975,11 +974,6 @@
         return mServices.hasForegroundServices();
     }
 
-    @GuardedBy("mService")
-    void scheduleCrashLocked(String message) {
-        scheduleCrashLocked(message, RemoteServiceException.TYPE_ID);
-    }
-
     /**
      * Let an app process throw an exception on a binder thread, which typically crashes the
      * process, unless it has an unhandled exception handler.
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 91ee4eb..9b731d5 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -28,6 +28,7 @@
 import android.app.IApplicationThread;
 import android.app.Notification;
 import android.app.PendingIntent;
+import android.app.RemoteServiceException.CannotPostForegroundServiceNotificationException;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -1059,7 +1060,8 @@
                         // If it gave us a garbage notification, it doesn't
                         // get to be foreground.
                         ams.mServices.killMisbehavingService(record,
-                                appUid, appPid, localPackageName);
+                                appUid, appPid, localPackageName,
+                                CannotPostForegroundServiceNotificationException.TYPE_ID);
                     }
                 }
             });
diff --git a/services/core/java/com/android/server/am/TraceErrorLogger.java b/services/core/java/com/android/server/am/TraceErrorLogger.java
index c658100..29a9b5c 100644
--- a/services/core/java/com/android/server/am/TraceErrorLogger.java
+++ b/services/core/java/com/android/server/am/TraceErrorLogger.java
@@ -54,4 +54,17 @@
                 COUNTER_PREFIX + processName + "#" + errorId.toString(),
                 PLACEHOLDER_VALUE);
     }
+
+    /**
+     * Pushes a counter containing an ANR/Watchdog subject and a unique id so that the subject
+     * can be uniquely identified.
+     *
+     * @param subject The subject to include in the trace.
+     * @param errorId The unique id with which to tag the trace.
+     */
+    public void addSubjectToTrace(String subject, UUID errorId) {
+        Trace.traceCounter(Trace.TRACE_TAG_ACTIVITY_MANAGER,
+                String.format("Subject(for ErrorId %s):%s", errorId.toString(), subject),
+                PLACEHOLDER_VALUE);
+    }
 }
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index d52f52e..0bab023 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -1809,7 +1809,8 @@
     private void showUserSwitchDialog(Pair<UserInfo, UserInfo> fromToUserPair) {
         // The dialog will show and then initiate the user switch by calling startUserInForeground
         mInjector.showUserSwitchingDialog(fromToUserPair.first, fromToUserPair.second,
-                getSwitchingFromSystemUserMessage(), getSwitchingToSystemUserMessage());
+                getSwitchingFromSystemUserMessageUnchecked(),
+                getSwitchingToSystemUserMessageUnchecked());
     }
 
     private void dispatchForegroundProfileChanged(@UserIdInt int userId) {
@@ -2622,18 +2623,40 @@
         }
     }
 
-    private String getSwitchingFromSystemUserMessage() {
+    // Called by AMS, must check permission
+    String getSwitchingFromSystemUserMessage() {
+        checkHasManageUsersPermission("getSwitchingFromSystemUserMessage()");
+
+        return getSwitchingFromSystemUserMessageUnchecked();
+    }
+
+    // Called by AMS, must check permission
+    String getSwitchingToSystemUserMessage() {
+        checkHasManageUsersPermission("getSwitchingToSystemUserMessage()");
+
+        return getSwitchingToSystemUserMessageUnchecked();
+    }
+
+    private String getSwitchingFromSystemUserMessageUnchecked() {
         synchronized (mLock) {
             return mSwitchingFromSystemUserMessage;
         }
     }
 
-    private String getSwitchingToSystemUserMessage() {
+    private String getSwitchingToSystemUserMessageUnchecked() {
         synchronized (mLock) {
             return mSwitchingToSystemUserMessage;
         }
     }
 
+    private void checkHasManageUsersPermission(String operation) {
+        if (mInjector.checkCallingPermission(
+                android.Manifest.permission.MANAGE_USERS) == PackageManager.PERMISSION_DENIED) {
+            throw new SecurityException(
+                    "You need MANAGE_USERS permission to call " + operation);
+        }
+    }
+
     void dumpDebug(ProtoOutputStream proto, long fieldId) {
         synchronized (mLock) {
             long token = proto.start(fieldId);
@@ -2706,6 +2729,12 @@
             pw.println("  mMaxRunningUsers:" + mMaxRunningUsers);
             pw.println("  mUserSwitchUiEnabled:" + mUserSwitchUiEnabled);
             pw.println("  mInitialized:" + mInitialized);
+            if (mSwitchingFromSystemUserMessage != null) {
+                pw.println("  mSwitchingFromSystemUserMessage: " + mSwitchingFromSystemUserMessage);
+            }
+            if (mSwitchingToSystemUserMessage != null) {
+                pw.println("  mSwitchingToSystemUserMessage: " + mSwitchingToSystemUserMessage);
+            }
         }
     }
 
diff --git a/services/core/java/com/android/server/app/OWNERS b/services/core/java/com/android/server/app/OWNERS
new file mode 100644
index 0000000..aaebbfa
--- /dev/null
+++ b/services/core/java/com/android/server/app/OWNERS
@@ -0,0 +1 @@
+per-file GameManager* = file:/GAME_MANAGER_OWNERS
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 18be9a10..0f3b082 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -133,6 +133,7 @@
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.os.VibrationAttributes;
 import android.os.VibrationEffect;
 import android.os.Vibrator;
 import android.os.VibratorManager;
@@ -550,10 +551,8 @@
     private final boolean mHasVibrator;
     // Used to play vibrations
     private Vibrator mVibrator;
-    private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder()
-            .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
-            .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
-            .build();
+    private static final VibrationAttributes TOUCH_VIBRATION_ATTRIBUTES =
+            VibrationAttributes.createForUsage(VibrationAttributes.USAGE_TOUCH);
 
     // Broadcast receiver for device connections intent broadcasts
     private final BroadcastReceiver mReceiver = new AudioServiceBroadcastReceiver();
@@ -4343,7 +4342,7 @@
             return false;
         }
         mVibrator.vibrate(Binder.getCallingUid(), mContext.getOpPackageName(), effect,
-                reason, VIBRATION_ATTRIBUTES);
+                reason, TOUCH_VIBRATION_ATTRIBUTES);
         return true;
     }
 
diff --git a/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java b/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java
index c2eb062..2465ec5 100644
--- a/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java
@@ -19,12 +19,12 @@
 import android.annotation.NonNull;
 import android.content.Context;
 import android.hardware.biometrics.BiometricConstants;
-import android.media.AudioAttributes;
 import android.os.IBinder;
 import android.os.PowerManager;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.SystemClock;
+import android.os.VibrationAttributes;
 import android.os.VibrationEffect;
 import android.os.Vibrator;
 import android.util.Slog;
@@ -38,11 +38,8 @@
 
     private static final String TAG = "Biometrics/AcquisitionClient";
 
-    private static final AudioAttributes VIBRATION_SONIFICATION_ATTRIBUTES =
-            new AudioAttributes.Builder()
-                    .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
-                    .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
-                    .build();
+    private static final VibrationAttributes TOUCH_VIBRATION_ATTRIBUTES =
+            VibrationAttributes.createForUsage(VibrationAttributes.USAGE_TOUCH);
 
     private static final VibrationEffect SUCCESS_VIBRATION_EFFECT =
             VibrationEffect.get(VibrationEffect.EFFECT_CLICK);
@@ -199,7 +196,7 @@
                     getContext().getOpPackageName(),
                     SUCCESS_VIBRATION_EFFECT,
                     getClass().getSimpleName() + "::success",
-                    VIBRATION_SONIFICATION_ATTRIBUTES);
+                    TOUCH_VIBRATION_ATTRIBUTES);
         }
     }
 
@@ -210,7 +207,7 @@
                     getContext().getOpPackageName(),
                     ERROR_VIBRATION_EFFECT,
                     getClass().getSimpleName() + "::error",
-                    VIBRATION_SONIFICATION_ATTRIBUTES);
+                    TOUCH_VIBRATION_ATTRIBUTES);
         }
     }
 }
diff --git a/services/core/java/com/android/server/connectivity/OWNERS b/services/core/java/com/android/server/connectivity/OWNERS
index 7311eee..62c5737 100644
--- a/services/core/java/com/android/server/connectivity/OWNERS
+++ b/services/core/java/com/android/server/connectivity/OWNERS
@@ -1,8 +1,2 @@
 set noparent
-
-codewiz@google.com
-ek@google.com
-jchalard@google.com
-lorenzo@google.com
-reminv@google.com
-satk@google.com
+file:platform/packages/modules/Connectivity:master:/OWNERS_core_networking
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index cb2cd14..e9af6011 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -220,13 +220,13 @@
             float dozeScaleFactor, int lightSensorRate, int initialLightSensorRate,
             long brighteningLightDebounceConfig, long darkeningLightDebounceConfig,
             boolean resetAmbientLuxAfterWarmUpConfig, HysteresisLevels ambientBrightnessThresholds,
-            HysteresisLevels screenBrightnessThresholds, LogicalDisplay display, Context context,
+            HysteresisLevels screenBrightnessThresholds, Context context,
             HighBrightnessModeController hbmController) {
         this(new Injector(), callbacks, looper, sensorManager, lightSensor, mapper,
                 lightSensorWarmUpTime, brightnessMin, brightnessMax, dozeScaleFactor,
                 lightSensorRate, initialLightSensorRate, brighteningLightDebounceConfig,
                 darkeningLightDebounceConfig, resetAmbientLuxAfterWarmUpConfig,
-                ambientBrightnessThresholds, screenBrightnessThresholds, display, context,
+                ambientBrightnessThresholds, screenBrightnessThresholds, context,
                 hbmController
         );
     }
@@ -238,7 +238,7 @@
             float dozeScaleFactor, int lightSensorRate, int initialLightSensorRate,
             long brighteningLightDebounceConfig, long darkeningLightDebounceConfig,
             boolean resetAmbientLuxAfterWarmUpConfig, HysteresisLevels ambientBrightnessThresholds,
-            HysteresisLevels screenBrightnessThresholds, LogicalDisplay display, Context context,
+            HysteresisLevels screenBrightnessThresholds, Context context,
             HighBrightnessModeController hbmController) {
         mInjector = injector;
         mContext = context;
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index e4bed3d..1c62699 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -110,6 +110,7 @@
 import android.view.DisplayInfo;
 import android.view.Surface;
 import android.view.SurfaceControl;
+import android.window.DisplayWindowPolicyController;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
@@ -239,6 +240,10 @@
     public final SparseArray<CallbackRecord> mCallbacks =
             new SparseArray<CallbackRecord>();
 
+    /** All {@link DisplayWindowPolicyController}s indexed by {@link DisplayInfo#displayId}. */
+    final SparseArray<DisplayWindowPolicyController> mDisplayWindowPolicyController =
+            new SparseArray<>();
+
     // List of all currently registered display adapters.
     private final ArrayList<DisplayAdapter> mDisplayAdapters = new ArrayList<DisplayAdapter>();
 
@@ -1117,7 +1122,8 @@
 
     private int createVirtualDisplayInternal(IVirtualDisplayCallback callback,
             IMediaProjection projection, int callingUid, String packageName, Surface surface,
-            int flags, VirtualDisplayConfig virtualDisplayConfig) {
+            int flags, VirtualDisplayConfig virtualDisplayConfig,
+            DisplayWindowPolicyController controller) {
         synchronized (mSyncRoot) {
             if (mVirtualDisplayAdapter == null) {
                 Slog.w(TAG, "Rejecting request to create private virtual display "
@@ -1145,6 +1151,9 @@
 
             final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(device);
             if (display != null) {
+                if (controller != null) {
+                    mDisplayWindowPolicyController.put(display.getDisplayIdLocked(), controller);
+                }
                 return display.getDisplayIdLocked();
             }
 
@@ -1188,6 +1197,10 @@
             DisplayDevice device =
                     mVirtualDisplayAdapter.releaseVirtualDisplayLocked(appToken);
             if (device != null) {
+                final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(device);
+                if (display != null) {
+                    mDisplayWindowPolicyController.delete(display.getDisplayIdLocked());
+                }
                 // TODO: multi-display - handle virtual displays the same as other display adapters.
                 mDisplayDeviceRepo.onDisplayDeviceEvent(device,
                         DisplayAdapter.DISPLAY_DEVICE_EVENT_REMOVED);
@@ -2139,6 +2152,15 @@
             }
             pw.println();
             mPersistentDataStore.dump(pw);
+
+            final int displayWindowPolicyControllerCount = mDisplayWindowPolicyController.size();
+            pw.println();
+            pw.println("Display Window Policy Controllers: size="
+                    + displayWindowPolicyControllerCount);
+            for (int i = 0; i < displayWindowPolicyControllerCount; i++) {
+                pw.print("Display " + mDisplayWindowPolicyController.keyAt(i) + ":");
+                mDisplayWindowPolicyController.valueAt(i).dump("  ", pw);
+            }
         }
         pw.println();
         mDisplayModeDirector.dump(pw);
@@ -2704,6 +2726,13 @@
         @Override // Binder call
         public int createVirtualDisplay(VirtualDisplayConfig virtualDisplayConfig,
                 IVirtualDisplayCallback callback, IMediaProjection projection, String packageName) {
+            return createVirtualDisplay(virtualDisplayConfig, callback, projection, packageName,
+                    null /* controller */);
+        }
+
+        public int createVirtualDisplay(VirtualDisplayConfig virtualDisplayConfig,
+                IVirtualDisplayCallback callback, IMediaProjection projection, String packageName,
+                DisplayWindowPolicyController controller) {
             final int callingUid = Binder.getCallingUid();
             if (!validatePackageName(callingUid, packageName)) {
                 throw new SecurityException("packageName must match the calling uid");
@@ -2803,7 +2832,7 @@
             final long token = Binder.clearCallingIdentity();
             try {
                 return createVirtualDisplayInternal(callback, projection, callingUid, packageName,
-                        surface, flags, virtualDisplayConfig);
+                        surface, flags, virtualDisplayConfig, controller);
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
@@ -3624,6 +3653,13 @@
         public void onEarlyInteractivityChange(boolean interactive) {
             mLogicalDisplayMapper.onEarlyInteractivityChange(interactive);
         }
+
+        @Override
+        public DisplayWindowPolicyController getDisplayWindowPolicyController(int displayId) {
+            synchronized (mSyncRoot) {
+                return mDisplayWindowPolicyController.get(displayId);
+            }
+        }
     }
 
     class DesiredDisplayModeSpecsObserver
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 22dd2c0..5f79f72 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -925,7 +925,7 @@
                     PowerManager.BRIGHTNESS_MAX, dozeScaleFactor, lightSensorRate,
                     initialLightSensorRate, brighteningLightDebounce, darkeningLightDebounce,
                     autoBrightnessResetAmbientLuxAfterWarmUp, ambientBrightnessThresholds,
-                    screenBrightnessThresholds, mLogicalDisplay, mContext, mHbmController);
+                    screenBrightnessThresholds, mContext, mHbmController);
         } else {
             mUseSoftwareAutoBrightnessConfig = false;
         }
diff --git a/services/core/java/com/android/server/health/HealthRegCallbackAidl.java b/services/core/java/com/android/server/health/HealthRegCallbackAidl.java
new file mode 100644
index 0000000..629011a
--- /dev/null
+++ b/services/core/java/com/android/server/health/HealthRegCallbackAidl.java
@@ -0,0 +1,119 @@
+/*
+ * 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.health;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.hardware.health.HealthInfo;
+import android.hardware.health.IHealth;
+import android.hardware.health.IHealthInfoCallback;
+import android.os.RemoteException;
+import android.os.Trace;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * On service registration, {@link #onRegistration} is called, which registers {@code this}, an
+ * {@link IHealthInfoCallback}, to the health service.
+ *
+ * <p>When the health service has updates to health info via {@link IHealthInfoCallback}, {@link
+ * HealthInfoCallback#update} is called.
+ *
+ * <p>AIDL variant of {@link HealthHalCallbackHidl}.
+ *
+ * @hide
+ */
+// It is made public so Mockito can access this class. It should have been package private if not
+// for testing.
+@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+public class HealthRegCallbackAidl {
+    private static final String TAG = "HealthRegCallbackAidl";
+    private final HealthInfoCallback mServiceInfoCallback;
+    private final IHealthInfoCallback mHalInfoCallback = new HalInfoCallback();
+
+    HealthRegCallbackAidl(@Nullable HealthInfoCallback healthInfoCallback) {
+        mServiceInfoCallback = healthInfoCallback;
+    }
+
+    /**
+     * Called when the service manager sees {@code newService} replacing {@code oldService}.
+     * This unregisters the health info callback from the old service (ignoring errors), then
+     * registers the health info callback to the new service.
+     *
+     * @param oldService the old IHealth service
+     * @param newService the new IHealth service
+     */
+    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+    public void onRegistration(@Nullable IHealth oldService, @NonNull IHealth newService) {
+        if (mServiceInfoCallback == null) return;
+
+        Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "HealthUnregisterCallbackAidl");
+        try {
+            unregisterCallback(oldService, mHalInfoCallback);
+        } finally {
+            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+        }
+
+        Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "HealthRegisterCallbackAidl");
+        try {
+            registerCallback(newService, mHalInfoCallback);
+        } finally {
+            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+        }
+    }
+
+    private static void unregisterCallback(@Nullable IHealth oldService, IHealthInfoCallback cb) {
+        if (oldService == null) return;
+        try {
+            oldService.unregisterCallback(cb);
+        } catch (RemoteException e) {
+            // Ignore errors. The service might have died.
+            Slog.w(
+                    TAG,
+                    "health: cannot unregister previous callback (transaction error): "
+                            + e.getMessage());
+        }
+    }
+
+    private static void registerCallback(@NonNull IHealth newService, IHealthInfoCallback cb) {
+        try {
+            newService.registerCallback(cb);
+        } catch (RemoteException e) {
+            Slog.e(
+                    TAG,
+                    "health: cannot register callback, framework may cease to"
+                            + " receive updates on health / battery info!",
+                    e);
+            return;
+        }
+        // registerCallback does NOT guarantee that update is called immediately, so request a
+        // manual update here.
+        try {
+            newService.update();
+        } catch (RemoteException e) {
+            Slog.e(TAG, "health: cannot update after registering health info callback", e);
+        }
+    }
+
+    private class HalInfoCallback extends IHealthInfoCallback.Stub {
+        @Override
+        public void healthInfoChanged(HealthInfo healthInfo) throws RemoteException {
+            mServiceInfoCallback.update(healthInfo);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/health/HealthServiceWrapper.java b/services/core/java/com/android/server/health/HealthServiceWrapper.java
index 9b97554..25d1a88 100644
--- a/services/core/java/com/android/server/health/HealthServiceWrapper.java
+++ b/services/core/java/com/android/server/health/HealthServiceWrapper.java
@@ -81,6 +81,8 @@
     public static HealthServiceWrapper create(@Nullable HealthInfoCallback healthInfoCallback)
             throws RemoteException, NoSuchElementException {
         return create(
+                healthInfoCallback == null ? null : new HealthRegCallbackAidl(healthInfoCallback),
+                new HealthServiceWrapperAidl.ServiceManagerStub() {},
                 healthInfoCallback == null ? null : new HealthHalCallbackHidl(healthInfoCallback),
                 new HealthServiceWrapperHidl.IServiceManagerSupplier() {},
                 new HealthServiceWrapperHidl.IHealthSupplier() {});
@@ -89,6 +91,9 @@
     /**
      * Create a new HealthServiceWrapper instance for testing.
      *
+     * @param aidlRegCallback callback for AIDL service registration, or {@code null} if the client
+     *     does not care about AIDL service registration notifications
+     * @param aidlServiceManager Stub for AIDL ServiceManager
      * @param hidlRegCallback callback for HIDL service registration, or {@code null} if the client
      *     does not care about HIDL service registration notifications
      * @param hidlServiceManagerSupplier supplier of HIDL service manager
@@ -97,10 +102,17 @@
      */
     @VisibleForTesting
     static @NonNull HealthServiceWrapper create(
+            @Nullable HealthRegCallbackAidl aidlRegCallback,
+            @NonNull HealthServiceWrapperAidl.ServiceManagerStub aidlServiceManager,
             @Nullable HealthServiceWrapperHidl.Callback hidlRegCallback,
             @NonNull HealthServiceWrapperHidl.IServiceManagerSupplier hidlServiceManagerSupplier,
             @NonNull HealthServiceWrapperHidl.IHealthSupplier hidlHealthSupplier)
             throws RemoteException, NoSuchElementException {
+        try {
+            return new HealthServiceWrapperAidl(aidlRegCallback, aidlServiceManager);
+        } catch (NoSuchElementException e) {
+            // Ignore, try HIDL
+        }
         return new HealthServiceWrapperHidl(
                 hidlRegCallback, hidlServiceManagerSupplier, hidlHealthSupplier);
     }
diff --git a/services/core/java/com/android/server/health/HealthServiceWrapperAidl.java b/services/core/java/com/android/server/health/HealthServiceWrapperAidl.java
new file mode 100644
index 0000000..4f2ed68
--- /dev/null
+++ b/services/core/java/com/android/server/health/HealthServiceWrapperAidl.java
@@ -0,0 +1,215 @@
+/*
+ * 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.health;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.hardware.health.HealthInfo;
+import android.hardware.health.IHealth;
+import android.os.BatteryManager;
+import android.os.BatteryProperty;
+import android.os.Binder;
+import android.os.HandlerThread;
+import android.os.IBinder;
+import android.os.IServiceCallback;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.ServiceSpecificException;
+import android.os.Trace;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.NoSuchElementException;
+import java.util.Objects;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * Implement {@link HealthServiceWrapper} backed by the AIDL HAL.
+ *
+ * @hide
+ */
+class HealthServiceWrapperAidl extends HealthServiceWrapper {
+    private static final String TAG = "HealthServiceWrapperAidl";
+    @VisibleForTesting static final String SERVICE_NAME = IHealth.DESCRIPTOR + "/default";
+    private final HandlerThread mHandlerThread = new HandlerThread("HealthServiceBinder");
+    private final AtomicReference<IHealth> mLastService = new AtomicReference<>();
+    private final IServiceCallback mServiceCallback = new ServiceCallback();
+    private final HealthRegCallbackAidl mRegCallback;
+
+    /** Stub interface into {@link ServiceManager} for testing. */
+    interface ServiceManagerStub {
+        default @Nullable IHealth waitForDeclaredService(@NonNull String name) {
+            return IHealth.Stub.asInterface(ServiceManager.waitForDeclaredService(name));
+        }
+
+        default void registerForNotifications(
+                @NonNull String name, @NonNull IServiceCallback callback) throws RemoteException {
+            ServiceManager.registerForNotifications(name, callback);
+        }
+    }
+
+    HealthServiceWrapperAidl(
+            @Nullable HealthRegCallbackAidl regCallback, @NonNull ServiceManagerStub serviceManager)
+            throws RemoteException, NoSuchElementException {
+
+        traceBegin("HealthInitGetServiceAidl");
+        IHealth newService;
+        try {
+            newService = serviceManager.waitForDeclaredService(SERVICE_NAME);
+        } finally {
+            traceEnd();
+        }
+        if (newService == null) {
+            throw new NoSuchElementException(
+                    "IHealth service instance isn't available. Perhaps no permission?");
+        }
+        mLastService.set(newService);
+        mRegCallback = regCallback;
+        if (mRegCallback != null) {
+            mRegCallback.onRegistration(null /* oldService */, newService);
+        }
+
+        traceBegin("HealthInitRegisterNotificationAidl");
+        mHandlerThread.start();
+        try {
+            serviceManager.registerForNotifications(SERVICE_NAME, mServiceCallback);
+        } finally {
+            traceEnd();
+        }
+        Slog.i(TAG, "health: HealthServiceWrapper listening to AIDL HAL");
+    }
+
+    @Override
+    @VisibleForTesting
+    public HandlerThread getHandlerThread() {
+        return mHandlerThread;
+    }
+
+    @Override
+    public int getProperty(int id, BatteryProperty prop) throws RemoteException {
+        traceBegin("HealthGetPropertyAidl");
+        try {
+            return getPropertyInternal(id, prop);
+        } finally {
+            traceEnd();
+        }
+    }
+
+    private int getPropertyInternal(int id, BatteryProperty prop) throws RemoteException {
+        IHealth service = mLastService.get();
+        if (service == null) throw new RemoteException("no health service");
+        try {
+            switch (id) {
+                case BatteryManager.BATTERY_PROPERTY_CHARGE_COUNTER:
+                    prop.setLong(service.getChargeCounterUah());
+                    break;
+                case BatteryManager.BATTERY_PROPERTY_CURRENT_NOW:
+                    prop.setLong(service.getCurrentNowMicroamps());
+                    break;
+                case BatteryManager.BATTERY_PROPERTY_CURRENT_AVERAGE:
+                    prop.setLong(service.getCurrentAverageMicroamps());
+                    break;
+                case BatteryManager.BATTERY_PROPERTY_CAPACITY:
+                    prop.setLong(service.getCapacity());
+                    break;
+                case BatteryManager.BATTERY_PROPERTY_STATUS:
+                    prop.setLong(service.getChargeStatus());
+                    break;
+                case BatteryManager.BATTERY_PROPERTY_ENERGY_COUNTER:
+                    prop.setLong(service.getEnergyCounterNwh());
+                    break;
+            }
+        } catch (UnsupportedOperationException e) {
+            // Leave prop untouched.
+            return -1;
+        } catch (ServiceSpecificException e) {
+            // Leave prop untouched.
+            return -2;
+        }
+        // throws RemoteException as-is. BatteryManager wraps it into a RuntimeException
+        // and throw it to apps.
+
+        // If no error, return 0.
+        return 0;
+    }
+
+    @Override
+    public void scheduleUpdate() throws RemoteException {
+        getHandlerThread()
+                .getThreadHandler()
+                .post(
+                        () -> {
+                            traceBegin("HealthScheduleUpdate");
+                            try {
+                                IHealth service = mLastService.get();
+                                if (service == null) {
+                                    Slog.e(TAG, "no health service");
+                                    return;
+                                }
+                                service.update();
+                            } catch (RemoteException | ServiceSpecificException ex) {
+                                Slog.e(TAG, "Cannot call update on health AIDL HAL", ex);
+                            } finally {
+                                traceEnd();
+                            }
+                        });
+    }
+
+    @Override
+    public HealthInfo getHealthInfo() throws RemoteException {
+        IHealth service = mLastService.get();
+        if (service == null) return null;
+        try {
+            return service.getHealthInfo();
+        } catch (UnsupportedOperationException | ServiceSpecificException ex) {
+            return null;
+        }
+    }
+
+    private static void traceBegin(String name) {
+        Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, name);
+    }
+
+    private static void traceEnd() {
+        Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+    }
+
+    private class ServiceCallback extends IServiceCallback.Stub {
+        @Override
+        public void onRegistration(String name, @NonNull final IBinder newBinder)
+                throws RemoteException {
+            if (!SERVICE_NAME.equals(name)) return;
+            // This runnable only runs on mHandlerThread and ordering is ensured, hence
+            // no locking is needed inside the runnable.
+            getHandlerThread()
+                    .getThreadHandler()
+                    .post(
+                            () -> {
+                                IHealth newService =
+                                        IHealth.Stub.asInterface(Binder.allowBlocking(newBinder));
+                                IHealth oldService = mLastService.getAndSet(newService);
+                                IBinder oldBinder =
+                                        oldService != null ? oldService.asBinder() : null;
+                                if (Objects.equals(newBinder, oldBinder)) return;
+
+                                Slog.i(TAG, "New health AIDL HAL service registered");
+                                mRegCallback.onRegistration(oldService, newService);
+                            });
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
new file mode 100644
index 0000000..05e1bdd
--- /dev/null
+++ b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
@@ -0,0 +1,476 @@
+/*
+ * 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.inputmethod;
+
+import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
+
+import static com.android.server.inputmethod.InputMethodManagerService.MSG_INITIALIZE_IME;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.PendingIntent;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.pm.PackageManagerInternal;
+import android.content.res.Resources;
+import android.inputmethodservice.InputMethodService;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.os.Trace;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.util.ArrayMap;
+import android.util.Slog;
+import android.view.IWindowManager;
+import android.view.WindowManager;
+import android.view.inputmethod.InputMethod;
+import android.view.inputmethod.InputMethodInfo;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.inputmethod.InputBindResult;
+import com.android.internal.inputmethod.UnbindReason;
+import com.android.internal.view.IInputMethod;
+import com.android.server.wm.WindowManagerInternal;
+
+/**
+ * A controller managing the state of the input method binding.
+ */
+final class InputMethodBindingController {
+    static final boolean DEBUG = false;
+    private static final String TAG = InputMethodBindingController.class.getSimpleName();
+
+    @NonNull private final InputMethodManagerService mService;
+    @NonNull private final Context mContext;
+    @NonNull private final ArrayMap<String, InputMethodInfo> mMethodMap;
+    @NonNull private final InputMethodUtils.InputMethodSettings mSettings;
+    @NonNull private final PackageManagerInternal mPackageManagerInternal;
+    @NonNull private final IWindowManager mIWindowManager;
+    @NonNull private final WindowManagerInternal mWindowManagerInternal;
+    @NonNull private final Resources mRes;
+
+    private long mLastBindTime;
+    private boolean mHasConnection;
+    @Nullable private String mCurId;
+    @Nullable private String mSelectedMethodId;
+    @Nullable private Intent mCurIntent;
+    @Nullable private IInputMethod mCurMethod;
+    private int mCurMethodUid = Process.INVALID_UID;
+    private IBinder mCurToken;
+    private int mCurSeq;
+    private boolean mVisibleBound;
+
+    /**
+     * Binding flags for establishing connection to the {@link InputMethodService}.
+     */
+    private static final int IME_CONNECTION_BIND_FLAGS =
+            Context.BIND_AUTO_CREATE
+                    | Context.BIND_NOT_VISIBLE
+                    | Context.BIND_NOT_FOREGROUND
+                    | Context.BIND_IMPORTANT_BACKGROUND;
+    /**
+     * Binding flags for establishing connection to the {@link InputMethodService} when
+     * config_killableInputMethods is enabled.
+     */
+    private static final int IME_CONNECTION_LOW_PRIORITY_BIND_FLAGS =
+            Context.BIND_AUTO_CREATE
+                    | Context.BIND_REDUCTION_FLAGS;
+    /**
+     * Binding flags used only while the {@link InputMethodService} is showing window.
+     */
+    private static final int IME_VISIBLE_BIND_FLAGS =
+            Context.BIND_AUTO_CREATE
+                    | Context.BIND_TREAT_LIKE_ACTIVITY
+                    | Context.BIND_FOREGROUND_SERVICE
+                    | Context.BIND_INCLUDE_CAPABILITIES
+                    | Context.BIND_SHOWING_UI
+                    | Context.BIND_SCHEDULE_LIKE_TOP_APP;
+
+    /**
+     * Binding flags for establishing connection to the {@link InputMethodService}.
+     *
+     * <p>
+     * This defaults to {@link InputMethodBindingController#IME_CONNECTION_BIND_FLAGS} unless
+     * config_killableInputMethods is enabled, in which case this takes the value of
+     * {@link InputMethodBindingController#IME_CONNECTION_LOW_PRIORITY_BIND_FLAGS}.
+     */
+    private final int mImeConnectionBindFlags;
+
+    InputMethodBindingController(@NonNull InputMethodManagerService service) {
+        mService = service;
+        mContext = mService.mContext;
+        mMethodMap = mService.mMethodMap;
+        mSettings = mService.mSettings;
+        mPackageManagerInternal = mService.mPackageManagerInternal;
+        mIWindowManager = mService.mIWindowManager;
+        mWindowManagerInternal = mService.mWindowManagerInternal;
+        mRes = mService.mRes;
+
+        // If configured, use low priority flags to make the IME killable by the lowmemorykiller
+        final boolean lowerIMEPriority = mRes.getBoolean(
+                com.android.internal.R.bool.config_killableInputMethods);
+
+        if (lowerIMEPriority) {
+            mImeConnectionBindFlags =
+                    InputMethodBindingController.IME_CONNECTION_LOW_PRIORITY_BIND_FLAGS;
+        } else {
+            mImeConnectionBindFlags = InputMethodBindingController.IME_CONNECTION_BIND_FLAGS;
+        }
+    }
+
+    /**
+     * Time that we last initiated a bind to the input method, to determine
+     * if we should try to disconnect and reconnect to it.
+     */
+    long getLastBindTime() {
+        return mLastBindTime;
+    }
+
+    /**
+     * Set to true if our ServiceConnection is currently actively bound to
+     * a service (whether or not we have gotten its IBinder back yet).
+     */
+    boolean hasConnection() {
+        return mHasConnection;
+    }
+
+    /**
+     * Id obtained with {@link InputMethodInfo#getId()} for the input method that we are currently
+     * connected to or in the process of connecting to.
+     *
+     * <p>This can be {@code null} when no input method is connected.</p>
+     *
+     * @see #getSelectedMethodId()
+     */
+    @Nullable
+    String getCurId() {
+        return mCurId;
+    }
+
+    /**
+     * Id obtained with {@link InputMethodInfo#getId()} for the currently selected input method.
+     * This is to be synchronized with the secure settings keyed with
+     * {@link android.provider.Settings.Secure#DEFAULT_INPUT_METHOD}.
+     *
+     * <p>This can be transiently {@code null} when the system is re-initializing input method
+     * settings, e.g., the system locale is just changed.</p>
+     *
+     * <p>Note that {@link #getCurId()} is used to track which IME is being connected to
+     * {@link com.android.server.inputmethod.InputMethodManagerService}.</p>
+     *
+     * @see #getCurId()
+     */
+    @Nullable
+    String getSelectedMethodId() {
+        return mSelectedMethodId;
+    }
+
+    void setSelectedMethodId(@Nullable String selectedMethodId) {
+        mSelectedMethodId = selectedMethodId;
+    }
+
+    /**
+     * The token we have made for the currently active input method, to
+     * identify it in the future.
+     */
+    IBinder getCurToken() {
+        return mCurToken;
+    }
+
+    /**
+     * The Intent used to connect to the current input method.
+     */
+    @Nullable
+    Intent getCurIntent() {
+        return mCurIntent;
+    }
+
+    /**
+     * The current binding sequence number, incremented every time there is
+     * a new bind performed.
+     */
+    int getSequenceNumber() {
+        return mCurSeq;
+    }
+
+    /**
+     * Increase the current binding sequence number by one.
+     * Reset to 1 on overflow.
+     */
+    void advanceSequenceNumber() {
+        mCurSeq += 1;
+        if (mCurSeq <= 0) {
+            mCurSeq = 1;
+        }
+    }
+
+    /**
+     * If non-null, this is the input method service we are currently connected
+     * to.
+     */
+    @Nullable
+    IInputMethod getCurMethod() {
+        return mCurMethod;
+    }
+
+    /**
+     * If not {@link Process#INVALID_UID}, then the UID of {@link #getCurIntent()}.
+     */
+    int getCurMethodUid() {
+        return mCurMethodUid;
+    }
+
+    /**
+     * Indicates whether {@link #getVisibleConnection} is currently in use.
+     */
+    boolean isVisibleBound() {
+        return mVisibleBound;
+    }
+
+    /**
+     * Used to bring IME service up to visible adjustment while it is being shown.
+     */
+    @NonNull
+    ServiceConnection getVisibleConnection() {
+        return mVisibleConnection;
+    }
+
+    private final ServiceConnection mVisibleConnection = new ServiceConnection() {
+        @Override public void onBindingDied(ComponentName name) {
+            synchronized (mMethodMap) {
+                if (mVisibleBound) {
+                    unbindVisibleConnectionLocked();
+                }
+            }
+        }
+
+        @Override public void onServiceConnected(ComponentName name, IBinder service) {
+        }
+
+        @Override public void onServiceDisconnected(ComponentName name) {
+        }
+    };
+
+    /**
+     * Used to bind the IME while it is not currently being shown.
+     */
+    private final ServiceConnection mMainConnection = new ServiceConnection() {
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.onServiceConnected");
+            synchronized (mMethodMap) {
+                if (mCurIntent != null && name.equals(mCurIntent.getComponent())) {
+                    mCurMethod = IInputMethod.Stub.asInterface(service);
+                    updateCurrentMethodUidLocked();
+                    if (mCurToken == null) {
+                        Slog.w(TAG, "Service connected without a token!");
+                        unbindCurrentMethodLocked();
+                        Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
+                        return;
+                    }
+                    if (DEBUG) Slog.v(TAG, "Initiating attach with token: " + mCurToken);
+                    // Dispatch display id for InputMethodService to update context display.
+                    mService.executeOrSendMessage(mCurMethod,
+                            mService.mCaller.obtainMessageIOO(MSG_INITIALIZE_IME,
+                                    mMethodMap.get(mSelectedMethodId).getConfigChanges(),
+                                    mCurMethod, mCurToken));
+                    mService.scheduleNotifyImeUidToAudioService(mCurMethodUid);
+                    mService.reRequestCurrentClientSessionLocked();
+                }
+            }
+            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
+        }
+
+        @GuardedBy("mMethodMap")
+        private void updateCurrentMethodUidLocked() {
+            final String curMethodPackage = mCurIntent.getComponent().getPackageName();
+            final int curMethodUid = mPackageManagerInternal.getPackageUid(
+                    curMethodPackage, 0 /* flags */, mSettings.getCurrentUserId());
+            if (curMethodUid < 0) {
+                Slog.e(TAG, "Failed to get UID for package=" + curMethodPackage);
+                mCurMethodUid = Process.INVALID_UID;
+            } else {
+                mCurMethodUid = curMethodUid;
+            }
+        }
+
+        @Override
+        public void onServiceDisconnected(@NonNull ComponentName name) {
+            // Note that mContext.unbindService(this) does not trigger this.  Hence if we are
+            // here the
+            // disconnection is not intended by IMMS (e.g. triggered because the current IMS
+            // crashed),
+            // which is irregular but can eventually happen for everyone just by continuing
+            // using the
+            // device.  Thus it is important to make sure that all the internal states are
+            // properly
+            // refreshed when this method is called back.  Running
+            //    adb install -r <APK that implements the current IME>
+            // would be a good way to trigger such a situation.
+            synchronized (mMethodMap) {
+                if (DEBUG) {
+                    Slog.v(TAG, "Service disconnected: " + name + " mCurIntent=" + mCurIntent);
+                }
+                if (mCurMethod != null && mCurIntent != null
+                        && name.equals(mCurIntent.getComponent())) {
+                    // We consider this to be a new bind attempt, since the system
+                    // should now try to restart the service for us.
+                    mLastBindTime = SystemClock.uptimeMillis();
+                    mService.clearClientSessionsLocked();
+                    mService.clearInputShowRequestLocked();
+                    mService.unbindCurrentClientLocked(UnbindReason.DISCONNECT_IME);
+                }
+            }
+        }
+    };
+
+    @GuardedBy("mMethodMap")
+    void unbindCurrentMethodLocked() {
+        if (mVisibleBound) {
+            unbindVisibleConnectionLocked();
+        }
+
+        if (mHasConnection) {
+            unbindMainConnectionLocked();
+        }
+
+        if (mCurToken != null) {
+            removeCurrentTokenLocked();
+            mService.resetSystemUiLocked();
+        }
+
+        mCurId = null;
+        mService.clearClientSessionsLocked();
+    }
+
+    @GuardedBy("mMethodMap")
+    void clearCurMethodLocked() {
+        mCurMethod = null;
+        mCurMethodUid = Process.INVALID_UID;
+    }
+
+    @GuardedBy("mMethodMap")
+    private void removeCurrentTokenLocked() {
+        int curTokenDisplayId = mService.getCurTokenDisplayId();
+
+        if (DEBUG) {
+            Slog.v(TAG,
+                    "Removing window token: " + mCurToken + " for display: " + curTokenDisplayId);
+        }
+        mWindowManagerInternal.removeWindowToken(mCurToken, false /* removeWindows */,
+                false /* animateExit */, curTokenDisplayId);
+        mCurToken = null;
+    }
+
+    @GuardedBy("mMethodMap")
+    @NonNull
+    InputBindResult bindCurrentMethodLocked(int displayIdToShowIme) {
+        InputMethodInfo info = mMethodMap.get(mSelectedMethodId);
+        if (info == null) {
+            throw new IllegalArgumentException("Unknown id: " + mSelectedMethodId);
+        }
+
+        mCurIntent = createImeBindingIntent(info.getComponent());
+
+        if (bindCurrentInputMethodServiceMainConnectionLocked()) {
+            mCurId = info.getId();
+            mLastBindTime = SystemClock.uptimeMillis();
+
+            addFreshWindowTokenLocked(displayIdToShowIme);
+            return new InputBindResult(
+                    InputBindResult.ResultCode.SUCCESS_WAITING_IME_BINDING,
+                    null, null, mCurId, mCurSeq, false);
+        }
+
+        Slog.w(InputMethodManagerService.TAG,
+                "Failure connecting to input method service: " + mCurIntent);
+        mCurIntent = null;
+        return InputBindResult.IME_NOT_CONNECTED;
+    }
+
+    @NonNull
+    private Intent createImeBindingIntent(ComponentName component) {
+        Intent intent = new Intent(InputMethod.SERVICE_INTERFACE);
+        intent.setComponent(component);
+        intent.putExtra(Intent.EXTRA_CLIENT_LABEL,
+                com.android.internal.R.string.input_method_binding_label);
+        intent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity(
+                mContext, 0, new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS),
+                PendingIntent.FLAG_IMMUTABLE));
+        return intent;
+    }
+
+    @GuardedBy("mMethodMap")
+    private void addFreshWindowTokenLocked(int displayIdToShowIme) {
+        mCurToken = new Binder();
+
+        mService.setCurTokenDisplayId(displayIdToShowIme);
+
+        try {
+            if (DEBUG) {
+                Slog.v(TAG, "Adding window token: " + mCurToken + " for display: "
+                        + displayIdToShowIme);
+            }
+            mIWindowManager.addWindowToken(mCurToken, WindowManager.LayoutParams.TYPE_INPUT_METHOD,
+                    displayIdToShowIme, null /* options */);
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Could not add window token " + mCurToken + " for display "
+                    + displayIdToShowIme, e);
+        }
+    }
+
+    @GuardedBy("mMethodMap")
+    void unbindMainConnectionLocked() {
+        mContext.unbindService(mMainConnection);
+        mHasConnection = false;
+    }
+
+    @GuardedBy("mMethodMap")
+    void unbindVisibleConnectionLocked() {
+        mContext.unbindService(mVisibleConnection);
+        mVisibleBound = false;
+    }
+
+    @GuardedBy("mMethodMap")
+    private boolean bindCurrentInputMethodServiceLocked(ServiceConnection conn, int flags) {
+        if (mCurIntent == null || conn == null) {
+            Slog.e(TAG, "--- bind failed: service = " + mCurIntent + ", conn = " + conn);
+            return false;
+        }
+        return mContext.bindServiceAsUser(mCurIntent, conn, flags,
+                new UserHandle(mSettings.getCurrentUserId()));
+    }
+
+    @GuardedBy("mMethodMap")
+    boolean bindCurrentInputMethodServiceVisibleConnectionLocked() {
+        mVisibleBound = bindCurrentInputMethodServiceLocked(mVisibleConnection,
+                IME_VISIBLE_BIND_FLAGS);
+        return mVisibleBound;
+    }
+
+    @GuardedBy("mMethodMap")
+    boolean bindCurrentInputMethodServiceMainConnectionLocked() {
+        mHasConnection = bindCurrentInputMethodServiceLocked(mMainConnection,
+                mImeConnectionBindFlags);
+        return mHasConnection;
+    }
+
+}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index d74b3d7..c879e3d 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -72,13 +72,11 @@
 import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
-import android.content.ComponentName;
 import android.content.ContentProvider;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.ServiceConnection;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
@@ -208,7 +206,7 @@
  * This class provides a system service that manages input methods.
  */
 public class InputMethodManagerService extends IInputMethodManager.Stub
-        implements ServiceConnection, Handler.Callback {
+        implements Handler.Callback {
     static final boolean DEBUG = false;
     static final String TAG = "InputMethodManagerService";
     public static final String PROTO_ARG = "--proto";
@@ -261,44 +259,6 @@
     private static final String HANDLER_THREAD_NAME = "android.imms";
 
     /**
-     * Binding flags for establishing connection to the {@link InputMethodService}.
-     */
-    private static final int IME_CONNECTION_BIND_FLAGS =
-            Context.BIND_AUTO_CREATE
-            | Context.BIND_NOT_VISIBLE
-            | Context.BIND_NOT_FOREGROUND
-            | Context.BIND_IMPORTANT_BACKGROUND;
-
-    /**
-     * Binding flags for establishing connection to the {@link InputMethodService} when
-     * config_killableInputMethods is enabled.
-     */
-    private static final int IME_CONNECTION_LOW_PRIORITY_BIND_FLAGS =
-            Context.BIND_AUTO_CREATE
-            | Context.BIND_REDUCTION_FLAGS;
-
-    /**
-     * Binding flags for establishing connection to the {@link InputMethodService}.
-     *
-     * <p>
-     * This defaults to {@link #IME_CONNECTION_BIND_FLAGS} unless config_killableInputMethods is
-     * enabled, in which case this takes the value of
-     * {@link #IME_CONNECTION_LOW_PRIORITY_BIND_FLAGS}.
-     */
-    private final int mImeConnectionBindFlags;
-
-    /**
-     * Binding flags used only while the {@link InputMethodService} is showing window.
-     */
-    private static final int IME_VISIBLE_BIND_FLAGS =
-            Context.BIND_AUTO_CREATE
-            | Context.BIND_TREAT_LIKE_ACTIVITY
-            | Context.BIND_FOREGROUND_SERVICE
-            | Context.BIND_INCLUDE_CAPABILITIES
-            | Context.BIND_SHOWING_UI
-            | Context.BIND_SCHEDULE_LIKE_TOP_APP;
-
-    /**
      * A protected broadcast intent action for internal use for {@link PendingIntent} in
      * the notification.
      */
@@ -321,11 +281,11 @@
     final boolean mHasFeature;
     private final ArrayMap<String, List<InputMethodSubtype>> mAdditionalSubtypeMap =
             new ArrayMap<>();
-    private final boolean mIsLowRam;
     private final AppOpsManager mAppOpsManager;
     private final UserManager mUserManager;
     private final UserManagerInternal mUserManagerInternal;
     private final InputMethodMenuController mMenuController;
+    private final InputMethodBindingController mBindingController;
 
     /**
      * Cache the result of {@code LocalServices.getService(AudioManagerInternal.class)}.
@@ -351,31 +311,20 @@
     @GuardedBy("mMethodMap")
     private int mMethodMapUpdateCount = 0;
 
-    // Used to bring IME service up to visible adjustment while it is being shown.
-    final ServiceConnection mVisibleConnection = new ServiceConnection() {
-        @Override public void onBindingDied(ComponentName name) {
-            synchronized (mMethodMap) {
-                if (mVisibleBound) {
-                    mContext.unbindService(mVisibleConnection);
-                    mVisibleBound = false;
-                }
-            }
-        }
-
-        @Override public void onServiceConnected(ComponentName name, IBinder service) {
-        }
-
-        @Override public void onServiceDisconnected(ComponentName name) {
-        }
-    };
-    boolean mVisibleBound = false;
+    /**
+     * Indicates whether {@link InputMethodBindingController#getVisibleConnection} is currently
+     * in use.
+     */
+    private boolean isVisibleBound() {
+        return mBindingController.isVisibleBound();
+    }
 
     // Ongoing notification
     private NotificationManager mNotificationManager;
     KeyguardManager mKeyguardManager;
     private @Nullable StatusBarManagerService mStatusBar;
-    private Notification.Builder mImeSwitcherNotification;
-    private PendingIntent mImeSwitchPendingIntent;
+    private final Notification.Builder mImeSwitcherNotification;
+    private final PendingIntent mImeSwitchPendingIntent;
     private boolean mShowOngoingImeSwitcherForPhones;
     private boolean mNotificationShown;
 
@@ -463,25 +412,41 @@
 
     /**
      * Id obtained with {@link InputMethodInfo#getId()} for the currently selected input method.
-     * method.  This is to be synchronized with the secure settings keyed with
+     * This is to be synchronized with the secure settings keyed with
      * {@link Settings.Secure#DEFAULT_INPUT_METHOD}.
      *
      * <p>This can be transiently {@code null} when the system is re-initializing input method
      * settings, e.g., the system locale is just changed.</p>
      *
-     * <p>Note that {@link #mCurId} is used to track which IME is being connected to
-     * {@link InputMethodManagerService}.</p>
+     * <p>Note that {@link InputMethodBindingController#getCurId()} is used to track which IME is
+     * being connected to {@link InputMethodManagerService}.</p>
      *
-     * @see #mCurId
+     * @see InputMethodBindingController#getCurId()
      */
     @Nullable
-    String mCurMethodId;
+    private String getSelectedMethodId() {
+        return mBindingController.getSelectedMethodId();
+    }
+
+    private void setSelectedMethodId(@Nullable String selectedMethodId) {
+        mBindingController.setSelectedMethodId(selectedMethodId);
+    }
 
     /**
      * The current binding sequence number, incremented every time there is
      * a new bind performed.
      */
-    int mCurSeq;
+    private int getSequenceNumber() {
+        return mBindingController.getSequenceNumber();
+    }
+
+    /**
+     * Increase the current binding sequence number by one.
+     * Reset to 1 on overflow.
+     */
+    private void advanceSequenceNumber() {
+        mBindingController.advanceSequenceNumber();
+    }
 
     /**
      * {@code true} if the Ime policy has been set to {@link WindowManager#DISPLAY_IME_POLICY_HIDE}.
@@ -493,7 +458,7 @@
     /**
      * The client that is currently bound to an input method.
      */
-    ClientState mCurClient;
+    private ClientState mCurClient;
 
     /**
      * The last window token that we confirmed to be focused.  This is always updated upon reports
@@ -538,19 +503,18 @@
      *
      * <p>This can be {@code null} when no input method is connected.</p>
      *
-     * @see #mCurMethodId
+     * @see #getSelectedMethodId()
      */
     @Nullable
-    String mCurId;
+    private String getCurId() {
+        return mBindingController.getCurId();
+    }
 
     /**
      * The current subtype of the current input method.
      */
     private InputMethodSubtype mCurrentSubtype;
 
-    // Was the keyguard locked when this client became current?
-    private boolean mCurClientInKeyguard;
-
     /**
      * {@code true} if the IME has not been mostly hidden via {@link android.view.InsetsController}
      */
@@ -560,12 +524,14 @@
      * Set to true if our ServiceConnection is currently actively bound to
      * a service (whether or not we have gotten its IBinder back yet).
      */
-    boolean mHaveConnection;
+    private boolean hasConnection() {
+        return mBindingController.hasConnection();
+    }
 
     /**
      * Set if the client has asked for the input method to be shown.
      */
-    boolean mShowRequested;
+    private boolean mShowRequested;
 
     /**
      * Set if we were explicitly told to show the input method.
@@ -580,7 +546,7 @@
     /**
      * Set if we last told the input method to show itself.
      */
-    boolean mInputShown;
+    private boolean mInputShown;
 
     /**
      * {@code true} if the current input method is in fullscreen mode.
@@ -590,17 +556,30 @@
     /**
      * The Intent used to connect to the current input method.
      */
-    Intent mCurIntent;
+    @Nullable
+    private Intent getCurIntent() {
+        return mBindingController.getCurIntent();
+    }
 
     /**
      * The token we have made for the currently active input method, to
      * identify it in the future.
      */
-    IBinder mCurToken;
+    private IBinder getCurToken() {
+        return mBindingController.getCurToken();
+    }
 
     /**
      * The displayId of current active input method.
      */
+    int getCurTokenDisplayId() {
+        return mCurTokenDisplayId;
+    }
+
+    void setCurTokenDisplayId(int curTokenDisplayId) {
+        mCurTokenDisplayId = curTokenDisplayId;
+    }
+
     int mCurTokenDisplayId = INVALID_DISPLAY;
 
     /**
@@ -622,18 +601,25 @@
      * If non-null, this is the input method service we are currently connected
      * to.
      */
-    IInputMethod mCurMethod;
+    @Nullable
+    private IInputMethod getCurMethod() {
+        return mBindingController.getCurMethod();
+    }
 
     /**
-     * If not {@link Process#INVALID_UID}, then the UID of {@link #mCurIntent}.
+     * If not {@link Process#INVALID_UID}, then the UID of {@link #getCurIntent()}.
      */
-    int mCurMethodUid = Process.INVALID_UID;
+    private int getCurMethodUid() {
+        return mBindingController.getCurMethodUid();
+    }
 
     /**
      * Time that we last initiated a bind to the input method, to determine
      * if we should try to disconnect and reconnect to it.
      */
-    long mLastBindTime;
+    private long getLastBindTime() {
+        return mBindingController.getLastBindTime();
+    }
 
     /**
      * Have we called mCurMethod.bindInput()?
@@ -651,7 +637,7 @@
      */
     boolean mIsInteractive = true;
 
-    private IPlatformCompat mPlatformCompat;
+    private final IPlatformCompat mPlatformCompat;
 
     int mBackDisposition = InputMethodService.BACK_DISPOSITION_DEFAULT;
 
@@ -674,7 +660,7 @@
      * </dd>
      * </dl>
      * <em>Do not update this value outside of {@link #setImeWindowStatus(IBinder, int, int)} and
-     * {@link #unbindCurrentMethodLocked()}.</em>
+     * {@link InputMethodBindingController#unbindCurrentMethodLocked()}.</em>
      */
     int mImeWindowVis;
 
@@ -761,7 +747,7 @@
     private final WeakHashMap<IBinder, IBinder> mImeTargetWindowMap = new WeakHashMap<>();
 
     private static final class SoftInputShowHideHistory {
-        private Entry[] mEntries = new Entry[16];
+        private final Entry[] mEntries = new Entry[16];
         private int mNextIndex = 0;
         private static final AtomicInteger sSequenceNumber = new AtomicInteger(0);
 
@@ -1515,7 +1501,7 @@
     private UserSwitchHandlerTask mUserSwitchHandlerTask;
 
     public static final class Lifecycle extends SystemService {
-        private InputMethodManagerService mService;
+        private final InputMethodManagerService mService;
 
         public Lifecycle(Context context) {
             super(context);
@@ -1613,13 +1599,9 @@
         mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
         mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
         mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
-        mImeDisplayValidator = displayId -> mWindowManagerInternal.getDisplayImePolicy(displayId);
-        mCaller = new HandlerCaller(context, thread.getLooper(), new HandlerCaller.Callback() {
-            @Override
-            public void executeMessage(Message msg) {
-                handleMessage(msg);
-            }
-        }, true /*asyncHandler*/);
+        mImeDisplayValidator = mWindowManagerInternal::getDisplayImePolicy;
+        mCaller = new HandlerCaller(context, thread.getLooper(), this::handleMessage,
+                true /*asyncHandler*/);
         mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
         mUserManager = mContext.getSystemService(UserManager.class);
         mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
@@ -1628,7 +1610,6 @@
         mPlatformCompat = IPlatformCompat.Stub.asInterface(
                 ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
         mSlotIme = mContext.getString(com.android.internal.R.string.status_bar_ime);
-        mIsLowRam = ActivityManager.isLowRamDeviceStatic();
 
         Bundle extras = new Bundle();
         extras.putBoolean(Notification.EXTRA_ALLOW_DURING_SETUP, true);
@@ -1669,22 +1650,14 @@
         mSwitchingController = InputMethodSubtypeSwitchingController.createInstanceLocked(
                 mSettings, context);
         mMenuController = new InputMethodMenuController(this);
-
-        // If configured, use low priority flags to make the IME killable by the lowmemorykiller
-        final boolean lowerIMEPriority = mRes.getBoolean(
-                com.android.internal.R.bool.config_killableInputMethods);
-
-        if (lowerIMEPriority) {
-            mImeConnectionBindFlags = IME_CONNECTION_LOW_PRIORITY_BIND_FLAGS;
-        } else {
-            mImeConnectionBindFlags = IME_CONNECTION_BIND_FLAGS;
-        }
+        mBindingController = new InputMethodBindingController(this);
     }
 
     @GuardedBy("mMethodMap")
     private void resetDefaultImeLocked(Context context) {
         // Do not reset the default (current) IME when it is a 3rd-party IME
-        if (mCurMethodId != null && !mMethodMap.get(mCurMethodId).isSystem()) {
+        String selectedMethodId = getSelectedMethodId();
+        if (selectedMethodId != null && !mMethodMap.get(selectedMethodId).isSystem()) {
             return;
         }
         final List<InputMethodInfo> suitableImes = InputMethodUtils.getDefaultEnabledImes(
@@ -1799,9 +1772,7 @@
                 mKeyguardManager = mContext.getSystemService(KeyguardManager.class);
                 mNotificationManager = mContext.getSystemService(NotificationManager.class);
                 mStatusBar = statusBar;
-                if (mStatusBar != null) {
-                    mStatusBar.setIconVisibility(mSlotIme, false);
-                }
+                hideStatusBarIconLocked();
                 updateSystemUiLocked(mImeWindowVis, mBackDisposition);
                 mShowOngoingImeSwitcherForPhones = mRes.getBoolean(
                         com.android.internal.R.bool.show_ongoing_ime_switcher);
@@ -1893,7 +1864,7 @@
         if (token == null) {
             throw new InvalidParameterException("token must not be null.");
         }
-        if (token != mCurToken) {
+        if (token != getCurToken()) {
             Slog.e(TAG, "Ignoring " + Debug.getCaller() + " due to an invalid token."
                     + " uid:" + Binder.getCallingUid() + " token:" + token);
             return false;
@@ -1901,17 +1872,6 @@
         return true;
     }
 
-    @GuardedBy("mMethodMap")
-    private boolean bindCurrentInputMethodServiceLocked(
-            Intent service, ServiceConnection conn, int flags) {
-        if (service == null || conn == null) {
-            Slog.e(TAG, "--- bind failed: service = " + service + ", conn = " + conn);
-            return false;
-        }
-        return mContext.bindServiceAsUser(service, conn, flags,
-                new UserHandle(mSettings.getCurrentUserId()));
-    }
-
     @Override
     public List<InputMethodInfo> getInputMethodList(@UserIdInt int userId) {
         if (UserHandle.getCallingUserId() != userId) {
@@ -1992,14 +1952,15 @@
     @GuardedBy("mMethodMap")
     private void onCreateInlineSuggestionsRequestLocked(@UserIdInt int userId,
             InlineSuggestionsRequestInfo requestInfo, IInlineSuggestionsRequestCallback callback) {
-        final InputMethodInfo imi = mMethodMap.get(mCurMethodId);
+        final InputMethodInfo imi = mMethodMap.get(getSelectedMethodId());
         try {
+            IInputMethod curMethod = getCurMethod();
             if (userId == mSettings.getCurrentUserId() && imi != null
-                    && imi.isInlineSuggestionsEnabled() && mCurMethod != null) {
-                executeOrSendMessage(mCurMethod,
-                        mCaller.obtainMessageOOO(MSG_INLINE_SUGGESTIONS_REQUEST, mCurMethod,
+                    && imi.isInlineSuggestionsEnabled() && curMethod != null) {
+                executeOrSendMessage(curMethod,
+                        mCaller.obtainMessageOOO(MSG_INLINE_SUGGESTIONS_REQUEST, curMethod,
                                 requestInfo, new InlineSuggestionsRequestCallbackDecorator(callback,
-                                        imi.getPackageName(), mCurTokenDisplayId, mCurToken,
+                                        imi.getPackageName(), mCurTokenDisplayId, getCurToken(),
                                         this)));
             } else {
                 callback.onInlineSuggestionsUnsupported();
@@ -2135,8 +2096,9 @@
             boolean allowsImplicitlySelectedSubtypes, @UserIdInt int userId) {
         if (userId == mSettings.getCurrentUserId()) {
             final InputMethodInfo imi;
-            if (imiId == null && mCurMethodId != null) {
-                imi = mMethodMap.get(mCurMethodId);
+            String selectedMethodId = getSelectedMethodId();
+            if (imiId == null && selectedMethodId != null) {
+                imi = mMethodMap.get(selectedMethodId);
             } else {
                 imi = mMethodMap.get(imiId);
             }
@@ -2233,9 +2195,10 @@
                             mCurFocusedWindow, 0, null, SoftInputShowHideReason.HIDE_REMOVE_CLIENT);
                     if (mBoundToMethod) {
                         mBoundToMethod = false;
-                        if (mCurMethod != null) {
-                            executeOrSendMessage(mCurMethod, mCaller.obtainMessageO(
-                                    MSG_UNBIND_INPUT, mCurMethod));
+                        IInputMethod curMethod = getCurMethod();
+                        if (curMethod != null) {
+                            executeOrSendMessage(curMethod, mCaller.obtainMessageO(
+                                    MSG_UNBIND_INPUT, curMethod));
                         }
                     }
                     mCurClient = null;
@@ -2263,16 +2226,17 @@
                     + mCurClient.client.asBinder());
             if (mBoundToMethod) {
                 mBoundToMethod = false;
-                if (mCurMethod != null) {
-                    executeOrSendMessage(mCurMethod, mCaller.obtainMessageO(
-                            MSG_UNBIND_INPUT, mCurMethod));
+                IInputMethod curMethod = getCurMethod();
+                if (curMethod != null) {
+                    executeOrSendMessage(curMethod, mCaller.obtainMessageO(
+                            MSG_UNBIND_INPUT, curMethod));
                 }
             }
 
             scheduleSetActiveToClient(mCurClient, false /* active */, false /* fullscreen */,
                     false /* reportToImeController */);
             executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIIO(
-                    MSG_UNBIND_CLIENT, mCurSeq, unbindClientReason, mCurClient.client));
+                    MSG_UNBIND_CLIENT, getSequenceNumber(), unbindClientReason, mCurClient.client));
             mCurClient.sessionRequested = false;
             mCurClient = null;
 
@@ -2281,6 +2245,12 @@
     }
 
     @GuardedBy("mMethodMap")
+    void clearInputShowRequestLocked() {
+        mShowRequested = mInputShown;
+        mInputShown = false;
+    }
+
+    @GuardedBy("mMethodMap")
     private int getImeShowFlagsLocked() {
         int flags = 0;
         if (mShowForced) {
@@ -2307,16 +2277,18 @@
     @NonNull
     InputBindResult attachNewInputLocked(@StartInputReason int startInputReason, boolean initial) {
         if (!mBoundToMethod) {
-            executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO(
-                    MSG_BIND_INPUT, mCurMethod, mCurClient.binding));
+            IInputMethod curMethod = getCurMethod();
+            executeOrSendMessage(curMethod, mCaller.obtainMessageOO(
+                    MSG_BIND_INPUT, curMethod, mCurClient.binding));
             mBoundToMethod = true;
         }
 
         final Binder startInputToken = new Binder();
-        final StartInputInfo info = new StartInputInfo(mSettings.getCurrentUserId(), mCurToken,
-                mCurTokenDisplayId, mCurId, startInputReason, !initial,
+        final StartInputInfo info = new StartInputInfo(mSettings.getCurrentUserId(), getCurToken(),
+                mCurTokenDisplayId, getCurId(), startInputReason, !initial,
                 UserHandle.getUserId(mCurClient.uid), mCurClient.selfReportedDisplayId,
-                mCurFocusedWindow, mCurAttribute, mCurFocusedWindowSoftInputMode, mCurSeq);
+                mCurFocusedWindow, mCurAttribute, mCurFocusedWindowSoftInputMode,
+                getSequenceNumber());
         mImeTargetWindowMap.put(startInputToken, mCurFocusedWindow);
         mStartInputHistory.addEntry(info);
 
@@ -2327,7 +2299,8 @@
         // INTERACT_ACROSS_USERS(_FULL) permissions, which is actually almost always the case.
         if (mSettings.getCurrentUserId() == UserHandle.getUserId(mCurClient.uid)) {
             mPackageManagerInternal.grantImplicitAccess(mSettings.getCurrentUserId(),
-                    null /* intent */, UserHandle.getAppId(mCurMethodUid), mCurClient.uid, true);
+                    null /* intent */, UserHandle.getAppId(getCurMethodUid()), mCurClient.uid,
+                    true /* direct */);
         }
 
         final SessionState session = mCurClient.curSession;
@@ -2339,12 +2312,14 @@
             showCurrentInputLocked(mCurFocusedWindow, getAppShowFlagsLocked(), null,
                     SoftInputShowHideReason.ATTACH_NEW_INPUT);
         }
-        final InputMethodInfo curInputMethodInfo = mMethodMap.get(mCurId);
+
+        String curId = getCurId();
+        final InputMethodInfo curInputMethodInfo = mMethodMap.get(curId);
         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, suppressesSpellChecker);
+                curId, getSequenceNumber(), suppressesSpellChecker);
     }
 
     @GuardedBy("mMethodMap")
@@ -2353,7 +2328,8 @@
             @NonNull EditorInfo attribute, @StartInputFlags int startInputFlags,
             @StartInputReason int startInputReason) {
         // If no method is currently selected, do nothing.
-        if (mCurMethodId == null) {
+        String selectedMethodId = getSelectedMethodId();
+        if (selectedMethodId == null) {
             return InputBindResult.NO_IME;
         }
 
@@ -2362,7 +2338,7 @@
             // party code.
             return new InputBindResult(
                     InputBindResult.ResultCode.ERROR_SYSTEM_NOT_READY,
-                    null, null, mCurMethodId, mCurSeq, false);
+                    null, null, selectedMethodId, getSequenceNumber(), false);
         }
 
         if (!InputMethodUtils.checkIfPackageBelongsToUid(mAppOpsManager, cs.uid,
@@ -2390,24 +2366,11 @@
         mImeHiddenByDisplayPolicy = false;
 
         if (mCurClient != cs) {
-            // Was the keyguard locked when switching over to the new client?
-            mCurClientInKeyguard = isKeyguardLocked();
-            // If the client is changing, we need to switch over to the new
-            // one.
-            unbindCurrentClientLocked(UnbindReason.SWITCH_CLIENT);
-            if (DEBUG) Slog.v(TAG, "switching to client: client="
-                    + cs.client.asBinder() + " keyguard=" + mCurClientInKeyguard);
-
-            // If the screen is on, inform the new client it is active
-            if (mIsInteractive) {
-                scheduleSetActiveToClient(cs, true /* active */, false /* fullscreen */,
-                        false /* reportToImeController */);
-            }
+            prepareClientSwitchLocked(cs);
         }
 
         // Bump up the sequence for this client and attach it.
-        mCurSeq++;
-        if (mCurSeq <= 0) mCurSeq = 1;
+        advanceSequenceNumber();
         mCurClient = cs;
         mCurInputContext = inputContext;
         mCurAttribute = attribute;
@@ -2415,24 +2378,57 @@
         // Check if the input method is changing.
         // We expect the caller has already verified that the client is allowed to access this
         // display ID.
-        if (mCurId != null && mCurId.equals(mCurMethodId)
-                && displayIdToShowIme == mCurTokenDisplayId) {
+        if (isSelectedMethodBound(displayIdToShowIme)) {
             if (cs.curSession != null) {
                 // Fast case: if we are already connected to the input method,
                 // then just return it.
                 return attachNewInputLocked(startInputReason,
                         (startInputFlags & StartInputFlags.INITIAL_CONNECTION) != 0);
             }
-            if (mHaveConnection) {
-                if (mCurMethod != null) {
-                    // Return to client, and we will get back with it when
-                    // we have had a session made for it.
-                    requestClientSessionLocked(cs);
-                    return new InputBindResult(
-                            InputBindResult.ResultCode.SUCCESS_WAITING_IME_SESSION,
-                            null, null, mCurId, mCurSeq, false);
-                } else if (SystemClock.uptimeMillis()
-                        < (mLastBindTime+TIME_TO_RECONNECT)) {
+
+            InputBindResult bindResult = tryReuseConnectionLocked(cs);
+            if (bindResult != null) {
+                return bindResult;
+            }
+        }
+
+        mBindingController.unbindCurrentMethodLocked();
+
+        return mBindingController.bindCurrentMethodLocked(displayIdToShowIme);
+    }
+
+    private boolean isSelectedMethodBound(int displayIdToShowIme) {
+        String curId = getCurId();
+        return curId != null && curId.equals(getSelectedMethodId())
+                && displayIdToShowIme == mCurTokenDisplayId;
+    }
+
+    @GuardedBy("mMethodMap")
+    private void prepareClientSwitchLocked(ClientState cs) {
+        // If the client is changing, we need to switch over to the new
+        // one.
+        unbindCurrentClientLocked(UnbindReason.SWITCH_CLIENT);
+        // If the screen is on, inform the new client it is active
+        if (mIsInteractive) {
+            scheduleSetActiveToClient(cs, true /* active */, false /* fullscreen */,
+                    false /* reportToImeController */);
+        }
+    }
+
+    @GuardedBy("mMethodMap")
+    @Nullable
+    private InputBindResult tryReuseConnectionLocked(@NonNull ClientState cs) {
+        if (hasConnection()) {
+            if (getCurMethod() != null) {
+                // Return to client, and we will get back with it when
+                // we have had a session made for it.
+                requestClientSessionLocked(cs);
+                return new InputBindResult(
+                        InputBindResult.ResultCode.SUCCESS_WAITING_IME_SESSION,
+                        null, null, getCurId(), getSequenceNumber(), false);
+            } else {
+                long bindingDuration = SystemClock.uptimeMillis() - getLastBindTime();
+                if (bindingDuration < TIME_TO_RECONNECT) {
                     // In this case we have connected to the service, but
                     // don't yet have its interface.  If it hasn't been too
                     // long since we did the connection, we'll return to
@@ -2442,51 +2438,14 @@
                     // 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, false);
+                            null, null, getCurId(), getSequenceNumber(), false);
                 } else {
                     EventLog.writeEvent(EventLogTags.IMF_FORCE_RECONNECT_IME,
-                            mCurMethodId, SystemClock.uptimeMillis()-mLastBindTime, 0);
+                            getSelectedMethodId(), bindingDuration, 0);
                 }
             }
         }
-
-        InputMethodInfo info = mMethodMap.get(mCurMethodId);
-        if (info == null) {
-            throw new IllegalArgumentException("Unknown id: " + mCurMethodId);
-        }
-
-        unbindCurrentMethodLocked();
-
-        mCurIntent = new Intent(InputMethod.SERVICE_INTERFACE);
-        mCurIntent.setComponent(info.getComponent());
-        mCurIntent.putExtra(Intent.EXTRA_CLIENT_LABEL,
-                com.android.internal.R.string.input_method_binding_label);
-        mCurIntent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity(
-                mContext, 0, new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS),
-                PendingIntent.FLAG_IMMUTABLE));
-
-        if (bindCurrentInputMethodServiceLocked(mCurIntent, this, mImeConnectionBindFlags)) {
-            mLastBindTime = SystemClock.uptimeMillis();
-            mHaveConnection = true;
-            mCurId = info.getId();
-            mCurToken = new Binder();
-            mCurTokenDisplayId = displayIdToShowIme;
-            try {
-                if (DEBUG) {
-                    Slog.v(TAG, "Adding window token: " + mCurToken + " for display: "
-                            + mCurTokenDisplayId);
-                }
-                mIWindowManager.addWindowToken(mCurToken, LayoutParams.TYPE_INPUT_METHOD,
-                        mCurTokenDisplayId, null /* options */);
-            } catch (RemoteException e) {
-            }
-            return new InputBindResult(
-                    InputBindResult.ResultCode.SUCCESS_WAITING_IME_BINDING,
-                    null, null, mCurId, mCurSeq, false);
-        }
-        mCurIntent = null;
-        Slog.w(TAG, "Failure connecting to input method service: " + mCurIntent);
-        return InputBindResult.IME_NOT_CONNECTED;
+        return null;
     }
 
     @FunctionalInterface
@@ -2522,46 +2481,11 @@
     }
 
     @AnyThread
-    private void scheduleNotifyImeUidToAudioService(int uid) {
+    void scheduleNotifyImeUidToAudioService(int uid) {
         mCaller.removeMessages(MSG_NOTIFY_IME_UID_TO_AUDIO_SERVICE);
         mCaller.obtainMessageI(MSG_NOTIFY_IME_UID_TO_AUDIO_SERVICE, uid).sendToTarget();
     }
 
-    @Override
-    public void onServiceConnected(ComponentName name, IBinder service) {
-        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.onServiceConnected");
-        synchronized (mMethodMap) {
-            if (mCurIntent != null && name.equals(mCurIntent.getComponent())) {
-                mCurMethod = IInputMethod.Stub.asInterface(service);
-                final String curMethodPackage = mCurIntent.getComponent().getPackageName();
-                final int curMethodUid = mPackageManagerInternal.getPackageUid(
-                        curMethodPackage, 0 /* flags */, mSettings.getCurrentUserId());
-                if (curMethodUid < 0) {
-                    Slog.e(TAG, "Failed to get UID for package=" + curMethodPackage);
-                    mCurMethodUid = Process.INVALID_UID;
-                } else {
-                    mCurMethodUid = curMethodUid;
-                }
-                if (mCurToken == null) {
-                    Slog.w(TAG, "Service connected without a token!");
-                    unbindCurrentMethodLocked();
-                    Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
-                    return;
-                }
-                if (DEBUG) Slog.v(TAG, "Initiating attach with token: " + mCurToken);
-                // Dispatch display id for InputMethodService to update context display.
-                executeOrSendMessage(mCurMethod, mCaller.obtainMessageIOO(MSG_INITIALIZE_IME,
-                        mMethodMap.get(mCurMethodId).getConfigChanges(), mCurMethod, mCurToken));
-                scheduleNotifyImeUidToAudioService(mCurMethodUid);
-                if (mCurClient != null) {
-                    clearClientSessionLocked(mCurClient);
-                    requestClientSessionLocked(mCurClient);
-                }
-            }
-        }
-        Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
-    }
-
     void onSessionCreated(IInputMethod method, IInputMethodSession session,
             InputChannel channel) {
         synchronized (mMethodMap) {
@@ -2570,8 +2494,9 @@
                 channel.dispose();
                 return;
             }
-            if (mCurMethod != null && method != null
-                    && mCurMethod.asBinder() == method.asBinder()) {
+            IInputMethod curMethod = getCurMethod();
+            if (curMethod != null && method != null
+                    && curMethod.asBinder() == method.asBinder()) {
                 if (mCurClient != null) {
                     clearClientSessionLocked(mCurClient);
                     mCurClient.curSession = new SessionState(mCurClient,
@@ -2592,53 +2517,40 @@
     }
 
     @GuardedBy("mMethodMap")
-    void unbindCurrentMethodLocked() {
-        if (mVisibleBound) {
-            mContext.unbindService(mVisibleConnection);
-            mVisibleBound = false;
-        }
-
-        if (mHaveConnection) {
-            mContext.unbindService(this);
-            mHaveConnection = false;
-        }
-
-        if (mCurToken != null) {
-            if (DEBUG) {
-                Slog.v(TAG, "Removing window token: " + mCurToken + " for display: "
-                        + mCurTokenDisplayId);
-            }
-            mWindowManagerInternal.removeWindowToken(mCurToken, false /* removeWindows */,
-                    false /* animateExit */, mCurTokenDisplayId);
-            // Set IME window status as invisible when unbind current method.
-            mImeWindowVis = 0;
-            mBackDisposition = InputMethodService.BACK_DISPOSITION_DEFAULT;
-            updateSystemUiLocked(mImeWindowVis, mBackDisposition);
-            mCurToken = null;
-            mCurTokenDisplayId = INVALID_DISPLAY;
-            mCurHostInputToken = null;
-        }
-
-        mCurId = null;
-        clearCurMethodLocked();
+    void resetSystemUiLocked() {
+        // Set IME window status as invisible when unbinding current method.
+        mImeWindowVis = 0;
+        mBackDisposition = InputMethodService.BACK_DISPOSITION_DEFAULT;
+        updateSystemUiLocked(mImeWindowVis, mBackDisposition);
+        mCurTokenDisplayId = INVALID_DISPLAY;
+        mCurHostInputToken = null;
     }
 
     @GuardedBy("mMethodMap")
     void resetCurrentMethodAndClientLocked(@UnbindReason int unbindClientReason) {
-        mCurMethodId = null;
-        unbindCurrentMethodLocked();
+        setSelectedMethodId(null);
+        mBindingController.unbindCurrentMethodLocked();
         unbindCurrentClientLocked(unbindClientReason);
     }
 
     @GuardedBy("mMethodMap")
+    void reRequestCurrentClientSessionLocked() {
+        if (mCurClient != null) {
+            clearClientSessionLocked(mCurClient);
+            requestClientSessionLocked(mCurClient);
+        }
+    }
+
+    @GuardedBy("mMethodMap")
     void requestClientSessionLocked(ClientState cs) {
         if (!cs.sessionRequested) {
             if (DEBUG) Slog.v(TAG, "Creating new session for client " + cs);
             InputChannel[] channels = InputChannel.openInputChannelPair(cs.toString());
             cs.sessionRequested = true;
-            executeOrSendMessage(mCurMethod, mCaller.obtainMessageOOO(
-                    MSG_CREATE_SESSION, mCurMethod, channels[1],
-                    new MethodCallback(this, mCurMethod, channels[0])));
+            IInputMethod curMethod = getCurMethod();
+            executeOrSendMessage(curMethod, mCaller.obtainMessageOOO(
+                    MSG_CREATE_SESSION, curMethod, channels[1],
+                    new MethodCallback(this, curMethod, channels[0])));
         }
     }
 
@@ -2669,8 +2581,8 @@
     }
 
     @GuardedBy("mMethodMap")
-    void clearCurMethodLocked() {
-        if (mCurMethod != null) {
+    void clearClientSessionsLocked() {
+        if (getCurMethod() != null) {
             final int numClients = mClients.size();
             for (int i = 0; i < numClients; ++i) {
                 clearClientSessionLocked(mClients.valueAt(i));
@@ -2678,41 +2590,13 @@
 
             finishSessionLocked(mEnabledSession);
             mEnabledSession = null;
-            mCurMethod = null;
-            mCurMethodUid = Process.INVALID_UID;
-            scheduleNotifyImeUidToAudioService(mCurMethodUid);
+            mBindingController.clearCurMethodLocked();
+            scheduleNotifyImeUidToAudioService(Process.INVALID_UID);
         }
-        if (mStatusBar != null) {
-            mStatusBar.setIconVisibility(mSlotIme, false);
-        }
+        hideStatusBarIconLocked();
         mInFullscreenMode = false;
     }
 
-    @Override
-    public void onServiceDisconnected(ComponentName name) {
-        // Note that mContext.unbindService(this) does not trigger this.  Hence if we are here the
-        // disconnection is not intended by IMMS (e.g. triggered because the current IMS crashed),
-        // which is irregular but can eventually happen for everyone just by continuing using the
-        // device.  Thus it is important to make sure that all the internal states are properly
-        // refreshed when this method is called back.  Running
-        //    adb install -r <APK that implements the current IME>
-        // would be a good way to trigger such a situation.
-        synchronized (mMethodMap) {
-            if (DEBUG) Slog.v(TAG, "Service disconnected: " + name
-                    + " mCurIntent=" + mCurIntent);
-            if (mCurMethod != null && mCurIntent != null
-                    && name.equals(mCurIntent.getComponent())) {
-                clearCurMethodLocked();
-                // We consider this to be a new bind attempt, since the system
-                // should now try to restart the service for us.
-                mLastBindTime = SystemClock.uptimeMillis();
-                mShowRequested = mInputShown;
-                mInputShown = false;
-                unbindCurrentClientLocked(UnbindReason.DISCONNECT_IME);
-            }
-        }
-    }
-
     @BinderThread
     private void updateStatusIcon(@NonNull IBinder token, String packageName,
             @DrawableRes int iconId) {
@@ -2724,9 +2608,7 @@
             try {
                 if (iconId == 0) {
                     if (DEBUG) Slog.d(TAG, "hide the small icon for the input method");
-                    if (mStatusBar != null) {
-                        mStatusBar.setIconVisibility(mSlotIme, false);
-                    }
+                    hideStatusBarIconLocked();
                 } else if (packageName != null) {
                     if (DEBUG) Slog.d(TAG, "show a small icon for the input method");
                     CharSequence contentDescription = null;
@@ -2753,6 +2635,13 @@
     }
 
     @GuardedBy("mMethodMap")
+    private void hideStatusBarIconLocked() {
+        if (mStatusBar != null) {
+            mStatusBar.setIconVisibility(mSlotIme, false);
+        }
+    }
+
+    @GuardedBy("mMethodMap")
     private boolean shouldShowImeSwitcherLocked(int visibility) {
         if (!mShowOngoingImeSwitcherForPhones) return false;
         if (mMenuController.getSwitchingDialogLocked() != null) return false;
@@ -2816,11 +2705,6 @@
         return false;
     }
 
-    @GuardedBy("mMethodMap")
-    private boolean isKeyguardLocked() {
-        return mKeyguardManager != null && mKeyguardManager.isKeyguardLocked();
-    }
-
     @BinderThread
     @SuppressWarnings("deprecation")
     private void setImeWindowStatus(@NonNull IBinder token, int vis, int backDisposition) {
@@ -2891,7 +2775,7 @@
     // Caution! This method is called in this class. Handle multi-user carefully
     @GuardedBy("mMethodMap")
     private void updateSystemUiLocked(int vis, int backDisposition) {
-        if (mCurToken == null) {
+        if (getCurToken() == null) {
             return;
         }
         if (DEBUG) {
@@ -2905,20 +2789,16 @@
         // all updateSystemUi happens on system previlege.
         final long ident = Binder.clearCallingIdentity();
         try {
-            // apply policy for binder calls
-            if (vis != 0 && isKeyguardLocked() && !mCurClientInKeyguard) {
-                vis = 0;
-            }
             if (!mCurPerceptible) {
                 vis &= ~InputMethodService.IME_VISIBLE;
             }
             // mImeWindowVis should be updated before calling shouldShowImeSwitcherLocked().
             final boolean needsToShowImeSwitcher = shouldShowImeSwitcherLocked(vis);
             if (mStatusBar != null) {
-                mStatusBar.setImeWindowStatus(mCurTokenDisplayId, mCurToken, vis, backDisposition,
-                        needsToShowImeSwitcher);
+                mStatusBar.setImeWindowStatus(mCurTokenDisplayId, getCurToken(), vis,
+                        backDisposition, needsToShowImeSwitcher);
             }
-            final InputMethodInfo imi = mMethodMap.get(mCurMethodId);
+            final InputMethodInfo imi = mMethodMap.get(getSelectedMethodId());
             if (imi != null && needsToShowImeSwitcher) {
                 // Used to load label
                 final CharSequence title = mRes.getText(
@@ -3026,7 +2906,7 @@
         }
 
         // See if we need to notify a subtype change within the same IME.
-        if (id.equals(mCurMethodId)) {
+        if (id.equals(getSelectedMethodId())) {
             final int subtypeCount = info.getSubtypeCount();
             if (subtypeCount <= 0) {
                 return;
@@ -3047,10 +2927,11 @@
             }
             if (newSubtype != oldSubtype) {
                 setSelectedInputMethodAndSubtypeLocked(info, subtypeId, true);
-                if (mCurMethod != null) {
+                IInputMethod curMethod = getCurMethod();
+                if (curMethod != null) {
                     try {
                         updateSystemUiLocked(mImeWindowVis, mBackDisposition);
-                        mCurMethod.changeInputMethodSubtype(newSubtype);
+                        curMethod.changeInputMethodSubtype(newSubtype);
                     } catch (RemoteException e) {
                         Slog.w(TAG, "Failed to call changeInputMethodSubtype");
                     }
@@ -3068,7 +2949,7 @@
             // mCurMethodId should be updated after setSelectedInputMethodAndSubtypeLocked()
             // because mCurMethodId is stored as a history in
             // setSelectedInputMethodAndSubtypeLocked().
-            mCurMethodId = id;
+            setSelectedMethodId(id);
 
             if (LocalServices.getService(ActivityManagerInternal.class).isSystemReady()) {
                 Intent intent = new Intent(Intent.ACTION_INPUT_METHOD_CHANGED);
@@ -3162,35 +3043,37 @@
         }
 
         boolean res = false;
-        if (mCurMethod != null) {
-            if (DEBUG) Slog.d(TAG, "showCurrentInputLocked: mCurToken=" + mCurToken);
+        IInputMethod curMethod = getCurMethod();
+        if (curMethod != null) {
+            if (DEBUG) Slog.d(TAG, "showCurrentInputLocked: mCurToken=" + getCurToken());
             // create a placeholder token for IMS so that IMS cannot inject windows into client app.
             Binder showInputToken = new Binder();
             mShowRequestWindowMap.put(showInputToken, windowToken);
-            executeOrSendMessage(mCurMethod, mCaller.obtainMessageIIOOO(MSG_SHOW_SOFT_INPUT,
-                    getImeShowFlagsLocked(), reason, mCurMethod, resultReceiver, showInputToken));
+            executeOrSendMessage(curMethod, mCaller.obtainMessageIIOOO(MSG_SHOW_SOFT_INPUT,
+                    getImeShowFlagsLocked(), reason, curMethod, resultReceiver,
+                    showInputToken));
             mInputShown = true;
-            if (mHaveConnection && !mVisibleBound) {
-                bindCurrentInputMethodServiceLocked(
-                        mCurIntent, mVisibleConnection, IME_VISIBLE_BIND_FLAGS);
-                mVisibleBound = true;
+            if (hasConnection() && !isVisibleBound()) {
+                mBindingController.bindCurrentInputMethodServiceVisibleConnectionLocked();
             }
             res = true;
-        } else if (mHaveConnection && SystemClock.uptimeMillis()
-                >= (mLastBindTime+TIME_TO_RECONNECT)) {
-            // The client has asked to have the input method shown, but
-            // we have been sitting here too long with a connection to the
-            // service and no interface received, so let's disconnect/connect
-            // to try to prod things along.
-            EventLog.writeEvent(EventLogTags.IMF_FORCE_RECONNECT_IME, mCurMethodId,
-                    SystemClock.uptimeMillis()-mLastBindTime,1);
-            Slog.w(TAG, "Force disconnect/connect to the IME in showCurrentInputLocked()");
-            mContext.unbindService(this);
-            bindCurrentInputMethodServiceLocked(mCurIntent, this, mImeConnectionBindFlags);
         } else {
-            if (DEBUG) {
-                Slog.d(TAG, "Can't show input: connection = " + mHaveConnection + ", time = "
-                        + ((mLastBindTime+TIME_TO_RECONNECT) - SystemClock.uptimeMillis()));
+            long bindingDuration = SystemClock.uptimeMillis() - getLastBindTime();
+            if (hasConnection() && bindingDuration >= TIME_TO_RECONNECT) {
+                // The client has asked to have the input method shown, but
+                // we have been sitting here too long with a connection to the
+                // service and no interface received, so let's disconnect/connect
+                // to try to prod things along.
+                EventLog.writeEvent(EventLogTags.IMF_FORCE_RECONNECT_IME, getSelectedMethodId(),
+                        bindingDuration, 1);
+                Slog.w(TAG, "Force disconnect/connect to the IME in showCurrentInputLocked()");
+                mBindingController.unbindMainConnectionLocked();
+                mBindingController.bindCurrentInputMethodServiceMainConnectionLocked();
+            } else {
+                if (DEBUG) {
+                    Slog.d(TAG, "Can't show input: connection = " + hasConnection() + ", time = "
+                            + (TIME_TO_RECONNECT - bindingDuration));
+                }
             }
         }
 
@@ -3261,7 +3144,8 @@
         // since Android Eclair.  That's why we need to accept IMM#hideSoftInput() even when only
         // IMMS#InputShown indicates that the software keyboard is shown.
         // TODO: Clean up, IMMS#mInputShown, IMMS#mImeWindowVis and mShowRequested.
-        final boolean shouldHideSoftInput = (mCurMethod != null) && (mInputShown
+        IInputMethod curMethod = getCurMethod();
+        final boolean shouldHideSoftInput = (curMethod != null) && (mInputShown
                 || (mImeWindowVis & InputMethodService.IME_ACTIVE) != 0);
         boolean res;
         if (shouldHideSoftInput) {
@@ -3271,15 +3155,14 @@
             // delivered to the IME process as an IPC.  Hence the inconsistency between
             // IMMS#mInputShown and IMMS#mImeWindowVis should be resolved spontaneously in
             // the final state.
-            executeOrSendMessage(mCurMethod, mCaller.obtainMessageIOOO(MSG_HIDE_SOFT_INPUT,
-                    reason, mCurMethod, resultReceiver, hideInputToken));
+            executeOrSendMessage(curMethod, mCaller.obtainMessageIOOO(MSG_HIDE_SOFT_INPUT,
+                    reason, curMethod, resultReceiver, hideInputToken));
             res = true;
         } else {
             res = false;
         }
-        if (mHaveConnection && mVisibleBound) {
-            mContext.unbindService(mVisibleConnection);
-            mVisibleBound = false;
+        if (hasConnection() && isVisibleBound()) {
+            mBindingController.unbindVisibleConnectionLocked();
         }
         mInputShown = false;
         mShowRequested = false;
@@ -3519,7 +3402,7 @@
                         // Note that we can trust client's display ID as long as it matches
                         // to the display ID obtained from the window.
                         if (cs.selfReportedDisplayId != mCurTokenDisplayId) {
-                            unbindCurrentMethodLocked();
+                            mBindingController.unbindCurrentMethodLocked();
                         }
                     }
                 } else if (isTextEditor && doAutoShow
@@ -3645,10 +3528,10 @@
         if (mCurFocusedWindowClient != null && client != null
                 && mCurFocusedWindowClient.client.asBinder() == client.asBinder()) {
             return true;
-        } else if (mCurIntent != null && InputMethodUtils.checkIfPackageBelongsToUid(
+        } else if (getCurIntent() != null && InputMethodUtils.checkIfPackageBelongsToUid(
                 mAppOpsManager,
                 uid,
-                mCurIntent.getComponent().getPackageName())) {
+                getCurIntent().getComponent().getPackageName())) {
             return true;
         }
         return false;
@@ -3734,7 +3617,7 @@
             if (!calledFromValidUserLocked()) {
                 return;
             }
-            executeOrSendMessage(mCurMethod, mCaller.obtainMessageO(
+            executeOrSendMessage(getCurMethod(), mCaller.obtainMessageO(
                     MSG_SHOW_IM_SUBTYPE_ENABLER, inputMethodId));
         }
     }
@@ -3755,7 +3638,7 @@
             String targetLastImiId = null;
             int subtypeId = NOT_A_SUBTYPE_ID;
             if (lastIme != null && lastImi != null) {
-                final boolean imiIdIsSame = lastImi.getId().equals(mCurMethodId);
+                final boolean imiIdIsSame = lastImi.getId().equals(getSelectedMethodId());
                 final int lastSubtypeHash = Integer.parseInt(lastIme.second);
                 final int currentSubtypeHash = mCurrentSubtype == null ? NOT_A_SUBTYPE_ID
                         : mCurrentSubtype.hashCode();
@@ -3801,7 +3684,7 @@
             if (!TextUtils.isEmpty(targetLastImiId)) {
                 if (DEBUG) {
                     Slog.d(TAG, "Switch to: " + lastImi.getId() + ", " + lastIme.second
-                            + ", from: " + mCurMethodId + ", " + subtypeId);
+                            + ", from: " + getSelectedMethodId() + ", " + subtypeId);
                 }
                 setInputMethodWithSubtypeIdLocked(token, targetLastImiId, subtypeId);
                 return true;
@@ -3818,7 +3701,7 @@
                 return false;
             }
             final ImeSubtypeListItem nextSubtype = mSwitchingController.getNextInputMethodLocked(
-                    onlyCurrentIme, mMethodMap.get(mCurMethodId), mCurrentSubtype);
+                    onlyCurrentIme, mMethodMap.get(getSelectedMethodId()), mCurrentSubtype);
             if (nextSubtype == null) {
                 return false;
             }
@@ -3835,7 +3718,8 @@
                 return false;
             }
             final ImeSubtypeListItem nextSubtype = mSwitchingController.getNextInputMethodLocked(
-                    false /* onlyCurrentIme */, mMethodMap.get(mCurMethodId), mCurrentSubtype);
+                    false /* onlyCurrentIme */, mMethodMap.get(getSelectedMethodId()),
+                    mCurrentSubtype);
             if (nextSubtype == null) {
                 return false;
             }
@@ -4049,8 +3933,8 @@
     private void dumpDebug(ProtoOutputStream proto, long fieldId) {
         synchronized (mMethodMap) {
             final long token = proto.start(fieldId);
-            proto.write(CUR_METHOD_ID, mCurMethodId);
-            proto.write(CUR_SEQ, mCurSeq);
+            proto.write(CUR_METHOD_ID, getSelectedMethodId());
+            proto.write(CUR_SEQ, getSequenceNumber());
             proto.write(CUR_CLIENT, Objects.toString(mCurClient));
             proto.write(CUR_FOCUSED_WINDOW_NAME,
                     mWindowManagerInternal.getWindowName(mCurFocusedWindow));
@@ -4061,17 +3945,17 @@
             if (mCurAttribute != null) {
                 mCurAttribute.dumpDebug(proto, CUR_ATTRIBUTE);
             }
-            proto.write(CUR_ID, mCurId);
+            proto.write(CUR_ID, getCurId());
             proto.write(SHOW_REQUESTED, mShowRequested);
             proto.write(SHOW_EXPLICITLY_REQUESTED, mShowExplicitlyRequested);
             proto.write(SHOW_FORCED, mShowForced);
             proto.write(INPUT_SHOWN, mInputShown);
             proto.write(IN_FULLSCREEN_MODE, mInFullscreenMode);
-            proto.write(CUR_TOKEN, Objects.toString(mCurToken));
+            proto.write(CUR_TOKEN, Objects.toString(getCurToken()));
             proto.write(CUR_TOKEN_DISPLAY_ID, mCurTokenDisplayId);
             proto.write(SYSTEM_READY, mSystemReady);
             proto.write(LAST_SWITCH_USER_ID, mLastSwitchUserId);
-            proto.write(HAVE_CONNECTION, mHaveConnection);
+            proto.write(HAVE_CONNECTION, hasConnection());
             proto.write(BOUND_TO_METHOD, mBoundToMethod);
             proto.write(IS_INTERACTIVE, mIsInteractive);
             proto.write(BACK_DISPOSITION, mBackDisposition);
@@ -4089,14 +3973,14 @@
             Slog.d(TAG, "Got the notification of a user action.");
         }
         synchronized (mMethodMap) {
-            if (mCurToken != token) {
+            if (getCurToken() != token) {
                 if (DEBUG) {
                     Slog.d(TAG, "Ignoring the user action notification from IMEs that are no longer"
                             + " active.");
                 }
                 return;
             }
-            final InputMethodInfo imi = mMethodMap.get(mCurMethodId);
+            final InputMethodInfo imi = mMethodMap.get(getSelectedMethodId());
             if (imi != null) {
                 mSwitchingController.onUserActionLocked(imi, mCurrentSubtype);
             }
@@ -4140,7 +4024,7 @@
                         "Using null token requires permission "
                         + android.Manifest.permission.WRITE_SECURE_SETTINGS);
             }
-        } else if (mCurToken != token) {
+        } else if (getCurToken() != token) {
             Slog.w(TAG, "Ignoring setInputMethod of uid " + Binder.getCallingUid()
                     + " token: " + token);
             return;
@@ -4512,7 +4396,7 @@
                 boolean reportToImeController = false;
                 try {
                     reportToImeController = mPlatformCompat.isChangeEnabledByUid(
-                            FINISH_INPUT_NO_FALLBACK_CONNECTION, mCurMethodUid);
+                            FINISH_INPUT_NO_FALLBACK_CONNECTION, getCurMethodUid());
                 } catch (RemoteException e) {
                 }
                 scheduleSetActiveToClient(mCurClient, mIsInteractive, mInFullscreenMode,
@@ -4802,7 +4686,7 @@
     @GuardedBy("mMethodMap")
     private void setSelectedInputMethodAndSubtypeLocked(InputMethodInfo imi, int subtypeId,
             boolean setSubtypeOnly) {
-        mSettings.saveCurrentInputMethodAndSubtypeToHistory(mCurMethodId, mCurrentSubtype);
+        mSettings.saveCurrentInputMethodAndSubtypeToHistory(getSelectedMethodId(), mCurrentSubtype);
 
         // Set Subtype here
         if (imi == null || subtypeId < 0) {
@@ -4861,17 +4745,18 @@
 
     @GuardedBy("mMethodMap")
     InputMethodSubtype getCurrentInputMethodSubtypeLocked() {
-        if (mCurMethodId == null) {
+        String selectedMethodId = getSelectedMethodId();
+        if (selectedMethodId == null) {
             return null;
         }
         final boolean subtypeIsSelected = mSettings.isSubtypeSelected();
-        final InputMethodInfo imi = mMethodMap.get(mCurMethodId);
+        final InputMethodInfo imi = mMethodMap.get(selectedMethodId);
         if (imi == null || imi.getSubtypeCount() == 0) {
             return null;
         }
         if (!subtypeIsSelected || mCurrentSubtype == null
                 || !InputMethodUtils.isValidSubtypeId(imi, mCurrentSubtype.hashCode())) {
-            int subtypeId = mSettings.getSelectedInputMethodSubtypeId(mCurMethodId);
+            int subtypeId = mSettings.getSelectedInputMethodSubtypeId(selectedMethodId);
             if (subtypeId == NOT_A_SUBTYPE_ID) {
                 // If there are no selected subtypes, the framework will try to find
                 // the most applicable subtype from explicitly or implicitly enabled
@@ -4901,7 +4786,7 @@
 
     @Nullable
     String getCurrentMethodId() {
-        return mCurMethodId;
+        return getSelectedMethodId();
     }
 
     private List<InputMethodInfo> getInputMethodListAsUser(@UserIdInt int userId) {
@@ -5075,11 +4960,11 @@
 
         synchronized (mMethodMap) {
             final int uid = Binder.getCallingUid();
-            if (mCurMethodId == null) {
+            if (getSelectedMethodId() == null) {
                 return null;
             }
-            if (mCurToken != token) {
-                Slog.e(TAG, "Ignoring createInputContentUriToken mCurToken=" + mCurToken
+            if (getCurToken() != token) {
+                Slog.e(TAG, "Ignoring createInputContentUriToken mCurToken=" + getCurToken()
                         + " token=" + token);
                 return null;
             }
@@ -5214,23 +5099,23 @@
                 p.println("    sessionRequested=" + ci.sessionRequested);
                 p.println("    curSession=" + ci.curSession);
             }
-            p.println("  mCurMethodId=" + mCurMethodId);
+            p.println("  mCurMethodId=" + getSelectedMethodId());
             client = mCurClient;
-            p.println("  mCurClient=" + client + " mCurSeq=" + mCurSeq);
+            p.println("  mCurClient=" + client + " mCurSeq=" + getSequenceNumber());
             p.println("  mCurPerceptible=" + mCurPerceptible);
             p.println("  mCurFocusedWindow=" + mCurFocusedWindow
                     + " softInputMode=" +
                     InputMethodDebug.softInputModeToString(mCurFocusedWindowSoftInputMode)
                     + " client=" + mCurFocusedWindowClient);
             focusedWindowClient = mCurFocusedWindowClient;
-            p.println("  mCurId=" + mCurId + " mHaveConnection=" + mHaveConnection
-                    + " mBoundToMethod=" + mBoundToMethod + " mVisibleBound=" + mVisibleBound);
-            p.println("  mCurToken=" + mCurToken);
+            p.println("  mCurId=" + getCurId() + " mHaveConnection=" + hasConnection()
+                    + " mBoundToMethod=" + mBoundToMethod + " mVisibleBound=" + isVisibleBound());
+            p.println("  mCurToken=" + getCurToken());
             p.println("  mCurTokenDisplayId=" + mCurTokenDisplayId);
             p.println("  mCurHostInputToken=" + mCurHostInputToken);
-            p.println("  mCurIntent=" + mCurIntent);
-            method = mCurMethod;
-            p.println("  mCurMethod=" + mCurMethod);
+            p.println("  mCurIntent=" + getCurIntent());
+            method = getCurMethod();
+            p.println("  mCurMethod=" + getCurMethod());
             p.println("  mEnabledSession=" + mEnabledSession);
             p.println("  mShowRequested=" + mShowRequested
                     + " mShowExplicitlyRequested=" + mShowExplicitlyRequested
@@ -5736,7 +5621,7 @@
                 if (userId == mSettings.getCurrentUserId()) {
                     hideCurrentInputLocked(mCurFocusedWindow, 0, null,
                             SoftInputShowHideReason.HIDE_RESET_SHELL_COMMAND);
-                    unbindCurrentMethodLocked();
+                    mBindingController.unbindCurrentMethodLocked();
                     // Reset the current IME
                     resetSelectedInputMethodAndSubtypeLocked(null);
                     // Also reset the settings of the current IME
diff --git a/services/core/java/com/android/server/locales/LocaleManagerService.java b/services/core/java/com/android/server/locales/LocaleManagerService.java
index ffeaad1..457c2fd 100644
--- a/services/core/java/com/android/server/locales/LocaleManagerService.java
+++ b/services/core/java/com/android/server/locales/LocaleManagerService.java
@@ -154,10 +154,10 @@
         final ActivityTaskManagerInternal.PackageConfigurationUpdater updater =
                 mActivityTaskManagerInternal.createPackageConfigurationUpdater(appPackageName,
                         userId);
-        boolean isSuccess = updater.setLocales(locales).commit();
+        boolean isConfigChanged = updater.setLocales(locales).commit();
 
         //We want to send the broadcasts only if config was actually updated on commit.
-        if (isSuccess) {
+        if (isConfigChanged) {
             notifyAppWhoseLocaleChanged(appPackageName, userId, locales);
             notifyInstallerOfAppWhoseLocaleChanged(appPackageName, userId, locales);
             notifyRegisteredReceivers(appPackageName, userId, locales);
diff --git a/services/core/java/com/android/server/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java
index cd26fb5..2550e3a 100644
--- a/services/core/java/com/android/server/location/LocationManagerService.java
+++ b/services/core/java/com/android/server/location/LocationManagerService.java
@@ -39,6 +39,7 @@
 import android.Manifest.permission;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
 import android.app.ActivityManager;
 import android.app.AppOpsManager;
 import android.app.PendingIntent;
@@ -1239,6 +1240,32 @@
     }
 
     @Override
+    @RequiresPermission(android.Manifest.permission.AUTOMOTIVE_GNSS_CONTROLS)
+    public void setAutoGnssSuspended(boolean suspended) {
+        mContext.enforceCallingPermission(permission.AUTOMOTIVE_GNSS_CONTROLS, null);
+
+        if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
+            throw new IllegalStateException(
+                    "setAutoGnssSuspended only allowed on automotive devices");
+        }
+
+        mGnssManagerService.setAutoGnssSuspended(suspended);
+    }
+
+    @Override
+    @RequiresPermission(android.Manifest.permission.AUTOMOTIVE_GNSS_CONTROLS)
+    public boolean isAutoGnssSuspended() {
+        mContext.enforceCallingPermission(permission.AUTOMOTIVE_GNSS_CONTROLS, null);
+
+        if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
+            throw new IllegalStateException(
+                    "isAutoGnssSuspended only allowed on automotive devices");
+        }
+
+        return mGnssManagerService.isAutoGnssSuspended();
+    }
+
+    @Override
     public boolean geocoderIsPresent() {
         return mGeocodeProvider != null;
     }
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubClientBroker.java b/services/core/java/com/android/server/location/contexthub/ContextHubClientBroker.java
index b676f28..efd3037 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubClientBroker.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubClientBroker.java
@@ -30,6 +30,7 @@
 import android.compat.annotation.EnabledAfter;
 import android.content.Context;
 import android.content.Intent;
+import android.hardware.contexthub.HostEndpointInfo;
 import android.hardware.location.ContextHubInfo;
 import android.hardware.location.ContextHubManager;
 import android.hardware.location.ContextHubTransaction;
@@ -42,6 +43,7 @@
 import android.os.Build;
 import android.os.IBinder;
 import android.os.Looper;
+import android.os.Process;
 import android.os.RemoteException;
 import android.util.Log;
 import android.util.proto.ProtoOutputStream;
@@ -329,6 +331,15 @@
         mAppOpsManager = context.getSystemService(AppOpsManager.class);
 
         startMonitoringOpChanges();
+
+        HostEndpointInfo info = new HostEndpointInfo();
+        info.hostEndpointId = (char) mHostEndPointId;
+        info.packageName = mPackage;
+        info.attributionTag = mAttributionTag;
+        info.type = (mUid == Process.SYSTEM_UID)
+             ? HostEndpointInfo.Type.TYPE_FRAMEWORK
+             : HostEndpointInfo.Type.TYPE_APP;
+        mContextHubProxy.onHostEndpointConnected(info);
     }
 
     /* package */ ContextHubClientBroker(
@@ -862,6 +873,8 @@
             mRegistered = false;
         }
         mAppOpsManager.stopWatchingMode(this);
+
+        mContextHubProxy.onHostEndpointDisconnected(mHostEndPointId);
     }
 
     private String authStateToString(@ContextHubManager.AuthorizationState int state) {
diff --git a/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java b/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java
index 74630d1..9078f3f 100644
--- a/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java
+++ b/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java
@@ -17,6 +17,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.hardware.contexthub.HostEndpointInfo;
 import android.hardware.contexthub.V1_0.ContextHub;
 import android.hardware.contexthub.V1_0.ContextHubMsg;
 import android.hardware.contexthub.V1_0.TransactionResult;
@@ -239,6 +240,20 @@
     public abstract void onMicrophoneSettingChanged(boolean enabled);
 
     /**
+     * Invoked whenever a host client connects with the framework.
+     *
+     * @param info The host endpoint info.
+     */
+    public void onHostEndpointConnected(HostEndpointInfo info) {}
+
+    /**
+     * Invoked whenever a host client disconnects from the framework.
+     *
+     * @param hostEndpointId The ID of the host endpoint that disconnected.
+     */
+    public void onHostEndpointDisconnected(short hostEndpointId) {}
+
+    /**
      * Sends a message to the Context Hub.
      *
      * @param hostEndpointId The host endpoint ID of the sender.
@@ -407,6 +422,24 @@
             onSettingChanged(android.hardware.contexthub.Setting.WIFI_SCANNING, enabled);
         }
 
+        @Override
+        public void onHostEndpointConnected(HostEndpointInfo info) {
+            try {
+                mHub.onHostEndpointConnected(info);
+            } catch (RemoteException e) {
+                Log.e(TAG, "RemoteException in onHostEndpointConnected");
+            }
+        }
+
+        @Override
+        public void onHostEndpointDisconnected(short hostEndpointId) {
+            try {
+                mHub.onHostEndpointDisconnected((char) hostEndpointId);
+            } catch (RemoteException e) {
+                Log.e(TAG, "RemoteException in onHostEndpointDisconnected");
+            }
+        }
+
         @ContextHubTransaction.Result
         public int sendMessageToContextHub(
                 short hostEndpointId, int contextHubId, NanoAppMessage message)
diff --git a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
index 7d0b98e..6c1df7f 100644
--- a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
@@ -243,6 +243,9 @@
     @GuardedBy("mLock")
     private boolean mBatchingEnabled;
 
+    @GuardedBy("mLock")
+    private boolean mAutomotiveSuspend;
+
     private boolean mShutdown;
     private boolean mStarted;
     private boolean mBatchingStarted;
@@ -721,6 +724,27 @@
         }
     }
 
+    /**
+     * Set whether the GnssLocationProvider is suspended. This method was added to help support
+     * power management use cases on automotive devices.
+     */
+    public void setAutoGnssSuspended(boolean suspended) {
+        synchronized (mLock) {
+            mAutomotiveSuspend = suspended;
+        }
+        mHandler.post(this::updateEnabled);
+    }
+
+    /**
+     * Return whether the GnssLocationProvider is suspended or not. This method was added to help
+     * support power management use cases on automotive devices.
+     */
+    public boolean isAutoGnssSuspended() {
+        synchronized (mLock) {
+            return mAutomotiveSuspend && !mGpsEnabled;
+        }
+    }
+
     private void handleEnable() {
         if (DEBUG) Log.d(TAG, "handleEnable");
 
@@ -776,6 +800,11 @@
                 && mProviderRequest.isActive()
                 && mProviderRequest.isBypass());
 
+        // .. disable if automotive device needs to go into suspend
+        synchronized (mLock) {
+            enabled &= !mAutomotiveSuspend;
+        }
+
         // ... and, finally, disable anyway, if device is being shut down
         enabled &= !mShutdown;
 
diff --git a/services/core/java/com/android/server/location/gnss/GnssManagerService.java b/services/core/java/com/android/server/location/gnss/GnssManagerService.java
index 5de9cf3..11fd727 100644
--- a/services/core/java/com/android/server/location/gnss/GnssManagerService.java
+++ b/services/core/java/com/android/server/location/gnss/GnssManagerService.java
@@ -109,6 +109,22 @@
         return mGnssLocationProvider;
     }
 
+    /**
+     * Set whether the GnssLocationProvider is suspended on the device. This method was added to
+     * help support power management use cases on automotive devices.
+     */
+    public void setAutoGnssSuspended(boolean suspended) {
+        mGnssLocationProvider.setAutoGnssSuspended(suspended);
+    }
+
+    /**
+     * Return whether the GnssLocationProvider is suspended or not. This method was added to
+     * help support power management use cases on automotive devices.
+     */
+    public boolean isAutoGnssSuspended() {
+        return mGnssLocationProvider.isAutoGnssSuspended();
+    }
+
     /** Retrieve the IGpsGeofenceHardware. */
     public IGpsGeofenceHardware getGnssGeofenceProxy() {
         return mGnssGeofenceProxy;
diff --git a/services/core/java/com/android/server/media/MediaRouterService.java b/services/core/java/com/android/server/media/MediaRouterService.java
index 14f5214..d4af681 100644
--- a/services/core/java/com/android/server/media/MediaRouterService.java
+++ b/services/core/java/com/android/server/media/MediaRouterService.java
@@ -101,6 +101,7 @@
 
     // State guarded by mLock.
     private final Object mLock = new Object();
+
     private final SparseArray<UserRecord> mUserRecords = new SparseArray<>();
     private final ArrayMap<IBinder, ClientRecord> mAllClientRecords = new ArrayMap<>();
     private int mCurrentUserId = -1;
@@ -351,9 +352,7 @@
 
         final long token = Binder.clearCallingIdentity();
         try {
-            synchronized (mLock) {
-                mAudioService.setBluetoothA2dpOn(on);
-            }
+            mAudioService.setBluetoothA2dpOn(on);
         } catch (RemoteException ex) {
             Slog.w(TAG, "RemoteException while calling setBluetoothA2dpOn. on=" + on);
         } finally {
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index e4ed0e5..4822d6a 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -291,35 +291,39 @@
                     asSystemService, useSuggested, previousFlagPlaySound);
         } else {
             if (mVolumeControlType == VolumeProvider.VOLUME_CONTROL_FIXED) {
-                // Nothing to do, the volume cannot be changed
-                return;
-            }
-            if (direction == AudioManager.ADJUST_TOGGLE_MUTE
+                if (DEBUG) {
+                    Log.d(TAG, "Session does not support volume adjustment");
+                }
+            } else if (direction == AudioManager.ADJUST_TOGGLE_MUTE
                     || direction == AudioManager.ADJUST_MUTE
                     || direction == AudioManager.ADJUST_UNMUTE) {
                 Log.w(TAG, "Muting remote playback is not supported");
-                return;
-            }
-            if (DEBUG) {
-                Log.w(TAG, "adjusting volume, pkg=" + packageName + ", asSystemService="
-                        + asSystemService + ", dir=" + direction);
-            }
-            mSessionCb.adjustVolume(packageName, pid, uid, asSystemService, direction);
+            } else {
+                if (DEBUG) {
+                    Log.w(TAG, "adjusting volume, pkg=" + packageName + ", asSystemService="
+                            + asSystemService + ", dir=" + direction);
+                }
+                mSessionCb.adjustVolume(packageName, pid, uid, asSystemService, direction);
 
-            int volumeBefore = (mOptimisticVolume < 0 ? mCurrentVolume : mOptimisticVolume);
-            mOptimisticVolume = volumeBefore + direction;
-            mOptimisticVolume = Math.max(0, Math.min(mOptimisticVolume, mMaxVolume));
-            mHandler.removeCallbacks(mClearOptimisticVolumeRunnable);
-            mHandler.postDelayed(mClearOptimisticVolumeRunnable, OPTIMISTIC_VOLUME_TIMEOUT);
-            if (volumeBefore != mOptimisticVolume) {
-                pushVolumeUpdate();
+                int volumeBefore = (mOptimisticVolume < 0 ? mCurrentVolume : mOptimisticVolume);
+                mOptimisticVolume = volumeBefore + direction;
+                mOptimisticVolume = Math.max(0, Math.min(mOptimisticVolume, mMaxVolume));
+                mHandler.removeCallbacks(mClearOptimisticVolumeRunnable);
+                mHandler.postDelayed(mClearOptimisticVolumeRunnable, OPTIMISTIC_VOLUME_TIMEOUT);
+                if (volumeBefore != mOptimisticVolume) {
+                    pushVolumeUpdate();
+                }
+
+                if (DEBUG) {
+                    Log.d(TAG, "Adjusted optimistic volume to " + mOptimisticVolume + " max is "
+                            + mMaxVolume);
+                }
             }
+            // Always notify, even if the volume hasn't changed. This is important to ensure that
+            // System UI receives an event if a hardware volume key is pressed but the session that
+            // handles it does not allow volume adjustment. Without such an event, System UI would
+            // not show volume controls to the user.
             mService.notifyRemoteVolumeChanged(flags, this);
-
-            if (DEBUG) {
-                Log.d(TAG, "Adjusted optimistic volume to " + mOptimisticVolume + " max is "
-                        + mMaxVolume);
-            }
         }
     }
 
@@ -343,25 +347,28 @@
             });
         } else {
             if (mVolumeControlType != VolumeProvider.VOLUME_CONTROL_ABSOLUTE) {
-                // Nothing to do. The volume can't be set directly.
-                return;
-            }
-            value = Math.max(0, Math.min(value, mMaxVolume));
-            mSessionCb.setVolumeTo(packageName, pid, uid, value);
+                if (DEBUG) {
+                    Log.d(TAG, "Session does not support setting volume");
+                }
+            } else {
+                value = Math.max(0, Math.min(value, mMaxVolume));
+                mSessionCb.setVolumeTo(packageName, pid, uid, value);
 
-            int volumeBefore = (mOptimisticVolume < 0 ? mCurrentVolume : mOptimisticVolume);
-            mOptimisticVolume = Math.max(0, Math.min(value, mMaxVolume));
-            mHandler.removeCallbacks(mClearOptimisticVolumeRunnable);
-            mHandler.postDelayed(mClearOptimisticVolumeRunnable, OPTIMISTIC_VOLUME_TIMEOUT);
-            if (volumeBefore != mOptimisticVolume) {
-                pushVolumeUpdate();
+                int volumeBefore = (mOptimisticVolume < 0 ? mCurrentVolume : mOptimisticVolume);
+                mOptimisticVolume = Math.max(0, Math.min(value, mMaxVolume));
+                mHandler.removeCallbacks(mClearOptimisticVolumeRunnable);
+                mHandler.postDelayed(mClearOptimisticVolumeRunnable, OPTIMISTIC_VOLUME_TIMEOUT);
+                if (volumeBefore != mOptimisticVolume) {
+                    pushVolumeUpdate();
+                }
+
+                if (DEBUG) {
+                    Log.d(TAG, "Set optimistic volume to " + mOptimisticVolume + " max is "
+                            + mMaxVolume);
+                }
             }
+            // Always notify, even if the volume hasn't changed.
             mService.notifyRemoteVolumeChanged(flags, this);
-
-            if (DEBUG) {
-                Log.d(TAG, "Set optimistic volume to " + mOptimisticVolume + " max is "
-                        + mMaxVolume);
-            }
         }
     }
 
diff --git a/services/core/java/com/android/server/net/NetworkStatsFactory.java b/services/core/java/com/android/server/net/NetworkStatsFactory.java
index 431b009..e6433db 100644
--- a/services/core/java/com/android/server/net/NetworkStatsFactory.java
+++ b/services/core/java/com/android/server/net/NetworkStatsFactory.java
@@ -159,7 +159,7 @@
     }
 
     public NetworkStatsFactory() {
-        this(new File("/proc/"), new File("/sys/fs/bpf/map_netd_app_uid_stats_map").exists());
+        this(new File("/proc/"), true);
     }
 
     @VisibleForTesting
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index 097b071..f4b72a1 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -215,8 +215,6 @@
 
     private final PowerManager.WakeLock mWakeLock;
 
-    private final boolean mUseBpfTrafficStats;
-
     private final ContentObserver mContentObserver;
     private final ContentResolver mContentResolver;
 
@@ -438,7 +436,6 @@
         mStatsObservers = Objects.requireNonNull(statsObservers, "missing NetworkStatsObservers");
         mSystemDir = Objects.requireNonNull(systemDir, "missing systemDir");
         mBaseDir = Objects.requireNonNull(baseDir, "missing baseDir");
-        mUseBpfTrafficStats = new File("/sys/fs/bpf/map_netd_app_uid_stats_map").exists();
         mDeps = Objects.requireNonNull(deps, "missing Dependencies");
 
         final HandlerThread handlerThread = mDeps.makeHandlerThread();
@@ -1084,13 +1081,13 @@
         if (callingUid != android.os.Process.SYSTEM_UID && callingUid != uid) {
             return UNSUPPORTED;
         }
-        return nativeGetUidStat(uid, type, checkBpfStatsEnable());
+        return nativeGetUidStat(uid, type);
     }
 
     @Override
     public long getIfaceStats(@NonNull String iface, int type) {
         Objects.requireNonNull(iface);
-        long nativeIfaceStats = nativeGetIfaceStat(iface, type, checkBpfStatsEnable());
+        long nativeIfaceStats = nativeGetIfaceStat(iface, type);
         if (nativeIfaceStats == -1) {
             return nativeIfaceStats;
         } else {
@@ -1104,7 +1101,7 @@
 
     @Override
     public long getTotalStats(int type) {
-        long nativeTotalStats = nativeGetTotalStat(type, checkBpfStatsEnable());
+        long nativeTotalStats = nativeGetTotalStat(type);
         if (nativeTotalStats == -1) {
             return nativeTotalStats;
         } else {
@@ -1137,10 +1134,6 @@
         }
     }
 
-    private boolean checkBpfStatsEnable() {
-        return mUseBpfTrafficStats;
-    }
-
     /**
      * Update {@link NetworkStatsRecorder} and {@link #mGlobalAlertBytes} to
      * reflect current {@link #mPersistThreshold} value. Always defers to
@@ -2249,7 +2242,7 @@
         }
     }
 
-    private static native long nativeGetTotalStat(int type, boolean useBpfStats);
-    private static native long nativeGetIfaceStat(String iface, int type, boolean useBpfStats);
-    private static native long nativeGetUidStat(int uid, int type, boolean useBpfStats);
+    private static native long nativeGetTotalStat(int type);
+    private static native long nativeGetIfaceStat(String iface, int type);
+    private static native long nativeGetUidStat(int uid, int type);
 }
diff --git a/services/core/java/com/android/server/net/OWNERS b/services/core/java/com/android/server/net/OWNERS
index a15fc3e..9c96d46f 100644
--- a/services/core/java/com/android/server/net/OWNERS
+++ b/services/core/java/com/android/server/net/OWNERS
@@ -1,6 +1,5 @@
 set noparent
-
-include platform/packages/modules/Connectivity:/OWNERS
+file:platform/packages/modules/Connectivity:master:/OWNERS_core_networking
 
 jsharkey@android.com
 sudheersai@google.com
diff --git a/services/core/java/com/android/server/notification/BadgeExtractor.java b/services/core/java/com/android/server/notification/BadgeExtractor.java
index 70edfa1..642cbb3 100644
--- a/services/core/java/com/android/server/notification/BadgeExtractor.java
+++ b/services/core/java/com/android/server/notification/BadgeExtractor.java
@@ -69,11 +69,8 @@
 
         if (mConfig.isMediaNotificationFilteringEnabled()) {
             final Notification notif = record.getNotification();
-            if (notif.hasMediaSession()) {
-                if (notif.isStyle(Notification.DecoratedMediaCustomViewStyle.class)
-                        || notif.isStyle(Notification.MediaStyle.class)) {
-                    record.setShowBadge(false);
-                }
+            if (notif.isMediaNotification()) {
+                record.setShowBadge(false);
             }
         }
         return null;
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index 7d31287..e6bc796 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -1065,7 +1065,7 @@
         }
     }
 
-    protected void setComponentState(ComponentName component, boolean enabled) {
+    protected void setComponentState(ComponentName component, int userId, boolean enabled) {
         boolean previous = !mSnoozingForCurrentProfiles.contains(component);
         if (previous == enabled) {
             return;
@@ -1082,20 +1082,15 @@
                 component.flattenToShortString());
 
         synchronized (mMutex) {
-            final IntArray userIds = mUserProfiles.getCurrentProfileIds();
-
-            for (int i = 0; i < userIds.size(); i++) {
-                final int userId = userIds.get(i);
-                if (enabled) {
-                    if (isPackageOrComponentAllowed(component.flattenToString(), userId)
-                            || isPackageOrComponentAllowed(component.getPackageName(), userId)) {
-                        registerServiceLocked(component, userId);
-                    } else {
-                        Slog.d(TAG, component + " no longer has permission to be bound");
-                    }
+            if (enabled) {
+                if (isPackageOrComponentAllowed(component.flattenToString(), userId)
+                        || isPackageOrComponentAllowed(component.getPackageName(), userId)) {
+                    registerServiceLocked(component, userId);
                 } else {
-                    unregisterServiceLocked(component, userId);
+                    Slog.d(TAG, component + " no longer has permission to be bound");
                 }
+            } else {
+                unregisterServiceLocked(component, userId);
             }
         }
     }
diff --git a/services/core/java/com/android/server/notification/NotificationComparator.java b/services/core/java/com/android/server/notification/NotificationComparator.java
index 8aae6e0..583cdd5 100644
--- a/services/core/java/com/android/server/notification/NotificationComparator.java
+++ b/services/core/java/com/android/server/notification/NotificationComparator.java
@@ -179,7 +179,7 @@
     }
 
     private boolean isMediaNotification(NotificationRecord record) {
-        return record.getNotification().hasMediaSession();
+        return record.getNotification().isMediaNotification();
     }
 
     private boolean isCallCategory(NotificationRecord record) {
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index cc965d3..e117cc6 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -151,6 +151,7 @@
 import android.app.NotificationManager;
 import android.app.NotificationManager.Policy;
 import android.app.PendingIntent;
+import android.app.RemoteServiceException.BadForegroundServiceNotificationException;
 import android.app.StatsManager;
 import android.app.StatusBarManager;
 import android.app.UriGrantsManager;
@@ -1265,10 +1266,11 @@
                 // Still crash for foreground services, preventing the not-crash behaviour abused
                 // by apps to give us a garbage notification and silently start a fg service.
                 Binder.withCleanCallingIdentity(
-                        () -> mAm.crashApplication(uid, initialPid, pkg, -1,
+                        () -> mAm.crashApplicationWithType(uid, initialPid, pkg, -1,
                             "Bad notification(tag=" + tag + ", id=" + id + ") posted from package "
                                 + pkg + ", crashing app(uid=" + uid + ", pid=" + initialPid + "): "
-                                + message, true /* force */));
+                                + message, true /* force */,
+                                BadForegroundServiceNotificationException.TYPE_ID));
             }
         }
 
@@ -4456,13 +4458,14 @@
         @Override
         public void requestBindListener(ComponentName component) {
             checkCallerIsSystemOrSameApp(component.getPackageName());
+            int uid = Binder.getCallingUid();
             final long identity = Binder.clearCallingIdentity();
             try {
                 ManagedServices manager =
                         mAssistants.isComponentEnabledForCurrentProfiles(component)
                         ? mAssistants
                         : mListeners;
-                manager.setComponentState(component, true);
+                manager.setComponentState(component, UserHandle.getUserId(uid), true);
             } finally {
                 Binder.restoreCallingIdentity(identity);
             }
@@ -4470,12 +4473,14 @@
 
         @Override
         public void requestUnbindListener(INotificationListener token) {
+            int uid = Binder.getCallingUid();
             final long identity = Binder.clearCallingIdentity();
             try {
                 // allow bound services to disable themselves
                 synchronized (mNotificationLock) {
                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
-                    info.getOwner().setComponentState(info.component, false);
+                    info.getOwner().setComponentState(
+                            info.component, UserHandle.getUserId(uid), false);
                 }
             } finally {
                 Binder.restoreCallingIdentity(identity);
@@ -4967,11 +4972,12 @@
 
         @Override
         public void requestUnbindProvider(IConditionProvider provider) {
+            int uid = Binder.getCallingUid();
             final long identity = Binder.clearCallingIdentity();
             try {
                 // allow bound services to disable themselves
                 final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
-                info.getOwner().setComponentState(info.component, false);
+                info.getOwner().setComponentState(info.component, UserHandle.getUserId(uid), false);
             } finally {
                 Binder.restoreCallingIdentity(identity);
             }
@@ -4980,9 +4986,10 @@
         @Override
         public void requestBindProvider(ComponentName component) {
             checkCallerIsSystemOrSameApp(component.getPackageName());
+            int uid = Binder.getCallingUid();
             final long identity = Binder.clearCallingIdentity();
             try {
-                mConditionProviders.setComponentState(component, true);
+                mConditionProviders.setComponentState(component, UserHandle.getUserId(uid), true);
             } finally {
                 Binder.restoreCallingIdentity(identity);
             }
@@ -6815,13 +6822,11 @@
 
 
         // blocked apps
-        boolean isMediaNotification = n.isMediaNotification()
-                && n.extras.getParcelable(Notification.EXTRA_MEDIA_SESSION) != null;
         boolean isBlocked = !areNotificationsEnabledForPackageInt(pkg, uid);
         synchronized (mNotificationLock) {
             isBlocked |= isRecordBlockedLocked(r);
         }
-        if (isBlocked && !isMediaNotification) {
+        if (isBlocked && !n.isMediaNotification()) {
             if (DBG) {
                 Slog.e(TAG, "Suppressing notification from package " + r.getSbn().getPackageName()
                         + " by user request.");
@@ -7210,10 +7215,8 @@
                     final StatusBarNotification n = r.getSbn();
                     final Notification notification = n.getNotification();
 
-                    boolean isMediaNotification = notification.isMediaNotification()
-                            && notification.extras.getParcelable(
-                                    Notification.EXTRA_MEDIA_SESSION) != null;
-                    if (!isMediaNotification && (appBanned || isRecordBlockedLocked(r))) {
+                    if (!notification.isMediaNotification()
+                            && (appBanned || isRecordBlockedLocked(r))) {
                         mUsageStats.registerBlocked(r);
                         if (DBG) {
                             Slog.e(TAG, "Suppressing notification from package " + pkg);
@@ -7240,7 +7243,9 @@
                     if (index < 0) {
                         mNotificationList.add(r);
                         mUsageStats.registerPostedByApp(r);
-                        r.setInterruptive(isVisuallyInterruptive(null, r));
+                        final boolean isInterruptive = isVisuallyInterruptive(null, r);
+                        r.setInterruptive(isInterruptive);
+                        r.setTextChanged(isInterruptive);
                     } else {
                         old = mNotificationList.get(index);  // Potentially *changes* old
                         mNotificationList.set(index, r);
diff --git a/services/core/java/com/android/server/notification/VibratorHelper.java b/services/core/java/com/android/server/notification/VibratorHelper.java
index 0a69aec..5199ef6 100644
--- a/services/core/java/com/android/server/notification/VibratorHelper.java
+++ b/services/core/java/com/android/server/notification/VibratorHelper.java
@@ -89,7 +89,7 @@
      */
     public void vibrate(VibrationEffect effect, AudioAttributes attrs, String reason) {
         mVibrator.vibrate(Process.SYSTEM_UID, PackageManagerService.PLATFORM_PACKAGE_NAME,
-                effect, reason, attrs);
+                effect, reason, new VibrationAttributes.Builder(attrs, effect).build());
     }
 
     /** Stop all notification vibrations (ringtone, alarm, notification usages). */
diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java
index 53c2802..6f54625 100644
--- a/services/core/java/com/android/server/pm/AppsFilter.java
+++ b/services/core/java/com/android/server/pm/AppsFilter.java
@@ -500,16 +500,10 @@
                 forcedQueryablePackageNames[i] = forcedQueryablePackageNames[i].intern();
             }
         }
-        final StateProvider stateProvider = new StateProvider() {
-            // TODO: This lock and its handling should be owned by AppsFilter
-            private final Object mLock = new Object();
-
-            @Override
-            public void runWithState(CurrentStateCallback command) {
-                synchronized (mLock) {
-                    command.currentState(pms.getPackageStates(),
-                            injector.getUserManagerInternal().getUserInfos());
-                }
+        final StateProvider stateProvider = command -> {
+            synchronized (injector.getLock()) {
+                command.currentState(injector.getSettings().getPackagesLocked().untrackedStorage(),
+                        injector.getUserManagerInternal().getUserInfos());
             }
         };
         AppsFilter appsFilter = new AppsFilter(stateProvider, featureConfig,
diff --git a/services/core/java/com/android/server/pm/Computer.java b/services/core/java/com/android/server/pm/Computer.java
index 6f61958..a9df4ba 100644
--- a/services/core/java/com/android/server/pm/Computer.java
+++ b/services/core/java/com/android/server/pm/Computer.java
@@ -514,6 +514,11 @@
     int getComponentEnabledSetting(@NonNull ComponentName component, int callingUid,
             @UserIdInt int userId);
 
+    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
+    @PackageManager.EnabledState
+    int getComponentEnabledSettingInternal(@NonNull ComponentName component, int callingUid,
+            @UserIdInt int userId);
+
     /**
      * @return true if the runtime app user enabled state, runtime component user enabled state,
      * install-time app manifest enabled state, and install-time component manifest enabled state
@@ -612,6 +617,10 @@
     @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     int getUidTargetSdkVersion(int uid);
 
+    /**
+     * @see PackageManagerInternal#getProcessesForUid(int)
+     */
+    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     @Nullable
     ArrayMap<String, ProcessInfo> getProcessesForUid(int uid);
     // End block
diff --git a/services/core/java/com/android/server/pm/ComputerEngine.java b/services/core/java/com/android/server/pm/ComputerEngine.java
index 9965097..887dfff 100644
--- a/services/core/java/com/android/server/pm/ComputerEngine.java
+++ b/services/core/java/com/android/server/pm/ComputerEngine.java
@@ -5015,20 +5015,26 @@
             @UserIdInt int userId) {
         enforceCrossUserPermission(callingUid, userId, false /*requireFullPermission*/,
                 false /*checkShell*/, "getComponentEnabled");
+        return getComponentEnabledSettingInternal(component, callingUid, userId);
+    }
 
+    @PackageManager.EnabledState
+    @Override
+    public int getComponentEnabledSettingInternal(@NonNull ComponentName component, int callingUid,
+            @UserIdInt int userId) {
         if (component == null) return COMPONENT_ENABLED_STATE_DEFAULT;
         if (!mUserManager.exists(userId)) return COMPONENT_ENABLED_STATE_DISABLED;
 
-            try {
-                if (shouldFilterApplication(
-                        mSettings.getPackage(component.getPackageName()), callingUid,
-                        component, TYPE_UNKNOWN, userId)) {
-                    throw new PackageManager.NameNotFoundException(component.getPackageName());
-                }
-                return mSettings.getComponentEnabledSetting(component, userId);
-            } catch (PackageManager.NameNotFoundException e) {
-                throw new IllegalArgumentException("Unknown component: " + component);
+        try {
+            if (shouldFilterApplication(
+                    mSettings.getPackage(component.getPackageName()), callingUid,
+                    component, TYPE_UNKNOWN, userId)) {
+                throw new PackageManager.NameNotFoundException(component.getPackageName());
             }
+            return mSettings.getComponentEnabledSetting(component, userId);
+        } catch (PackageManager.NameNotFoundException e) {
+            throw new IllegalArgumentException("Unknown component: " + component);
+        }
     }
 
     @Override
diff --git a/services/core/java/com/android/server/pm/ComputerLocked.java b/services/core/java/com/android/server/pm/ComputerLocked.java
index d234d4d..801aaef 100644
--- a/services/core/java/com/android/server/pm/ComputerLocked.java
+++ b/services/core/java/com/android/server/pm/ComputerLocked.java
@@ -650,6 +650,14 @@
     }
 
     @Override
+    public int getComponentEnabledSettingInternal(@NonNull ComponentName component, int callingUid,
+            @UserIdInt int userId) {
+        synchronized (mLock) {
+            return super.getComponentEnabledSettingInternal(component, callingUid, userId);
+        }
+    }
+
+    @Override
     public boolean isComponentEffectivelyEnabled(@NonNull ComponentInfo componentInfo,
             @UserIdInt int userId) {
         synchronized (mLock) {
diff --git a/services/core/java/com/android/server/pm/ComputerTracker.java b/services/core/java/com/android/server/pm/ComputerTracker.java
index 37298cd..ca17d66 100644
--- a/services/core/java/com/android/server/pm/ComputerTracker.java
+++ b/services/core/java/com/android/server/pm/ComputerTracker.java
@@ -1090,6 +1090,15 @@
     }
 
     @Override
+    public int getComponentEnabledSettingInternal(@NonNull ComponentName component, int callingUid,
+            @UserIdInt int userId) {
+        try (ThreadComputer current = snapshot()) {
+            return current.mComputer.getComponentEnabledSettingInternal(
+                    component, callingUid, userId);
+        }
+    }
+
+    @Override
     public boolean isComponentEffectivelyEnabled(@NonNull ComponentInfo componentInfo,
             @UserIdInt int userId) {
         try (ThreadComputer current = snapshot()) {
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index 39ed9c2..6622a77 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -2050,6 +2050,7 @@
             }
         }
 
+        final String packageName = pkg.getPackageName();
         for (Map.Entry<String, String> entry : fsverityCandidates.entrySet()) {
             final String filePath = entry.getKey();
             final String signaturePath = entry.getValue();
@@ -2077,10 +2078,13 @@
                     try {
                         // A file may already have fs-verity, e.g. when reused during a split
                         // install. If the measurement succeeds, no need to attempt to set up.
-                        mPm.mInstaller.assertFsverityRootHashMatches(filePath, rootHash);
+                        mPm.mInstaller.assertFsverityRootHashMatches(packageName, filePath,
+                                rootHash);
                     } catch (Installer.InstallerException e) {
-                        mPm.mInstaller.installApkVerity(filePath, fd, result.getContentSize());
-                        mPm.mInstaller.assertFsverityRootHashMatches(filePath, rootHash);
+                        mPm.mInstaller.installApkVerity(packageName, filePath, fd,
+                                result.getContentSize());
+                        mPm.mInstaller.assertFsverityRootHashMatches(packageName, filePath,
+                                rootHash);
                     }
                 } finally {
                     IoUtils.closeQuietly(fd);
@@ -2349,10 +2353,9 @@
                 // Set install reason for users that are having the package newly installed.
                 final int[] allUsersList = mPm.mUserManager.getUserIds();
                 if (userId == UserHandle.USER_ALL) {
-                    // TODO(b/152629990): It appears that the package doesn't actually get newly
-                    //  installed in this case, so the installReason shouldn't get modified?
                     for (int currentUserId : allUsersList) {
-                        if (!previousUserIds.contains(currentUserId)) {
+                        if (!previousUserIds.contains(currentUserId)
+                                && ps.getInstalled(currentUserId)) {
                             ps.setInstallReason(installReason, currentUserId);
                         }
                     }
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index c8bd2c0..a380344 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -497,7 +497,7 @@
      *
      * @throws InstallerException if {@code dexopt} fails.
      */
-    public boolean dexopt(String apkPath, int uid, @Nullable String pkgName, String instructionSet,
+    public boolean dexopt(String apkPath, int uid, String pkgName, String instructionSet,
             int dexoptNeeded, @Nullable String outputPath, int dexFlags,
             String compilerFilter, @Nullable String volumeUuid, @Nullable String classLoaderContext,
             @Nullable String seInfo, boolean downgrade, int targetSdkVersion,
@@ -585,11 +585,14 @@
         }
     }
 
-    public void rmPackageDir(String packageDir) throws InstallerException {
+    /**
+     * Remove a directory belonging to a package.
+     */
+    public void rmPackageDir(String packageName, String packageDir) throws InstallerException {
         if (!checkBeforeRemote()) return;
         BlockGuard.getVmPolicy().onPathAccess(packageDir);
         try {
-            mInstalld.rmPackageDir(packageDir);
+            mInstalld.rmPackageDir(packageName, packageDir);
         } catch (Exception e) {
             throw InstallerException.from(e);
         }
@@ -662,35 +665,44 @@
         }
     }
 
-    public void createOatDir(String oatDir, String dexInstructionSet)
+    /**
+     * Creates an oat dir for given package and instruction set.
+     */
+    public void createOatDir(String packageName, String oatDir, String dexInstructionSet)
             throws InstallerException {
         if (!checkBeforeRemote()) return;
         try {
-            mInstalld.createOatDir(oatDir, dexInstructionSet);
+            mInstalld.createOatDir(packageName, oatDir, dexInstructionSet);
         } catch (Exception e) {
             throw InstallerException.from(e);
         }
     }
 
-    public void linkFile(String relativePath, String fromBase, String toBase)
+    /**
+     * Creates a hardlink for a path.
+     */
+    public void linkFile(String packageName, String relativePath, String fromBase, String toBase)
             throws InstallerException {
         if (!checkBeforeRemote()) return;
         BlockGuard.getVmPolicy().onPathAccess(fromBase);
         BlockGuard.getVmPolicy().onPathAccess(toBase);
         try {
-            mInstalld.linkFile(relativePath, fromBase, toBase);
+            mInstalld.linkFile(packageName, relativePath, fromBase, toBase);
         } catch (Exception e) {
             throw InstallerException.from(e);
         }
     }
 
-    public void moveAb(String apkPath, String instructionSet, String outputPath)
+    /**
+     * Moves oat/vdex/art from "B" set defined by ro.boot.slot_suffix to the default set.
+     */
+    public void moveAb(String packageName, String apkPath, String instructionSet, String outputPath)
             throws InstallerException {
         if (!checkBeforeRemote()) return;
         BlockGuard.getVmPolicy().onPathAccess(apkPath);
         BlockGuard.getVmPolicy().onPathAccess(outputPath);
         try {
-            mInstalld.moveAb(apkPath, instructionSet, outputPath);
+            mInstalld.moveAb(packageName, apkPath, instructionSet, outputPath);
         } catch (Exception e) {
             throw InstallerException.from(e);
         }
@@ -700,35 +712,41 @@
      * Deletes the optimized artifacts generated by ART and returns the number
      * of freed bytes.
      */
-    public long deleteOdex(String apkPath, String instructionSet, String outputPath)
-            throws InstallerException {
+    public long deleteOdex(String packageName, String apkPath, String instructionSet,
+            String outputPath) throws InstallerException {
         if (!checkBeforeRemote()) return -1;
         BlockGuard.getVmPolicy().onPathAccess(apkPath);
         BlockGuard.getVmPolicy().onPathAccess(outputPath);
         try {
-            return mInstalld.deleteOdex(apkPath, instructionSet, outputPath);
+            return mInstalld.deleteOdex(packageName, apkPath, instructionSet, outputPath);
         } catch (Exception e) {
             throw InstallerException.from(e);
         }
     }
 
-    public void installApkVerity(String filePath, FileDescriptor verityInput, int contentSize)
-            throws InstallerException {
+    /**
+     * Enables legacy apk-verity for an apk.
+     */
+    public void installApkVerity(String packageName, String filePath, FileDescriptor verityInput,
+            int contentSize) throws InstallerException {
         if (!checkBeforeRemote()) return;
         BlockGuard.getVmPolicy().onPathAccess(filePath);
         try {
-            mInstalld.installApkVerity(filePath, verityInput, contentSize);
+            mInstalld.installApkVerity(packageName, filePath, verityInput, contentSize);
         } catch (Exception e) {
             throw InstallerException.from(e);
         }
     }
 
-    public void assertFsverityRootHashMatches(String filePath, @NonNull byte[] expectedHash)
-            throws InstallerException {
+    /**
+     * Checks if provided hash matches the file's fs-verity merkle tree root hash.
+     */
+    public void assertFsverityRootHashMatches(String packageName, String filePath,
+            @NonNull byte[] expectedHash) throws InstallerException {
         if (!checkBeforeRemote()) return;
         BlockGuard.getVmPolicy().onPathAccess(filePath);
         try {
-            mInstalld.assertFsverityRootHashMatches(filePath, expectedHash);
+            mInstalld.assertFsverityRootHashMatches(packageName, filePath, expectedHash);
         } catch (Exception e) {
             throw InstallerException.from(e);
         }
diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
index 9e6f4f7..c125fe1 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptService.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
@@ -411,6 +411,7 @@
             final List<String> paths =
                     AndroidPackageUtils.getAllCodePathsExcludingResourceOnly(pkg);
             final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
+            final String packageName = pkg.getPackageName();
             for (String dexCodeInstructionSet : dexCodeInstructionSets) {
                 for (String path : paths) {
                     String oatDir = PackageDexOptimizer.getOatDir(
@@ -420,7 +421,7 @@
 
                     packagePaths++;
                     try {
-                        installer.moveAb(path, dexCodeInstructionSet, oatDir);
+                        installer.moveAb(packageName, path, dexCodeInstructionSet, oatDir);
                         pathsSuccessful++;
                     } catch (InstallerException e) {
                     }
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index c47ca4b..8f14cf8 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -558,10 +558,7 @@
                 Slog.d(TAG, "Marking session " + sessionId + " as failed: " + errorMessage);
                 childSessions = getChildSessionsLocked();
             }
-            destroyInternal();
-            for (PackageInstallerSession child : childSessions) {
-                child.destroyInternal();
-            }
+            destroy();
             mCallback.onStagedSessionChanged(PackageInstallerSession.this);
         }
 
@@ -579,10 +576,7 @@
                 Slog.d(TAG, "Marking session " + sessionId + " as applied");
                 childSessions = getChildSessionsLocked();
             }
-            destroyInternal();
-            for (PackageInstallerSession child : childSessions) {
-                child.destroyInternal();
-            }
+            destroy();
             mCallback.onStagedSessionChanged(PackageInstallerSession.this);
         }
 
@@ -2111,18 +2105,14 @@
     private void onSessionVerificationFailure(int error, String msg) {
         final String msgWithErrorCode = PackageManager.installStatusToString(error, msg);
         Slog.e(TAG, "Failed to verify session " + sessionId + " [" + msgWithErrorCode + "]");
-        // Session is sealed and committed but could not be verified, we need to destroy it.
-        destroyInternal();
-        if (isMultiPackage()) {
-            for (PackageInstallerSession childSession : getChildSessions()) {
-                childSession.destroyInternal();
-            }
-        }
         if (isStaged()) {
+            // This will clean up the session when it reaches the terminal state
             mStagedSession.setSessionFailed(
                     SessionInfo.STAGED_SESSION_VERIFICATION_FAILED, msgWithErrorCode);
             mStagedSession.notifyEndPreRebootVerification();
         } else {
+            // Session is sealed and committed but could not be verified, we need to destroy it.
+            destroy();
             // Dispatch message to remove session from PackageInstallerService.
             dispatchSessionFinished(error, msg, null);
         }
@@ -2412,6 +2402,7 @@
             try {
                 final List<File> fromFiles = mResolvedInheritedFiles;
                 final File toDir = stageDir;
+                final String tempPackageName = toDir.getName();
 
                 if (LOGD) Slog.d(TAG, "Inherited files: " + mResolvedInheritedFiles);
                 if (!mResolvedInheritedFiles.isEmpty() && mInheritedFilesBase == null) {
@@ -2421,7 +2412,7 @@
                 if (isLinkPossible(fromFiles, toDir)) {
                     if (!mResolvedInstructionSets.isEmpty()) {
                         final File oatDir = new File(toDir, "oat");
-                        createOatDirs(mResolvedInstructionSets, oatDir);
+                        createOatDirs(tempPackageName, mResolvedInstructionSets, oatDir);
                     }
                     // pre-create lib dirs for linking if necessary
                     if (!mResolvedNativeLibPaths.isEmpty()) {
@@ -2444,7 +2435,7 @@
                                     new File(libDir, archDirPath));
                         }
                     }
-                    linkFiles(fromFiles, toDir, mInheritedFilesBase);
+                    linkFiles(tempPackageName, fromFiles, toDir, mInheritedFilesBase);
                 } else {
                     // TODO: this should delegate to DCS so the system process
                     // avoids holding open FDs into containers.
@@ -3539,18 +3530,19 @@
         throw new IOException("File: " + pathStr + " outside base: " + baseStr);
     }
 
-    private void createOatDirs(List<String> instructionSets, File fromDir)
+    private void createOatDirs(String packageName, List<String> instructionSets, File fromDir)
             throws PackageManagerException {
         for (String instructionSet : instructionSets) {
             try {
-                mInstaller.createOatDir(fromDir.getAbsolutePath(), instructionSet);
+                mInstaller.createOatDir(packageName, fromDir.getAbsolutePath(), instructionSet);
             } catch (InstallerException e) {
                 throw PackageManagerException.from(e);
             }
         }
     }
 
-    private void linkFile(String relativePath, String fromBase, String toBase) throws IOException {
+    private void linkFile(String packageName, String relativePath, String fromBase, String toBase)
+            throws IOException {
         try {
             // Try
             final IncrementalFileStorages incrementalFileStorages = getIncrementalFileStorages();
@@ -3558,21 +3550,21 @@
                     fromBase, toBase)) {
                 return;
             }
-            mInstaller.linkFile(relativePath, fromBase, toBase);
+            mInstaller.linkFile(packageName, relativePath, fromBase, toBase);
         } catch (InstallerException | IOException e) {
             throw new IOException("failed linkOrCreateDir(" + relativePath + ", "
                     + fromBase + ", " + toBase + ")", e);
         }
     }
 
-    private void linkFiles(List<File> fromFiles, File toDir, File fromDir)
+    private void linkFiles(String packageName, List<File> fromFiles, File toDir, File fromDir)
             throws IOException {
         for (File fromFile : fromFiles) {
             final String relativePath = getRelativePath(fromFile, fromDir);
             final String fromBase = fromDir.getAbsolutePath();
             final String toBase = toDir.getAbsolutePath();
 
-            linkFile(relativePath, fromBase, toBase);
+            linkFile(packageName, relativePath, fromBase, toBase);
         }
 
         Slog.d(TAG, "Linked " + fromFiles.size() + " files into " + toDir);
@@ -4265,6 +4257,28 @@
         return params.isStaged ? mStagedSession.getSessionErrorMessage() : "";
     }
 
+    /**
+     * Free up storage used by this session and its children.
+     * Must not be called on a child session.
+     */
+    private void destroy() {
+        // TODO(b/173194203): destroy() is called indirectly by
+        //  PackageInstallerService#restoreAndApplyStagedSessionIfNeeded on an orphan child session.
+        //  Enable this assertion when we figure out a better way to clean up orphan sessions.
+        // assertNotChild("destroy");
+
+        // TODO(b/173194203): destroyInternal() should be used by destroy() only.
+        //  For the sake of consistency, a session should be destroyed as a whole. The caller
+        //  should always call destroy() for cleanup without knowing it has child sessions or not.
+        destroyInternal();
+        for (PackageInstallerSession child : getChildSessions()) {
+            child.destroyInternal();
+        }
+    }
+
+    /**
+     * Free up storage used by this session.
+     */
     private void destroyInternal() {
         final IncrementalFileStorages incrementalFileStorages;
         synchronized (mLock) {
@@ -4287,7 +4301,8 @@
                 incrementalFileStorages.cleanUpAndMarkComplete();
             }
             if (stageDir != null) {
-                mInstaller.rmPackageDir(stageDir.getAbsolutePath());
+                final String tempPackageName = stageDir.getName();
+                mInstaller.rmPackageDir(tempPackageName, stageDir.getAbsolutePath());
             }
         } catch (InstallerException ignored) {
         }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 5f56d4e..747bbfa5 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -1500,16 +1500,19 @@
         final CompatChange.ChangeListener selinuxChangeListener = packageName -> {
             synchronized (m.mInstallLock) {
                 final AndroidPackage pkg;
+                final PackageSetting ps;
                 final SharedUserSetting sharedUser;
                 final String oldSeInfo;
-                final PackageStateInternal packageState = m.getPackageStateInternal(packageName);
-                if (packageState == null) {
-                    Slog.e(TAG, "Failed to find package setting " + packageName);
-                    return;
+                synchronized (m.mLock) {
+                    ps = m.mSettings.getPackageLPr(packageName);
+                    if (ps == null) {
+                        Slog.e(TAG, "Failed to find package setting " + packageName);
+                        return;
+                    }
+                    pkg = ps.getPkg();
+                    sharedUser = ps.getSharedUser();
+                    oldSeInfo = AndroidPackageUtils.getSeInfo(pkg, ps);
                 }
-                pkg = packageState.getPkg();
-                sharedUser = packageState.getSharedUser();
-                oldSeInfo = AndroidPackageUtils.getSeInfo(pkg, packageState);
 
                 if (pkg == null) {
                     Slog.e(TAG, "Failed to find package " + packageName);
@@ -1521,7 +1524,7 @@
                 if (!newSeInfo.equals(oldSeInfo)) {
                     Slog.i(TAG, "Updating seInfo for package " + packageName + " from: "
                             + oldSeInfo + " to: " + newSeInfo);
-                    packageState.getTransientState().setOverrideSeInfo(newSeInfo);
+                    ps.getPkgState().setOverrideSeInfo(newSeInfo);
                     m.mAppDataHelper.prepareAppDataAfterInstallLIF(pkg);
                 }
             }
@@ -5646,6 +5649,9 @@
                         synchronized (mLock) {
                             mInstantAppRegistry.deleteInstantApplicationMetadataLPw(
                                     packageName, userId);
+                            if (succeeded) {
+                                resetComponentEnabledSettingsIfNeededLPw(packageName, userId);
+                            }
                         }
                     }
                     if (succeeded) {
@@ -5722,6 +5728,62 @@
     }
 
     /**
+     * Update component enabled settings to {@link PackageManager#COMPONENT_ENABLED_STATE_DEFAULT}
+     * if the resetEnabledSettingsOnAppDataCleared is {@code true}.
+     */
+    private void resetComponentEnabledSettingsIfNeededLPw(String packageName, int userId) {
+        final AndroidPackage pkg = packageName != null ? mPackages.get(packageName) : null;
+        if (pkg == null || !pkg.isResetEnabledSettingsOnAppDataCleared()) {
+            return;
+        }
+        final PackageSetting pkgSetting = mSettings.getPackageLPr(packageName);
+        if (pkgSetting == null) {
+            return;
+        }
+        final ArrayList<String> updatedComponents = new ArrayList<>();
+        final Consumer<? super ParsedMainComponent> resetSettings = (component) -> {
+            if (pkgSetting.restoreComponentLPw(component.getClassName(), userId)) {
+                updatedComponents.add(component.getClassName());
+            }
+        };
+        for (int i = 0; i < pkg.getActivities().size(); i++) {
+            resetSettings.accept(pkg.getActivities().get(i));
+        }
+        for (int i = 0; i < pkg.getReceivers().size(); i++) {
+            resetSettings.accept(pkg.getReceivers().get(i));
+        }
+        for (int i = 0; i < pkg.getServices().size(); i++) {
+            resetSettings.accept(pkg.getServices().get(i));
+        }
+        for (int i = 0; i < pkg.getProviders().size(); i++) {
+            resetSettings.accept(pkg.getProviders().get(i));
+        }
+        if (ArrayUtils.isEmpty(updatedComponents)) {
+            // nothing changed
+            return;
+        }
+
+        updateSequenceNumberLP(pkgSetting, new int[] { userId });
+        updateInstantAppInstallerLocked(packageName);
+        scheduleWritePackageRestrictionsLocked(userId);
+
+        final ArrayList<String> pendingComponents = mPendingBroadcasts.get(userId, packageName);
+        if (pendingComponents == null) {
+            mPendingBroadcasts.put(userId, packageName, updatedComponents);
+        } else {
+            for (int i = 0; i < updatedComponents.size(); i++) {
+                final String updatedComponent = updatedComponents.get(i);
+                if (!pendingComponents.contains(updatedComponent)) {
+                    pendingComponents.add(updatedComponent);
+                }
+            }
+        }
+        if (!mHandler.hasMessages(SEND_PENDING_BROADCAST)) {
+            mHandler.sendEmptyMessageDelayed(SEND_PENDING_BROADCAST, BROADCAST_DELAY);
+        }
+    }
+
+    /**
      * Remove entries from the keystore daemon. Will only remove it if the
      * {@code appId} is valid.
      */
@@ -6789,24 +6851,24 @@
         }
         enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */,
                 true /* checkShell */, "stop package");
-        boolean shouldUnhibernate = false;
         // writer
         synchronized (mLock) {
             final PackageSetting ps = mSettings.getPackageLPr(packageName);
-            if (ps != null && ps.getStopped(userId) && !stopped) {
-                shouldUnhibernate = true;
-            }
             if (!shouldFilterApplication(ps, callingUid, userId)
                     && mSettings.setPackageStoppedStateLPw(this, packageName, stopped, userId)) {
                 scheduleWritePackageRestrictionsLocked(userId);
             }
         }
-        if (shouldUnhibernate) {
+        // If this would cause the app to leave force-stop, then also make sure to unhibernate the
+        // app if needed.
+        if (!stopped) {
             mHandler.post(() -> {
                 AppHibernationManagerInternal ah =
                         mInjector.getLocalService(AppHibernationManagerInternal.class);
-                ah.setHibernatingForUser(packageName, userId, false);
-                ah.setHibernatingGlobally(packageName, false);
+                if (ah != null && ah.isHibernatingForUser(packageName, userId)) {
+                    ah.setHibernatingForUser(packageName, userId, false);
+                    ah.setHibernatingGlobally(packageName, false);
+                }
             });
         }
     }
@@ -8195,8 +8257,8 @@
         @Override
         public @PackageManager.EnabledState int getComponentEnabledSetting(
                 @NonNull ComponentName componentName, int callingUid, int userId) {
-            return PackageManagerService.this.mComputer.getComponentEnabledSetting(componentName,
-                    callingUid, userId);
+            return PackageManagerService.this.mComputer.getComponentEnabledSettingInternal(
+                    componentName, callingUid, userId);
         }
 
         @Override
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index d213469..6d031dd 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -67,6 +67,7 @@
 import android.system.ErrnoException;
 import android.system.Os;
 import android.util.ArraySet;
+import android.util.AtomicFile;
 import android.util.Base64;
 import android.util.Log;
 import android.util.LogPrinter;
@@ -100,7 +101,6 @@
 import java.io.FilenameFilter;
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.OutputStream;
 import java.io.PrintWriter;
 import java.nio.file.Path;
 import java.security.SecureRandom;
@@ -679,17 +679,23 @@
                     + "; src: " + srcFile.getAbsolutePath()
                     + ", dst: " + dstFile.getAbsolutePath());
         }
+        final AtomicFile atomicFile = new AtomicFile(dstFile);
+        FileOutputStream outputStream = null;
         try (
-                InputStream fileIn = new GZIPInputStream(new FileInputStream(srcFile));
-                OutputStream fileOut = new FileOutputStream(dstFile, false /*append*/);
+                InputStream fileIn = new GZIPInputStream(new FileInputStream(srcFile))
         ) {
-            FileUtils.copy(fileIn, fileOut);
-            Os.chmod(dstFile.getAbsolutePath(), 0644);
+            outputStream = atomicFile.startWrite();
+            FileUtils.copy(fileIn, outputStream);
+            // Flush anything in buffer before chmod, because any writes after chmod will fail.
+            outputStream.flush();
+            Os.fchmod(outputStream.getFD(), 0644);
+            atomicFile.finishWrite(outputStream);
             return PackageManager.INSTALL_SUCCEEDED;
         } catch (IOException e) {
             logCriticalInfo(Log.ERROR, "Failed to decompress file"
                     + "; src: " + srcFile.getAbsolutePath()
                     + ", dst: " + dstFile.getAbsolutePath());
+            atomicFile.failWrite(outputStream);
         }
         return PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
     }
diff --git a/services/core/java/com/android/server/pm/PackageSessionVerifier.java b/services/core/java/com/android/server/pm/PackageSessionVerifier.java
index 866712c..4f21d0e 100644
--- a/services/core/java/com/android/server/pm/PackageSessionVerifier.java
+++ b/services/core/java/com/android/server/pm/PackageSessionVerifier.java
@@ -527,6 +527,9 @@
     @VisibleForTesting
     void checkRollbacks(StagingManager.StagedSession session)
             throws PackageManagerException {
+        if (session.isDestroyed() || session.isInTerminalState()) {
+            return;
+        }
         for (StagingManager.StagedSession stagedSession : mStagedSessions) {
             if (stagedSession.isDestroyed() || stagedSession.isInTerminalState()) {
                 continue;
@@ -565,6 +568,9 @@
     @VisibleForTesting
     void checkOverlaps(StagingManager.StagedSession parent,
             StagingManager.StagedSession child) throws PackageManagerException {
+        if (parent.isDestroyed() || parent.isInTerminalState()) {
+            return;
+        }
         final String packageName = child.getPackageName();
         if (packageName == null) {
             throw new PackageManagerException(
diff --git a/services/core/java/com/android/server/pm/RemovePackageHelper.java b/services/core/java/com/android/server/pm/RemovePackageHelper.java
index 3a2ac1c..48b893b 100644
--- a/services/core/java/com/android/server/pm/RemovePackageHelper.java
+++ b/services/core/java/com/android/server/pm/RemovePackageHelper.java
@@ -94,9 +94,10 @@
                     }
                 }
 
-                mInstaller.rmPackageDir(codePath.getAbsolutePath());
+                final String packageName = codePath.getName();
+                mInstaller.rmPackageDir(packageName, codePath.getAbsolutePath());
                 if (needRemoveParent) {
-                    mInstaller.rmPackageDir(codePathParent.getAbsolutePath());
+                    mInstaller.rmPackageDir(packageName, codePathParent.getAbsolutePath());
                     removeCachedResult(codePathParent);
                 }
             } catch (Installer.InstallerException e) {
diff --git a/services/core/java/com/android/server/pm/ScanPackageHelper.java b/services/core/java/com/android/server/pm/ScanPackageHelper.java
index 6cc94ce..9b08ef9 100644
--- a/services/core/java/com/android/server/pm/ScanPackageHelper.java
+++ b/services/core/java/com/android/server/pm/ScanPackageHelper.java
@@ -894,14 +894,15 @@
      * Returns if forced apk verification can be skipped for the whole package, including splits.
      */
     private boolean canSkipForcedPackageVerification(AndroidPackage pkg) {
-        if (!canSkipForcedApkVerification(pkg.getBaseApkPath())) {
+        final String packageName = pkg.getPackageName();
+        if (!canSkipForcedApkVerification(packageName, pkg.getBaseApkPath())) {
             return false;
         }
         // TODO: Allow base and splits to be verified individually.
         String[] splitCodePaths = pkg.getSplitCodePaths();
         if (!ArrayUtils.isEmpty(splitCodePaths)) {
             for (int i = 0; i < splitCodePaths.length; i++) {
-                if (!canSkipForcedApkVerification(splitCodePaths[i])) {
+                if (!canSkipForcedApkVerification(packageName, splitCodePaths[i])) {
                     return false;
                 }
             }
@@ -914,7 +915,7 @@
      * whether the apk contains signed root hash.  Note that the signer's certificate still needs to
      * match one in a trusted source, and should be done separately.
      */
-    private boolean canSkipForcedApkVerification(String apkPath) {
+    private boolean canSkipForcedApkVerification(String packageName, String apkPath) {
         if (!PackageManagerServiceUtils.isLegacyApkVerityEnabled()) {
             return VerityUtils.hasFsverity(apkPath);
         }
@@ -926,7 +927,8 @@
             }
             synchronized (mPm.mInstallLock) {
                 // Returns whether the observed root hash matches what kernel has.
-                mPm.mInstaller.assertFsverityRootHashMatches(apkPath, rootHashObserved);
+                mPm.mInstaller.assertFsverityRootHashMatches(packageName, apkPath,
+                        rootHashObserved);
                 return true;
             }
         } catch (Installer.InstallerException | IOException | DigestException
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 302826f..40d8845 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -20,6 +20,8 @@
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
 
 import android.Manifest;
+import android.accounts.Account;
+import android.accounts.AccountManager;
 import android.annotation.ColorRes;
 import android.annotation.DrawableRes;
 import android.annotation.NonNull;
@@ -85,6 +87,7 @@
 import android.security.GateKeeper;
 import android.service.gatekeeper.IGateKeeperService;
 import android.stats.devicepolicy.DevicePolicyEnums;
+import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.AtomicFile;
@@ -3512,6 +3515,39 @@
         }
     }
 
+    @Override
+    public UserHandle createUserWithAttributes(
+            String userName, String userType, @UserInfoFlag int flags,
+            Bitmap userIcon,
+            String accountName, String accountType, PersistableBundle accountOptions) {
+        checkManageOrCreateUsersPermission(flags);
+
+        if (someUserHasAccountNoChecks(accountName, accountType)) {
+            throw new ServiceSpecificException(
+                    UserManager.USER_OPERATION_ERROR_USER_ACCOUNT_ALREADY_EXISTS);
+        }
+
+        UserInfo userInfo;
+        try {
+            userInfo = createUserInternal(userName, userType, flags,
+                    UserHandle.USER_NULL, null);
+
+            if (userInfo == null) {
+                throw new ServiceSpecificException(UserManager.USER_OPERATION_ERROR_UNKNOWN);
+            }
+        } catch (UserManager.CheckedUserOperationException e) {
+            throw e.toServiceSpecificException();
+        }
+
+        if (userIcon != null) {
+            mLocalService.setUserIcon(userInfo.id, userIcon);
+        }
+
+        setSeedAccountDataNoChecks(userInfo.id, accountName, accountType, accountOptions, true);
+
+        return userInfo.getUserHandle();
+    }
+
     private UserInfo createUserInternal(@Nullable String name, @NonNull String userType,
             @UserInfoFlag int flags, @UserIdInt int parentId,
             @Nullable String[] disallowedPackages)
@@ -4934,7 +4970,12 @@
     @Override
     public void setSeedAccountData(@UserIdInt int userId, String accountName, String accountType,
             PersistableBundle accountOptions, boolean persist) {
-        checkManageUsersPermission("Require MANAGE_USERS permission to set user seed data");
+        checkManageUsersPermission("set user seed account data");
+        setSeedAccountDataNoChecks(userId, accountName, accountType, accountOptions, persist);
+    }
+
+    private void setSeedAccountDataNoChecks(@UserIdInt int userId, String accountName,
+            String accountType, PersistableBundle accountOptions, boolean persist) {
         synchronized (mPackagesLock) {
             final UserData userData;
             synchronized (mUsersLock) {
@@ -4996,14 +5037,18 @@
     }
 
     @Override
-    public boolean someUserHasSeedAccount(String accountName, String accountType)
-            throws RemoteException {
-        checkManageUsersPermission("Cannot check seed account information");
+    public boolean someUserHasSeedAccount(String accountName, String accountType) {
+        checkManageUsersPermission("check seed account information");
+        return someUserHasSeedAccountNoChecks(accountName, accountType);
+    }
+
+    private boolean someUserHasSeedAccountNoChecks(String accountName, String accountType) {
         synchronized (mUsersLock) {
             final int userSize = mUsers.size();
             for (int i = 0; i < userSize; i++) {
                 final UserData data = mUsers.valueAt(i);
                 if (data.info.isInitialized()) continue;
+                if (mRemovingUserIds.get(data.info.id)) continue;
                 if (data.seedAccountName == null || !data.seedAccountName.equals(accountName)) {
                     continue;
                 }
@@ -5017,6 +5062,25 @@
     }
 
     @Override
+    public boolean someUserHasAccount(String accountName, String accountType) {
+        checkManageOrCreateUsersPermission("check seed account information");
+        return someUserHasAccountNoChecks(accountName, accountType);
+    }
+
+    private boolean someUserHasAccountNoChecks(
+            String accountName, String accountType) {
+        if (TextUtils.isEmpty(accountName) || TextUtils.isEmpty(accountType)) {
+            return false;
+        }
+
+        final Account account = new Account(accountName, accountType);
+
+        return Binder.withCleanCallingIdentity(() ->
+                AccountManager.get(mContext).someUserHasAccount(account)
+                        || someUserHasSeedAccountNoChecks(accountName, accountType));
+    }
+
+    @Override
     public void onShellCommand(FileDescriptor in, FileDescriptor out,
             FileDescriptor err, String[] args, ShellCallback callback,
             ResultReceiver resultReceiver) {
diff --git a/services/core/java/com/android/server/pm/dex/DexManager.java b/services/core/java/com/android/server/pm/dex/DexManager.java
index 5820489..5371454 100644
--- a/services/core/java/com/android/server/pm/dex/DexManager.java
+++ b/services/core/java/com/android/server/pm/dex/DexManager.java
@@ -1043,10 +1043,12 @@
     public long deleteOptimizedFiles(ArtPackageInfo packageInfo) {
         long freedBytes = 0;
         boolean hadErrors = false;
+        final String packageName = packageInfo.getPackageName();
         for (String codePath : packageInfo.getCodePaths()) {
             for (String isa : packageInfo.getInstructionSets()) {
                 try {
-                    freedBytes += mInstaller.deleteOdex(codePath, isa, packageInfo.getOatDir());
+                    freedBytes += mInstaller.deleteOdex(packageName, codePath, isa,
+                            packageInfo.getOatDir());
                 } catch (InstallerException e) {
                     Log.e(TAG, "Failed deleting oat files for " + codePath, e);
                     hadErrors = true;
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index ece0a62b..e207ff1 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -702,6 +702,14 @@
                         DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, userId),
                 userId, CONTACTS_PERMISSIONS);
 
+        // Maps
+        if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, 0)) {
+            grantPermissionsToSystemPackage(pm,
+                getDefaultSystemHandlerActivityPackageForCategory(pm,
+                        Intent.CATEGORY_APP_MAPS, userId),
+                userId, FOREGROUND_LOCATION_PERMISSIONS);
+        }
+
         // Email
         grantPermissionsToSystemPackage(pm,
                 getDefaultSystemHandlerActivityPackageForCategory(pm,
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index c6ff8a0..131e587 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -124,7 +124,6 @@
 import android.hardware.hdmi.HdmiPlaybackClient;
 import android.hardware.hdmi.HdmiPlaybackClient.OneTouchPlayCallback;
 import android.hardware.input.InputManagerInternal;
-import android.media.AudioAttributes;
 import android.media.AudioManager;
 import android.media.AudioManagerInternal;
 import android.media.AudioSystem;
@@ -149,6 +148,7 @@
 import android.os.Trace;
 import android.os.UEventObserver;
 import android.os.UserHandle;
+import android.os.VibrationAttributes;
 import android.os.VibrationEffect;
 import android.os.Vibrator;
 import android.provider.DeviceConfig;
@@ -330,10 +330,12 @@
     private static final String TALKBACK_LABEL = "TalkBack";
 
     private static final int POWER_BUTTON_SUPPRESSION_DELAY_DEFAULT_MILLIS = 800;
-    private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder()
-            .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
-            .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
-            .build();
+    private static final VibrationAttributes TOUCH_VIBRATION_ATTRIBUTES =
+            VibrationAttributes.createForUsage(VibrationAttributes.USAGE_TOUCH);
+    private static final VibrationAttributes PHYSICAL_EMULATION_VIBRATION_ATTRIBUTES =
+            VibrationAttributes.createForUsage(VibrationAttributes.USAGE_PHYSICAL_EMULATION);
+    private static final VibrationAttributes HARDWARE_FEEDBACK_VIBRATION_ATTRIBUTES =
+            VibrationAttributes.createForUsage(VibrationAttributes.USAGE_HARDWARE_FEEDBACK);
 
     /**
      * Keyguard stuff
@@ -1117,21 +1119,21 @@
                 break;
             case LONG_PRESS_POWER_GLOBAL_ACTIONS:
                 mPowerKeyHandled = true;
-                performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, false,
+                performHapticFeedback(HapticFeedbackConstants.LONG_PRESS_POWER_BUTTON, false,
                         "Power - Long Press - Global Actions");
                 showGlobalActions();
                 break;
             case LONG_PRESS_POWER_SHUT_OFF:
             case LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM:
                 mPowerKeyHandled = true;
-                performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, false,
+                performHapticFeedback(HapticFeedbackConstants.LONG_PRESS_POWER_BUTTON, false,
                         "Power - Long Press - Shut Off");
                 sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
                 mWindowManagerFuncs.shutdown(behavior == LONG_PRESS_POWER_SHUT_OFF);
                 break;
             case LONG_PRESS_POWER_GO_TO_VOICE_ASSIST:
                 mPowerKeyHandled = true;
-                performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, false,
+                performHapticFeedback(HapticFeedbackConstants.LONG_PRESS_POWER_BUTTON, false,
                         "Power - Long Press - Go To Voice Assist");
                 // Some devices allow the voice assistant intent during setup (and use that intent
                 // to launch something else, like Settings). So we explicitly allow that via the
@@ -1155,7 +1157,7 @@
                 break;
             case VERY_LONG_PRESS_POWER_GLOBAL_ACTIONS:
                 mPowerKeyHandled = true;
-                performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, false,
+                performHapticFeedback(HapticFeedbackConstants.LONG_PRESS_POWER_BUTTON, false,
                         "Power - Very Long Press - Show Global Actions");
                 showGlobalActions();
                 break;
@@ -2100,7 +2102,8 @@
                                 mPowerKeyHandled = true;
                                 break;
                             case POWER_VOLUME_UP_BEHAVIOR_GLOBAL_ACTIONS:
-                                performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, false,
+                                performHapticFeedback(
+                                        HapticFeedbackConstants.LONG_PRESS_POWER_BUTTON, false,
                                         "Power + Volume Up - Global Actions");
                                 showGlobalActions();
                                 mPowerKeyHandled = true;
@@ -5293,7 +5296,7 @@
             return false;
         }
 
-        mVibrator.vibrate(uid, packageName, effect, reason, VIBRATION_ATTRIBUTES);
+        mVibrator.vibrate(uid, packageName, effect, reason, getVibrationAttributes(effectId));
         return true;
     }
 
@@ -5322,6 +5325,7 @@
             case HapticFeedbackConstants.GESTURE_START:
                 return VibrationEffect.get(VibrationEffect.EFFECT_CLICK);
             case HapticFeedbackConstants.LONG_PRESS:
+            case HapticFeedbackConstants.LONG_PRESS_POWER_BUTTON:
             case HapticFeedbackConstants.EDGE_SQUEEZE:
                 return VibrationEffect.get(VibrationEffect.EFFECT_HEAVY_CLICK);
             case HapticFeedbackConstants.REJECT:
@@ -5360,6 +5364,22 @@
         }
     }
 
+    private VibrationAttributes getVibrationAttributes(int effectId) {
+        switch (effectId) {
+            case HapticFeedbackConstants.EDGE_SQUEEZE:
+            case HapticFeedbackConstants.EDGE_RELEASE:
+                return PHYSICAL_EMULATION_VIBRATION_ATTRIBUTES;
+            case HapticFeedbackConstants.ASSISTANT_BUTTON:
+            case HapticFeedbackConstants.LONG_PRESS_POWER_BUTTON:
+            case HapticFeedbackConstants.ROTARY_SCROLL_TICK:
+            case HapticFeedbackConstants.ROTARY_SCROLL_ITEM_FOCUS:
+            case HapticFeedbackConstants.ROTARY_SCROLL_LIMIT:
+                return HARDWARE_FEEDBACK_VIBRATION_ATTRIBUTES;
+            default:
+                return TOUCH_VIBRATION_ATTRIBUTES;
+        }
+    }
+
     @Override
     public void keepScreenOnStartedLw() {
     }
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index 14b2eab..70a804b 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -26,7 +26,6 @@
 import android.content.Intent;
 import android.hardware.display.DisplayManagerInternal;
 import android.hardware.input.InputManagerInternal;
-import android.media.AudioAttributes;
 import android.media.AudioManager;
 import android.media.Ringtone;
 import android.media.RingtoneManager;
@@ -42,6 +41,7 @@
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.UserHandle;
+import android.os.VibrationAttributes;
 import android.os.VibrationEffect;
 import android.os.Vibrator;
 import android.os.WorkSource;
@@ -110,9 +110,8 @@
     private static final VibrationEffect CHARGING_VIBRATION_EFFECT =
             VibrationEffect.createWaveform(CHARGING_VIBRATION_TIME, CHARGING_VIBRATION_AMPLITUDE,
                     -1);
-    private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder()
-            .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
-            .build();
+    private static final VibrationAttributes HARDWARE_FEEDBACK_VIBRATION_ATTRIBUTES =
+            VibrationAttributes.createForUsage(VibrationAttributes.USAGE_HARDWARE_FEEDBACK);
 
     private final Object mLock = new Object();
 
@@ -808,7 +807,7 @@
         final boolean vibrate = Settings.Secure.getIntForUser(mContext.getContentResolver(),
                 Settings.Secure.CHARGING_VIBRATION_ENABLED, 1, userId) != 0;
         if (vibrate) {
-            mVibrator.vibrate(CHARGING_VIBRATION_EFFECT, VIBRATION_ATTRIBUTES);
+            mVibrator.vibrate(CHARGING_VIBRATION_EFFECT, HARDWARE_FEEDBACK_VIBRATION_ATTRIBUTES);
         }
 
         // play sound
diff --git a/services/core/java/com/android/server/stats/bootstrap/StatsBootstrapAtomService.java b/services/core/java/com/android/server/stats/bootstrap/StatsBootstrapAtomService.java
new file mode 100644
index 0000000..0d420a5
--- /dev/null
+++ b/services/core/java/com/android/server/stats/bootstrap/StatsBootstrapAtomService.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 com.android.server.stats.bootstrap;
+
+import android.content.Context;
+import android.os.IStatsBootstrapAtomService;
+import android.os.StatsBootstrapAtom;
+import android.os.StatsBootstrapAtomValue;
+import android.util.Slog;
+import android.util.StatsEvent;
+import android.util.StatsLog;
+
+import com.android.server.SystemService;
+
+/**
+ * Proxy service for logging pushed atoms to statsd
+ *
+ * @hide
+ */
+public class StatsBootstrapAtomService extends IStatsBootstrapAtomService.Stub {
+
+    private static final String TAG = "StatsBootstrapAtomService";
+    private static final boolean DEBUG = false;
+
+    @Override
+    public void reportBootstrapAtom(StatsBootstrapAtom atom) {
+        if (atom.atomId < 1 || atom.atomId >= 10000) {
+            Slog.e(TAG, "Atom ID " + atom.atomId + " is not a valid atom ID");
+            return;
+        }
+        StatsEvent.Builder builder = StatsEvent.newBuilder().setAtomId(atom.atomId);
+        for (StatsBootstrapAtomValue value : atom.values) {
+            switch (value.getTag()) {
+                case StatsBootstrapAtomValue.boolValue:
+                    builder.writeBoolean(value.getBoolValue());
+                    break;
+                case StatsBootstrapAtomValue.intValue:
+                    builder.writeInt(value.getIntValue());
+                    break;
+                case StatsBootstrapAtomValue.longValue:
+                    builder.writeLong(value.getLongValue());
+                    break;
+                case StatsBootstrapAtomValue.floatValue:
+                    builder.writeFloat(value.getFloatValue());
+                    break;
+                case StatsBootstrapAtomValue.stringValue:
+                    builder.writeString(value.getStringValue());
+                    break;
+                case StatsBootstrapAtomValue.bytesValue:
+                    builder.writeByteArray(value.getBytesValue());
+                    break;
+                default:
+                    Slog.e(TAG, "Unexpected value type " + value.getTag()
+                            + " when logging atom " + atom.atomId);
+                    return;
+
+            }
+        }
+        StatsLog.write(builder.usePooledBuffer().build());
+    }
+
+    /**
+     * Lifecycle and related code
+     */
+    public static final class Lifecycle extends SystemService {
+        private StatsBootstrapAtomService mStatsBootstrapAtomService;
+
+        public Lifecycle(Context context) {
+            super(context);
+        }
+
+        @Override
+        public void onStart() {
+            mStatsBootstrapAtomService = new StatsBootstrapAtomService();
+            try {
+                publishBinderService(Context.STATS_BOOTSTRAP_ATOM_SERVICE,
+                        mStatsBootstrapAtomService);
+                if (DEBUG) Slog.d(TAG, "Published " + Context.STATS_BOOTSTRAP_ATOM_SERVICE);
+            } catch (Exception e) {
+                Slog.e(TAG, "Failed to publishBinderService", e);
+            }
+        }
+    }
+
+}
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index 7cdae58..3182290 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -56,6 +56,7 @@
 import static com.android.internal.util.FrameworkStatsLog.TIME_ZONE_DETECTOR_STATE__DETECTION_MODE__GEO;
 import static com.android.internal.util.FrameworkStatsLog.TIME_ZONE_DETECTOR_STATE__DETECTION_MODE__MANUAL;
 import static com.android.internal.util.FrameworkStatsLog.TIME_ZONE_DETECTOR_STATE__DETECTION_MODE__TELEPHONY;
+import static com.android.internal.util.FrameworkStatsLog.TIME_ZONE_DETECTOR_STATE__DETECTION_MODE__UNKNOWN;
 import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem;
 import static com.android.server.stats.pull.IonMemoryUtil.readProcessSystemIonHeapSizesFromDebugfs;
 import static com.android.server.stats.pull.IonMemoryUtil.readSystemIonHeapSizeFromDebugfs;
@@ -3407,7 +3408,7 @@
             pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag,
                     metricsState.isTelephonyDetectionSupported(),
                     metricsState.isGeoDetectionSupported(),
-                    metricsState.isUserLocationEnabled(),
+                    metricsState.getUserLocationEnabledSetting(),
                     metricsState.getAutoDetectionEnabledSetting(),
                     metricsState.getGeoDetectionEnabledSetting(),
                     convertToMetricsDetectionMode(metricsState.getDetectionMode()),
@@ -3434,7 +3435,7 @@
             case MetricsTimeZoneDetectorState.DETECTION_MODE_TELEPHONY:
                 return TIME_ZONE_DETECTOR_STATE__DETECTION_MODE__TELEPHONY;
             default:
-                throw new IllegalArgumentException("" + detectionMode);
+                return TIME_ZONE_DETECTOR_STATE__DETECTION_MODE__UNKNOWN;
         }
     }
 
diff --git a/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java b/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java
index 22814b3..1a5945e 100644
--- a/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java
+++ b/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java
@@ -39,21 +39,21 @@
 
     private final boolean mTelephonyDetectionSupported;
     private final boolean mGeoDetectionSupported;
-    private final boolean mAutoDetectionEnabled;
+    private final boolean mAutoDetectionEnabledSetting;
     private final @UserIdInt int mUserId;
     private final boolean mUserConfigAllowed;
-    private final boolean mLocationEnabled;
-    private final boolean mGeoDetectionEnabled;
+    private final boolean mLocationEnabledSetting;
+    private final boolean mGeoDetectionEnabledSetting;
 
     private ConfigurationInternal(Builder builder) {
         mTelephonyDetectionSupported = builder.mTelephonyDetectionSupported;
         mGeoDetectionSupported = builder.mGeoDetectionSupported;
-        mAutoDetectionEnabled = builder.mAutoDetectionEnabled;
+        mAutoDetectionEnabledSetting = builder.mAutoDetectionEnabledSetting;
 
         mUserId = builder.mUserId;
         mUserConfigAllowed = builder.mUserConfigAllowed;
-        mLocationEnabled = builder.mLocationEnabled;
-        mGeoDetectionEnabled = builder.mGeoDetectionEnabled;
+        mLocationEnabledSetting = builder.mLocationEnabledSetting;
+        mGeoDetectionEnabledSetting = builder.mGeoDetectionEnabledSetting;
     }
 
     /** Returns true if the device supports any form of auto time zone detection. */
@@ -73,7 +73,7 @@
 
     /** Returns the value of the auto time zone detection enabled setting. */
     public boolean getAutoDetectionEnabledSetting() {
-        return mAutoDetectionEnabled;
+        return mAutoDetectionEnabledSetting;
     }
 
     /**
@@ -81,7 +81,7 @@
      * from the raw setting value.
      */
     public boolean getAutoDetectionEnabledBehavior() {
-        return isAutoDetectionSupported() && mAutoDetectionEnabled;
+        return isAutoDetectionSupported() && mAutoDetectionEnabledSetting;
     }
 
     /** Returns the ID of the user this configuration is associated with. */
@@ -101,13 +101,13 @@
     }
 
     /** Returns true if user's location can be used generally. */
-    public boolean isLocationEnabled() {
-        return mLocationEnabled;
+    public boolean getLocationEnabledSetting() {
+        return mLocationEnabledSetting;
     }
 
     /** Returns the value of the geolocation time zone detection enabled setting. */
     public boolean getGeoDetectionEnabledSetting() {
-        return mGeoDetectionEnabled;
+        return mGeoDetectionEnabledSetting;
     }
 
     /**
@@ -117,7 +117,7 @@
     public boolean getGeoDetectionEnabledBehavior() {
         return getAutoDetectionEnabledBehavior()
                 && isGeoDetectionSupported()
-                && isLocationEnabled()
+                && getLocationEnabledSetting()
                 && getGeoDetectionEnabledSetting();
     }
 
@@ -154,7 +154,7 @@
         final int configureGeolocationDetectionEnabledCapability;
         if (!deviceHasLocationTimeZoneDetection) {
             configureGeolocationDetectionEnabledCapability = CAPABILITY_NOT_SUPPORTED;
-        } else if (!mAutoDetectionEnabled || !isLocationEnabled()) {
+        } else if (!mAutoDetectionEnabledSetting || !getLocationEnabledSetting()) {
             configureGeolocationDetectionEnabledCapability = CAPABILITY_NOT_APPLICABLE;
         } else {
             configureGeolocationDetectionEnabledCapability = CAPABILITY_POSSESSED;
@@ -195,10 +195,10 @@
     public ConfigurationInternal merge(TimeZoneConfiguration newConfiguration) {
         Builder builder = new Builder(this);
         if (newConfiguration.hasIsAutoDetectionEnabled()) {
-            builder.setAutoDetectionEnabled(newConfiguration.isAutoDetectionEnabled());
+            builder.setAutoDetectionEnabledSetting(newConfiguration.isAutoDetectionEnabled());
         }
         if (newConfiguration.hasIsGeoDetectionEnabled()) {
-            builder.setGeoDetectionEnabled(newConfiguration.isGeoDetectionEnabled());
+            builder.setGeoDetectionEnabledSetting(newConfiguration.isGeoDetectionEnabled());
         }
         return builder.build();
     }
@@ -216,16 +216,16 @@
                 && mUserConfigAllowed == that.mUserConfigAllowed
                 && mTelephonyDetectionSupported == that.mTelephonyDetectionSupported
                 && mGeoDetectionSupported == that.mGeoDetectionSupported
-                && mAutoDetectionEnabled == that.mAutoDetectionEnabled
-                && mLocationEnabled == that.mLocationEnabled
-                && mGeoDetectionEnabled == that.mGeoDetectionEnabled;
+                && mAutoDetectionEnabledSetting == that.mAutoDetectionEnabledSetting
+                && mLocationEnabledSetting == that.mLocationEnabledSetting
+                && mGeoDetectionEnabledSetting == that.mGeoDetectionEnabledSetting;
     }
 
     @Override
     public int hashCode() {
         return Objects.hash(mUserId, mUserConfigAllowed, mTelephonyDetectionSupported,
-                mGeoDetectionSupported, mAutoDetectionEnabled, mLocationEnabled,
-                mGeoDetectionEnabled);
+                mGeoDetectionSupported, mAutoDetectionEnabledSetting, mLocationEnabledSetting,
+                mGeoDetectionEnabledSetting);
     }
 
     @Override
@@ -235,9 +235,9 @@
                 + ", mUserConfigAllowed=" + mUserConfigAllowed
                 + ", mTelephonyDetectionSupported=" + mTelephonyDetectionSupported
                 + ", mGeoDetectionSupported=" + mGeoDetectionSupported
-                + ", mAutoDetectionEnabled=" + mAutoDetectionEnabled
-                + ", mLocationEnabled=" + mLocationEnabled
-                + ", mGeoDetectionEnabled=" + mGeoDetectionEnabled
+                + ", mAutoDetectionEnabledSetting=" + mAutoDetectionEnabledSetting
+                + ", mLocationEnabledSetting=" + mLocationEnabledSetting
+                + ", mGeoDetectionEnabledSetting=" + mGeoDetectionEnabledSetting
                 + '}';
     }
 
@@ -251,9 +251,9 @@
         private boolean mUserConfigAllowed;
         private boolean mTelephonyDetectionSupported;
         private boolean mGeoDetectionSupported;
-        private boolean mAutoDetectionEnabled;
-        private boolean mLocationEnabled;
-        private boolean mGeoDetectionEnabled;
+        private boolean mAutoDetectionEnabledSetting;
+        private boolean mLocationEnabledSetting;
+        private boolean mGeoDetectionEnabledSetting;
 
         /**
          * Creates a new Builder with only the userId set.
@@ -270,9 +270,9 @@
             this.mUserConfigAllowed = toCopy.mUserConfigAllowed;
             this.mTelephonyDetectionSupported = toCopy.mTelephonyDetectionSupported;
             this.mGeoDetectionSupported = toCopy.mGeoDetectionSupported;
-            this.mAutoDetectionEnabled = toCopy.mAutoDetectionEnabled;
-            this.mLocationEnabled = toCopy.mLocationEnabled;
-            this.mGeoDetectionEnabled = toCopy.mGeoDetectionEnabled;
+            this.mAutoDetectionEnabledSetting = toCopy.mAutoDetectionEnabledSetting;
+            this.mLocationEnabledSetting = toCopy.mLocationEnabledSetting;
+            this.mGeoDetectionEnabledSetting = toCopy.mGeoDetectionEnabledSetting;
         }
 
         /**
@@ -302,24 +302,24 @@
         /**
          * Sets the value of the automatic time zone detection enabled setting for this device.
          */
-        public Builder setAutoDetectionEnabled(boolean enabled) {
-            mAutoDetectionEnabled = enabled;
+        public Builder setAutoDetectionEnabledSetting(boolean enabled) {
+            mAutoDetectionEnabledSetting = enabled;
             return this;
         }
 
         /**
          * Sets the value of the location mode setting for this user.
          */
-        public Builder setLocationEnabled(boolean enabled) {
-            mLocationEnabled = enabled;
+        public Builder setLocationEnabledSetting(boolean enabled) {
+            mLocationEnabledSetting = enabled;
             return this;
         }
 
         /**
          * Sets the value of the geolocation time zone detection setting for this user.
          */
-        public Builder setGeoDetectionEnabled(boolean enabled) {
-            mGeoDetectionEnabled = enabled;
+        public Builder setGeoDetectionEnabledSetting(boolean enabled) {
+            mGeoDetectionEnabledSetting = enabled;
             return this;
         }
 
diff --git a/services/core/java/com/android/server/timezonedetector/EnvironmentImpl.java b/services/core/java/com/android/server/timezonedetector/EnvironmentImpl.java
index fc6e372..ec620b5 100644
--- a/services/core/java/com/android/server/timezonedetector/EnvironmentImpl.java
+++ b/services/core/java/com/android/server/timezonedetector/EnvironmentImpl.java
@@ -16,126 +16,44 @@
 
 package com.android.server.timezonedetector;
 
-import static android.content.Intent.ACTION_USER_SWITCHED;
-
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UserIdInt;
-import android.app.ActivityManagerInternal;
 import android.app.AlarmManager;
-import android.app.time.TimeZoneConfiguration;
-import android.content.BroadcastReceiver;
-import android.content.ContentResolver;
 import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.database.ContentObserver;
-import android.location.LocationManager;
 import android.os.Handler;
 import android.os.SystemProperties;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.provider.Settings;
-import android.util.Slog;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.server.LocalServices;
 
 import java.util.Objects;
-import java.util.Optional;
 
 /**
  * The real implementation of {@link TimeZoneDetectorStrategyImpl.Environment}.
  */
 final class EnvironmentImpl implements TimeZoneDetectorStrategyImpl.Environment {
 
-    private static final String LOG_TAG = TimeZoneDetectorService.TAG;
     private static final String TIMEZONE_PROPERTY = "persist.sys.timezone";
 
     @NonNull private final Context mContext;
     @NonNull private final Handler mHandler;
-    @NonNull private final ContentResolver mCr;
-    @NonNull private final UserManager mUserManager;
     @NonNull private final ServiceConfigAccessor mServiceConfigAccessor;
-    @NonNull private final LocationManager mLocationManager;
-
-    // @NonNull after setConfigChangeListener() is called.
-    @GuardedBy("this")
-    private ConfigurationChangeListener mConfigChangeListener;
 
     EnvironmentImpl(@NonNull Context context, @NonNull Handler handler,
             @NonNull ServiceConfigAccessor serviceConfigAccessor) {
         mContext = Objects.requireNonNull(context);
         mHandler = Objects.requireNonNull(handler);
-        mCr = context.getContentResolver();
-        mUserManager = context.getSystemService(UserManager.class);
-        mLocationManager = context.getSystemService(LocationManager.class);
         mServiceConfigAccessor = Objects.requireNonNull(serviceConfigAccessor);
-
-        // Wire up the config change listeners for anything that could affect the return values from
-        // this object. All listener invocations are performed on the mHandler thread.
-
-        // Listen for the user changing / the user's location mode changing.
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(ACTION_USER_SWITCHED);
-        filter.addAction(LocationManager.MODE_CHANGED_ACTION);
-        mContext.registerReceiverForAllUsers(new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                handleConfigChangeOnHandlerThread();
-            }
-        }, filter, null, mHandler);
-
-        // Add async callbacks for global settings being changed.
-        ContentResolver contentResolver = mContext.getContentResolver();
-        ContentObserver contentObserver = new ContentObserver(mHandler) {
-            @Override
-            public void onChange(boolean selfChange) {
-                handleConfigChangeOnHandlerThread();
-            }
-        };
-        contentResolver.registerContentObserver(
-                Settings.Global.getUriFor(Settings.Global.AUTO_TIME_ZONE), true, contentObserver);
-
-        // Add async callbacks for user scoped location settings being changed.
-        contentResolver.registerContentObserver(
-                Settings.Secure.getUriFor(Settings.Secure.LOCATION_TIME_ZONE_DETECTION_ENABLED),
-                true, contentObserver, UserHandle.USER_ALL);
-    }
-
-    private void handleConfigChangeOnHandlerThread() {
-        synchronized (this) {
-            if (mConfigChangeListener == null) {
-                Slog.wtf(LOG_TAG, "mConfigChangeListener is unexpectedly null");
-            }
-            mConfigChangeListener.onChange();
-        }
     }
 
     @Override
-    public void setConfigChangeListener(@NonNull ConfigurationChangeListener listener) {
-        synchronized (this) {
-            mConfigChangeListener = Objects.requireNonNull(listener);
-        }
+    public void setConfigurationInternalChangeListener(
+            @NonNull ConfigurationChangeListener listener) {
+        ConfigurationChangeListener configurationChangeListener =
+                () -> mHandler.post(listener::onChange);
+        mServiceConfigAccessor.addConfigurationInternalChangeListener(configurationChangeListener);
     }
 
     @Override
-    public ConfigurationInternal getConfigurationInternal(@UserIdInt int userId) {
-        return new ConfigurationInternal.Builder(userId)
-                .setTelephonyDetectionFeatureSupported(
-                        mServiceConfigAccessor.isTelephonyTimeZoneDetectionFeatureSupported())
-                .setGeoDetectionFeatureSupported(
-                        mServiceConfigAccessor.isGeoTimeZoneDetectionFeatureSupported())
-                .setAutoDetectionEnabled(isAutoDetectionEnabled())
-                .setUserConfigAllowed(isUserConfigAllowed(userId))
-                .setLocationEnabled(isLocationEnabled(userId))
-                .setGeoDetectionEnabled(isGeoDetectionEnabled(userId))
-                .build();
-    }
-
-    @Override
-    public @UserIdInt int getCurrentUserId() {
-        return LocalServices.getService(ActivityManagerInternal.class).getCurrentUserId();
+    public ConfigurationInternal getCurrentUserConfigurationInternal() {
+        return mServiceConfigAccessor.getCurrentUserConfigurationInternal();
     }
 
     @Override
@@ -161,78 +79,4 @@
         AlarmManager alarmManager = mContext.getSystemService(AlarmManager.class);
         alarmManager.setTimeZone(zoneId);
     }
-
-    @Override
-    public void storeConfiguration(@UserIdInt int userId, TimeZoneConfiguration configuration) {
-        Objects.requireNonNull(configuration);
-
-        // Avoid writing the auto detection enabled setting for devices that do not support auto
-        // time zone detection: if we wrote it down then we'd set the value explicitly, which would
-        // prevent detecting "default" later. That might influence what happens on later releases
-        // that support new types of auto detection on the same hardware.
-        if (mServiceConfigAccessor.isAutoDetectionFeatureSupported()) {
-            final boolean autoDetectionEnabled = configuration.isAutoDetectionEnabled();
-            setAutoDetectionEnabledIfRequired(autoDetectionEnabled);
-
-            // Avoid writing the geo detection enabled setting for devices with settings that
-            // are currently overridden by server flags: otherwise we might overwrite a droidfood
-            // user's real setting permanently.
-            // Also avoid writing the geo detection enabled setting for devices that do not support
-            // geo time zone detection: if we wrote it down then we'd set the value explicitly,
-            // which would prevent detecting "default" later. That might influence what happens on
-            // later releases that start to support geo detection on the same hardware.
-            if (!mServiceConfigAccessor.getGeoDetectionSettingEnabledOverride().isPresent()
-                    && mServiceConfigAccessor.isGeoTimeZoneDetectionFeatureSupported()) {
-                final boolean geoTzDetectionEnabled = configuration.isGeoDetectionEnabled();
-                setGeoDetectionEnabledIfRequired(userId, geoTzDetectionEnabled);
-            }
-        }
-    }
-
-    private boolean isUserConfigAllowed(@UserIdInt int userId) {
-        UserHandle userHandle = UserHandle.of(userId);
-        return !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_DATE_TIME, userHandle);
-    }
-
-    private boolean isAutoDetectionEnabled() {
-        return Settings.Global.getInt(mCr, Settings.Global.AUTO_TIME_ZONE, 1 /* default */) > 0;
-    }
-
-    private void setAutoDetectionEnabledIfRequired(boolean enabled) {
-        // This check is racey, but the whole settings update process is racey. This check prevents
-        // a ConfigurationChangeListener callback triggering due to ContentObserver's still
-        // triggering *sometimes* for no-op updates. Because callbacks are async this is necessary
-        // for stable behavior during tests.
-        if (isAutoDetectionEnabled() != enabled) {
-            Settings.Global.putInt(mCr, Settings.Global.AUTO_TIME_ZONE, enabled ? 1 : 0);
-        }
-    }
-
-    private boolean isLocationEnabled(@UserIdInt int userId) {
-        return mLocationManager.isLocationEnabledForUser(UserHandle.of(userId));
-    }
-
-    private boolean isGeoDetectionEnabled(@UserIdInt int userId) {
-        // We may never use this, but it gives us a way to force location-based time zone detection
-        // on/off for testers (but only where their other settings would allow them to turn it on
-        // for themselves).
-        Optional<Boolean> override = mServiceConfigAccessor.getGeoDetectionSettingEnabledOverride();
-        if (override.isPresent()) {
-            return override.get();
-        }
-
-        final boolean geoDetectionEnabledByDefault =
-                mServiceConfigAccessor.isGeoDetectionEnabledForUsersByDefault();
-        return Settings.Secure.getIntForUser(mCr,
-                Settings.Secure.LOCATION_TIME_ZONE_DETECTION_ENABLED,
-                (geoDetectionEnabledByDefault ? 1 : 0) /* defaultValue */, userId) != 0;
-    }
-
-    private void setGeoDetectionEnabledIfRequired(@UserIdInt int userId, boolean enabled) {
-        // See comment in setAutoDetectionEnabledIfRequired. http://b/171953500
-        if (isGeoDetectionEnabled(userId) != enabled) {
-            Settings.Secure.putIntForUser(mCr, Settings.Secure.LOCATION_TIME_ZONE_DETECTION_ENABLED,
-                    enabled ? 1 : 0, userId);
-        }
-    }
 }
diff --git a/services/core/java/com/android/server/timezonedetector/MetricsTimeZoneDetectorState.java b/services/core/java/com/android/server/timezonedetector/MetricsTimeZoneDetectorState.java
index 9eb6a45..f8ba0d2 100644
--- a/services/core/java/com/android/server/timezonedetector/MetricsTimeZoneDetectorState.java
+++ b/services/core/java/com/android/server/timezonedetector/MetricsTimeZoneDetectorState.java
@@ -56,16 +56,11 @@
     public static final @DetectionMode int DETECTION_MODE_GEO = 1;
     public static final @DetectionMode int DETECTION_MODE_TELEPHONY = 2;
 
-    @NonNull
-    private final ConfigurationInternal mConfigurationInternal;
-    @NonNull
+    @NonNull private final ConfigurationInternal mConfigurationInternal;
     private final int mDeviceTimeZoneIdOrdinal;
-    @Nullable
-    private final MetricsTimeZoneSuggestion mLatestManualSuggestion;
-    @Nullable
-    private final MetricsTimeZoneSuggestion mLatestTelephonySuggestion;
-    @Nullable
-    private final MetricsTimeZoneSuggestion mLatestGeolocationSuggestion;
+    @Nullable private final MetricsTimeZoneSuggestion mLatestManualSuggestion;
+    @Nullable private final MetricsTimeZoneSuggestion mLatestTelephonySuggestion;
+    @Nullable private final MetricsTimeZoneSuggestion mLatestGeolocationSuggestion;
 
     private MetricsTimeZoneDetectorState(
             @NonNull ConfigurationInternal configurationInternal,
@@ -117,8 +112,8 @@
     }
 
     /** Returns true if user's location can be used generally. */
-    public boolean isUserLocationEnabled() {
-        return mConfigurationInternal.isLocationEnabled();
+    public boolean getUserLocationEnabledSetting() {
+        return mConfigurationInternal.getLocationEnabledSetting();
     }
 
     /** Returns the value of the geolocation time zone detection enabled setting. */
@@ -149,7 +144,6 @@
      * 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;
     }
@@ -281,6 +275,7 @@
             return new MetricsTimeZoneSuggestion(null);
         }
 
+        @NonNull
         public static MetricsTimeZoneSuggestion createCertain(
                 @NonNull int[] zoneIdOrdinals) {
             return new MetricsTimeZoneSuggestion(zoneIdOrdinals);
diff --git a/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessor.java b/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessor.java
index f7ac9b6..984b9ba 100644
--- a/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessor.java
+++ b/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessor.java
@@ -18,165 +18,96 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.StringDef;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.content.res.Resources;
-import android.util.ArraySet;
-
-import com.android.internal.R;
-import com.android.internal.annotations.GuardedBy;
-import com.android.server.timedetector.ServerFlags;
+import android.annotation.UserIdInt;
+import android.app.time.TimeZoneConfiguration;
 
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 import java.time.Duration;
-import java.util.Collections;
-import java.util.Objects;
 import java.util.Optional;
-import java.util.Set;
 
 /**
- * A singleton that provides access to service configuration for time zone detection. This hides how
- * configuration is split between static, compile-time config and dynamic, server-pushed flags. It
- * provides a rudimentary mechanism to signal when values have changed.
+ * An interface that provides access to service configuration for time zone detection. This hides
+ * how configuration is split between static, compile-time config, dynamic server-pushed flags and
+ * user settings. It provides listeners to signal when values that affect different components have
+ * changed.
  */
-public final class ServiceConfigAccessor {
+public interface ServiceConfigAccessor {
 
     @StringDef(prefix = "PROVIDER_MODE_",
-            value = { PROVIDER_MODE_DISABLED, PROVIDER_MODE_ENABLED})
+            value = { PROVIDER_MODE_DISABLED, PROVIDER_MODE_ENABLED })
     @Retention(RetentionPolicy.SOURCE)
     @Target({ ElementType.TYPE_USE, ElementType.TYPE_PARAMETER })
-    @interface ProviderMode {}
+    @interface ProviderMode {
+    }
 
     /**
      * The "disabled" provider mode. For use with {@link #getPrimaryLocationTimeZoneProviderMode()}
      * and {@link #getSecondaryLocationTimeZoneProviderMode()}.
      */
-    public static final @ProviderMode String PROVIDER_MODE_DISABLED = "disabled";
+    @ProviderMode String PROVIDER_MODE_DISABLED = "disabled";
 
     /**
      * The "enabled" provider mode. For use with {@link #getPrimaryLocationTimeZoneProviderMode()}
      * and {@link #getSecondaryLocationTimeZoneProviderMode()}.
      */
-    public static final @ProviderMode String PROVIDER_MODE_ENABLED = "enabled";
+    @ProviderMode String PROVIDER_MODE_ENABLED = "enabled";
 
     /**
-     * Device config keys that can affect {@link
-     * com.android.server.timezonedetector.location.LocationTimeZoneManagerService} behavior.
+     * Adds a listener that will be invoked when {@link ConfigurationInternal} may have changed.
+     * The listener is invoked on the main thread.
      */
-    private static final Set<String> LOCATION_TIME_ZONE_MANAGER_SERVER_FLAGS_KEYS_TO_WATCH =
-            Collections.unmodifiableSet(new ArraySet<>(new String[] {
-                    ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_FEATURE_SUPPORTED,
-                    ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_DEFAULT,
-                    ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_OVERRIDE,
-                    ServerFlags.KEY_PRIMARY_LTZP_MODE_OVERRIDE,
-                    ServerFlags.KEY_SECONDARY_LTZP_MODE_OVERRIDE,
-                    ServerFlags.KEY_LTZP_INITIALIZATION_TIMEOUT_MILLIS,
-                    ServerFlags.KEY_LTZP_INITIALIZATION_TIMEOUT_FUZZ_MILLIS,
-                    ServerFlags.KEY_LTZP_EVENT_FILTERING_AGE_THRESHOLD_MILLIS,
-                    ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_UNCERTAINTY_DELAY_MILLIS
-            }));
-
-    private static final Duration DEFAULT_LTZP_INITIALIZATION_TIMEOUT = Duration.ofMinutes(5);
-    private static final Duration DEFAULT_LTZP_INITIALIZATION_TIMEOUT_FUZZ = Duration.ofMinutes(1);
-    private static final Duration DEFAULT_LTZP_UNCERTAINTY_DELAY = Duration.ofMinutes(5);
-    private static final Duration DEFAULT_LTZP_EVENT_FILTER_AGE_THRESHOLD = Duration.ofMinutes(1);
-
-    private static final Object SLOCK = new Object();
-
-    /** The singleton instance. Initialized once in {@link #getInstance(Context)}. */
-    @GuardedBy("SLOCK")
-    @Nullable
-    private static ServiceConfigAccessor sInstance;
-
-    @NonNull private final Context mContext;
-
-    @NonNull private final ServerFlags mServerFlags;
+    void addConfigurationInternalChangeListener(
+            @NonNull ConfigurationChangeListener listener);
 
     /**
-     * The mode to use for the primary location time zone provider in a test. Setting this
-     * disables some permission checks.
-     * This state is volatile: it is never written to storage / never survives a reboot. This is to
-     * avoid a test provider accidentally being left configured on a device.
-     * See also {@link #resetVolatileTestConfig()}.
+     * Removes a listener previously added via {@link
+     * #addConfigurationInternalChangeListener(ConfigurationChangeListener)}.
      */
-    @Nullable
-    private String mTestPrimaryLocationTimeZoneProviderMode;
+    void removeConfigurationInternalChangeListener(
+            @NonNull ConfigurationChangeListener listener);
 
     /**
-     * The package name to use for the primary location time zone provider in a test.
-     * This state is volatile: it is never written to storage / never survives a reboot. This is to
-     * avoid a test provider accidentally being left configured on a device.
-     * See also {@link #resetVolatileTestConfig()}.
+     * Returns a snapshot of the {@link ConfigurationInternal} for the current user. This is only a
+     * snapshot so callers must use {@link
+     * #addConfigurationInternalChangeListener(ConfigurationChangeListener)} to be notified when it
+     * changes.
      */
-    @Nullable
-    private String mTestPrimaryLocationTimeZoneProviderPackageName;
+    @NonNull
+    ConfigurationInternal getCurrentUserConfigurationInternal();
 
     /**
-     * See {@link #mTestPrimaryLocationTimeZoneProviderMode}; this is the equivalent for the
-     * secondary provider.
+     * Updates the configuration properties that control a device's time zone behavior.
+     *
+     * <p>This method returns {@code true} if the configuration was changed,
+     * {@code false} otherwise.
      */
-    @Nullable
-    private String mTestSecondaryLocationTimeZoneProviderMode;
+    boolean updateConfiguration(@UserIdInt int userId,
+            @NonNull TimeZoneConfiguration requestedConfiguration);
 
     /**
-     * See {@link #mTestPrimaryLocationTimeZoneProviderPackageName}; this is the equivalent for the
-     * secondary provider.
+     * Returns a snapshot of the configuration that controls time zone detector behavior for the
+     * specified user.
      */
-    @Nullable
-    private String mTestSecondaryLocationTimeZoneProviderPackageName;
-
-    /**
-     * Whether to record state changes for tests.
-     * This state is volatile: it is never written to storage / never survives a reboot. This is to
-     * avoid a test state accidentally being left configured on a device.
-     * See also {@link #resetVolatileTestConfig()}.
-     */
-    private boolean mRecordProviderStateChanges;
-
-    private ServiceConfigAccessor(@NonNull Context context) {
-        mContext = Objects.requireNonNull(context);
-
-        mServerFlags = ServerFlags.getInstance(mContext);
-    }
-
-    /** Returns the singleton instance. */
-    public static ServiceConfigAccessor getInstance(Context context) {
-        synchronized (SLOCK) {
-            if (sInstance == null) {
-                sInstance = new ServiceConfigAccessor(context);
-            }
-            return sInstance;
-        }
-    }
+    @NonNull
+    ConfigurationInternal getConfigurationInternal(@UserIdInt int userId);
 
     /**
      * Adds a listener that will be called when server flags related to location_time_zone_manager
      * change. The callbacks are delivered on the main looper thread.
      *
-     * <p>Note: Only for use by long-lived objects. There is deliberately no associated remove
-     * method.
+     * <p>Note: Currently only for use by long-lived objects; there is no associated remove method.
      */
-    public void addLocationTimeZoneManagerConfigListener(
-            @NonNull ConfigurationChangeListener listener) {
-        mServerFlags.addListener(listener, LOCATION_TIME_ZONE_MANAGER_SERVER_FLAGS_KEYS_TO_WATCH);
-    }
-
-    /** Returns {@code true} if any form of automatic time zone detection is supported. */
-    public boolean isAutoDetectionFeatureSupported() {
-        return isTelephonyTimeZoneDetectionFeatureSupported()
-                || isGeoTimeZoneDetectionFeatureSupported();
-    }
+    void addLocationTimeZoneManagerConfigListener(
+            @NonNull ConfigurationChangeListener listener);
 
     /**
      * Returns {@code true} if the telephony-based time zone detection feature is supported on the
      * device.
      */
-    public boolean isTelephonyTimeZoneDetectionFeatureSupported() {
-        return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY);
-    }
+    boolean isTelephonyTimeZoneDetectionFeatureSupported();
 
     /**
      * Returns {@code true} if the location-based time zone detection feature can be supported on
@@ -191,239 +122,116 @@
      * Typically {@link #isGeoTimeZoneDetectionFeatureSupported()} should be used except during
      * boot.
      */
-    public boolean isGeoTimeZoneDetectionFeatureSupportedInConfig() {
-        return mContext.getResources().getBoolean(
-                com.android.internal.R.bool.config_enableGeolocationTimeZoneDetection);
-    }
+    boolean isGeoTimeZoneDetectionFeatureSupportedInConfig();
 
     /**
      * Returns {@code true} if the location-based time zone detection feature is supported on the
      * device.
      */
-    public boolean isGeoTimeZoneDetectionFeatureSupported() {
-        // For the feature to be enabled it must:
-        // 1) Be turned on in config.
-        // 2) Not be turned off via a server flag.
-        // 3) There must be at least one location time zone provider enabled / configured.
-        return isGeoTimeZoneDetectionFeatureSupportedInConfig()
-                && isGeoTimeZoneDetectionFeatureSupportedInternal()
-                && atLeastOneProviderIsEnabled();
-    }
-
-    private boolean atLeastOneProviderIsEnabled() {
-        return !(Objects.equals(getPrimaryLocationTimeZoneProviderMode(), PROVIDER_MODE_DISABLED)
-                && Objects.equals(getSecondaryLocationTimeZoneProviderMode(),
-                PROVIDER_MODE_DISABLED));
-    }
-
-    /**
-     * Returns {@code true} if the location-based time zone detection feature is not explicitly
-     * disabled by a server flag.
-     */
-    private boolean isGeoTimeZoneDetectionFeatureSupportedInternal() {
-        final boolean defaultEnabled = true;
-        return mServerFlags.getBoolean(
-                ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_FEATURE_SUPPORTED,
-                defaultEnabled);
-    }
+    boolean isGeoTimeZoneDetectionFeatureSupported();
 
     /** Returns the package name of the app hosting the primary location time zone provider. */
     @NonNull
-    public String getPrimaryLocationTimeZoneProviderPackageName() {
-        if (mTestPrimaryLocationTimeZoneProviderMode != null) {
-            // In test mode: use the test setting value.
-            return mTestPrimaryLocationTimeZoneProviderPackageName;
-        }
-        return mContext.getResources().getString(
-                R.string.config_primaryLocationTimeZoneProviderPackageName);
-    }
+    String getPrimaryLocationTimeZoneProviderPackageName();
 
     /**
      * Sets the package name of the app hosting the primary location time zone provider for tests.
      * Setting a {@code null} value means the provider is to be disabled.
      * The values are reset with {@link #resetVolatileTestConfig()}.
      */
-    public void setTestPrimaryLocationTimeZoneProviderPackageName(
-            @Nullable String testPrimaryLocationTimeZoneProviderPackageName) {
-        mTestPrimaryLocationTimeZoneProviderPackageName =
-                testPrimaryLocationTimeZoneProviderPackageName;
-        mTestPrimaryLocationTimeZoneProviderMode =
-                mTestPrimaryLocationTimeZoneProviderPackageName == null
-                        ? PROVIDER_MODE_DISABLED : PROVIDER_MODE_ENABLED;
-    }
+    void setTestPrimaryLocationTimeZoneProviderPackageName(
+            @Nullable String testPrimaryLocationTimeZoneProviderPackageName);
 
     /**
      * Returns {@code true} if the usual permission checks are to be bypassed for the primary
      * provider. Returns {@code true} only if {@link
      * #setTestPrimaryLocationTimeZoneProviderPackageName} has been called.
      */
-    public boolean isTestPrimaryLocationTimeZoneProvider() {
-        return mTestPrimaryLocationTimeZoneProviderMode != null;
-    }
+    boolean isTestPrimaryLocationTimeZoneProvider();
 
     /** Returns the package name of the app hosting the secondary location time zone provider. */
     @NonNull
-    public String getSecondaryLocationTimeZoneProviderPackageName() {
-        if (mTestSecondaryLocationTimeZoneProviderMode != null) {
-            // In test mode: use the test setting value.
-            return mTestSecondaryLocationTimeZoneProviderPackageName;
-        }
-        return mContext.getResources().getString(
-                R.string.config_secondaryLocationTimeZoneProviderPackageName);
-    }
+    String getSecondaryLocationTimeZoneProviderPackageName();
 
     /**
      * Sets the package name of the app hosting the secondary location time zone provider for tests.
      * Setting a {@code null} value means the provider is to be disabled.
      * The values are reset with {@link #resetVolatileTestConfig()}.
      */
-    public void setTestSecondaryLocationTimeZoneProviderPackageName(
-            @Nullable String testSecondaryLocationTimeZoneProviderPackageName) {
-        mTestSecondaryLocationTimeZoneProviderPackageName =
-                testSecondaryLocationTimeZoneProviderPackageName;
-        mTestSecondaryLocationTimeZoneProviderMode =
-                mTestSecondaryLocationTimeZoneProviderPackageName == null
-                        ? PROVIDER_MODE_DISABLED : PROVIDER_MODE_ENABLED;
-    }
+    void setTestSecondaryLocationTimeZoneProviderPackageName(
+            @Nullable String testSecondaryLocationTimeZoneProviderPackageName);
 
     /**
      * Returns {@code true} if the usual permission checks are to be bypassed for the secondary
      * provider. Returns {@code true} only if {@link
      * #setTestSecondaryLocationTimeZoneProviderPackageName} has been called.
      */
-    public boolean isTestSecondaryLocationTimeZoneProvider() {
-        return mTestSecondaryLocationTimeZoneProviderMode != null;
-    }
+    boolean isTestSecondaryLocationTimeZoneProvider();
 
     /**
      * Enables/disables the state recording mode for tests. The value is reset with {@link
      * #resetVolatileTestConfig()}.
      */
-    public void setRecordProviderStateChanges(boolean enabled) {
-        mRecordProviderStateChanges = enabled;
-    }
+    void setRecordProviderStateChanges(boolean enabled);
 
     /**
      * Returns {@code true} if providers are expected to record their state changes for tests.
      */
-    public boolean getRecordProviderStateChanges() {
-        return mRecordProviderStateChanges;
-    }
+    boolean getRecordProviderStateChanges();
 
     /**
      * Returns the mode for the primary location time zone provider.
      */
     @NonNull
-    public @ProviderMode String getPrimaryLocationTimeZoneProviderMode() {
-        if (mTestPrimaryLocationTimeZoneProviderMode != null) {
-            // In test mode: use the test setting value.
-            return mTestPrimaryLocationTimeZoneProviderMode;
-        }
-        return mServerFlags.getOptionalString(ServerFlags.KEY_PRIMARY_LTZP_MODE_OVERRIDE)
-                .orElse(getPrimaryLocationTimeZoneProviderModeFromConfig());
-    }
-
-    @NonNull
-    private @ProviderMode String getPrimaryLocationTimeZoneProviderModeFromConfig() {
-        int providerEnabledConfigId = R.bool.config_enablePrimaryLocationTimeZoneProvider;
-        return getConfigBoolean(providerEnabledConfigId)
-                ? PROVIDER_MODE_ENABLED : PROVIDER_MODE_DISABLED;
-    }
+    @ProviderMode String getPrimaryLocationTimeZoneProviderMode();
 
     /**
      * Returns the mode for the secondary location time zone provider.
      */
-    public @ProviderMode String getSecondaryLocationTimeZoneProviderMode() {
-        if (mTestSecondaryLocationTimeZoneProviderMode != null) {
-            // In test mode: use the test setting value.
-            return mTestSecondaryLocationTimeZoneProviderMode;
-        }
-        return mServerFlags.getOptionalString(ServerFlags.KEY_SECONDARY_LTZP_MODE_OVERRIDE)
-                .orElse(getSecondaryLocationTimeZoneProviderModeFromConfig());
-    }
-
-    @NonNull
-    private @ProviderMode String getSecondaryLocationTimeZoneProviderModeFromConfig() {
-        int providerEnabledConfigId = R.bool.config_enableSecondaryLocationTimeZoneProvider;
-        return getConfigBoolean(providerEnabledConfigId)
-                ? PROVIDER_MODE_ENABLED : PROVIDER_MODE_DISABLED;
-    }
+    @ProviderMode String getSecondaryLocationTimeZoneProviderMode();
 
     /**
      * Returns whether location time zone detection is enabled for users when there's no setting
      * value. Intended for use during feature release testing to "opt-in" users that haven't shown
      * an explicit preference.
      */
-    public boolean isGeoDetectionEnabledForUsersByDefault() {
-        return mServerFlags.getBoolean(
-                ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_DEFAULT, false);
-    }
+    boolean isGeoDetectionEnabledForUsersByDefault();
 
     /**
      * Returns whether location time zone detection is force enabled/disabled for users. Intended
      * for use during feature release testing to force a given state.
      */
     @NonNull
-    public Optional<Boolean> getGeoDetectionSettingEnabledOverride() {
-        return mServerFlags.getOptionalBoolean(
-                ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_OVERRIDE);
-    }
+    Optional<Boolean> getGeoDetectionSettingEnabledOverride();
 
     /**
      * Returns the time to send to a location time zone provider that informs it how long it has
      * to return its first time zone suggestion.
      */
     @NonNull
-    public Duration getLocationTimeZoneProviderInitializationTimeout() {
-        return mServerFlags.getDurationFromMillis(
-                ServerFlags.KEY_LTZP_INITIALIZATION_TIMEOUT_MILLIS,
-                DEFAULT_LTZP_INITIALIZATION_TIMEOUT);
-    }
+    Duration getLocationTimeZoneProviderInitializationTimeout();
 
     /**
      * Returns the time added to {@link #getLocationTimeZoneProviderInitializationTimeout()} by the
      * server before unilaterally declaring the provider is uncertain.
      */
     @NonNull
-    public Duration getLocationTimeZoneProviderInitializationTimeoutFuzz() {
-        return mServerFlags.getDurationFromMillis(
-                ServerFlags.KEY_LTZP_INITIALIZATION_TIMEOUT_FUZZ_MILLIS,
-                DEFAULT_LTZP_INITIALIZATION_TIMEOUT_FUZZ);
-    }
+    Duration getLocationTimeZoneProviderInitializationTimeoutFuzz();
 
     /**
      * Returns the time after uncertainty is detected by providers before the location time zone
      * manager makes a suggestion to the time zone detector.
      */
     @NonNull
-    public Duration getLocationTimeZoneUncertaintyDelay() {
-        return mServerFlags.getDurationFromMillis(
-                ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_UNCERTAINTY_DELAY_MILLIS,
-                DEFAULT_LTZP_UNCERTAINTY_DELAY);
-    }
+    Duration getLocationTimeZoneUncertaintyDelay();
 
     /**
      * Returns the time between equivalent events before the provider process will send the event
      * to the system server.
      */
     @NonNull
-    public Duration getLocationTimeZoneProviderEventFilteringAgeThreshold() {
-        return mServerFlags.getDurationFromMillis(
-                ServerFlags.KEY_LTZP_EVENT_FILTERING_AGE_THRESHOLD_MILLIS,
-                DEFAULT_LTZP_EVENT_FILTER_AGE_THRESHOLD);
-    }
+    Duration getLocationTimeZoneProviderEventFilteringAgeThreshold();
 
     /** Clears all in-memory test config. */
-    public void resetVolatileTestConfig() {
-        mTestPrimaryLocationTimeZoneProviderPackageName = null;
-        mTestPrimaryLocationTimeZoneProviderMode = null;
-        mTestSecondaryLocationTimeZoneProviderPackageName = null;
-        mTestSecondaryLocationTimeZoneProviderMode = null;
-        mRecordProviderStateChanges = false;
-    }
-
-    private boolean getConfigBoolean(int providerEnabledConfigId) {
-        Resources resources = mContext.getResources();
-        return resources.getBoolean(providerEnabledConfigId);
-    }
+    void resetVolatileTestConfig();
 }
diff --git a/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessorImpl.java b/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessorImpl.java
new file mode 100644
index 0000000..be4b6bd
--- /dev/null
+++ b/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessorImpl.java
@@ -0,0 +1,556 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * 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 android.content.Intent.ACTION_USER_SWITCHED;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.app.ActivityManagerInternal;
+import android.app.time.TimeZoneCapabilities;
+import android.app.time.TimeZoneCapabilitiesAndConfig;
+import android.app.time.TimeZoneConfiguration;
+import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.database.ContentObserver;
+import android.location.LocationManager;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.provider.Settings;
+import android.util.ArraySet;
+
+import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
+import com.android.server.LocalServices;
+import com.android.server.timedetector.ServerFlags;
+
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+
+/**
+ * A singleton implementation of {@link ServiceConfigAccessor}.
+ */
+public final class ServiceConfigAccessorImpl implements ServiceConfigAccessor {
+
+    /**
+     * Device config keys that can affect the content of {@link ConfigurationInternal}.
+     */
+    private static final Set<String> CONFIGURATION_INTERNAL_SERVER_FLAGS_KEYS_TO_WATCH =
+            Collections.unmodifiableSet(new ArraySet<>(new String[] {
+                    ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_FEATURE_SUPPORTED,
+                    ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_DEFAULT,
+                    ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_OVERRIDE,
+            }));
+
+    /**
+     * Device config keys that can affect {@link
+     * com.android.server.timezonedetector.location.LocationTimeZoneManagerService} behavior.
+     */
+    private static final Set<String> LOCATION_TIME_ZONE_MANAGER_SERVER_FLAGS_KEYS_TO_WATCH =
+            Collections.unmodifiableSet(new ArraySet<>(new String[] {
+                    ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_FEATURE_SUPPORTED,
+                    ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_DEFAULT,
+                    ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_OVERRIDE,
+                    ServerFlags.KEY_PRIMARY_LTZP_MODE_OVERRIDE,
+                    ServerFlags.KEY_SECONDARY_LTZP_MODE_OVERRIDE,
+                    ServerFlags.KEY_LTZP_INITIALIZATION_TIMEOUT_MILLIS,
+                    ServerFlags.KEY_LTZP_INITIALIZATION_TIMEOUT_FUZZ_MILLIS,
+                    ServerFlags.KEY_LTZP_EVENT_FILTERING_AGE_THRESHOLD_MILLIS,
+                    ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_UNCERTAINTY_DELAY_MILLIS
+            }));
+
+    private static final Duration DEFAULT_LTZP_INITIALIZATION_TIMEOUT = Duration.ofMinutes(5);
+    private static final Duration DEFAULT_LTZP_INITIALIZATION_TIMEOUT_FUZZ = Duration.ofMinutes(1);
+    private static final Duration DEFAULT_LTZP_UNCERTAINTY_DELAY = Duration.ofMinutes(5);
+    private static final Duration DEFAULT_LTZP_EVENT_FILTER_AGE_THRESHOLD = Duration.ofMinutes(1);
+
+    private static final Object SLOCK = new Object();
+
+    /** The singleton instance. Initialized once in {@link #getInstance(Context)}. */
+    @GuardedBy("SLOCK")
+    @Nullable
+    private static ServiceConfigAccessor sInstance;
+
+    @NonNull private final Context mContext;
+    @NonNull private final ServerFlags mServerFlags;
+    @NonNull private final ContentResolver mCr;
+    @NonNull private final UserManager mUserManager;
+    @NonNull private final LocationManager mLocationManager;
+
+    @GuardedBy("this")
+    @NonNull private final List<ConfigurationChangeListener> mConfigurationInternalListeners =
+            new ArrayList<>();
+
+    /**
+     * The mode to use for the primary location time zone provider in a test. Setting this
+     * disables some permission checks.
+     * This state is volatile: it is never written to storage / never survives a reboot. This is to
+     * avoid a test provider accidentally being left configured on a device.
+     * See also {@link #resetVolatileTestConfig()}.
+     */
+    @GuardedBy("this")
+    @Nullable
+    private String mTestPrimaryLocationTimeZoneProviderMode;
+
+    /**
+     * The package name to use for the primary location time zone provider in a test.
+     * This state is volatile: it is never written to storage / never survives a reboot. This is to
+     * avoid a test provider accidentally being left configured on a device.
+     * See also {@link #resetVolatileTestConfig()}.
+     */
+    @GuardedBy("this")
+    @Nullable
+    private String mTestPrimaryLocationTimeZoneProviderPackageName;
+
+    /**
+     * See {@link #mTestPrimaryLocationTimeZoneProviderMode}; this is the equivalent for the
+     * secondary provider.
+     */
+    @GuardedBy("this")
+    @Nullable
+    private String mTestSecondaryLocationTimeZoneProviderMode;
+
+    /**
+     * See {@link #mTestPrimaryLocationTimeZoneProviderPackageName}; this is the equivalent for the
+     * secondary provider.
+     */
+    @GuardedBy("this")
+    @Nullable
+    private String mTestSecondaryLocationTimeZoneProviderPackageName;
+
+    /**
+     * Whether to record state changes for tests.
+     * This state is volatile: it is never written to storage / never survives a reboot. This is to
+     * avoid a test state accidentally being left configured on a device.
+     * See also {@link #resetVolatileTestConfig()}.
+     */
+    @GuardedBy("this")
+    private boolean mRecordProviderStateChanges;
+
+    private ServiceConfigAccessorImpl(@NonNull Context context) {
+        mContext = Objects.requireNonNull(context);
+        mCr = context.getContentResolver();
+        mUserManager = context.getSystemService(UserManager.class);
+        mLocationManager = context.getSystemService(LocationManager.class);
+        mServerFlags = ServerFlags.getInstance(mContext);
+
+        // Wire up the config change listeners for anything that could affect ConfigurationInternal.
+        // Use the main thread for event delivery, listeners can post to their chosen thread.
+
+        // Listen for the user changing / the user's location mode changing. Report on the main
+        // thread.
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(ACTION_USER_SWITCHED);
+        filter.addAction(LocationManager.MODE_CHANGED_ACTION);
+        mContext.registerReceiverForAllUsers(new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                handleConfigurationInternalChangeOnMainThread();
+            }
+        }, filter, null, null /* main thread */);
+
+        // Add async callbacks for global settings being changed.
+        ContentResolver contentResolver = mContext.getContentResolver();
+        ContentObserver contentObserver = new ContentObserver(mContext.getMainThreadHandler()) {
+            @Override
+            public void onChange(boolean selfChange) {
+                handleConfigurationInternalChangeOnMainThread();
+            }
+        };
+        contentResolver.registerContentObserver(
+                Settings.Global.getUriFor(Settings.Global.AUTO_TIME_ZONE), true, contentObserver);
+
+        // Add async callbacks for user scoped location settings being changed.
+        contentResolver.registerContentObserver(
+                Settings.Secure.getUriFor(Settings.Secure.LOCATION_TIME_ZONE_DETECTION_ENABLED),
+                true, contentObserver, UserHandle.USER_ALL);
+
+        // Watch server flags.
+        mServerFlags.addListener(this::handleConfigurationInternalChangeOnMainThread,
+                CONFIGURATION_INTERNAL_SERVER_FLAGS_KEYS_TO_WATCH);
+    }
+
+    /** Returns the singleton instance. */
+    public static ServiceConfigAccessor getInstance(Context context) {
+        synchronized (SLOCK) {
+            if (sInstance == null) {
+                sInstance = new ServiceConfigAccessorImpl(context);
+            }
+            return sInstance;
+        }
+    }
+
+    private synchronized void handleConfigurationInternalChangeOnMainThread() {
+        for (ConfigurationChangeListener changeListener : mConfigurationInternalListeners) {
+            changeListener.onChange();
+        }
+    }
+
+    @Override
+    public synchronized void addConfigurationInternalChangeListener(
+            @NonNull ConfigurationChangeListener listener) {
+        mConfigurationInternalListeners.add(Objects.requireNonNull(listener));
+    }
+
+    @Override
+    public synchronized void removeConfigurationInternalChangeListener(
+            @NonNull ConfigurationChangeListener listener) {
+        mConfigurationInternalListeners.remove(Objects.requireNonNull(listener));
+    }
+
+    @Override
+    @NonNull
+    public synchronized ConfigurationInternal getCurrentUserConfigurationInternal() {
+        int currentUserId =
+                LocalServices.getService(ActivityManagerInternal.class).getCurrentUserId();
+        return getConfigurationInternal(currentUserId);
+    }
+
+    @Override
+    public synchronized boolean updateConfiguration(@UserIdInt int userId,
+            @NonNull TimeZoneConfiguration requestedConfiguration) {
+        Objects.requireNonNull(requestedConfiguration);
+
+        TimeZoneCapabilitiesAndConfig capabilitiesAndConfig =
+                getConfigurationInternal(userId).createCapabilitiesAndConfig();
+        TimeZoneCapabilities capabilities = capabilitiesAndConfig.getCapabilities();
+        TimeZoneConfiguration oldConfiguration = capabilitiesAndConfig.getConfiguration();
+
+        final TimeZoneConfiguration newConfiguration =
+                capabilities.tryApplyConfigChanges(oldConfiguration, requestedConfiguration);
+        if (newConfiguration == null) {
+            // The changes could not be made because the user's capabilities do not allow it.
+            return false;
+        }
+
+        // Store the configuration / notify as needed. This will cause the mEnvironment to invoke
+        // handleConfigChanged() asynchronously.
+        storeConfiguration(userId, newConfiguration);
+
+        return true;
+    }
+
+    /**
+     * Stores the configuration properties contained in {@code newConfiguration}.
+     * All checks about user capabilities must be done by the caller and
+     * {@link TimeZoneConfiguration#isComplete()} must be {@code true}.
+     */
+    @GuardedBy("this")
+    private void storeConfiguration(@UserIdInt int userId,
+            @NonNull TimeZoneConfiguration configuration) {
+        Objects.requireNonNull(configuration);
+
+        // Avoid writing the auto detection enabled setting for devices that do not support auto
+        // time zone detection: if we wrote it down then we'd set the value explicitly, which would
+        // prevent detecting "default" later. That might influence what happens on later releases
+        // that support new types of auto detection on the same hardware.
+        if (isAutoDetectionFeatureSupported()) {
+            final boolean autoDetectionEnabled = configuration.isAutoDetectionEnabled();
+            setAutoDetectionEnabledIfRequired(autoDetectionEnabled);
+
+            // Avoid writing the geo detection enabled setting for devices with settings that
+            // are currently overridden by server flags: otherwise we might overwrite a droidfood
+            // user's real setting permanently.
+            // Also avoid writing the geo detection enabled setting for devices that do not support
+            // geo time zone detection: if we wrote it down then we'd set the value explicitly,
+            // which would prevent detecting "default" later. That might influence what happens on
+            // later releases that start to support geo detection on the same hardware.
+            if (!getGeoDetectionSettingEnabledOverride().isPresent()
+                    && isGeoTimeZoneDetectionFeatureSupported()) {
+                final boolean geoDetectionEnabledSetting = configuration.isGeoDetectionEnabled();
+                setGeoDetectionEnabledSettingIfRequired(userId, geoDetectionEnabledSetting);
+            }
+        }
+    }
+
+    @Override
+    @NonNull
+    public synchronized ConfigurationInternal getConfigurationInternal(@UserIdInt int userId) {
+        return new ConfigurationInternal.Builder(userId)
+                .setTelephonyDetectionFeatureSupported(
+                        isTelephonyTimeZoneDetectionFeatureSupported())
+                .setGeoDetectionFeatureSupported(isGeoTimeZoneDetectionFeatureSupported())
+                .setAutoDetectionEnabledSetting(getAutoDetectionEnabledSetting())
+                .setUserConfigAllowed(isUserConfigAllowed(userId))
+                .setLocationEnabledSetting(getLocationEnabledSetting(userId))
+                .setGeoDetectionEnabledSetting(getGeoDetectionEnabledSetting(userId))
+                .build();
+    }
+
+    private void setAutoDetectionEnabledIfRequired(boolean enabled) {
+        // This check is racey, but the whole settings update process is racey. This check prevents
+        // a ConfigurationChangeListener callback triggering due to ContentObserver's still
+        // triggering *sometimes* for no-op updates. Because callbacks are async this is necessary
+        // for stable behavior during tests.
+        if (getAutoDetectionEnabledSetting() != enabled) {
+            Settings.Global.putInt(mCr, Settings.Global.AUTO_TIME_ZONE, enabled ? 1 : 0);
+        }
+    }
+
+    private boolean getLocationEnabledSetting(@UserIdInt int userId) {
+        return mLocationManager.isLocationEnabledForUser(UserHandle.of(userId));
+    }
+
+    private boolean isUserConfigAllowed(@UserIdInt int userId) {
+        UserHandle userHandle = UserHandle.of(userId);
+        return !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_DATE_TIME, userHandle);
+    }
+
+    private boolean getAutoDetectionEnabledSetting() {
+        return Settings.Global.getInt(mCr, Settings.Global.AUTO_TIME_ZONE, 1 /* default */) > 0;
+    }
+
+    private boolean getGeoDetectionEnabledSetting(@UserIdInt int userId) {
+        // We may never use this, but it gives us a way to force location-based time zone detection
+        // on/off for testers (but only where their other settings would allow them to turn it on
+        // for themselves).
+        Optional<Boolean> override = getGeoDetectionSettingEnabledOverride();
+        if (override.isPresent()) {
+            return override.get();
+        }
+
+        final boolean geoDetectionEnabledByDefault = isGeoDetectionEnabledForUsersByDefault();
+        return Settings.Secure.getIntForUser(mCr,
+                Settings.Secure.LOCATION_TIME_ZONE_DETECTION_ENABLED,
+                (geoDetectionEnabledByDefault ? 1 : 0) /* defaultValue */, userId) != 0;
+    }
+
+    private void setGeoDetectionEnabledSettingIfRequired(@UserIdInt int userId, boolean enabled) {
+        // See comment in setAutoDetectionEnabledIfRequired. http://b/171953500
+        if (getGeoDetectionEnabledSetting(userId) != enabled) {
+            Settings.Secure.putIntForUser(mCr, Settings.Secure.LOCATION_TIME_ZONE_DETECTION_ENABLED,
+                    enabled ? 1 : 0, userId);
+        }
+    }
+
+    @Override
+    public void addLocationTimeZoneManagerConfigListener(
+            @NonNull ConfigurationChangeListener listener) {
+        mServerFlags.addListener(listener, LOCATION_TIME_ZONE_MANAGER_SERVER_FLAGS_KEYS_TO_WATCH);
+    }
+
+    /** Returns {@code true} if any form of automatic time zone detection is supported. */
+    private boolean isAutoDetectionFeatureSupported() {
+        return isTelephonyTimeZoneDetectionFeatureSupported()
+                || isGeoTimeZoneDetectionFeatureSupported();
+    }
+
+    @Override
+    public boolean isTelephonyTimeZoneDetectionFeatureSupported() {
+        return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY);
+    }
+
+    @Override
+    public boolean isGeoTimeZoneDetectionFeatureSupportedInConfig() {
+        return mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_enableGeolocationTimeZoneDetection);
+    }
+
+    @Override
+    public boolean isGeoTimeZoneDetectionFeatureSupported() {
+        // For the feature to be enabled it must:
+        // 1) Be turned on in config.
+        // 2) Not be turned off via a server flag.
+        // 3) There must be at least one location time zone provider enabled / configured.
+        return isGeoTimeZoneDetectionFeatureSupportedInConfig()
+                && isGeoTimeZoneDetectionFeatureSupportedInternal()
+                && atLeastOneProviderIsEnabled();
+    }
+
+    private boolean atLeastOneProviderIsEnabled() {
+        return !(Objects.equals(getPrimaryLocationTimeZoneProviderMode(), PROVIDER_MODE_DISABLED)
+                && Objects.equals(getSecondaryLocationTimeZoneProviderMode(),
+                PROVIDER_MODE_DISABLED));
+    }
+
+    /**
+     * Returns {@code true} if the location-based time zone detection feature is not explicitly
+     * disabled by a server flag.
+     */
+    private boolean isGeoTimeZoneDetectionFeatureSupportedInternal() {
+        final boolean defaultEnabled = true;
+        return mServerFlags.getBoolean(
+                ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_FEATURE_SUPPORTED,
+                defaultEnabled);
+    }
+
+    @Override
+    @NonNull
+    public synchronized String getPrimaryLocationTimeZoneProviderPackageName() {
+        if (mTestPrimaryLocationTimeZoneProviderMode != null) {
+            // In test mode: use the test setting value.
+            return mTestPrimaryLocationTimeZoneProviderPackageName;
+        }
+        return mContext.getResources().getString(
+                R.string.config_primaryLocationTimeZoneProviderPackageName);
+    }
+
+    @Override
+    public synchronized void setTestPrimaryLocationTimeZoneProviderPackageName(
+            @Nullable String testPrimaryLocationTimeZoneProviderPackageName) {
+        mTestPrimaryLocationTimeZoneProviderPackageName =
+                testPrimaryLocationTimeZoneProviderPackageName;
+        mTestPrimaryLocationTimeZoneProviderMode =
+                mTestPrimaryLocationTimeZoneProviderPackageName == null
+                        ? PROVIDER_MODE_DISABLED : PROVIDER_MODE_ENABLED;
+    }
+
+    @Override
+    public synchronized boolean isTestPrimaryLocationTimeZoneProvider() {
+        return mTestPrimaryLocationTimeZoneProviderMode != null;
+    }
+
+    @Override
+    @NonNull
+    public synchronized String getSecondaryLocationTimeZoneProviderPackageName() {
+        if (mTestSecondaryLocationTimeZoneProviderMode != null) {
+            // In test mode: use the test setting value.
+            return mTestSecondaryLocationTimeZoneProviderPackageName;
+        }
+        return mContext.getResources().getString(
+                R.string.config_secondaryLocationTimeZoneProviderPackageName);
+    }
+
+    @Override
+    public synchronized void setTestSecondaryLocationTimeZoneProviderPackageName(
+            @Nullable String testSecondaryLocationTimeZoneProviderPackageName) {
+        mTestSecondaryLocationTimeZoneProviderPackageName =
+                testSecondaryLocationTimeZoneProviderPackageName;
+        mTestSecondaryLocationTimeZoneProviderMode =
+                mTestSecondaryLocationTimeZoneProviderPackageName == null
+                        ? PROVIDER_MODE_DISABLED : PROVIDER_MODE_ENABLED;
+    }
+
+    @Override
+    public synchronized boolean isTestSecondaryLocationTimeZoneProvider() {
+        return mTestSecondaryLocationTimeZoneProviderMode != null;
+    }
+
+    @Override
+    public synchronized void setRecordProviderStateChanges(boolean enabled) {
+        mRecordProviderStateChanges = enabled;
+    }
+
+    @Override
+    public synchronized boolean getRecordProviderStateChanges() {
+        return mRecordProviderStateChanges;
+    }
+
+    @Override
+    @NonNull
+    public synchronized @ProviderMode String getPrimaryLocationTimeZoneProviderMode() {
+        if (mTestPrimaryLocationTimeZoneProviderMode != null) {
+            // In test mode: use the test setting value.
+            return mTestPrimaryLocationTimeZoneProviderMode;
+        }
+        return mServerFlags.getOptionalString(ServerFlags.KEY_PRIMARY_LTZP_MODE_OVERRIDE)
+                .orElse(getPrimaryLocationTimeZoneProviderModeFromConfig());
+    }
+
+    @NonNull
+    private synchronized @ProviderMode String getPrimaryLocationTimeZoneProviderModeFromConfig() {
+        int providerEnabledConfigId = R.bool.config_enablePrimaryLocationTimeZoneProvider;
+        return getConfigBoolean(providerEnabledConfigId)
+                ? PROVIDER_MODE_ENABLED : PROVIDER_MODE_DISABLED;
+    }
+
+    @Override
+    public synchronized @ProviderMode String getSecondaryLocationTimeZoneProviderMode() {
+        if (mTestSecondaryLocationTimeZoneProviderMode != null) {
+            // In test mode: use the test setting value.
+            return mTestSecondaryLocationTimeZoneProviderMode;
+        }
+        return mServerFlags.getOptionalString(ServerFlags.KEY_SECONDARY_LTZP_MODE_OVERRIDE)
+                .orElse(getSecondaryLocationTimeZoneProviderModeFromConfig());
+    }
+
+    @NonNull
+    private synchronized @ProviderMode String getSecondaryLocationTimeZoneProviderModeFromConfig() {
+        int providerEnabledConfigId = R.bool.config_enableSecondaryLocationTimeZoneProvider;
+        return getConfigBoolean(providerEnabledConfigId)
+                ? PROVIDER_MODE_ENABLED : PROVIDER_MODE_DISABLED;
+    }
+
+    @Override
+    public boolean isGeoDetectionEnabledForUsersByDefault() {
+        return mServerFlags.getBoolean(
+                ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_DEFAULT, false);
+    }
+
+    @Override
+    @NonNull
+    public Optional<Boolean> getGeoDetectionSettingEnabledOverride() {
+        return mServerFlags.getOptionalBoolean(
+                ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_OVERRIDE);
+    }
+
+    @Override
+    @NonNull
+    public Duration getLocationTimeZoneProviderInitializationTimeout() {
+        return mServerFlags.getDurationFromMillis(
+                ServerFlags.KEY_LTZP_INITIALIZATION_TIMEOUT_MILLIS,
+                DEFAULT_LTZP_INITIALIZATION_TIMEOUT);
+    }
+
+    @Override
+    @NonNull
+    public Duration getLocationTimeZoneProviderInitializationTimeoutFuzz() {
+        return mServerFlags.getDurationFromMillis(
+                ServerFlags.KEY_LTZP_INITIALIZATION_TIMEOUT_FUZZ_MILLIS,
+                DEFAULT_LTZP_INITIALIZATION_TIMEOUT_FUZZ);
+    }
+
+    @Override
+    @NonNull
+    public Duration getLocationTimeZoneUncertaintyDelay() {
+        return mServerFlags.getDurationFromMillis(
+                ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_UNCERTAINTY_DELAY_MILLIS,
+                DEFAULT_LTZP_UNCERTAINTY_DELAY);
+    }
+
+    @Override
+    @NonNull
+    public Duration getLocationTimeZoneProviderEventFilteringAgeThreshold() {
+        return mServerFlags.getDurationFromMillis(
+                ServerFlags.KEY_LTZP_EVENT_FILTERING_AGE_THRESHOLD_MILLIS,
+                DEFAULT_LTZP_EVENT_FILTER_AGE_THRESHOLD);
+    }
+
+    @Override
+    public synchronized void resetVolatileTestConfig() {
+        mTestPrimaryLocationTimeZoneProviderPackageName = null;
+        mTestPrimaryLocationTimeZoneProviderMode = null;
+        mTestSecondaryLocationTimeZoneProviderPackageName = null;
+        mTestSecondaryLocationTimeZoneProviderMode = null;
+        mRecordProviderStateChanges = false;
+    }
+
+    private boolean getConfigBoolean(int providerEnabledConfigId) {
+        Resources resources = mContext.getResources();
+        return resources.getBoolean(providerEnabledConfigId);
+    }
+}
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternal.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternal.java
index 4161177..b6ce802 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternal.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternal.java
@@ -27,23 +27,6 @@
  */
 public interface TimeZoneDetectorInternal {
 
-    /** Adds a listener that will be invoked when {@link ConfigurationInternal} may have changed. */
-    void addConfigurationListener(@NonNull ConfigurationChangeListener listener);
-
-    /**
-     * Removes a listener previously added via {@link
-     * #addConfigurationListener(ConfigurationChangeListener)}.
-     */
-    void removeConfigurationListener(@NonNull ConfigurationChangeListener listener);
-
-    /**
-     * Returns a snapshot of the {@link ConfigurationInternal} for the current user. This is only a
-     * snapshot so callers must use {@link #addConfigurationListener(ConfigurationChangeListener)}
-     * to be notified when it changes.
-     */
-    @NonNull
-    ConfigurationInternal getCurrentUserConfigurationInternal();
-
     /**
      * Suggests the current time zone, determined using geolocation, to the detector. The
      * detector may ignore the signal based on system settings, whether better information is
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternalImpl.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternalImpl.java
index ca87811..f61df82 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternalImpl.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternalImpl.java
@@ -20,8 +20,6 @@
 import android.content.Context;
 import android.os.Handler;
 
-import java.util.ArrayList;
-import java.util.List;
 import java.util.Objects;
 
 /**
@@ -34,46 +32,12 @@
     @NonNull private final Context mContext;
     @NonNull private final Handler mHandler;
     @NonNull private final TimeZoneDetectorStrategy mTimeZoneDetectorStrategy;
-    @NonNull private final List<ConfigurationChangeListener> mConfigurationListeners =
-            new ArrayList<>();
 
     public TimeZoneDetectorInternalImpl(@NonNull Context context, @NonNull Handler handler,
             @NonNull TimeZoneDetectorStrategy timeZoneDetectorStrategy) {
         mContext = Objects.requireNonNull(context);
         mHandler = Objects.requireNonNull(handler);
         mTimeZoneDetectorStrategy = Objects.requireNonNull(timeZoneDetectorStrategy);
-
-        // Wire up a change listener so that any downstream listeners can be notified when
-        // the configuration changes for any reason.
-        mTimeZoneDetectorStrategy.addConfigChangeListener(this::handleConfigurationChanged);
-    }
-
-    private void handleConfigurationChanged() {
-        synchronized (mConfigurationListeners) {
-            for (ConfigurationChangeListener listener : mConfigurationListeners) {
-                listener.onChange();
-            }
-        }
-    }
-
-    @Override
-    public void addConfigurationListener(ConfigurationChangeListener listener) {
-        synchronized (mConfigurationListeners) {
-            mConfigurationListeners.add(Objects.requireNonNull(listener));
-        }
-    }
-
-    @Override
-    public void removeConfigurationListener(ConfigurationChangeListener listener) {
-        synchronized (mConfigurationListeners) {
-            mConfigurationListeners.remove(Objects.requireNonNull(listener));
-        }
-    }
-
-    @Override
-    @NonNull
-    public ConfigurationInternal getCurrentUserConfigurationInternal() {
-        return mTimeZoneDetectorStrategy.getCurrentUserConfigurationInternal();
     }
 
     @Override
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
index e6a58a1..e0c39ad 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
@@ -80,7 +80,7 @@
             Handler handler = FgThread.getHandler();
 
             ServiceConfigAccessor serviceConfigAccessor =
-                    ServiceConfigAccessor.getInstance(context);
+                    ServiceConfigAccessorImpl.getInstance(context);
             TimeZoneDetectorStrategy timeZoneDetectorStrategy =
                     TimeZoneDetectorStrategyImpl.create(context, handler, serviceConfigAccessor);
 
@@ -92,7 +92,7 @@
             // Publish the binder service so it can be accessed from other (appropriately
             // permissioned) processes.
             TimeZoneDetectorService service = TimeZoneDetectorService.create(
-                    context, handler, timeZoneDetectorStrategy);
+                    context, handler, serviceConfigAccessor, timeZoneDetectorStrategy);
             publishBinderService(Context.TIME_ZONE_DETECTOR_SERVICE, service);
         }
     }
@@ -107,6 +107,9 @@
     private final CallerIdentityInjector mCallerIdentityInjector;
 
     @NonNull
+    private final ServiceConfigAccessor mServiceConfigAccessor;
+
+    @NonNull
     private final TimeZoneDetectorStrategy mTimeZoneDetectorStrategy;
 
     /**
@@ -126,25 +129,29 @@
 
     private static TimeZoneDetectorService create(
             @NonNull Context context, @NonNull Handler handler,
+            @NonNull ServiceConfigAccessor serviceConfigAccessor,
             @NonNull TimeZoneDetectorStrategy timeZoneDetectorStrategy) {
 
         CallerIdentityInjector callerIdentityInjector = CallerIdentityInjector.REAL;
-        return new TimeZoneDetectorService(
-                context, handler, callerIdentityInjector, timeZoneDetectorStrategy);
+        return new TimeZoneDetectorService(context, handler, callerIdentityInjector,
+                serviceConfigAccessor, timeZoneDetectorStrategy);
     }
 
     @VisibleForTesting
     public TimeZoneDetectorService(@NonNull Context context, @NonNull Handler handler,
             @NonNull CallerIdentityInjector callerIdentityInjector,
+            @NonNull ServiceConfigAccessor serviceConfigAccessor,
             @NonNull TimeZoneDetectorStrategy timeZoneDetectorStrategy) {
         mContext = Objects.requireNonNull(context);
         mHandler = Objects.requireNonNull(handler);
         mCallerIdentityInjector = Objects.requireNonNull(callerIdentityInjector);
+        mServiceConfigAccessor = Objects.requireNonNull(serviceConfigAccessor);
         mTimeZoneDetectorStrategy = Objects.requireNonNull(timeZoneDetectorStrategy);
 
         // Wire up a change listener so that ITimeZoneDetectorListeners can be notified when
         // the configuration changes for any reason.
-        mTimeZoneDetectorStrategy.addConfigChangeListener(this::handleConfigurationChanged);
+        mServiceConfigAccessor.addConfigurationInternalChangeListener(
+                () -> mHandler.post(this::handleConfigurationInternalChangedOnHandlerThread));
     }
 
     @Override
@@ -160,7 +167,7 @@
         final long token = mCallerIdentityInjector.clearCallingIdentity();
         try {
             ConfigurationInternal configurationInternal =
-                    mTimeZoneDetectorStrategy.getConfigurationInternal(userId);
+                    mServiceConfigAccessor.getConfigurationInternal(userId);
             return configurationInternal.createCapabilitiesAndConfig();
         } finally {
             mCallerIdentityInjector.restoreCallingIdentity(token);
@@ -184,7 +191,7 @@
 
         final long token = mCallerIdentityInjector.clearCallingIdentity();
         try {
-            return mTimeZoneDetectorStrategy.updateConfiguration(userId, configuration);
+            return mServiceConfigAccessor.updateConfiguration(userId, configuration);
         } finally {
             mCallerIdentityInjector.restoreCallingIdentity(token);
         }
@@ -264,7 +271,7 @@
         }
     }
 
-    void handleConfigurationChanged() {
+    void handleConfigurationInternalChangedOnHandlerThread() {
         // Configuration has changed, but each user may have a different view of the configuration.
         // It's possible that this will cause unnecessary notifications but that shouldn't be a
         // problem.
@@ -315,14 +322,13 @@
     boolean isTelephonyTimeZoneDetectionSupported() {
         enforceManageTimeZoneDetectorPermission();
 
-        return ServiceConfigAccessor.getInstance(mContext)
-                .isTelephonyTimeZoneDetectionFeatureSupported();
+        return mServiceConfigAccessor.isTelephonyTimeZoneDetectionFeatureSupported();
     }
 
     boolean isGeoTimeZoneDetectionSupported() {
         enforceManageTimeZoneDetectorPermission();
 
-        return ServiceConfigAccessor.getInstance(mContext).isGeoTimeZoneDetectionFeatureSupported();
+        return mServiceConfigAccessor.isGeoTimeZoneDetectionFeatureSupported();
     }
 
     /**
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java
index e2cc679..ede52ba 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java
@@ -17,7 +17,6 @@
 
 import android.annotation.NonNull;
 import android.annotation.UserIdInt;
-import android.app.time.TimeZoneConfiguration;
 import android.app.timezonedetector.ManualTimeZoneSuggestion;
 import android.app.timezonedetector.TelephonyTimeZoneSuggestion;
 import android.util.IndentingPrintWriter;
@@ -72,46 +71,15 @@
  *
  * <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()},
- * {@link #generateMetricsState()} and debug calls like {@link
- * #dump(IndentingPrintWriter, String[])}, may be called on a different thread concurrently with
- * other operations.
+ * <p>Implementations of this class must be thread-safe as calls calls like {@link
+ * #generateMetricsState()} and {@link #dump(IndentingPrintWriter, String[])} may be called on
+ * differents thread concurrently with other operations.
  *
  * @hide
  */
 public interface TimeZoneDetectorStrategy extends Dumpable {
 
     /**
-     * Adds a listener that will be triggered whenever {@link ConfigurationInternal} may have
-     * changed.
-     */
-    void addConfigChangeListener(@NonNull ConfigurationChangeListener listener);
-
-    /**
-     * Returns a snapshot of the configuration that controls time zone detector behavior for the
-     * specified user.
-     */
-    @NonNull
-    ConfigurationInternal getConfigurationInternal(@UserIdInt int userId);
-
-    /**
-     * Returns a snapshot of the configuration that controls time zone detector behavior for the
-     * current user.
-     */
-    @NonNull
-    ConfigurationInternal getCurrentUserConfigurationInternal();
-
-    /**
-     * Updates the configuration properties that control a device's time zone behavior.
-     *
-     * <p>This method returns {@code true} if the configuration was changed,
-     * {@code false} otherwise.
-     */
-    boolean updateConfiguration(
-            @UserIdInt int userId, @NonNull TimeZoneConfiguration configuration);
-
-    /**
      * Suggests zero, one or more time zones for the device, or withdraws a previous suggestion if
      * {@link GeolocationTimeZoneSuggestion#getZoneIds()} is {@code null}.
      */
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java
index 1b09f44..3b6c1ea 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java
@@ -27,7 +27,6 @@
 import android.annotation.UserIdInt;
 import android.app.time.TimeZoneCapabilities;
 import android.app.time.TimeZoneCapabilitiesAndConfig;
-import android.app.time.TimeZoneConfiguration;
 import android.app.timezonedetector.ManualTimeZoneSuggestion;
 import android.app.timezonedetector.TelephonyTimeZoneSuggestion;
 import android.content.Context;
@@ -39,7 +38,6 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 
-import java.util.ArrayList;
 import java.util.List;
 import java.util.Objects;
 
@@ -63,16 +61,13 @@
 
         /**
          * Sets a {@link ConfigurationChangeListener} that will be invoked when there are any
-         * changes that could affect time zone detection. This is invoked during system server
-         * setup.
+         * changes that could affect the content of {@link ConfigurationInternal}.
+         * This is invoked during system server setup.
          */
-        void setConfigChangeListener(@NonNull ConfigurationChangeListener listener);
+        void setConfigurationInternalChangeListener(@NonNull ConfigurationChangeListener listener);
 
-        /** Returns the current user at the instant it is called. */
-        @UserIdInt int getCurrentUserId();
-
-        /** Returns the {@link ConfigurationInternal} for the specified user. */
-        ConfigurationInternal getConfigurationInternal(@UserIdInt int userId);
+        /** Returns the {@link ConfigurationInternal} for the current user. */
+        @NonNull ConfigurationInternal getCurrentUserConfigurationInternal();
 
         /**
          * Returns true if the device has had an explicit time zone set.
@@ -88,13 +83,6 @@
          * Sets the device's time zone.
          */
         void setDeviceTimeZone(@NonNull String zoneId);
-
-        /**
-         * Stores the configuration properties contained in {@code newConfiguration}.
-         * All checks about user capabilities must be done by the caller and
-         * {@link TimeZoneConfiguration#isComplete()} must be {@code true}.
-         */
-        void storeConfiguration(@UserIdInt int userId, TimeZoneConfiguration newConfiguration);
     }
 
     private static final String LOG_TAG = TimeZoneDetectorService.TAG;
@@ -166,10 +154,6 @@
     @NonNull
     private final Environment mEnvironment;
 
-    @GuardedBy("this")
-    @NonNull
-    private final List<ConfigurationChangeListener> mConfigChangeListeners = new ArrayList<>();
-
     /**
      * A log that records the decisions / decision metadata that affected the device's time zone.
      * This is logged in bug reports to assist with debugging issues with detection.
@@ -202,6 +186,9 @@
     private final ReferenceWithHistory<ManualTimeZoneSuggestion> mLatestManualSuggestion =
             new ReferenceWithHistory<>(KEEP_SUGGESTION_HISTORY_SIZE);
 
+    @GuardedBy("this")
+    @NonNull
+    private ConfigurationInternal mCurrentConfigurationInternal;
 
     /**
      * Creates a new instance of {@link TimeZoneDetectorStrategyImpl}.
@@ -217,71 +204,19 @@
     @VisibleForTesting
     public TimeZoneDetectorStrategyImpl(@NonNull Environment environment) {
         mEnvironment = Objects.requireNonNull(environment);
-        mEnvironment.setConfigChangeListener(this::handleConfigChanged);
-    }
 
-    /**
-     * Adds a listener that allows the strategy to communicate with the surrounding service /
-     * internal. This must be called before the instance is used.
-     */
-    @Override
-    public synchronized void addConfigChangeListener(
-            @NonNull ConfigurationChangeListener listener) {
-        Objects.requireNonNull(listener);
-        mConfigChangeListeners.add(listener);
-    }
-
-    @Override
-    @NonNull
-    public ConfigurationInternal getConfigurationInternal(@UserIdInt int userId) {
-        return mEnvironment.getConfigurationInternal(userId);
-    }
-
-    @Override
-    @NonNull
-    public synchronized ConfigurationInternal getCurrentUserConfigurationInternal() {
-        int currentUserId = mEnvironment.getCurrentUserId();
-        return getConfigurationInternal(currentUserId);
-    }
-
-    @Override
-    public synchronized boolean updateConfiguration(@UserIdInt int userId,
-            @NonNull TimeZoneConfiguration requestedConfiguration) {
-        Objects.requireNonNull(requestedConfiguration);
-
-        TimeZoneCapabilitiesAndConfig capabilitiesAndConfig =
-                getConfigurationInternal(userId).createCapabilitiesAndConfig();
-        TimeZoneCapabilities capabilities = capabilitiesAndConfig.getCapabilities();
-        TimeZoneConfiguration oldConfiguration = capabilitiesAndConfig.getConfiguration();
-
-        final TimeZoneConfiguration newConfiguration =
-                capabilities.tryApplyConfigChanges(oldConfiguration, requestedConfiguration);
-        if (newConfiguration == null) {
-            // The changes could not be made because the user's capabilities do not allow it.
-            return false;
+        synchronized (this) {
+            mEnvironment.setConfigurationInternalChangeListener(
+                    this::handleConfigurationInternalChanged);
+            mCurrentConfigurationInternal = mEnvironment.getCurrentUserConfigurationInternal();
         }
-
-        // Store the configuration / notify as needed. This will cause the mEnvironment to invoke
-        // handleConfigChanged() asynchronously.
-        mEnvironment.storeConfiguration(userId, newConfiguration);
-
-        String logMsg = "Configuration changed:"
-                + " oldConfiguration=" + oldConfiguration
-                + ", newConfiguration=" + newConfiguration;
-        mTimeZoneChangesLog.log(logMsg);
-        if (DBG) {
-            Slog.d(LOG_TAG, logMsg);
-        }
-        return true;
     }
 
     @Override
     public synchronized void suggestGeolocationTimeZone(
             @NonNull GeolocationTimeZoneSuggestion suggestion) {
 
-        int currentUserId = mEnvironment.getCurrentUserId();
-        ConfigurationInternal currentUserConfig =
-                mEnvironment.getConfigurationInternal(currentUserId);
+        ConfigurationInternal currentUserConfig = mCurrentConfigurationInternal;
         if (DBG) {
             Slog.d(LOG_TAG, "Geolocation suggestion received."
                     + " currentUserConfig=" + currentUserConfig
@@ -308,8 +243,8 @@
     public synchronized boolean suggestManualTimeZone(
             @UserIdInt int userId, @NonNull ManualTimeZoneSuggestion suggestion) {
 
-        int currentUserId = mEnvironment.getCurrentUserId();
-        if (userId != currentUserId) {
+        ConfigurationInternal currentUserConfig = mCurrentConfigurationInternal;
+        if (currentUserConfig.getUserId() != userId) {
             Slog.w(LOG_TAG, "Manual suggestion received but user != current user, userId=" + userId
                     + " suggestion=" + suggestion);
 
@@ -323,7 +258,7 @@
         String cause = "Manual time suggestion received: suggestion=" + suggestion;
 
         TimeZoneCapabilitiesAndConfig capabilitiesAndConfig =
-                getConfigurationInternal(userId).createCapabilitiesAndConfig();
+                currentUserConfig.createCapabilitiesAndConfig();
         TimeZoneCapabilities capabilities = capabilitiesAndConfig.getCapabilities();
         if (capabilities.getSuggestManualTimeZoneCapability() != CAPABILITY_POSSESSED) {
             Slog.i(LOG_TAG, "User does not have the capability needed to set the time zone manually"
@@ -347,9 +282,7 @@
     public synchronized void suggestTelephonyTimeZone(
             @NonNull TelephonyTimeZoneSuggestion suggestion) {
 
-        int currentUserId = mEnvironment.getCurrentUserId();
-        ConfigurationInternal currentUserConfig =
-                mEnvironment.getConfigurationInternal(currentUserId);
+        ConfigurationInternal currentUserConfig = mCurrentConfigurationInternal;
         if (DBG) {
             Slog.d(LOG_TAG, "Telephony suggestion received. currentUserConfig=" + currentUserConfig
                     + " newSuggestion=" + suggestion);
@@ -364,8 +297,8 @@
         // Store the suggestion against the correct slotIndex.
         mTelephonySuggestionsBySlotIndex.put(suggestion.getSlotIndex(), scoredSuggestion);
 
-        // Now perform auto time zone detection. The new suggestion may be used to modify the time
-        // zone setting.
+        // Now perform auto time zone detection: the new suggestion might be used to modify the
+        // time zone setting.
         String reason = "New telephony time zone suggested. suggestion=" + suggestion;
         doAutoTimeZoneDetection(currentUserConfig, reason);
     }
@@ -373,7 +306,6 @@
     @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 =
@@ -386,7 +318,7 @@
                 new OrdinalGenerator<>(new TimeZoneCanonicalizer());
         return MetricsTimeZoneDetectorState.create(
                 tzIdOrdinalGenerator,
-                getConfigurationInternal(currentUserId),
+                mCurrentConfigurationInternal,
                 mEnvironment.getDeviceTimeZone(),
                 getLatestManualSuggestion(),
                 telephonySuggestion,
@@ -593,26 +525,20 @@
         return findBestTelephonySuggestion();
     }
 
-    private synchronized void handleConfigChanged() {
-        if (DBG) {
-            Slog.d(LOG_TAG, "handleConfigChanged()");
-        }
-
-        // This method is called whenever the user changes or the config for any user changes. We
-        // don't know what happened, so we capture the current user's config, check to see if we
-        // need to clear state associated with a previous user, and rerun detection.
-        int currentUserId = mEnvironment.getCurrentUserId();
+    private synchronized void handleConfigurationInternalChanged() {
         ConfigurationInternal currentUserConfig =
-                mEnvironment.getConfigurationInternal(currentUserId);
+                mEnvironment.getCurrentUserConfigurationInternal();
+        String logMsg = "handleConfigurationInternalChanged:"
+                + " oldConfiguration=" + mCurrentConfigurationInternal
+                + ", newConfiguration=" + currentUserConfig;
+        if (DBG) {
+            Slog.d(LOG_TAG, logMsg);
+        }
+        mCurrentConfigurationInternal = currentUserConfig;
 
         // The configuration change may have changed available suggestions or the way suggestions
         // are used, so re-run detection.
-        doAutoTimeZoneDetection(currentUserConfig, "handleConfigChanged()");
-
-        // Pass on the signal to sub-components.
-        for (ConfigurationChangeListener listener : mConfigChangeListeners) {
-            listener.onChange();
-        }
+        doAutoTimeZoneDetection(currentUserConfig, logMsg);
     }
 
     /**
@@ -623,11 +549,9 @@
         ipw.println("TimeZoneDetectorStrategy:");
 
         ipw.increaseIndent(); // level 1
-        int currentUserId = mEnvironment.getCurrentUserId();
-        ipw.println("mEnvironment.getCurrentUserId()=" + currentUserId);
-        ConfigurationInternal configuration = mEnvironment.getConfigurationInternal(currentUserId);
-        ipw.println("mEnvironment.getConfiguration(currentUserId)=" + configuration);
-        ipw.println("[Capabilities=" + configuration.createCapabilitiesAndConfig() + "]");
+        ipw.println("mCurrentConfigurationInternal=" + mCurrentConfigurationInternal);
+        ipw.println("[Capabilities=" + mCurrentConfigurationInternal.createCapabilitiesAndConfig()
+                + "]");
         ipw.println("mEnvironment.isDeviceTimeZoneInitialized()="
                 + mEnvironment.isDeviceTimeZoneInitialized());
         ipw.println("mEnvironment.getDeviceTimeZone()=" + mEnvironment.getDeviceTimeZone());
diff --git a/services/core/java/com/android/server/timezonedetector/location/ControllerEnvironmentImpl.java b/services/core/java/com/android/server/timezonedetector/location/ControllerEnvironmentImpl.java
index 20fb61d..33cdc5f 100644
--- a/services/core/java/com/android/server/timezonedetector/location/ControllerEnvironmentImpl.java
+++ b/services/core/java/com/android/server/timezonedetector/location/ControllerEnvironmentImpl.java
@@ -20,11 +20,9 @@
 import android.annotation.NonNull;
 import android.os.SystemClock;
 
-import com.android.server.LocalServices;
 import com.android.server.timezonedetector.ConfigurationChangeListener;
 import com.android.server.timezonedetector.ConfigurationInternal;
 import com.android.server.timezonedetector.ServiceConfigAccessor;
-import com.android.server.timezonedetector.TimeZoneDetectorInternal;
 
 import java.time.Duration;
 import java.util.Objects;
@@ -35,32 +33,32 @@
  */
 class ControllerEnvironmentImpl extends LocationTimeZoneProviderController.Environment {
 
-    @NonNull private final TimeZoneDetectorInternal mTimeZoneDetectorInternal;
     @NonNull private final ServiceConfigAccessor mServiceConfigAccessor;
-    @NonNull private final ConfigurationChangeListener mConfigurationChangeListener;
+    @NonNull private final ConfigurationChangeListener mConfigurationInternalChangeListener;
 
     ControllerEnvironmentImpl(@NonNull ThreadingDomain threadingDomain,
             @NonNull ServiceConfigAccessor serviceConfigAccessor,
             @NonNull LocationTimeZoneProviderController controller) {
         super(threadingDomain);
         mServiceConfigAccessor = Objects.requireNonNull(serviceConfigAccessor);
-        mTimeZoneDetectorInternal = LocalServices.getService(TimeZoneDetectorInternal.class);
 
-        // Listen for configuration changes.
-        mConfigurationChangeListener = () -> mThreadingDomain.post(controller::onConfigChanged);
-        mTimeZoneDetectorInternal.addConfigurationListener(mConfigurationChangeListener);
+        // Listen for configuration internal changes.
+        mConfigurationInternalChangeListener =
+                () -> mThreadingDomain.post(controller::onConfigurationInternalChanged);
+        mServiceConfigAccessor.addConfigurationInternalChangeListener(
+                mConfigurationInternalChangeListener);
     }
 
-
     @Override
     void destroy() {
-        mTimeZoneDetectorInternal.removeConfigurationListener(mConfigurationChangeListener);
+        mServiceConfigAccessor.removeConfigurationInternalChangeListener(
+                mConfigurationInternalChangeListener);
     }
 
     @Override
     @NonNull
     ConfigurationInternal getCurrentUserConfigurationInternal() {
-        return mTimeZoneDetectorInternal.getCurrentUserConfigurationInternal();
+        return mServiceConfigAccessor.getCurrentUserConfigurationInternal();
     }
 
     @Override
diff --git a/services/core/java/com/android/server/timezonedetector/location/ControllerImpl.java b/services/core/java/com/android/server/timezonedetector/location/ControllerImpl.java
index 466a039..b9da2eb 100644
--- a/services/core/java/com/android/server/timezonedetector/location/ControllerImpl.java
+++ b/services/core/java/com/android/server/timezonedetector/location/ControllerImpl.java
@@ -122,7 +122,7 @@
     }
 
     @Override
-    void onConfigChanged() {
+    void onConfigurationInternalChanged() {
         mThreadingDomain.assertCurrentThread();
 
         synchronized (mSharedLock) {
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 942df53..ddbeac4 100644
--- a/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerService.java
+++ b/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerService.java
@@ -41,6 +41,7 @@
 import com.android.server.SystemService;
 import com.android.server.timezonedetector.Dumpable;
 import com.android.server.timezonedetector.ServiceConfigAccessor;
+import com.android.server.timezonedetector.ServiceConfigAccessorImpl;
 import com.android.server.timezonedetector.TimeZoneDetectorInternal;
 import com.android.server.timezonedetector.location.LocationTimeZoneProvider.ProviderMetricsLogger;
 
@@ -77,18 +78,18 @@
         private LocationTimeZoneManagerService mService;
 
         @NonNull
-        private final ServiceConfigAccessor mServerConfigAccessor;
+        private final ServiceConfigAccessor mServiceConfigAccessor;
 
         public Lifecycle(@NonNull Context context) {
             super(Objects.requireNonNull(context));
-            mServerConfigAccessor = ServiceConfigAccessor.getInstance(context);
+            mServiceConfigAccessor = ServiceConfigAccessorImpl.getInstance(context);
         }
 
         @Override
         public void onStart() {
             Context context = getContext();
-            if (mServerConfigAccessor.isGeoTimeZoneDetectionFeatureSupportedInConfig()) {
-                mService = new LocationTimeZoneManagerService(context);
+            if (mServiceConfigAccessor.isGeoTimeZoneDetectionFeatureSupportedInConfig()) {
+                mService = new LocationTimeZoneManagerService(context, mServiceConfigAccessor);
 
                 // The service currently exposes no LocalService or Binder API, but it extends
                 // Binder and is registered as a binder service so it can receive shell commands.
@@ -100,7 +101,7 @@
 
         @Override
         public void onBootPhase(@BootPhase int phase) {
-            if (mServerConfigAccessor.isGeoTimeZoneDetectionFeatureSupportedInConfig()) {
+            if (mServiceConfigAccessor.isGeoTimeZoneDetectionFeatureSupportedInConfig()) {
                 if (phase == PHASE_SYSTEM_SERVICES_READY) {
                     // The location service must be functioning after this boot phase.
                     mService.onSystemReady();
@@ -157,12 +158,13 @@
     @GuardedBy("mSharedLock")
     private ControllerEnvironmentImpl mEnvironment;
 
-    LocationTimeZoneManagerService(Context context) {
+    LocationTimeZoneManagerService(@NonNull Context context,
+            @NonNull ServiceConfigAccessor serviceConfigAccessor) {
         mContext = context.createAttributionContext(ATTRIBUTION_TAG);
         mHandler = FgThread.getHandler();
         mThreadingDomain = new HandlerThreadingDomain(mHandler);
         mSharedLock = mThreadingDomain.getLockObject();
-        mServiceConfigAccessor = ServiceConfigAccessor.getInstance(mContext);
+        mServiceConfigAccessor = Objects.requireNonNull(serviceConfigAccessor);
     }
 
     // According to the SystemService docs: All lifecycle methods are called from the system
diff --git a/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneProviderController.java b/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneProviderController.java
index fdb9c14..4dff02e 100644
--- a/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneProviderController.java
+++ b/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneProviderController.java
@@ -39,7 +39,7 @@
  * <p>The controller interacts with the following components:
  * <ul>
  *     <li>The surrounding service, which calls {@link #initialize(Environment, Callback)} and
- *     {@link #onConfigChanged()}.</li>
+ *     {@link #onConfigurationInternalChanged()}.</li>
  *     <li>The {@link Environment} through which obtains information it needs.</li>
  *     <li>The {@link Callback} through which it makes time zone suggestions.</li>
  *     <li>Any {@link LocationTimeZoneProvider} instances it owns, which communicate via the
@@ -81,12 +81,11 @@
     abstract void initialize(@NonNull Environment environment, @NonNull Callback callback);
 
     /**
-     * Called when any settings or other device state that affect location-based time zone detection
-     * have changed. The receiver should call {@link
-     * Environment#getCurrentUserConfigurationInternal()} to get the current user's config. This
-     * call must be made on the {@link ThreadingDomain} handler thread.
+     * Called when the content of the {@link ConfigurationInternal} may have changed. The receiver
+     * should call {@link Environment#getCurrentUserConfigurationInternal()} to get the current
+     * user's config. This call must be made on the {@link ThreadingDomain} handler thread.
      */
-    abstract void onConfigChanged();
+    abstract void onConfigurationInternalChanged();
 
     @VisibleForTesting
     abstract boolean isUncertaintyTimeoutSet();
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index e9d5ad6..e69acc3 100755
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -470,14 +470,16 @@
     }
 
     private void stopUser(int userId) {
-        if (userId == mCurrentUserId) {
-            switchUser(ActivityManager.getCurrentUser());
-            return;
-        }
+        synchronized (mLock) {
+            if (userId == mCurrentUserId) {
+                switchUser(ActivityManager.getCurrentUser());
+                return;
+            }
 
-        releaseSessionOfUserLocked(userId);
-        unbindServiceOfUserLocked(userId);
-        mRunningProfiles.remove(userId);
+            releaseSessionOfUserLocked(userId);
+            unbindServiceOfUserLocked(userId);
+            mRunningProfiles.remove(userId);
+        }
     }
 
     private void startProfileLocked(int userId) {
diff --git a/services/core/java/com/android/server/tv/interactive/TvIAppManagerService.java b/services/core/java/com/android/server/tv/interactive/TvIAppManagerService.java
index 8bbac7a..dfb0752 100644
--- a/services/core/java/com/android/server/tv/interactive/TvIAppManagerService.java
+++ b/services/core/java/com/android/server/tv/interactive/TvIAppManagerService.java
@@ -27,8 +27,10 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
+import android.content.pm.UserInfo;
 import android.media.tv.interactive.ITvIAppClient;
 import android.media.tv.interactive.ITvIAppManager;
+import android.media.tv.interactive.ITvIAppManagerCallback;
 import android.media.tv.interactive.ITvIAppService;
 import android.media.tv.interactive.ITvIAppServiceCallback;
 import android.media.tv.interactive.ITvIAppSession;
@@ -38,9 +40,12 @@
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.Process;
+import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.util.ArrayMap;
+import android.util.Slog;
 import android.util.SparseArray;
 import android.view.Surface;
 
@@ -55,10 +60,12 @@
 import java.util.Comparator;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
+
 /**
  * This class provides a system service that manages interactive TV applications.
  */
@@ -78,6 +85,8 @@
     @GuardedBy("mLock")
     private final SparseArray<UserState> mUserStates = new SparseArray<>();
 
+    private final UserManager mUserManager;
+
     /**
      * Initializes the system service.
      * <p>
@@ -90,6 +99,7 @@
     public TvIAppManagerService(Context context) {
         super(context);
         mContext = context;
+        mUserManager = (UserManager) getContext().getSystemService(Context.USER_SERVICE);
     }
 
     @GuardedBy("mLock")
@@ -145,12 +155,85 @@
             iAppState.mIAppNumber = count;
         }
 
-        // TODO: notify iApp added / removed
+        for (String iAppServiceId : iAppMap.keySet()) {
+            if (!userState.mIAppMap.containsKey(iAppServiceId)) {
+                notifyIAppServiceAddedLocked(userState, iAppServiceId);
+            } else if (updatedPackages != null) {
+                // Notify the package updates
+                ComponentName component = iAppMap.get(iAppServiceId).mInfo.getComponent();
+                for (String updatedPackage : updatedPackages) {
+                    if (component.getPackageName().equals(updatedPackage)) {
+                        updateServiceConnectionLocked(component, userId);
+                        notifyIAppServiceUpdatedLocked(userState, iAppServiceId);
+                        break;
+                    }
+                }
+            }
+        }
+
+        for (String iAppServiceId : userState.mIAppMap.keySet()) {
+            if (!iAppMap.containsKey(iAppServiceId)) {
+                TvIAppInfo info = userState.mIAppMap.get(iAppServiceId).mInfo;
+                ServiceState serviceState = userState.mServiceStateMap.get(info.getComponent());
+                if (serviceState != null) {
+                    abortPendingCreateSessionRequestsLocked(serviceState, iAppServiceId, userId);
+                }
+                notifyIAppServiceRemovedLocked(userState, iAppServiceId);
+            }
+        }
 
         userState.mIAppMap.clear();
         userState.mIAppMap = iAppMap;
     }
 
+    @GuardedBy("mLock")
+    private void notifyIAppServiceAddedLocked(UserState userState, String iAppServiceId) {
+        if (DEBUG) {
+            Slog.d(TAG, "notifyIAppServiceAddedLocked(iAppServiceId=" + iAppServiceId + ")");
+        }
+        int n = userState.mCallbacks.beginBroadcast();
+        for (int i = 0; i < n; ++i) {
+            try {
+                userState.mCallbacks.getBroadcastItem(i).onIAppServiceAdded(iAppServiceId);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "failed to report added IApp service to callback", e);
+            }
+        }
+        userState.mCallbacks.finishBroadcast();
+    }
+
+    @GuardedBy("mLock")
+    private void notifyIAppServiceRemovedLocked(UserState userState, String iAppServiceId) {
+        if (DEBUG) {
+            Slog.d(TAG, "notifyIAppServiceRemovedLocked(iAppServiceId=" + iAppServiceId + ")");
+        }
+        int n = userState.mCallbacks.beginBroadcast();
+        for (int i = 0; i < n; ++i) {
+            try {
+                userState.mCallbacks.getBroadcastItem(i).onIAppServiceRemoved(iAppServiceId);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "failed to report removed IApp service to callback", e);
+            }
+        }
+        userState.mCallbacks.finishBroadcast();
+    }
+
+    @GuardedBy("mLock")
+    private void notifyIAppServiceUpdatedLocked(UserState userState, String iAppServiceId) {
+        if (DEBUG) {
+            Slog.d(TAG, "notifyIAppServiceUpdatedLocked(iAppServiceId=" + iAppServiceId + ")");
+        }
+        int n = userState.mCallbacks.beginBroadcast();
+        for (int i = 0; i < n; ++i) {
+            try {
+                userState.mCallbacks.getBroadcastItem(i).onIAppServiceUpdated(iAppServiceId);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "failed to report updated IApp service to callback", e);
+            }
+        }
+        userState.mCallbacks.finishBroadcast();
+    }
+
     private int getIAppUid(TvIAppInfo info) {
         try {
             return getContext().getPackageManager().getApplicationInfo(
@@ -254,11 +337,188 @@
         mContext.registerReceiverAsUser(new BroadcastReceiver() {
             @Override
             public void onReceive(Context context, Intent intent) {
-                // TODO: handle switch / start / stop user
+                String action = intent.getAction();
+                if (Intent.ACTION_USER_SWITCHED.equals(action)) {
+                    switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
+                } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
+                    removeUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
+                } else if (Intent.ACTION_USER_STARTED.equals(action)) {
+                    int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
+                    startUser(userId);
+                } else if (Intent.ACTION_USER_STOPPED.equals(action)) {
+                    int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
+                    stopUser(userId);
+                }
             }
         }, UserHandle.ALL, intentFilter, null, null);
     }
 
+    private void switchUser(int userId) {
+        synchronized (mLock) {
+            if (mCurrentUserId == userId) {
+                return;
+            }
+            UserInfo userInfo = mUserManager.getUserInfo(userId);
+            if (userInfo.isProfile()) {
+                Slog.w(TAG, "cannot switch to a profile!");
+                return;
+            }
+
+            for (int runningId : mRunningProfiles) {
+                releaseSessionOfUserLocked(runningId);
+                unbindServiceOfUserLocked(runningId);
+            }
+            mRunningProfiles.clear();
+            releaseSessionOfUserLocked(mCurrentUserId);
+            unbindServiceOfUserLocked(mCurrentUserId);
+
+            mCurrentUserId = userId;
+            buildTvIAppServiceListLocked(userId, null);
+        }
+    }
+
+    private void removeUser(int userId) {
+        synchronized (mLock) {
+            UserState userState = getUserStateLocked(userId);
+            if (userState == null) {
+                return;
+            }
+            // Release all created sessions.
+            for (SessionState state : userState.mSessionStateMap.values()) {
+                if (state.mSession != null) {
+                    try {
+                        state.mSession.release();
+                    } catch (RemoteException e) {
+                        Slog.e(TAG, "error in release", e);
+                    }
+                }
+            }
+            userState.mSessionStateMap.clear();
+
+            // Unregister all callbacks and unbind all services.
+            for (ServiceState serviceState : userState.mServiceStateMap.values()) {
+                if (serviceState.mService != null) {
+                    if (serviceState.mCallback != null) {
+                        try {
+                            serviceState.mService.unregisterCallback(serviceState.mCallback);
+                        } catch (RemoteException e) {
+                            Slog.e(TAG, "error in unregisterCallback", e);
+                        }
+                    }
+                    mContext.unbindService(serviceState.mConnection);
+                }
+            }
+            userState.mServiceStateMap.clear();
+
+            // Clear everything else.
+            userState.mIAppMap.clear();
+            userState.mPackageSet.clear();
+            userState.mClientStateMap.clear();
+            userState.mCallbacks.kill();
+
+            mRunningProfiles.remove(userId);
+            mUserStates.remove(userId);
+
+            if (userId == mCurrentUserId) {
+                switchUser(UserHandle.USER_SYSTEM);
+            }
+        }
+    }
+
+    private void startUser(int userId) {
+        synchronized (mLock) {
+            if (userId == mCurrentUserId || mRunningProfiles.contains(userId)) {
+                // user already started
+                return;
+            }
+            UserInfo userInfo = mUserManager.getUserInfo(userId);
+            UserInfo parentInfo = mUserManager.getProfileParent(userId);
+            if (userInfo.isProfile()
+                    && parentInfo != null
+                    && parentInfo.id == mCurrentUserId) {
+                // only the children of the current user can be started in background
+                startProfileLocked(userId);
+            }
+        }
+    }
+
+    private void stopUser(int userId) {
+        synchronized (mLock) {
+            if (userId == mCurrentUserId) {
+                switchUser(ActivityManager.getCurrentUser());
+                return;
+            }
+
+            releaseSessionOfUserLocked(userId);
+            unbindServiceOfUserLocked(userId);
+            mRunningProfiles.remove(userId);
+        }
+    }
+
+    @GuardedBy("mLock")
+    private void startProfileLocked(int userId) {
+        mRunningProfiles.add(userId);
+        buildTvIAppServiceListLocked(userId, null);
+    }
+
+    @GuardedBy("mLock")
+    private void releaseSessionOfUserLocked(int userId) {
+        UserState userState = getUserStateLocked(userId);
+        if (userState == null) {
+            return;
+        }
+        List<SessionState> sessionStatesToRelease = new ArrayList<>();
+        for (SessionState sessionState : userState.mSessionStateMap.values()) {
+            if (sessionState.mSession != null) {
+                sessionStatesToRelease.add(sessionState);
+            }
+        }
+        for (SessionState sessionState : sessionStatesToRelease) {
+            try {
+                sessionState.mSession.release();
+            } catch (RemoteException e) {
+                Slog.e(TAG, "error in release", e);
+            }
+            clearSessionAndNotifyClientLocked(sessionState);
+        }
+    }
+
+    @GuardedBy("mLock")
+    private void unbindServiceOfUserLocked(int userId) {
+        UserState userState = getUserStateLocked(userId);
+        if (userState == null) {
+            return;
+        }
+        for (Iterator<ComponentName> it = userState.mServiceStateMap.keySet().iterator();
+                it.hasNext(); ) {
+            ComponentName component = it.next();
+            ServiceState serviceState = userState.mServiceStateMap.get(component);
+            if (serviceState != null && serviceState.mSessionTokens.isEmpty()) {
+                if (serviceState.mCallback != null) {
+                    try {
+                        serviceState.mService.unregisterCallback(serviceState.mCallback);
+                    } catch (RemoteException e) {
+                        Slog.e(TAG, "error in unregisterCallback", e);
+                    }
+                }
+                mContext.unbindService(serviceState.mConnection);
+                it.remove();
+            }
+        }
+    }
+
+    @GuardedBy("mLock")
+    private void clearSessionAndNotifyClientLocked(SessionState state) {
+        if (state.mClient != null) {
+            try {
+                state.mClient.onSessionReleased(state.mSeq);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "error in onSessionReleased", e);
+            }
+        }
+        removeSessionStateLocked(state.mSessionToken, state.mUserId);
+    }
+
     private SessionState getSessionState(IBinder sessionToken) {
         // TODO: implement user state and get session from it.
         return null;
@@ -319,6 +579,25 @@
     private final class BinderService extends ITvIAppManager.Stub {
 
         @Override
+        public List<TvIAppInfo> getTvIAppServiceList(int userId) {
+            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
+                    Binder.getCallingUid(), userId, "getTvIAppServiceList");
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    UserState userState = getOrCreateUserStateLocked(resolvedUserId);
+                    List<TvIAppInfo> iAppList = new ArrayList<>();
+                    for (TvIAppState state : userState.mIAppMap.values()) {
+                        iAppList.add(state.mInfo);
+                    }
+                    return iAppList;
+                }
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
         public void createSession(final ITvIAppClient client, final String iAppServiceId, int type,
                 int seq, int userId) {
             final int callingUid = Binder.getCallingUid();
@@ -463,6 +742,40 @@
                 Binder.restoreCallingIdentity(identity);
             }
         }
+
+        @Override
+        public void registerCallback(final ITvIAppManagerCallback callback, int userId) {
+            int callingPid = Binder.getCallingPid();
+            int callingUid = Binder.getCallingUid();
+            final int resolvedUserId = resolveCallingUserId(callingPid, callingUid, userId,
+                    "registerCallback");
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    final UserState userState = getOrCreateUserStateLocked(resolvedUserId);
+                    if (!userState.mCallbacks.register(callback)) {
+                        Slog.e(TAG, "client process has already died");
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
+        public void unregisterCallback(ITvIAppManagerCallback callback, int userId) {
+            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
+                    Binder.getCallingUid(), userId, "unregisterCallback");
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    UserState userState = getOrCreateUserStateLocked(resolvedUserId);
+                    userState.mCallbacks.unregister(callback);
+                }
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
     }
 
     @GuardedBy("mLock")
@@ -634,6 +947,10 @@
         // A set of all TV IApp service packages.
         private final Set<String> mPackageSet = new HashSet<>();
 
+        // A list of callbacks.
+        private final RemoteCallbackList<ITvIAppManagerCallback> mCallbacks =
+                new RemoteCallbackList<>();
+
         private UserState(int userId) {
             mUserId = userId;
         }
diff --git a/services/core/java/com/android/server/vibrator/VibrationSettings.java b/services/core/java/com/android/server/vibrator/VibrationSettings.java
index 95305ba..71a6b22 100644
--- a/services/core/java/com/android/server/vibrator/VibrationSettings.java
+++ b/services/core/java/com/android/server/vibrator/VibrationSettings.java
@@ -16,6 +16,14 @@
 
 package com.android.server.vibrator;
 
+import static android.os.VibrationAttributes.USAGE_ALARM;
+import static android.os.VibrationAttributes.USAGE_COMMUNICATION_REQUEST;
+import static android.os.VibrationAttributes.USAGE_HARDWARE_FEEDBACK;
+import static android.os.VibrationAttributes.USAGE_NOTIFICATION;
+import static android.os.VibrationAttributes.USAGE_PHYSICAL_EMULATION;
+import static android.os.VibrationAttributes.USAGE_RINGTONE;
+import static android.os.VibrationAttributes.USAGE_TOUCH;
+
 import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.IUidObserver;
@@ -90,6 +98,8 @@
     @GuardedBy("mLock")
     private int mHapticFeedbackIntensity;
     @GuardedBy("mLock")
+    private int mHardwareFeedbackIntensity;
+    @GuardedBy("mLock")
     private int mNotificationIntensity;
     @GuardedBy("mLock")
     private int mRingIntensity;
@@ -171,7 +181,9 @@
                     }
                 });
 
-        mContext.registerReceiver(mUserReceiver, new IntentFilter(Intent.ACTION_USER_SWITCHED));
+        IntentFilter filter = new IntentFilter(Intent.ACTION_USER_SWITCHED);
+        mContext.registerReceiver(mUserReceiver, filter, Context.RECEIVER_NOT_EXPORTED);
+
         registerSettingsObserver(Settings.System.getUriFor(Settings.System.VIBRATE_INPUT_DEVICES));
         registerSettingsObserver(Settings.System.getUriFor(Settings.System.VIBRATE_WHEN_RINGING));
         registerSettingsObserver(Settings.Global.getUriFor(Settings.Global.APPLY_RAMPING_RINGER));
@@ -230,17 +242,20 @@
      * @return The vibration intensity, one of Vibrator.VIBRATION_INTENSITY_*
      */
     public int getDefaultIntensity(int usageHint) {
-        if (isAlarm(usageHint)) {
+        if (usageHint == USAGE_ALARM) {
             return Vibrator.VIBRATION_INTENSITY_HIGH;
         }
         synchronized (mLock) {
             if (mVibrator != null) {
-                if (isRingtone(usageHint)) {
-                    return mVibrator.getDefaultRingVibrationIntensity();
-                } else if (isNotification(usageHint)) {
-                    return mVibrator.getDefaultNotificationVibrationIntensity();
-                } else if (isHapticFeedback(usageHint)) {
-                    return mVibrator.getDefaultHapticFeedbackIntensity();
+                switch (usageHint) {
+                    case USAGE_RINGTONE:
+                        return mVibrator.getDefaultRingVibrationIntensity();
+                    case USAGE_NOTIFICATION:
+                        return mVibrator.getDefaultNotificationVibrationIntensity();
+                    case USAGE_TOUCH:
+                    case USAGE_HARDWARE_FEEDBACK:
+                    case USAGE_PHYSICAL_EMULATION:
+                        return mVibrator.getDefaultHapticFeedbackIntensity();
                 }
             }
         }
@@ -255,16 +270,20 @@
      */
     public int getCurrentIntensity(int usageHint) {
         synchronized (mLock) {
-            if (isRingtone(usageHint)) {
-                return mRingIntensity;
-            } else if (isNotification(usageHint)) {
-                return mNotificationIntensity;
-            } else if (isHapticFeedback(usageHint)) {
-                return mHapticFeedbackIntensity;
-            } else if (isAlarm(usageHint)) {
-                return Vibrator.VIBRATION_INTENSITY_HIGH;
-            } else {
-                return Vibrator.VIBRATION_INTENSITY_MEDIUM;
+            switch (usageHint) {
+                case USAGE_RINGTONE:
+                    return mRingIntensity;
+                case USAGE_NOTIFICATION:
+                    return mNotificationIntensity;
+                case USAGE_TOUCH:
+                    return mHapticFeedbackIntensity;
+                case USAGE_HARDWARE_FEEDBACK:
+                case USAGE_PHYSICAL_EMULATION:
+                    return mHardwareFeedbackIntensity;
+                case USAGE_ALARM:
+                    return Vibrator.VIBRATION_INTENSITY_HIGH;
+                default:
+                    return Vibrator.VIBRATION_INTENSITY_MEDIUM;
             }
         }
     }
@@ -287,7 +306,7 @@
      * for ringtone usage only. All other usages are allowed independently of ringer mode.
      */
     public boolean shouldVibrateForRingerMode(int usageHint) {
-        if (!isRingtone(usageHint)) {
+        if (usageHint != USAGE_RINGTONE) {
             return true;
         }
         synchronized (mLock) {
@@ -322,8 +341,10 @@
      * {@link VibrationAttributes#USAGE_COMMUNICATION_REQUEST} usages are allowed to vibrate.
      */
     public boolean shouldVibrateForPowerMode(int usageHint) {
-        return !mLowPowerMode || isRingtone(usageHint) || isAlarm(usageHint)
-                || usageHint == VibrationAttributes.USAGE_COMMUNICATION_REQUEST;
+        synchronized (mLock) {
+            return !mLowPowerMode || usageHint == USAGE_RINGTONE || usageHint == USAGE_ALARM
+                    || usageHint == USAGE_COMMUNICATION_REQUEST;
+        }
     }
 
     /** Return {@code true} if input devices should vibrate instead of this device. */
@@ -336,22 +357,6 @@
         return mZenMode != Settings.Global.ZEN_MODE_OFF;
     }
 
-    private static boolean isNotification(int usageHint) {
-        return usageHint == VibrationAttributes.USAGE_NOTIFICATION;
-    }
-
-    private static boolean isRingtone(int usageHint) {
-        return usageHint == VibrationAttributes.USAGE_RINGTONE;
-    }
-
-    private static boolean isHapticFeedback(int usageHint) {
-        return usageHint == VibrationAttributes.USAGE_TOUCH;
-    }
-
-    private static boolean isAlarm(int usageHint) {
-        return usageHint == VibrationAttributes.USAGE_ALARM;
-    }
-
     private static boolean isClassAlarm(int usageHint) {
         return (usageHint & VibrationAttributes.USAGE_CLASS_MASK)
                 == VibrationAttributes.USAGE_CLASS_ALARM;
@@ -363,18 +368,35 @@
             mVibrateWhenRinging = getSystemSetting(Settings.System.VIBRATE_WHEN_RINGING, 0) != 0;
             mApplyRampingRinger = getGlobalSetting(Settings.Global.APPLY_RAMPING_RINGER, 0) != 0;
             mHapticFeedbackIntensity = getSystemSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY,
-                    getDefaultIntensity(VibrationAttributes.USAGE_TOUCH));
+                    getDefaultIntensity(USAGE_TOUCH));
+            mHardwareFeedbackIntensity = getSystemSetting(
+                    Settings.System.HARDWARE_HAPTIC_FEEDBACK_INTENSITY,
+                    getHardwareFeedbackIntensityWhenSettingIsMissing(mHapticFeedbackIntensity));
             mNotificationIntensity = getSystemSetting(
                     Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
-                    getDefaultIntensity(VibrationAttributes.USAGE_NOTIFICATION));
+                    getDefaultIntensity(USAGE_NOTIFICATION));
             mRingIntensity = getSystemSetting(Settings.System.RING_VIBRATION_INTENSITY,
-                    getDefaultIntensity(VibrationAttributes.USAGE_RINGTONE));
+                    getDefaultIntensity(USAGE_RINGTONE));
             mVibrateInputDevices = getSystemSetting(Settings.System.VIBRATE_INPUT_DEVICES, 0) > 0;
             mZenMode = getGlobalSetting(Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF);
         }
         notifyListeners();
     }
 
+    /**
+     * Return the value to be used for {@link Settings.System#HARDWARE_HAPTIC_FEEDBACK_INTENSITY}
+     * when the value was not set by the user.
+     *
+     * <p>This should adapt the behavior preceding the introduction of this new setting key, which
+     * is to apply {@link Settings.System#HAPTIC_FEEDBACK_INTENSITY} unless it's disabled.
+     */
+    private int getHardwareFeedbackIntensityWhenSettingIsMissing(int hapticFeedbackIntensity) {
+        if (hapticFeedbackIntensity == Vibrator.VIBRATION_INTENSITY_OFF) {
+            return getDefaultIntensity(USAGE_HARDWARE_FEEDBACK);
+        }
+        return hapticFeedbackIntensity;
+    }
+
     @Override
     public String toString() {
         return "VibrationSettings{"
@@ -387,18 +409,20 @@
                 + ", mHapticChannelMaxVibrationAmplitude=" + getHapticChannelMaxVibrationAmplitude()
                 + ", mRampStepDuration=" + mRampStepDuration
                 + ", mRampDownDuration=" + mRampDownDuration
+                + ", mHardwareHapticFeedbackIntensity="
+                + intensityToString(getCurrentIntensity(USAGE_HARDWARE_FEEDBACK))
                 + ", mHapticFeedbackIntensity="
-                + intensityToString(getCurrentIntensity(VibrationAttributes.USAGE_TOUCH))
+                + intensityToString(getCurrentIntensity(USAGE_TOUCH))
                 + ", mHapticFeedbackDefaultIntensity="
-                + intensityToString(getDefaultIntensity(VibrationAttributes.USAGE_TOUCH))
+                + intensityToString(getDefaultIntensity(USAGE_TOUCH))
                 + ", mNotificationIntensity="
-                + intensityToString(getCurrentIntensity(VibrationAttributes.USAGE_NOTIFICATION))
+                + intensityToString(getCurrentIntensity(USAGE_NOTIFICATION))
                 + ", mNotificationDefaultIntensity="
-                + intensityToString(getDefaultIntensity(VibrationAttributes.USAGE_NOTIFICATION))
+                + intensityToString(getDefaultIntensity(USAGE_NOTIFICATION))
                 + ", mRingIntensity="
-                + intensityToString(getCurrentIntensity(VibrationAttributes.USAGE_RINGTONE))
+                + intensityToString(getCurrentIntensity(USAGE_RINGTONE))
                 + ", mRingDefaultIntensity="
-                + intensityToString(getDefaultIntensity(VibrationAttributes.USAGE_RINGTONE))
+                + intensityToString(getDefaultIntensity(USAGE_RINGTONE))
                 + '}';
     }
 
@@ -408,15 +432,15 @@
             proto.write(VibratorManagerServiceDumpProto.HAPTIC_FEEDBACK_INTENSITY,
                     mHapticFeedbackIntensity);
             proto.write(VibratorManagerServiceDumpProto.HAPTIC_FEEDBACK_DEFAULT_INTENSITY,
-                    getDefaultIntensity(VibrationAttributes.USAGE_TOUCH));
+                    getDefaultIntensity(USAGE_TOUCH));
             proto.write(VibratorManagerServiceDumpProto.NOTIFICATION_INTENSITY,
                     mNotificationIntensity);
             proto.write(VibratorManagerServiceDumpProto.NOTIFICATION_DEFAULT_INTENSITY,
-                    getDefaultIntensity(VibrationAttributes.USAGE_NOTIFICATION));
+                    getDefaultIntensity(USAGE_NOTIFICATION));
             proto.write(VibratorManagerServiceDumpProto.RING_INTENSITY,
                     mRingIntensity);
             proto.write(VibratorManagerServiceDumpProto.RING_DEFAULT_INTENSITY,
-                    getDefaultIntensity(VibrationAttributes.USAGE_RINGTONE));
+                    getDefaultIntensity(USAGE_RINGTONE));
         }
     }
 
diff --git a/services/core/java/com/android/server/vibrator/VibrationThread.java b/services/core/java/com/android/server/vibrator/VibrationThread.java
index a327382..fdd9913 100644
--- a/services/core/java/com/android/server/vibrator/VibrationThread.java
+++ b/services/core/java/com/android/server/vibrator/VibrationThread.java
@@ -287,6 +287,9 @@
                 }
                 // If we waited, the queue may have changed, so let the loop run again.
                 if (waitTime <= 0) {
+                    if (DEBUG) {
+                        Slog.d(TAG, "Play vibration consuming next step...");
+                    }
                     mStepQueue.consumeNext();
                 }
                 Vibration.Status status = mStop ? Vibration.Status.CANCELLED
diff --git a/services/core/java/com/android/server/vibrator/VibratorController.java b/services/core/java/com/android/server/vibrator/VibratorController.java
index 4b7fd90..4a1b95b 100644
--- a/services/core/java/com/android/server/vibrator/VibratorController.java
+++ b/services/core/java/com/android/server/vibrator/VibratorController.java
@@ -40,21 +40,22 @@
     private static final int SUGGESTED_FREQUENCY_SAFE_RANGE = 200;
 
     private final Object mLock = new Object();
-    private final NativeWrapper mNativeWrapper;
 
     @GuardedBy("mLock")
-    private VibratorInfo mVibratorInfo;
-    @GuardedBy("mLock")
-    private boolean mVibratorInfoLoadSuccessful;
-    @GuardedBy("mLock")
+    private final NativeWrapper mNativeWrapper;
+
+    // Vibrator state listeners that support concurrent updates and broadcasts, but should lock
+    // while broadcasting to guarantee delivery order.
     private final RemoteCallbackList<IVibratorStateListener> mVibratorStateListeners =
             new RemoteCallbackList<>();
-    @GuardedBy("mLock")
-    private boolean mIsVibrating;
-    @GuardedBy("mLock")
-    private boolean mIsUnderExternalControl;
-    @GuardedBy("mLock")
-    private float mCurrentAmplitude;
+
+    // Vibrator state variables that are updated from synchronized blocks but can be read anytime
+    // for a snippet of the current known vibrator state/info.
+    private volatile VibratorInfo mVibratorInfo;
+    private volatile boolean mVibratorInfoLoadSuccessful;
+    private volatile boolean mIsVibrating;
+    private volatile boolean mIsUnderExternalControl;
+    private volatile float mCurrentAmplitude;
 
     /** Listener for vibration completion callbacks from native. */
     public interface OnVibrationCompleteListener {
@@ -86,35 +87,39 @@
 
     /** Register state listener for this vibrator. */
     public boolean registerVibratorStateListener(IVibratorStateListener listener) {
-        synchronized (mLock) {
-            final long token = Binder.clearCallingIdentity();
-            try {
+        final long token = Binder.clearCallingIdentity();
+        try {
+            // Register the listener and send the first state atomically, to avoid potentially
+            // out of order broadcasts in between.
+            synchronized (mLock) {
                 if (!mVibratorStateListeners.register(listener)) {
                     return false;
                 }
                 // Notify its callback after new client registered.
-                notifyStateListenerLocked(listener);
-                return true;
-            } finally {
-                Binder.restoreCallingIdentity(token);
+                notifyStateListener(listener, mIsVibrating);
             }
+            return true;
+        } finally {
+            Binder.restoreCallingIdentity(token);
         }
     }
 
     /** Remove registered state listener for this vibrator. */
     public boolean unregisterVibratorStateListener(IVibratorStateListener listener) {
-        synchronized (mLock) {
-            final long token = Binder.clearCallingIdentity();
-            try {
-                return mVibratorStateListeners.unregister(listener);
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
+        final long token = Binder.clearCallingIdentity();
+        try {
+            return mVibratorStateListeners.unregister(listener);
+        } finally {
+            Binder.restoreCallingIdentity(token);
         }
     }
 
     /** Reruns the query to the vibrator to load the {@link VibratorInfo}, if not yet successful. */
     public void reloadVibratorInfoIfNeeded() {
+        // Early check outside lock, for quick return.
+        if (mVibratorInfoLoadSuccessful) {
+            return;
+        }
         synchronized (mLock) {
             if (mVibratorInfoLoadSuccessful) {
                 return;
@@ -132,16 +137,12 @@
 
     /** Checks if the {@link VibratorInfo} was loaded from the vibrator hardware successfully. */
     boolean isVibratorInfoLoadSuccessful() {
-        synchronized (mLock) {
-            return mVibratorInfoLoadSuccessful;
-        }
+        return mVibratorInfoLoadSuccessful;
     }
 
     /** Return the {@link VibratorInfo} representing the vibrator controlled by this instance. */
     public VibratorInfo getVibratorInfo() {
-        synchronized (mLock) {
-            return mVibratorInfo;
-        }
+        return mVibratorInfo;
     }
 
     /**
@@ -151,9 +152,7 @@
      * automatically notified to any registered {@link IVibratorStateListener} on change.
      */
     public boolean isVibrating() {
-        synchronized (mLock) {
-            return mIsVibrating;
-        }
+        return mIsVibrating;
     }
 
     /**
@@ -168,16 +167,12 @@
      * <p>If {@link #isVibrating()} is false then this will be zero.
      */
     public float getCurrentAmplitude() {
-        synchronized (mLock) {
-            return mCurrentAmplitude;
-        }
+        return mCurrentAmplitude;
     }
 
     /** Return {@code true} if this vibrator is under external control, false otherwise. */
     public boolean isUnderExternalControl() {
-        synchronized (mLock) {
-            return mIsUnderExternalControl;
-        }
+        return mIsUnderExternalControl;
     }
 
     /**
@@ -187,14 +182,14 @@
      * @return true if this vibrator has this capability, false otherwise
      */
     public boolean hasCapability(long capability) {
-        synchronized (mLock) {
-            return mVibratorInfo.hasCapability(capability);
-        }
+        return mVibratorInfo.hasCapability(capability);
     }
 
     /** Return {@code true} if the underlying vibrator is currently available, false otherwise. */
     public boolean isAvailable() {
-        return mNativeWrapper.isAvailable();
+        synchronized (mLock) {
+            return mNativeWrapper.isAvailable();
+        }
     }
 
     /**
@@ -203,10 +198,10 @@
      * <p>This will affect the state of {@link #isUnderExternalControl()}.
      */
     public void setExternalControl(boolean externalControl) {
+        if (!mVibratorInfo.hasCapability(IVibrator.CAP_EXTERNAL_CONTROL)) {
+            return;
+        }
         synchronized (mLock) {
-            if (!mVibratorInfo.hasCapability(IVibrator.CAP_EXTERNAL_CONTROL)) {
-                return;
-            }
             mIsUnderExternalControl = externalControl;
             mNativeWrapper.setExternalControl(externalControl);
         }
@@ -217,10 +212,10 @@
      * if given {@code effect} is {@code null}.
      */
     public void updateAlwaysOn(int id, @Nullable PrebakedSegment prebaked) {
+        if (!mVibratorInfo.hasCapability(IVibrator.CAP_ALWAYS_ON_CONTROL)) {
+            return;
+        }
         synchronized (mLock) {
-            if (!mVibratorInfo.hasCapability(IVibrator.CAP_ALWAYS_ON_CONTROL)) {
-                return;
-            }
             if (prebaked == null) {
                 mNativeWrapper.alwaysOnDisable(id);
             } else {
@@ -256,7 +251,7 @@
             long duration = mNativeWrapper.on(milliseconds, vibrationId);
             if (duration > 0) {
                 mCurrentAmplitude = -1;
-                notifyVibratorOnLocked();
+                notifyListenerOnVibrating(true);
             }
             return duration;
         }
@@ -277,7 +272,7 @@
                     prebaked.getEffectStrength(), vibrationId);
             if (duration > 0) {
                 mCurrentAmplitude = -1;
-                notifyVibratorOnLocked();
+                notifyListenerOnVibrating(true);
             }
             return duration;
         }
@@ -293,14 +288,14 @@
      * do not support the input or a negative number if the operation failed.
      */
     public long on(PrimitiveSegment[] primitives, long vibrationId) {
+        if (!mVibratorInfo.hasCapability(IVibrator.CAP_COMPOSE_EFFECTS)) {
+            return 0;
+        }
         synchronized (mLock) {
-            if (!mVibratorInfo.hasCapability(IVibrator.CAP_COMPOSE_EFFECTS)) {
-                return 0;
-            }
             long duration = mNativeWrapper.compose(primitives, vibrationId);
             if (duration > 0) {
                 mCurrentAmplitude = -1;
-                notifyVibratorOnLocked();
+                notifyListenerOnVibrating(true);
             }
             return duration;
         }
@@ -315,15 +310,15 @@
      * @return The duration of the effect playing, or 0 if unsupported.
      */
     public long on(RampSegment[] primitives, long vibrationId) {
+        if (!mVibratorInfo.hasCapability(IVibrator.CAP_COMPOSE_PWLE_EFFECTS)) {
+            return 0;
+        }
         synchronized (mLock) {
-            if (!mVibratorInfo.hasCapability(IVibrator.CAP_COMPOSE_PWLE_EFFECTS)) {
-                return 0;
-            }
             int braking = mVibratorInfo.getDefaultBraking();
             long duration = mNativeWrapper.composePwle(primitives, braking, vibrationId);
             if (duration > 0) {
                 mCurrentAmplitude = -1;
-                notifyVibratorOnLocked();
+                notifyListenerOnVibrating(true);
             }
             return duration;
         }
@@ -334,7 +329,7 @@
         synchronized (mLock) {
             mNativeWrapper.off();
             mCurrentAmplitude = 0;
-            notifyVibratorOffLocked();
+            notifyListenerOnVibrating(false);
         }
     }
 
@@ -349,51 +344,31 @@
 
     @Override
     public String toString() {
-        synchronized (mLock) {
-            return "VibratorController{"
-                    + "mVibratorInfo=" + mVibratorInfo
-                    + ", mVibratorInfoLoadSuccessful=" + mVibratorInfoLoadSuccessful
-                    + ", mIsVibrating=" + mIsVibrating
-                    + ", mCurrentAmplitude=" + mCurrentAmplitude
-                    + ", mIsUnderExternalControl=" + mIsUnderExternalControl
-                    + ", mVibratorStateListeners count="
-                    + mVibratorStateListeners.getRegisteredCallbackCount()
-                    + '}';
-        }
+        return "VibratorController{"
+                + "mVibratorInfo=" + mVibratorInfo
+                + ", mVibratorInfoLoadSuccessful=" + mVibratorInfoLoadSuccessful
+                + ", mIsVibrating=" + mIsVibrating
+                + ", mCurrentAmplitude=" + mCurrentAmplitude
+                + ", mIsUnderExternalControl=" + mIsUnderExternalControl
+                + ", mVibratorStateListeners count="
+                + mVibratorStateListeners.getRegisteredCallbackCount()
+                + '}';
     }
 
     @GuardedBy("mLock")
-    private void notifyVibratorOnLocked() {
-        if (!mIsVibrating) {
-            mIsVibrating = true;
-            notifyStateListenersLocked();
+    private void notifyListenerOnVibrating(boolean isVibrating) {
+        if (mIsVibrating != isVibrating) {
+            mIsVibrating = isVibrating;
+            // The broadcast method is safe w.r.t. register/unregister listener methods, but lock
+            // is required here to guarantee delivery order.
+            mVibratorStateListeners.broadcast(
+                    listener -> notifyStateListener(listener, isVibrating));
         }
     }
 
-    @GuardedBy("mLock")
-    private void notifyVibratorOffLocked() {
-        if (mIsVibrating) {
-            mIsVibrating = false;
-            notifyStateListenersLocked();
-        }
-    }
-
-    @GuardedBy("mLock")
-    private void notifyStateListenersLocked() {
-        final int length = mVibratorStateListeners.beginBroadcast();
+    private void notifyStateListener(IVibratorStateListener listener, boolean isVibrating) {
         try {
-            for (int i = 0; i < length; i++) {
-                notifyStateListenerLocked(mVibratorStateListeners.getBroadcastItem(i));
-            }
-        } finally {
-            mVibratorStateListeners.finishBroadcast();
-        }
-    }
-
-    @GuardedBy("mLock")
-    private void notifyStateListenerLocked(IVibratorStateListener listener) {
-        try {
-            listener.onVibrating(mIsVibrating);
+            listener.onVibrating(isVibrating);
         } catch (RemoteException | RuntimeException e) {
             Slog.e(TAG, "Vibrator state listener failed to call", e);
         }
diff --git a/services/core/java/com/android/server/vibrator/VibratorManagerService.java b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
index 3a3ce5b..5d40c23 100644
--- a/services/core/java/com/android/server/vibrator/VibratorManagerService.java
+++ b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
@@ -229,7 +229,7 @@
 
         IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_SCREEN_OFF);
-        context.registerReceiver(mIntentReceiver, filter);
+        context.registerReceiver(mIntentReceiver, filter, Context.RECEIVER_NOT_EXPORTED);
 
         injector.addService(EXTERNAL_VIBRATOR_SERVICE, new ExternalVibratorService());
     }
@@ -391,6 +391,9 @@
             fillVibrationFallbacks(vib, effect);
 
             synchronized (mLock) {
+                if (DEBUG) {
+                    Slog.d(TAG, "Starting vibrate for vibration  " + vib.id);
+                }
                 Vibration.Status ignoreStatus = shouldIgnoreVibrationLocked(vib);
                 if (ignoreStatus != null) {
                     endVibrationLocked(vib, ignoreStatus);
@@ -498,6 +501,9 @@
     @VisibleForTesting
     void updateServiceState() {
         synchronized (mLock) {
+            if (DEBUG) {
+                Slog.d(TAG, "Updating device state...");
+            }
             boolean inputDevicesChanged = mInputDeviceDelegate.updateInputDeviceVibrators(
                     mVibrationSettings.shouldVibrateInputDevices());
 
@@ -611,6 +617,9 @@
         Trace.asyncTraceEnd(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
         try {
             Vibration vib = mCurrentVibration.getVibration();
+            if (DEBUG) {
+                Slog.d(TAG, "Reporting vibration " + vib.id + " finished with status " + status);
+            }
             endVibrationLocked(vib, status);
             finishAppOpModeLocked(vib.uid, vib.opPkg);
         } finally {
@@ -1062,11 +1071,17 @@
                 Slog.d(TAG, "Vibrators released after finished vibration");
             }
             synchronized (mLock) {
+                if (DEBUG) {
+                    Slog.d(TAG, "Processing vibrators released callback");
+                }
                 mCurrentVibration = null;
                 if (mNextVibration != null) {
                     VibrationThread vibThread = mNextVibration;
                     mNextVibration = null;
-                    startVibrationThreadLocked(vibThread);
+                    Vibration.Status status = startVibrationThreadLocked(vibThread);
+                    if (status != Vibration.Status.RUNNING) {
+                        endVibrationLocked(vibThread.getVibration(), status);
+                    }
                 }
             }
         }
@@ -1248,6 +1263,9 @@
         void dumpText(PrintWriter pw) {
             pw.println("Vibrator Manager Service:");
             synchronized (mLock) {
+                if (DEBUG) {
+                    Slog.d(TAG, "Dumping vibrator manager service to text...");
+                }
                 pw.println("  mVibrationSettings:");
                 pw.println("    " + mVibrationSettings);
                 pw.println();
@@ -1290,6 +1308,9 @@
             final ProtoOutputStream proto = new ProtoOutputStream(fd);
 
             synchronized (mLock) {
+                if (DEBUG) {
+                    Slog.d(TAG, "Dumping vibrator manager service to proto...");
+                }
                 mVibrationSettings.dumpProto(proto);
                 if (mCurrentVibration != null) {
                     mCurrentVibration.getVibration().getDebugInfo().dumpProto(proto,
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 5b062fc..2a1bb0b 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -5971,10 +5971,11 @@
         // because it may be a trampoline.
         if (!wasTaskVisible && mStartingData != null && !finishing && !mLaunchedFromBubble
                 && !mDisplayContent.mAppTransition.isReady()
-                && !mDisplayContent.mAppTransition.isRunning()) {
+                && !mDisplayContent.mAppTransition.isRunning()
+                && mDisplayContent.isNextTransitionForward()) {
             // The pending transition state will be cleared after the transition is started, so
             // save the state for launching the client later (used by LaunchActivityItem).
-            mStartingData.mIsTransitionForward = mDisplayContent.isNextTransitionForward();
+            mStartingData.mIsTransitionForward = true;
             mDisplayContent.executeAppTransition();
         }
     }
@@ -6223,15 +6224,15 @@
     public boolean inputDispatchingTimedOut(String reason, int windowPid) {
         ActivityRecord anrActivity;
         WindowProcessController anrApp;
-        boolean windowFromSameProcessAsActivity;
+        boolean blameActivityProcess;
         synchronized (mAtmService.mGlobalLock) {
             anrActivity = getWaitingHistoryRecordLocked();
             anrApp = app;
-            windowFromSameProcessAsActivity =
-                    !hasProcess() || app.getPid() == windowPid || windowPid == INVALID_PID;
+            blameActivityProcess =  hasProcess()
+                    && (app.getPid() == windowPid || windowPid == INVALID_PID);
         }
 
-        if (windowFromSameProcessAsActivity) {
+        if (blameActivityProcess) {
             return mAtmService.mAmInternal.inputDispatchingTimedOut(anrApp.mOwner,
                     anrActivity.shortComponentName, anrActivity.info.applicationInfo,
                     shortComponentName, app, false, reason);
diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java
index 210b0ae..ecc8587 100644
--- a/services/core/java/com/android/server/wm/ActivityStartController.java
+++ b/services/core/java/com/android/server/wm/ActivityStartController.java
@@ -496,11 +496,13 @@
      * @param activityIntent intent to start the activity.
      * @param activityOptions ActivityOptions to start the activity with.
      * @param resultTo the caller activity
+     * @param callingUid the caller uid
+     * @param callingPid the caller pid
      * @return the start result.
      */
     int startActivityInTaskFragment(@NonNull TaskFragment taskFragment,
             @NonNull Intent activityIntent, @Nullable Bundle activityOptions,
-            @Nullable IBinder resultTo) {
+            @Nullable IBinder resultTo, int callingUid, int callingPid) {
         final ActivityRecord caller =
                 resultTo != null ? ActivityRecord.forTokenLocked(resultTo) : null;
         return obtainStarter(activityIntent, "startActivityInTaskFragment")
@@ -508,8 +510,8 @@
                 .setInTaskFragment(taskFragment)
                 .setResultTo(resultTo)
                 .setRequestCode(-1)
-                .setCallingUid(Binder.getCallingUid())
-                .setCallingPid(Binder.getCallingPid())
+                .setCallingUid(callingUid)
+                .setCallingPid(callingPid)
                 .setUserId(caller != null ? caller.mUserId : mService.getCurrentUserId())
                 .execute();
     }
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index f947773..8788225 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -65,7 +65,10 @@
 import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_SPLASH_SCREEN;
 import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_WINDOWS_DRAWN;
 import static com.android.server.wm.AppTransition.isNormalTransit;
+import static com.android.server.wm.NonAppWindowAnimationAdapter.shouldAttachNavBarToApp;
+import static com.android.server.wm.NonAppWindowAnimationAdapter.shouldStartNonAppWindowAnimationsForKeyguardExit;
 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION;
+import static com.android.server.wm.WallpaperAnimationAdapter.shouldStartWallpaperAnimation;
 import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -529,18 +532,9 @@
         // Having {@code transit} of those types doesn't mean it will contain non-app windows, but
         // non-app windows will only be included with those transition types. And we don't currently
         // have any use case of those for TaskFragment transition.
-        // @see NonAppWindowAnimationAdapter#startNonAppWindowAnimations
-        if (transit == TRANSIT_OLD_KEYGUARD_GOING_AWAY
-                || transit == TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER
-                || transit == TRANSIT_OLD_TASK_OPEN || transit == TRANSIT_OLD_TASK_TO_FRONT
-                || transit == TRANSIT_OLD_WALLPAPER_CLOSE) {
-            return true;
-        }
-
-        // Check if the wallpaper is going to participate in the transition. We don't want to have
-        // the client to animate the wallpaper windows.
-        // @see WallpaperAnimationAdapter#startWallpaperAnimations
-        return mDisplayContent.mWallpaperController.isWallpaperVisible();
+        return shouldStartNonAppWindowAnimationsForKeyguardExit(transit)
+                || shouldAttachNavBarToApp(mService, mDisplayContent, transit)
+                || shouldStartWallpaperAnimation(mDisplayContent);
     }
 
     /**
@@ -596,7 +590,7 @@
             }
             // We don't want the organizer to handle transition of non-embedded activity of other
             // app.
-            if (r.getUid() != rootActivity.getUid() && !r.isEmbedded()) {
+            if (r.getUid() != task.effectiveUid && !r.isEmbedded()) {
                 leafTask = null;
                 break;
             }
diff --git a/services/core/java/com/android/server/wm/DisplayArea.java b/services/core/java/com/android/server/wm/DisplayArea.java
index 63fb793..132396b 100644
--- a/services/core/java/com/android/server/wm/DisplayArea.java
+++ b/services/core/java/com/android/server/wm/DisplayArea.java
@@ -586,7 +586,11 @@
         };
 
         Tokens(WindowManagerService wms, Type type, String name) {
-            super(wms, type, name, FEATURE_WINDOW_TOKENS);
+            this(wms, type, name, FEATURE_WINDOW_TOKENS);
+        }
+
+        Tokens(WindowManagerService wms, Type type, String name, int featureId) {
+            super(wms, type, name, featureId);
         }
 
         void addChild(WindowToken token) {
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 4cb70fd..55acfb6 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -78,6 +78,7 @@
 import static android.view.WindowManager.TRANSIT_CHANGE;
 import static android.view.WindowManager.TRANSIT_OPEN;
 import static android.view.WindowManager.TRANSIT_TO_FRONT;
+import static android.window.DisplayAreaOrganizer.FEATURE_IME;
 import static android.window.DisplayAreaOrganizer.FEATURE_ROOT;
 import static android.window.DisplayAreaOrganizer.FEATURE_WINDOWED_MAGNIFICATION;
 
@@ -217,6 +218,7 @@
 import android.view.WindowManager;
 import android.view.WindowManager.DisplayImePolicy;
 import android.view.WindowManagerPolicyConstants.PointerEventListener;
+import android.window.DisplayWindowPolicyController;
 import android.window.IDisplayAreaOrganizer;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -632,7 +634,8 @@
     @interface InputMethodTarget {}
 
     /** The surface parent of the IME container. */
-    private SurfaceControl mInputMethodSurfaceParent;
+    @VisibleForTesting
+    SurfaceControl mInputMethodSurfaceParent;
 
     /** The screenshot IME surface to place on the task while transitioning to the next task. */
     SurfaceControl mImeScreenshot;
@@ -694,6 +697,14 @@
     // well and thus won't change the top resumed / focused record
     boolean mDontMoveToTop;
 
+    /**
+     * The policy controller of the windows that can be displayed on the virtual display.
+     *
+     * @see DisplayWindowPolicyController
+     */
+    @Nullable
+    DisplayWindowPolicyController mDisplayWindowPolicyController;
+
     private final Consumer<WindowState> mUpdateWindowsForAnimator = w -> {
         WindowStateAnimator winAnimator = w.mWinAnimator;
         final ActivityRecord activity = w.mActivityRecord;
@@ -2737,6 +2748,9 @@
             if (newDisplayInfo != null) {
                 mDisplayInfo.copyFrom(newDisplayInfo);
             }
+
+            mDisplayWindowPolicyController =
+                    displayManagerInternal.getDisplayWindowPolicyController(mDisplayId);
         }
 
         updateBaseDisplayMetrics(mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight,
@@ -3418,6 +3432,10 @@
         mInputMonitor.dump(pw, "  ");
         pw.println();
         mInsetsStateController.dump(prefix, pw);
+        if (mDisplayWindowPolicyController != null) {
+            pw.println();
+            mDisplayWindowPolicyController.dump(prefix, pw);
+        }
     }
 
     @Override
@@ -3831,6 +3849,10 @@
     }
 
     boolean shouldImeAttachedToApp() {
+        if (mImeWindowsContainer.isOrganized()) {
+            return false;
+        }
+
         // Force attaching IME to the display when magnifying, or it would be magnified with
         // target app together.
         final boolean allowAttachToApp = (mMagnificationSpec == null);
@@ -3959,8 +3981,9 @@
         mImeLayeringTarget = target;
 
         // 1. Reparent the IME container window to the target root DA to get the correct bounds and
-        // config. (Only happens when the target window is in a different root DA)
-        if (target != null) {
+        // config. Only happens when the target window is in a different root DA and ImeContainer
+        // is not organized (see FEATURE_IME and updateImeParent).
+        if (target != null && !mImeWindowsContainer.isOrganized()) {
             RootDisplayArea targetRoot = target.getRootDisplayArea();
             if (targetRoot != null && targetRoot != mImeWindowsContainer.getRootDisplayArea()) {
                 // Reposition the IME container to the target root to get the correct bounds and
@@ -4144,6 +4167,16 @@
     }
 
     void updateImeParent() {
+        if (mImeWindowsContainer.isOrganized()) {
+            if (DEBUG_INPUT_METHOD) {
+                Slog.i(TAG_WM, "ImeContainer is organized. Skip updateImeParent.");
+            }
+            // Leave the ImeContainer where the DisplayAreaPolicy placed it.
+            // FEATURE_IME is organized by vendor so they are responible for placing the surface.
+            mInputMethodSurfaceParent = null;
+            return;
+        }
+
         final SurfaceControl newParent = computeImeParent();
         if (newParent != null && newParent != mInputMethodSurfaceParent) {
             mInputMethodSurfaceParent = newParent;
@@ -4750,7 +4783,7 @@
         boolean mNeedsLayer = false;
 
         ImeContainer(WindowManagerService wms) {
-            super(wms, Type.ABOVE_TASKS, "ImeContainer");
+            super(wms, Type.ABOVE_TASKS, "ImeContainer", FEATURE_IME);
         }
 
         public void setNeedsLayer() {
@@ -4811,6 +4844,12 @@
             super.assignRelativeLayer(t, relativeTo, layer, forceUpdate);
             mNeedsLayer = false;
         }
+
+        @Override
+        void setOrganizer(IDisplayAreaOrganizer organizer, boolean skipDisplayAreaAppeared) {
+            super.setOrganizer(organizer, skipDisplayAreaAppeared);
+            mDisplayContent.updateImeParent();
+        }
     }
 
     @Override
@@ -4909,6 +4948,15 @@
     }
 
     private void assignRelativeLayerForIme(SurfaceControl.Transaction t, boolean forceUpdate) {
+        if (mImeWindowsContainer.isOrganized()) {
+            if (DEBUG_INPUT_METHOD) {
+                Slog.i(TAG_WM, "ImeContainer is organized. Skip assignRelativeLayerForIme.");
+            }
+            // Leave the ImeContainer where the DisplayAreaPolicy placed it.
+            // When using FEATURE_IME, Organizer assumes the responsibility for placing the surface.
+            return;
+        }
+
         mImeWindowsContainer.setNeedsLayer();
         final WindowState imeTarget = mImeLayeringTarget;
         // In the case where we have an IME target that is not in split-screen mode IME
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index a492b7a..09de6b3 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -1577,7 +1577,7 @@
         applyKeyguardPolicy(win, imeTarget);
 
         // Check if the freeform window overlaps with the navigation bar area.
-        final boolean isOverlappingWithNavBar = isOverlappingWithNavBar(win, mNavigationBar);
+        final boolean isOverlappingWithNavBar = isOverlappingWithNavBar(win);
         if (isOverlappingWithNavBar && !mIsFreeformWindowOverlappingWithNavBar
                 && win.inFreeformWindowingMode()) {
             mIsFreeformWindowOverlappingWithNavBar = true;
@@ -2343,7 +2343,7 @@
     private int getStatusBarAppearance(WindowState opaque, WindowState opaqueOrDimming) {
         final boolean onKeyguard = isKeyguardShowing() && !isKeyguardOccluded();
         final WindowState colorWin = onKeyguard ? mNotificationShade : opaqueOrDimming;
-        return isLightBarAllowed(colorWin, ITYPE_STATUS_BAR) && (colorWin == opaque || onKeyguard)
+        return isLightBarAllowed(colorWin, Type.statusBars()) && (colorWin == opaque || onKeyguard)
                 ? (colorWin.mAttrs.insetsFlags.appearance & APPEARANCE_LIGHT_STATUS_BARS)
                 : 0;
     }
@@ -2391,7 +2391,7 @@
     @VisibleForTesting
     int updateLightNavigationBarLw(int appearance, WindowState navColorWin) {
         if (navColorWin == null || navColorWin.isDimming()
-                || !isLightBarAllowed(navColorWin, ITYPE_NAVIGATION_BAR)) {
+                || !isLightBarAllowed(navColorWin, Type.navigationBars())) {
             // Clear the light flag while not allowed.
             appearance &= ~APPEARANCE_LIGHT_NAVIGATION_BARS;
             return appearance;
@@ -2456,12 +2456,11 @@
         return appearance;
     }
 
-    private boolean isLightBarAllowed(WindowState win, @InternalInsetsType int type) {
+    private static boolean isLightBarAllowed(WindowState win, @InsetsType int type) {
         if (win == null) {
             return false;
         }
-        final InsetsSource source = win.getInsetsState().peekSource(type);
-        return source != null && Rect.intersects(win.getFrame(), source.getFrame());
+        return intersectsAnyInsets(win.getFrame(), win.getInsetsState(), type);
     }
 
     private Rect getBarContentFrameForWindow(WindowState win, @InternalInsetsType int type) {
@@ -2838,17 +2837,34 @@
     }
 
     @VisibleForTesting
-    static boolean isOverlappingWithNavBar(@NonNull WindowState targetWindow,
-            WindowState navBarWindow) {
-        if (navBarWindow == null || !navBarWindow.isVisible()
-                || targetWindow.mActivityRecord == null || !targetWindow.isVisible()) {
+    static boolean isOverlappingWithNavBar(@NonNull WindowState win) {
+        if (win.mActivityRecord == null || !win.isVisible()) {
             return false;
         }
 
         // When the window is dimming means it's requesting dim layer to its host container, so
-        // checking whether it's overlapping with navigation bar by its container's bounds.
-        return Rect.intersects(targetWindow.isDimming()
-                ? targetWindow.getBounds() : targetWindow.getFrame(), navBarWindow.getFrame());
+        // checking whether it's overlapping with a navigation bar by its container's bounds.
+        return intersectsAnyInsets(win.isDimming() ? win.getBounds() : win.getFrame(),
+                win.getInsetsState(), Type.navigationBars());
+    }
+
+    /**
+     * Returns whether the given {@param bounds} intersects with any insets of the
+     * provided {@param insetsType}.
+     */
+    private static boolean intersectsAnyInsets(Rect bounds, InsetsState insetsState,
+            @InsetsType int insetsType) {
+        final ArraySet<Integer> internalTypes = InsetsState.toInternalType(insetsType);
+        for (int i = 0; i < internalTypes.size(); i++) {
+            final InsetsSource source = insetsState.peekSource(internalTypes.valueAt(i));
+            if (source == null || !source.isVisible()) {
+                continue;
+            }
+            if (Rect.intersects(bounds, source.getFrame())) {
+                return true;
+            }
+        }
+        return false;
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java b/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
index badb1f5..963f326 100644
--- a/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
+++ b/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
@@ -139,9 +139,6 @@
                 setActivityVisibilityState(child.asActivityRecord(), starting, resumeTopActivity);
             }
         }
-        if (mTaskFragment.mTransitionController.isShellTransitionsEnabled()) {
-            mTaskFragment.getDisplayContent().mWallpaperController.adjustWallpaperWindows();
-        }
     }
 
     private void setActivityVisibilityState(ActivityRecord r, ActivityRecord starting,
diff --git a/services/core/java/com/android/server/wm/NonAppWindowAnimationAdapter.java b/services/core/java/com/android/server/wm/NonAppWindowAnimationAdapter.java
index 9f28509..7c35a21 100644
--- a/services/core/java/com/android/server/wm/NonAppWindowAnimationAdapter.java
+++ b/services/core/java/com/android/server/wm/NonAppWindowAnimationAdapter.java
@@ -69,25 +69,32 @@
             long durationHint, long statusBarTransitionDelay,
             ArrayList<NonAppWindowAnimationAdapter> adaptersOut) {
         final ArrayList<RemoteAnimationTarget> targets = new ArrayList<>();
-        if (transit == TRANSIT_OLD_KEYGUARD_GOING_AWAY
-                || transit == TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER) {
+        if (shouldStartNonAppWindowAnimationsForKeyguardExit(transit)) {
             startNonAppWindowAnimationsForKeyguardExit(
                     service, durationHint, statusBarTransitionDelay, targets, adaptersOut);
-        } else if (transit == TRANSIT_OLD_TASK_OPEN || transit == TRANSIT_OLD_TASK_TO_FRONT
-                || transit == TRANSIT_OLD_WALLPAPER_CLOSE) {
-            final boolean shouldAttachNavBarToApp =
-                    displayContent.getDisplayPolicy().shouldAttachNavBarToAppDuringTransition()
-                            && service.getRecentsAnimationController() == null
-                            && displayContent.getFadeRotationAnimationController() == null;
-            if (shouldAttachNavBarToApp) {
-                startNavigationBarWindowAnimation(
-                        displayContent, durationHint, statusBarTransitionDelay, targets,
-                        adaptersOut);
-            }
+        } else if (shouldAttachNavBarToApp(service, displayContent, transit)) {
+            startNavigationBarWindowAnimation(
+                    displayContent, durationHint, statusBarTransitionDelay, targets,
+                    adaptersOut);
         }
         return targets.toArray(new RemoteAnimationTarget[targets.size()]);
     }
 
+    static boolean shouldStartNonAppWindowAnimationsForKeyguardExit(
+            @WindowManager.TransitionOldType int transit) {
+        return transit == TRANSIT_OLD_KEYGUARD_GOING_AWAY
+                || transit == TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
+    }
+
+    static boolean shouldAttachNavBarToApp(WindowManagerService service,
+            DisplayContent displayContent, @WindowManager.TransitionOldType int transit) {
+        return (transit == TRANSIT_OLD_TASK_OPEN || transit == TRANSIT_OLD_TASK_TO_FRONT
+                || transit == TRANSIT_OLD_WALLPAPER_CLOSE)
+                && displayContent.getDisplayPolicy().shouldAttachNavBarToAppDuringTransition()
+                && service.getRecentsAnimationController() == null
+                && displayContent.getFadeRotationAnimationController() == null;
+    }
+
     /**
      * Creates and starts remote animations for all the visible non app windows.
      *
diff --git a/services/core/java/com/android/server/wm/PackageConfigPersister.java b/services/core/java/com/android/server/wm/PackageConfigPersister.java
index 3de98f1..7a7fb65 100644
--- a/services/core/java/com/android/server/wm/PackageConfigPersister.java
+++ b/services/core/java/com/android/server/wm/PackageConfigPersister.java
@@ -169,21 +169,35 @@
         }
     }
 
+    /**
+     * Returns true when the app specific configuration is successfully stored or removed based on
+     * the current requested configuration. It will return false when the requested
+     * configuration is same as the pre-existing app-specific configuration.
+     */
     @GuardedBy("mLock")
     boolean updateFromImpl(String packageName, int userId,
             PackageConfigurationUpdaterImpl impl) {
         synchronized (mLock) {
-            PackageConfigRecord record = findRecordOrCreate(mModified, packageName, userId);
-            if (impl.getNightMode() != null) {
-                record.mNightMode = impl.getNightMode();
+            boolean isRecordPresent = false;
+            PackageConfigRecord record = findRecord(mModified, packageName, userId);
+            if (record != null) {
+                isRecordPresent = true;
+            } else {
+                record = findRecordOrCreate(mModified, packageName, userId);
             }
-            if (impl.getLocales() != null) {
-                record.mLocales = impl.getLocales();
-            }
+            boolean isNightModeChanged = updateNightMode(impl.getNightMode(), record);
+            boolean isLocalesChanged = updateLocales(impl.getLocales(), record);
+
             if ((record.mNightMode == null || record.isResetNightMode())
                     && (record.mLocales == null || record.mLocales.isEmpty())) {
                 // if all values default to system settings, we can remove the package.
                 removePackage(packageName, userId);
+                // if there was a pre-existing record for the package that was deleted,
+                // we return true (since it was successfully deleted), else false (since there was
+                // no change to the previous state).
+                return isRecordPresent;
+            } else if (!isNightModeChanged && !isLocalesChanged) {
+                return false;
             } else {
                 final PackageConfigRecord pendingRecord =
                         findRecord(mPendingWrite, record.mName, record.mUserId);
@@ -195,7 +209,8 @@
                     writeRecord = pendingRecord;
                 }
 
-                if (!updateNightMode(record, writeRecord) && !updateLocales(record, writeRecord)) {
+                if (!updateNightMode(record.mNightMode, writeRecord)
+                        && !updateLocales(record.mLocales, writeRecord)) {
                     return false;
                 }
 
@@ -203,24 +218,24 @@
                     Slog.d(TAG, "PackageConfigUpdater save config " + writeRecord);
                 }
                 mPersisterQueue.addItem(new WriteProcessItem(writeRecord), false /* flush */);
+                return true;
             }
-            return true;
         }
     }
 
-    private boolean updateNightMode(PackageConfigRecord record, PackageConfigRecord writeRecord) {
-        if (record.mNightMode == null || record.mNightMode.equals(writeRecord.mNightMode)) {
+    private boolean updateNightMode(Integer requestedNightMode, PackageConfigRecord record) {
+        if (requestedNightMode == null || requestedNightMode.equals(record.mNightMode)) {
             return false;
         }
-        writeRecord.mNightMode = record.mNightMode;
+        record.mNightMode = requestedNightMode;
         return true;
     }
 
-    private boolean updateLocales(PackageConfigRecord record, PackageConfigRecord writeRecord) {
-        if (record.mLocales == null || record.mLocales.equals(writeRecord.mLocales)) {
+    private boolean updateLocales(LocaleList requestedLocaleList, PackageConfigRecord record) {
+        if (requestedLocaleList == null || requestedLocaleList.equals(record.mLocales)) {
             return false;
         }
-        writeRecord.mLocales = record.mLocales;
+        record.mLocales = requestedLocaleList;
         return true;
     }
 
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 0eaa25b..929f221 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -1413,29 +1413,29 @@
 
         boolean pauseImmediately = false;
         boolean shouldAutoPip = false;
-        if (resuming != null && (resuming.info.flags & FLAG_RESUME_WHILE_PAUSING) != 0) {
-            // If the flag RESUME_WHILE_PAUSING is set, then continue to schedule the previous
-            // activity to be paused, while at the same time resuming the new resume activity
-            // only if the previous activity can't go into Pip since we want to give Pip
-            // activities a chance to enter Pip before resuming the next activity.
-            final boolean lastResumedCanPip = prev != null && prev.checkEnterPictureInPictureState(
-                    "shouldResumeWhilePausing", userLeaving);
+        if (resuming != null) {
+            // Resuming the new resume activity only if the previous activity can't go into Pip
+            // since we want to give Pip activities a chance to enter Pip before resuming the
+            // next activity.
+            final boolean lastResumedCanPip = prev.checkEnterPictureInPictureState(
+                    "shouldAutoPipWhilePausing", userLeaving);
             if (lastResumedCanPip && prev.pictureInPictureArgs.isAutoEnterEnabled()) {
                 shouldAutoPip = true;
             } else if (!lastResumedCanPip) {
-                pauseImmediately = true;
+                // If the flag RESUME_WHILE_PAUSING is set, then continue to schedule the previous
+                // activity to be paused.
+                pauseImmediately = (resuming.info.flags & FLAG_RESUME_WHILE_PAUSING) != 0;
             } else {
                 // The previous activity may still enter PIP even though it did not allow auto-PIP.
             }
         }
 
-        boolean didAutoPip = false;
         if (prev.attachedToProcess()) {
             if (shouldAutoPip) {
+                boolean didAutoPip = mAtmService.enterPictureInPictureMode(
+                        prev, prev.pictureInPictureArgs);
                 ProtoLog.d(WM_DEBUG_STATES, "Auto-PIP allowed, entering PIP mode "
-                        + "directly: %s", prev);
-
-                didAutoPip = mAtmService.enterPictureInPictureMode(prev, prev.pictureInPictureArgs);
+                        + "directly: %s, didAutoPip: %b", prev, didAutoPip);
             } else {
                 schedulePauseActivity(prev, userLeaving, pauseImmediately, reason);
             }
diff --git a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
index d911656..29c27f9 100644
--- a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
@@ -31,10 +31,8 @@
 import android.util.ArrayMap;
 import android.util.Slog;
 import android.view.RemoteAnimationDefinition;
-import android.view.SurfaceControl;
 import android.window.ITaskFragmentOrganizer;
 import android.window.ITaskFragmentOrganizerController;
-import android.window.TaskFragmentAppearedInfo;
 import android.window.TaskFragmentInfo;
 
 import com.android.internal.protolog.common.ProtoLog;
@@ -135,11 +133,8 @@
         void onTaskFragmentAppeared(ITaskFragmentOrganizer organizer, TaskFragment tf) {
             ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "TaskFragment appeared name=%s", tf.getName());
             final TaskFragmentInfo info = tf.getTaskFragmentInfo();
-            final SurfaceControl outSurfaceControl = new SurfaceControl(tf.getSurfaceControl(),
-                    "TaskFragmentOrganizerController.onTaskFragmentInfoAppeared");
             try {
-                organizer.onTaskFragmentAppeared(
-                        new TaskFragmentAppearedInfo(info, outSurfaceControl));
+                organizer.onTaskFragmentAppeared(info);
                 mLastSentTaskFragmentInfos.put(tf, info);
                 tf.mTaskFragmentAppearedSent = true;
             } catch (RemoteException e) {
@@ -434,6 +429,9 @@
         private final TaskFragment mTaskFragment;
         private final IBinder mErrorCallback;
         private final Throwable mException;
+        // Set when the event is deferred due to the host task is invisible. The defer time will
+        // be the last active time of the host task.
+        private long mDeferTime;
 
         private PendingTaskFragmentEvent(TaskFragment taskFragment,
                 ITaskFragmentOrganizer taskFragmentOrg, @EventType int eventType) {
@@ -503,11 +501,45 @@
                 || mPendingTaskFragmentEvents.isEmpty()) {
             return;
         }
+
+        final ArrayList<Task> visibleTasks = new ArrayList<>();
+        final ArrayList<Task> invisibleTasks = new ArrayList<>();
+        final ArrayList<PendingTaskFragmentEvent> candidateEvents = new ArrayList<>();
         for (int i = 0, n = mPendingTaskFragmentEvents.size(); i < n; i++) {
-            PendingTaskFragmentEvent event = mPendingTaskFragmentEvents.get(i);
-            dispatchEvent(event);
+            final PendingTaskFragmentEvent event = mPendingTaskFragmentEvents.get(i);
+            final Task task = event.mTaskFragment != null ? event.mTaskFragment.getTask() : null;
+            if (task != null && (task.lastActiveTime <= event.mDeferTime
+                    || !isTaskVisible(task, visibleTasks, invisibleTasks))) {
+                // Defer sending events to the TaskFragment until the host task is active again.
+                event.mDeferTime = task.lastActiveTime;
+                continue;
+            }
+            candidateEvents.add(event);
         }
-        mPendingTaskFragmentEvents.clear();
+        final int numEvents = candidateEvents.size();
+        for (int i = 0; i < numEvents; i++) {
+            dispatchEvent(candidateEvents.get(i));
+        }
+        if (numEvents > 0) {
+            mPendingTaskFragmentEvents.removeAll(candidateEvents);
+        }
+    }
+
+    private static boolean isTaskVisible(Task task, ArrayList<Task> knownVisibleTasks,
+            ArrayList<Task> knownInvisibleTasks) {
+        if (knownVisibleTasks.contains(task)) {
+            return true;
+        }
+        if (knownInvisibleTasks.contains(task)) {
+            return false;
+        }
+        if (task.shouldBeVisible(null /* starting */)) {
+            knownVisibleTasks.add(task);
+            return true;
+        } else {
+            knownInvisibleTasks.add(task);
+            return false;
+        }
     }
 
     void dispatchPendingInfoChangedEvent(TaskFragment taskFragment) {
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index f175eec..7349594 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -244,11 +244,11 @@
         }
         mParticipants.add(wc);
         if (info.mShowWallpaper) {
-            // Collect the wallpaper so it is part of the sync set.
-            final WindowContainer wallpaper =
+            // Collect the wallpaper token (for isWallpaper(wc)) so it is part of the sync set.
+            final WindowState wallpaper =
                     wc.getDisplayContent().mWallpaperController.getTopVisibleWallpaper();
             if (wallpaper != null) {
-                collect(wallpaper);
+                collect(wallpaper.mToken);
             }
         }
     }
@@ -495,25 +495,35 @@
             Slog.e(TAG, "Unexpected Sync ID " + syncId + ". Expected " + mSyncId);
             return;
         }
-        int displayId = DEFAULT_DISPLAY;
-        for (WindowContainer container : mParticipants) {
-            if (container.mDisplayContent == null) continue;
-            displayId = container.mDisplayContent.getDisplayId();
+        boolean hasWallpaper = false;
+        DisplayContent dc = null;
+        for (int i = mParticipants.size() - 1; i >= 0; --i) {
+            final WindowContainer<?> wc = mParticipants.valueAt(i);
+            if (dc == null && wc.mDisplayContent != null) {
+                dc = wc.mDisplayContent;
+            }
+            if (!hasWallpaper && isWallpaper(wc)) {
+                hasWallpaper = true;
+            }
         }
+        if (dc == null) dc = mController.mAtm.mRootWindowContainer.getDefaultDisplay();
 
         if (mState == STATE_ABORT) {
             mController.abort(this);
-            mController.mAtm.mRootWindowContainer.getDisplayContent(displayId)
-                    .getPendingTransaction().merge(transaction);
+            dc.getPendingTransaction().merge(transaction);
             mSyncId = -1;
             mOverrideOptions = null;
             return;
         }
+        // Ensure that wallpaper visibility is updated with the latest wallpaper target.
+        if (hasWallpaper) {
+            dc.mWallpaperController.adjustWallpaperWindows();
+        }
 
         mState = STATE_PLAYING;
         mController.moveToPlaying(this);
 
-        if (mController.mAtm.mTaskSupervisor.getKeyguardController().isKeyguardLocked(displayId)) {
+        if (dc.isKeyguardLocked()) {
             mFlags |= TRANSIT_FLAG_KEYGUARD_LOCKED;
         }
 
@@ -523,9 +533,9 @@
         info.setAnimationOptions(mOverrideOptions);
 
         // TODO(b/188669821): Move to animation impl in shell.
-        handleLegacyRecentsStartBehavior(displayId, info);
+        handleLegacyRecentsStartBehavior(dc, info);
 
-        handleNonAppWindowsInTransition(displayId, mType, mFlags);
+        handleNonAppWindowsInTransition(dc, mType, mFlags);
 
         reportStartReasonsToLogger();
 
@@ -627,14 +637,11 @@
     }
 
     /** @see RecentsAnimationController#attachNavigationBarToApp */
-    private void handleLegacyRecentsStartBehavior(int displayId, TransitionInfo info) {
+    private void handleLegacyRecentsStartBehavior(DisplayContent dc, TransitionInfo info) {
         if ((mFlags & TRANSIT_FLAG_IS_RECENTS) == 0) {
             return;
         }
-        final DisplayContent dc =
-                mController.mAtm.mRootWindowContainer.getDisplayContent(displayId);
-        if (dc == null) return;
-        mRecentsDisplayId = displayId;
+        mRecentsDisplayId = dc.mDisplayId;
 
         // Recents has an input-consumer to grab input from the "live tile" app. Set that up here
         final InputConsumerImpl recentsAnimationInputConsumer =
@@ -679,7 +686,7 @@
         // Find the top-most non-home, closing app.
         for (int i = 0; i < info.getChanges().size(); ++i) {
             final TransitionInfo.Change c = info.getChanges().get(i);
-            if (c.getTaskInfo() == null || c.getTaskInfo().displayId != displayId
+            if (c.getTaskInfo() == null || c.getTaskInfo().displayId != mRecentsDisplayId
                     || c.getTaskInfo().getActivityType() != ACTIVITY_TYPE_STANDARD
                     || !(c.getMode() == TRANSIT_CLOSE || c.getMode() == TRANSIT_TO_BACK)) {
                 continue;
@@ -710,7 +717,7 @@
             t.setLayer(navSurfaceControl, Integer.MAX_VALUE);
         }
         if (mController.mStatusBar != null) {
-            mController.mStatusBar.setNavigationBarLumaSamplingEnabled(displayId, false);
+            mController.mStatusBar.setNavigationBarLumaSamplingEnabled(mRecentsDisplayId, false);
         }
     }
 
@@ -760,13 +767,8 @@
         }
     }
 
-    private void handleNonAppWindowsInTransition(int displayId,
+    private void handleNonAppWindowsInTransition(@NonNull DisplayContent dc,
             @TransitionType int transit, @TransitionFlags int flags) {
-        final DisplayContent dc =
-                mController.mAtm.mRootWindowContainer.getDisplayContent(displayId);
-        if (dc == null) {
-            return;
-        }
         if ((transit == TRANSIT_KEYGUARD_GOING_AWAY
                 || (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY) != 0)
                 && !WindowManagerService.sEnableRemoteKeyguardGoingAwayAnimation) {
diff --git a/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java b/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java
index 2652723..4a5a20e 100644
--- a/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java
+++ b/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java
@@ -69,7 +69,7 @@
             long durationHint, long statusBarTransitionDelay,
             Consumer<WallpaperAnimationAdapter> animationCanceledRunnable,
             ArrayList<WallpaperAnimationAdapter> adaptersOut) {
-        if (!displayContent.mWallpaperController.isWallpaperVisible()) {
+        if (!shouldStartWallpaperAnimation(displayContent)) {
             ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS,
                     "\tWallpaper of display=%s is not visible", displayContent);
             return new RemoteAnimationTarget[0];
@@ -87,6 +87,10 @@
         return targets.toArray(new RemoteAnimationTarget[targets.size()]);
     }
 
+    static boolean shouldStartWallpaperAnimation(DisplayContent displayContent) {
+        return displayContent.mWallpaperController.isWallpaperVisible();
+    }
+
     /**
      * Create a remote animation target for this animation adapter.
      */
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index 08b1a2f..e24be37 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -611,8 +611,9 @@
     private void updateWallpaperTokens(boolean visible) {
         for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
             final WallpaperWindowToken token = mWallpaperTokens.get(curTokenNdx);
-            token.updateWallpaperWindows(visible);
-            token.getDisplayContent().assignWindowLayers(false);
+            if (token.updateWallpaperWindows(visible)) {
+                token.mDisplayContent.assignWindowLayers(false /* setLayoutNeeded */);
+            }
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/WallpaperWindowToken.java b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
index 3a639f5..fe405e5 100644
--- a/services/core/java/com/android/server/wm/WallpaperWindowToken.java
+++ b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
@@ -104,18 +104,21 @@
         }
     }
 
-    void updateWallpaperWindows(boolean visible) {
+    /** Returns {@code true} if visibility is changed. */
+    boolean updateWallpaperWindows(boolean visible) {
+        boolean changed = false;
         if (isVisible() != visible) {
             ProtoLog.d(WM_DEBUG_WALLPAPER, "Wallpaper token %s visible=%b",
                     token, visible);
             setVisibility(visible);
+            changed = true;
         }
-        final WallpaperController wallpaperController = mDisplayContent.mWallpaperController;
         if (mTransitionController.isShellTransitionsEnabled()) {
-            return;
+            return changed;
         }
 
-        final WindowState wallpaperTarget = wallpaperController.getWallpaperTarget();
+        final WindowState wallpaperTarget =
+                mDisplayContent.mWallpaperController.getWallpaperTarget();
 
         if (visible && wallpaperTarget != null) {
             final RecentsAnimationController recentsAnimationController =
@@ -137,6 +140,7 @@
         }
 
         setVisible(visible);
+        return changed;
     }
 
     private void setVisible(boolean visible) {
@@ -155,10 +159,12 @@
      * transition. In that situation, make sure to call {@link #commitVisibility} when done.
      */
     void setVisibility(boolean visible) {
-        // Before setting mVisibleRequested so we can track changes.
-        mTransitionController.collect(this);
+        if (mVisibleRequested != visible) {
+            // Before setting mVisibleRequested so we can track changes.
+            mTransitionController.collect(this);
 
-        setVisibleRequested(visible);
+            setVisibleRequested(visible);
+        }
 
         // If in a transition, defer commits for activities that are going invisible
         if (!visible && (mTransitionController.inTransition()
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 3d479d1..0649b25 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -587,7 +587,7 @@
             case HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT: {
                 final TaskFragmentCreationParams taskFragmentCreationOptions =
                         hop.getTaskFragmentCreationOptions();
-                createTaskFragment(taskFragmentCreationOptions, errorCallbackToken);
+                createTaskFragment(taskFragmentCreationOptions, errorCallbackToken, caller);
                 break;
             }
             case HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT: {
@@ -630,7 +630,7 @@
                 final TaskFragment tf = mLaunchTaskFragments.get(fragmentToken);
                 final int result = mService.getActivityStartController()
                         .startActivityInTaskFragment(tf, activityIntent, activityOptions,
-                                hop.getCallingActivity());
+                                hop.getCallingActivity(), caller.mUid, caller.mPid);
                 if (!isStartResultSuccessful(result)) {
                     sendTaskFragmentOperationFailure(tf.getTaskFragmentOrganizer(),
                             errorCallbackToken,
@@ -1199,7 +1199,7 @@
     }
 
     void createTaskFragment(@NonNull TaskFragmentCreationParams creationParams,
-            @Nullable IBinder errorCallbackToken) {
+            @Nullable IBinder errorCallbackToken, @NonNull CallerInfo caller) {
         final ActivityRecord ownerActivity =
                 ActivityRecord.forTokenLocked(creationParams.getOwnerToken());
         final ITaskFragmentOrganizer organizer = ITaskFragmentOrganizer.Stub.asInterface(
@@ -1217,9 +1217,9 @@
             sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception);
             return;
         }
-        // The ownerActivity has to belong to the same app as the root Activity of the target Task.
-        final ActivityRecord rootActivity = ownerActivity.getTask().getRootActivity();
-        if (rootActivity.getUid() != ownerActivity.getUid()) {
+        // The ownerActivity has to belong to the same app as the target Task.
+        if (ownerActivity.getTask().effectiveUid != ownerActivity.getUid()
+                || ownerActivity.getTask().effectiveUid != caller.mUid) {
             final Throwable exception =
                     new IllegalArgumentException("Not allowed to operate with the ownerToken while "
                             + "the root activity of the target task belong to the different app");
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index 0a55003..e4c8871 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -29,6 +29,8 @@
 #include <android/hardware/gnss/2.1/IGnssMeasurement.h>
 #include <android/hardware/gnss/BnGnss.h>
 #include <android/hardware/gnss/BnGnssCallback.h>
+#include <android/hardware/gnss/BnGnssGeofence.h>
+#include <android/hardware/gnss/BnGnssGeofenceCallback.h>
 #include <android/hardware/gnss/BnGnssMeasurementCallback.h>
 #include <android/hardware/gnss/BnGnssPowerIndicationCallback.h>
 #include <android/hardware/gnss/BnGnssPsdsCallback.h>
@@ -191,6 +193,9 @@
 using android::hardware::gnss::PsdsType;
 using IGnssAidl = android::hardware::gnss::IGnss;
 using IGnssCallbackAidl = android::hardware::gnss::IGnssCallback;
+using IGnssBatchingAidl = android::hardware::gnss::IGnssBatching;
+using IGnssGeofenceAidl = android::hardware::gnss::IGnssGeofence;
+using IGnssGeofenceCallbackAidl = android::hardware::gnss::IGnssGeofenceCallback;
 using IGnssPsdsAidl = android::hardware::gnss::IGnssPsds;
 using IGnssPsdsCallbackAidl = android::hardware::gnss::IGnssPsdsCallback;
 using IGnssConfigurationAidl = android::hardware::gnss::IGnssConfiguration;
@@ -216,6 +221,8 @@
 sp<IGnss_V2_0> gnssHal_V2_0 = nullptr;
 sp<IGnss_V2_1> gnssHal_V2_1 = nullptr;
 sp<IGnssAidl> gnssHalAidl = nullptr;
+sp<IGnssBatchingAidl> gnssBatchingAidlIface = nullptr;
+sp<IGnssGeofenceAidl> gnssGeofenceAidlIface = nullptr;
 sp<IGnssPsdsAidl> gnssPsdsAidlIface = nullptr;
 sp<IGnssXtra> gnssXtraIface = nullptr;
 sp<IAGnssRil_V1_0> agnssRilIface = nullptr;
@@ -709,35 +716,25 @@
     return Void();
 }
 
-/*
- * GnssGeofenceCallback class implements the callback methods for the
- * IGnssGeofence interface.
- */
-struct GnssGeofenceCallback : public IGnssGeofenceCallback {
-    // Methods from ::android::hardware::gps::V1_0::IGnssGeofenceCallback follow.
-    Return<void> gnssGeofenceTransitionCb(
-            int32_t geofenceId,
-            const GnssLocation_V1_0& location,
-            GeofenceTransition transition,
-            hardware::gnss::V1_0::GnssUtcTime timestamp) override;
-    Return<void>
-    gnssGeofenceStatusCb(
-            GeofenceAvailability status,
-            const GnssLocation_V1_0& location) override;
-    Return<void> gnssGeofenceAddCb(int32_t geofenceId,
-                                   GeofenceStatus status) override;
-    Return<void> gnssGeofenceRemoveCb(int32_t geofenceId,
-                                      GeofenceStatus status) override;
-    Return<void> gnssGeofencePauseCb(int32_t geofenceId,
-                                     GeofenceStatus status) override;
-    Return<void> gnssGeofenceResumeCb(int32_t geofenceId,
-                                      GeofenceStatus status) override;
+/** Util class for GnssGeofenceCallback methods. */
+struct GnssGeofenceCallbackUtil {
+    template <class T>
+    static void gnssGeofenceTransitionCb(int geofenceId, const T& location, int transition,
+                                         int64_t timestampMillis);
+    template <class T>
+    static void gnssGeofenceStatusCb(int availability, const T& lastLocation);
+    static void gnssGeofenceAddCb(int geofenceId, int status);
+    static void gnssGeofenceRemoveCb(int geofenceId, int status);
+    static void gnssGeofencePauseCb(int geofenceId, int status);
+    static void gnssGeofenceResumeCb(int geofenceId, int status);
+
+private:
+    GnssGeofenceCallbackUtil() = delete;
 };
 
-Return<void> GnssGeofenceCallback::gnssGeofenceTransitionCb(
-        int32_t geofenceId, const GnssLocation_V1_0& location,
-        GeofenceTransition transition,
-        hardware::gnss::V1_0::GnssUtcTime timestamp) {
+template <class T>
+void GnssGeofenceCallbackUtil::gnssGeofenceTransitionCb(int geofenceId, const T& location,
+                                                        int transition, int64_t timestamp) {
     JNIEnv* env = getJniEnv();
 
     jobject jLocation = translateGnssLocation(env, location);
@@ -751,27 +748,22 @@
 
     checkAndClearExceptionFromCallback(env, __FUNCTION__);
     env->DeleteLocalRef(jLocation);
-    return Void();
 }
 
-Return<void>
-GnssGeofenceCallback::gnssGeofenceStatusCb(GeofenceAvailability status,
-                                           const GnssLocation_V1_0& location) {
+template <class T>
+void GnssGeofenceCallbackUtil::gnssGeofenceStatusCb(int availability, const T& lastLocation) {
     JNIEnv* env = getJniEnv();
 
-    jobject jLocation = translateGnssLocation(env, location);
+    jobject jLocation = translateGnssLocation(env, lastLocation);
 
-    env->CallVoidMethod(mCallbacksObj, method_reportGeofenceStatus, status,
-                        jLocation);
+    env->CallVoidMethod(mCallbacksObj, method_reportGeofenceStatus, availability, jLocation);
     checkAndClearExceptionFromCallback(env, __FUNCTION__);
     env->DeleteLocalRef(jLocation);
-    return Void();
 }
 
-Return<void> GnssGeofenceCallback::gnssGeofenceAddCb(int32_t geofenceId,
-                                                    GeofenceStatus status) {
+void GnssGeofenceCallbackUtil::gnssGeofenceAddCb(int geofenceId, int status) {
     JNIEnv* env = getJniEnv();
-    if (status != IGnssGeofenceCallback::GeofenceStatus::OPERATION_SUCCESS) {
+    if (status != IGnssGeofenceCallbackAidl::OPERATION_SUCCESS) {
         ALOGE("%s: Error in adding a Geofence: %d\n", __func__, status);
     }
 
@@ -780,13 +772,11 @@
                         geofenceId,
                         status);
     checkAndClearExceptionFromCallback(env, __FUNCTION__);
-    return Void();
 }
 
-Return<void> GnssGeofenceCallback::gnssGeofenceRemoveCb(int32_t geofenceId,
-                                                       GeofenceStatus status) {
+void GnssGeofenceCallbackUtil::gnssGeofenceRemoveCb(int geofenceId, int status) {
     JNIEnv* env = getJniEnv();
-    if (status != IGnssGeofenceCallback::GeofenceStatus::OPERATION_SUCCESS) {
+    if (status != IGnssGeofenceCallbackAidl::OPERATION_SUCCESS) {
         ALOGE("%s: Error in removing a Geofence: %d\n", __func__, status);
     }
 
@@ -794,13 +784,11 @@
                         method_reportGeofenceRemoveStatus,
                         geofenceId, status);
     checkAndClearExceptionFromCallback(env, __FUNCTION__);
-    return Void();
 }
 
-Return<void> GnssGeofenceCallback::gnssGeofencePauseCb(int32_t geofenceId,
-                                                      GeofenceStatus status) {
+void GnssGeofenceCallbackUtil::gnssGeofencePauseCb(int geofenceId, int status) {
     JNIEnv* env = getJniEnv();
-    if (status != IGnssGeofenceCallback::GeofenceStatus::OPERATION_SUCCESS) {
+    if (status != IGnssGeofenceCallbackAidl::OPERATION_SUCCESS) {
         ALOGE("%s: Error in pausing Geofence: %d\n", __func__, status);
     }
 
@@ -808,13 +796,11 @@
                         method_reportGeofencePauseStatus,
                         geofenceId, status);
     checkAndClearExceptionFromCallback(env, __FUNCTION__);
-    return Void();
 }
 
-Return<void> GnssGeofenceCallback::gnssGeofenceResumeCb(int32_t geofenceId,
-                                                       GeofenceStatus status) {
+void GnssGeofenceCallbackUtil::gnssGeofenceResumeCb(int geofenceId, int status) {
     JNIEnv* env = getJniEnv();
-    if (status != IGnssGeofenceCallback::GeofenceStatus::OPERATION_SUCCESS) {
+    if (status != IGnssGeofenceCallbackAidl::OPERATION_SUCCESS) {
         ALOGE("%s: Error in resuming Geofence: %d\n", __func__, status);
     }
 
@@ -822,6 +808,104 @@
                         method_reportGeofenceResumeStatus,
                         geofenceId, status);
     checkAndClearExceptionFromCallback(env, __FUNCTION__);
+}
+
+/*
+ * GnssGeofenceCallbackAidl class implements the callback methods for the IGnssGeofence AIDL
+ * interface.
+ */
+struct GnssGeofenceCallbackAidl : public android::hardware::gnss::BnGnssGeofenceCallback {
+    Status gnssGeofenceTransitionCb(int geofenceId, const GnssLocationAidl& location,
+                                    int transition, int64_t timestampMillis) override;
+    Status gnssGeofenceStatusCb(int availability, const GnssLocationAidl& lastLocation) override;
+    Status gnssGeofenceAddCb(int geofenceId, int status) override;
+    Status gnssGeofenceRemoveCb(int geofenceId, int status) override;
+    Status gnssGeofencePauseCb(int geofenceId, int status) override;
+    Status gnssGeofenceResumeCb(int geofenceId, int status) override;
+};
+
+Status GnssGeofenceCallbackAidl::gnssGeofenceTransitionCb(int geofenceId,
+                                                          const GnssLocationAidl& location,
+                                                          int transition, int64_t timestampMillis) {
+    GnssGeofenceCallbackUtil::gnssGeofenceTransitionCb(geofenceId, location, transition,
+                                                       timestampMillis);
+    return Status::ok();
+}
+
+Status GnssGeofenceCallbackAidl::gnssGeofenceStatusCb(int availability,
+                                                      const GnssLocationAidl& lastLocation) {
+    GnssGeofenceCallbackUtil::gnssGeofenceStatusCb(availability, lastLocation);
+    return Status::ok();
+}
+
+Status GnssGeofenceCallbackAidl::gnssGeofenceAddCb(int geofenceId, int status) {
+    GnssGeofenceCallbackUtil::gnssGeofenceAddCb(geofenceId, status);
+    return Status::ok();
+}
+
+Status GnssGeofenceCallbackAidl::gnssGeofenceRemoveCb(int geofenceId, int status) {
+    GnssGeofenceCallbackUtil::gnssGeofenceRemoveCb(geofenceId, status);
+    return Status::ok();
+}
+
+Status GnssGeofenceCallbackAidl::gnssGeofencePauseCb(int geofenceId, int status) {
+    GnssGeofenceCallbackUtil::gnssGeofencePauseCb(geofenceId, status);
+    return Status::ok();
+}
+
+Status GnssGeofenceCallbackAidl::gnssGeofenceResumeCb(int geofenceId, int status) {
+    GnssGeofenceCallbackUtil::gnssGeofenceResumeCb(geofenceId, status);
+    return Status::ok();
+}
+
+/*
+ * GnssGeofenceCallback class implements the callback methods for the
+ * IGnssGeofence HIDL interface.
+ */
+struct GnssGeofenceCallback : public IGnssGeofenceCallback {
+    // Methods from ::android::hardware::gps::V1_0::IGnssGeofenceCallback follow.
+    Return<void> gnssGeofenceTransitionCb(int32_t geofenceId, const GnssLocation_V1_0& location,
+                                          GeofenceTransition transition,
+                                          hardware::gnss::V1_0::GnssUtcTime timestamp) override;
+    Return<void> gnssGeofenceStatusCb(GeofenceAvailability status,
+                                      const GnssLocation_V1_0& location) override;
+    Return<void> gnssGeofenceAddCb(int32_t geofenceId, GeofenceStatus status) override;
+    Return<void> gnssGeofenceRemoveCb(int32_t geofenceId, GeofenceStatus status) override;
+    Return<void> gnssGeofencePauseCb(int32_t geofenceId, GeofenceStatus status) override;
+    Return<void> gnssGeofenceResumeCb(int32_t geofenceId, GeofenceStatus status) override;
+};
+
+Return<void> GnssGeofenceCallback::gnssGeofenceTransitionCb(
+        int32_t geofenceId, const GnssLocation_V1_0& location, GeofenceTransition transition,
+        hardware::gnss::V1_0::GnssUtcTime timestamp) {
+    GnssGeofenceCallbackUtil::gnssGeofenceTransitionCb(geofenceId, location, (int)transition,
+                                                       (int64_t)timestamp);
+    return Void();
+}
+
+Return<void> GnssGeofenceCallback::gnssGeofenceStatusCb(GeofenceAvailability availability,
+                                                        const GnssLocation_V1_0& location) {
+    GnssGeofenceCallbackUtil::gnssGeofenceStatusCb((int)availability, location);
+    return Void();
+}
+
+Return<void> GnssGeofenceCallback::gnssGeofenceAddCb(int32_t geofenceId, GeofenceStatus status) {
+    GnssGeofenceCallbackUtil::gnssGeofenceAddCb(geofenceId, (int)status);
+    return Void();
+}
+
+Return<void> GnssGeofenceCallback::gnssGeofenceRemoveCb(int32_t geofenceId, GeofenceStatus status) {
+    GnssGeofenceCallbackUtil::gnssGeofenceRemoveCb(geofenceId, (int)status);
+    return Void();
+}
+
+Return<void> GnssGeofenceCallback::gnssGeofencePauseCb(int32_t geofenceId, GeofenceStatus status) {
+    GnssGeofenceCallbackUtil::gnssGeofencePauseCb(geofenceId, (int)status);
+    return Void();
+}
+
+Return<void> GnssGeofenceCallback::gnssGeofenceResumeCb(int32_t geofenceId, GeofenceStatus status) {
+    GnssGeofenceCallbackUtil::gnssGeofenceResumeCb(geofenceId, (int)status);
     return Void();
 }
 
@@ -1279,11 +1363,13 @@
         android_location_gnss_hal_GnssNative_set_gps_service_handle();
     }
 
-    if (gnssHal == nullptr) {
+    if (gnssHal == nullptr && gnssHalAidl == nullptr) {
         ALOGE("Unable to get GPS service\n");
         return;
     }
 
+    // TODO: linkToDeath for AIDL HAL
+
     gnssHalDeathRecipient = new GnssDeathRecipient();
     hardware::Return<bool> linked = gnssHal->linkToDeath(gnssHalDeathRecipient, /*cookie*/ 0);
     if (!linked.isOk()) {
@@ -1303,7 +1389,7 @@
         } else {
             ALOGD("Unable to get a handle to PSDS AIDL interface.");
         }
-    } else {
+    } else if (gnssHal != nullptr) {
         auto gnssXtra = gnssHal->getExtensionXtra();
         if (!gnssXtra.isOk()) {
             ALOGD("Unable to get a handle to Xtra");
@@ -1320,7 +1406,7 @@
             agnssRilIface_V2_0 = agnssRil_V2_0;
             agnssRilIface = agnssRilIface_V2_0;
         }
-    } else {
+    } else if (gnssHal != nullptr) {
         auto agnssRil_V1_0 = gnssHal->getExtensionAGnssRil();
         if (!agnssRil_V1_0.isOk()) {
             ALOGD("Unable to get a handle to AGnssRil");
@@ -1336,7 +1422,7 @@
         } else {
             agnssIface_V2_0 = agnss_V2_0;
         }
-    } else {
+    } else if (gnssHal != nullptr) {
         auto agnss_V1_0 = gnssHal->getExtensionAGnss();
         if (!agnss_V1_0.isOk()) {
             ALOGD("Unable to get a handle to AGnss");
@@ -1345,11 +1431,13 @@
         }
     }
 
-    auto gnssNavigationMessage = gnssHal->getExtensionGnssNavigationMessage();
-    if (!gnssNavigationMessage.isOk()) {
-        ALOGD("Unable to get a handle to GnssNavigationMessage");
-    } else {
-        gnssNavigationMessageIface = gnssNavigationMessage;
+    if (gnssHal != nullptr) {
+        auto gnssNavigationMessage = gnssHal->getExtensionGnssNavigationMessage();
+        if (!gnssNavigationMessage.isOk()) {
+            ALOGD("Unable to get a handle to GnssNavigationMessage");
+        } else {
+            gnssNavigationMessageIface = gnssNavigationMessage;
+        }
     }
 
     // Allow all causal combinations between IGnss.hal and IGnssMeasurement.hal. That means,
@@ -1387,12 +1475,12 @@
                     std::make_unique<android::gnss::GnssMeasurement_V1_1>(gnssMeasurement);
         }
     }
-    if (gnssMeasurementIface == nullptr) {
-         auto gnssMeasurement = gnssHal->getExtensionGnssMeasurement();
-         if (checkHidlReturn(gnssMeasurement, "Unable to get a handle to GnssMeasurement_V1_0")) {
-             gnssMeasurementIface =
-                     std::make_unique<android::gnss::GnssMeasurement_V1_0>(gnssMeasurement);
-         }
+    if (gnssHal != nullptr && gnssMeasurementIface == nullptr) {
+        auto gnssMeasurement = gnssHal->getExtensionGnssMeasurement();
+        if (checkHidlReturn(gnssMeasurement, "Unable to get a handle to GnssMeasurement_V1_0")) {
+            gnssMeasurementIface =
+                    std::make_unique<android::gnss::GnssMeasurement_V1_0>(gnssMeasurement);
+        }
     }
 
     if (gnssHal_V2_1 != nullptr) {
@@ -1434,7 +1522,7 @@
             gnssDebugIface = gnssDebugIface_V2_0;
         }
     }
-    if (gnssDebugIface == nullptr) {
+    if (gnssHal != nullptr && gnssDebugIface == nullptr) {
         auto gnssDebug = gnssHal->getExtensionGnssDebug();
         if (!gnssDebug.isOk()) {
             ALOGD("Unable to get a handle to GnssDebug");
@@ -1443,11 +1531,13 @@
         }
     }
 
-    auto gnssNi = gnssHal->getExtensionGnssNi();
-    if (!gnssNi.isOk()) {
-        ALOGD("Unable to get a handle to GnssNi");
-    } else {
-        gnssNiIface = gnssNi;
+    if (gnssHal != nullptr) {
+        auto gnssNi = gnssHal->getExtensionGnssNi();
+        if (!gnssNi.isOk()) {
+            ALOGD("Unable to get a handle to GnssNi");
+        } else {
+            gnssNiIface = gnssNi;
+        }
     }
 
     if (gnssHalAidl != nullptr) {
@@ -1488,11 +1578,17 @@
         }
     }
 
-    auto gnssGeofencing = gnssHal->getExtensionGnssGeofencing();
-    if (!gnssGeofencing.isOk()) {
-        ALOGD("Unable to get a handle to GnssGeofencing");
-    } else {
-        gnssGeofencingIface = gnssGeofencing;
+    if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
+        sp<IGnssGeofenceAidl> gnssGeofenceAidl;
+        auto status = gnssHalAidl->getExtensionGnssGeofence(&gnssGeofenceAidl);
+        if (checkAidlStatus(status, "Unable to get a handle to GnssGeofence interface.")) {
+            gnssGeofenceAidlIface = gnssGeofenceAidl;
+        }
+    } else if (gnssHal != nullptr) {
+        auto gnssGeofencing = gnssHal->getExtensionGnssGeofencing();
+        if (checkHidlReturn(gnssGeofencing, "Unable to get a handle to GnssGeofencing")) {
+            gnssGeofencingIface = gnssGeofencing;
+        }
     }
 
     if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
@@ -1507,7 +1603,7 @@
             gnssBatchingIface = std::make_unique<gnss::GnssBatching_V2_0>(gnssBatching_V2_0);
         }
     }
-    if (gnssBatchingIface == nullptr) {
+    if (gnssHal != nullptr && gnssBatchingIface == nullptr) {
         auto gnssBatching_V1_0 = gnssHal->getExtensionGnssBatching();
         if (checkHidlReturn(gnssBatching_V1_0, "Unable to get a handle to GnssBatching")) {
             gnssBatchingIface = std::make_unique<gnss::GnssBatching_V1_0>(gnssBatching_V1_0);
@@ -1568,7 +1664,7 @@
     /*
      * Fail if the main interface fails to initialize
      */
-    if (gnssHal == nullptr) {
+    if (gnssHal == nullptr && gnssHalAidl == nullptr) {
         ALOGE("Unable to initialize GNSS HAL.");
         return JNI_FALSE;
     }
@@ -1583,7 +1679,7 @@
         result = gnssHal_V2_0->setCallback_2_0(gnssCbIface);
     } else if (gnssHal_V1_1 != nullptr) {
         result = gnssHal_V1_1->setCallback_1_1(gnssCbIface);
-    } else {
+    } else if (gnssHal != nullptr) {
         result = gnssHal->setCallback(gnssCbIface);
     }
 
@@ -1630,10 +1726,18 @@
     }
 
     // Set IGnssGeofencing.hal callback.
-    sp<IGnssGeofenceCallback> gnssGeofencingCbIface = new GnssGeofenceCallback();
-    if (gnssGeofencingIface != nullptr) {
+    if (gnssGeofenceAidlIface != nullptr) {
+        sp<IGnssGeofenceCallbackAidl> gnssGeofenceCallbackAidl = new GnssGeofenceCallbackAidl();
+        auto status = gnssGeofenceAidlIface->setCallback(gnssGeofenceCallbackAidl);
+        if (!checkAidlStatus(status, "IGnssGeofenceAidl setCallback() failed.")) {
+            gnssGeofenceAidlIface = nullptr;
+        }
+    } else if (gnssGeofencingIface != nullptr) {
+        sp<IGnssGeofenceCallback> gnssGeofencingCbIface = new GnssGeofenceCallback();
         auto status = gnssGeofencingIface->setCallback(gnssGeofencingCbIface);
-        checkHidlReturn(status, "IGnssGeofencing setCallback() failed.");
+        if (!checkHidlReturn(status, "IGnssGeofencing setCallback() failed.")) {
+            gnssGeofencingIface = nullptr;
+        }
     } else {
         ALOGI("Unable to initialize IGnssGeofencing interface.");
     }
@@ -1693,12 +1797,15 @@
 }
 
 static void android_location_gnss_hal_GnssNative_cleanup(JNIEnv* /* env */, jclass) {
-    if (gnssHal == nullptr) {
-        return;
+    if (gnssHalAidl != nullptr) {
+        auto status = gnssHalAidl->close();
+        checkAidlStatus(status, "IGnssAidl close() failed.");
     }
 
-    auto result = gnssHal->cleanup();
-    checkHidlReturn(result, "IGnss cleanup() failed.");
+    if (gnssHal != nullptr) {
+        auto result = gnssHal->cleanup();
+        checkHidlReturn(result, "IGnss cleanup() failed.");
+    }
 }
 
 static jboolean android_location_gnss_hal_GnssNative_set_position_mode(
@@ -2177,57 +2284,85 @@
 
 static jboolean android_location_gnss_hal_GnssNative_is_geofence_supported(JNIEnv* /* env */,
                                                                            jclass) {
-    return (gnssGeofencingIface != nullptr) ? JNI_TRUE : JNI_FALSE;
+    if (gnssGeofencingIface == nullptr && gnssGeofenceAidlIface == nullptr) {
+        return JNI_FALSE;
+    }
+    return JNI_TRUE;
 }
 
 static jboolean android_location_gnss_hal_GnssNative_add_geofence(
         JNIEnv* /* env */, jclass, jint geofenceId, jdouble latitude, jdouble longitude,
         jdouble radius, jint last_transition, jint monitor_transition,
         jint notification_responsiveness, jint unknown_timer) {
-    if (gnssGeofencingIface == nullptr) {
-        ALOGE("%s: IGnssGeofencing interface not available.", __func__);
-        return JNI_FALSE;
+    if (gnssGeofenceAidlIface != nullptr) {
+        auto status =
+                gnssGeofenceAidlIface->addGeofence(geofenceId, latitude, longitude, radius,
+                                                   last_transition, monitor_transition,
+                                                   notification_responsiveness, unknown_timer);
+        return checkAidlStatus(status, "IGnssGeofenceAidl addGeofence() failed.");
     }
 
-    auto result = gnssGeofencingIface->addGeofence(
-            geofenceId, latitude, longitude, radius,
-            static_cast<IGnssGeofenceCallback::GeofenceTransition>(last_transition),
-            monitor_transition, notification_responsiveness, unknown_timer);
-    return checkHidlReturn(result, "IGnssGeofencing addGeofence() failed.");
+    if (gnssGeofencingIface != nullptr) {
+        auto result = gnssGeofencingIface
+                              ->addGeofence(geofenceId, latitude, longitude, radius,
+                                            static_cast<IGnssGeofenceCallback::GeofenceTransition>(
+                                                    last_transition),
+                                            monitor_transition, notification_responsiveness,
+                                            unknown_timer);
+        return checkHidlReturn(result, "IGnssGeofencing addGeofence() failed.");
+    }
+
+    ALOGE("%s: IGnssGeofencing interface not available.", __func__);
+    return JNI_FALSE;
 }
 
 static jboolean android_location_gnss_hal_GnssNative_remove_geofence(JNIEnv* /* env */, jclass,
                                                                      jint geofenceId) {
-    if (gnssGeofencingIface == nullptr) {
-        ALOGE("%s: IGnssGeofencing interface not available.", __func__);
-        return JNI_FALSE;
+    if (gnssGeofenceAidlIface != nullptr) {
+        auto status = gnssGeofenceAidlIface->removeGeofence(geofenceId);
+        return checkAidlStatus(status, "IGnssGeofenceAidl removeGeofence() failed.");
     }
 
-    auto result = gnssGeofencingIface->removeGeofence(geofenceId);
-    return checkHidlReturn(result, "IGnssGeofencing removeGeofence() failed.");
+    if (gnssGeofencingIface != nullptr) {
+        auto result = gnssGeofencingIface->removeGeofence(geofenceId);
+        return checkHidlReturn(result, "IGnssGeofencing removeGeofence() failed.");
+    }
+
+    ALOGE("%s: IGnssGeofencing interface not available.", __func__);
+    return JNI_FALSE;
 }
 
 static jboolean android_location_gnss_hal_GnssNative_pause_geofence(JNIEnv* /* env */, jclass,
                                                                     jint geofenceId) {
-    if (gnssGeofencingIface == nullptr) {
-        ALOGE("%s: IGnssGeofencing interface not available.", __func__);
-        return JNI_FALSE;
+    if (gnssGeofenceAidlIface != nullptr) {
+        auto status = gnssGeofenceAidlIface->pauseGeofence(geofenceId);
+        return checkAidlStatus(status, "IGnssGeofenceAidl pauseGeofence() failed.");
     }
 
-    auto result = gnssGeofencingIface->pauseGeofence(geofenceId);
-    return checkHidlReturn(result, "IGnssGeofencing pauseGeofence() failed.");
+    if (gnssGeofencingIface != nullptr) {
+        auto result = gnssGeofencingIface->pauseGeofence(geofenceId);
+        return checkHidlReturn(result, "IGnssGeofencing pauseGeofence() failed.");
+    }
+
+    ALOGE("%s: IGnssGeofencing interface not available.", __func__);
+    return JNI_FALSE;
 }
 
 static jboolean android_location_gnss_hal_GnssNative_resume_geofence(JNIEnv* /* env */, jclass,
                                                                      jint geofenceId,
                                                                      jint monitor_transition) {
-    if (gnssGeofencingIface == nullptr) {
-        ALOGE("%s: IGnssGeofencing interface not available.", __func__);
-        return JNI_FALSE;
+    if (gnssGeofenceAidlIface != nullptr) {
+        auto status = gnssGeofenceAidlIface->resumeGeofence(geofenceId, monitor_transition);
+        return checkAidlStatus(status, "IGnssGeofenceAidl resumeGeofence() failed.");
     }
 
-    auto result = gnssGeofencingIface->resumeGeofence(geofenceId, monitor_transition);
-    return checkHidlReturn(result, "IGnssGeofencing resumeGeofence() failed.");
+    if (gnssGeofencingIface != nullptr) {
+        auto result = gnssGeofencingIface->resumeGeofence(geofenceId, monitor_transition);
+        return checkHidlReturn(result, "IGnssGeofencing resumeGeofence() failed.");
+    }
+
+    ALOGE("%s: IGnssGeofencing interface not available.", __func__);
+    return JNI_FALSE;
 }
 
 static jboolean android_location_gnss_hal_GnssNative_is_antenna_info_supported(JNIEnv* env,
diff --git a/services/core/jni/com_android_server_net_NetworkStatsService.cpp b/services/core/jni/com_android_server_net_NetworkStatsService.cpp
index 10b248a..5178132 100644
--- a/services/core/jni/com_android_server_net_NetworkStatsService.cpp
+++ b/services/core/jni/com_android_server_net_NetworkStatsService.cpp
@@ -38,9 +38,6 @@
 
 namespace android {
 
-static const char* QTAGUID_IFACE_STATS = "/proc/net/xt_qtaguid/iface_stat_fmt";
-static const char* QTAGUID_UID_STATS = "/proc/net/xt_qtaguid/stats";
-
 // NOTE: keep these in sync with TrafficStats.java
 static const uint64_t UNKNOWN = -1;
 
@@ -72,102 +69,17 @@
     }
 }
 
-static int parseIfaceStats(const char* iface, Stats* stats) {
-    FILE *fp = fopen(QTAGUID_IFACE_STATS, "r");
-    if (fp == NULL) {
-        return -1;
-    }
-
-    char buffer[384];
-    char cur_iface[32];
-    bool foundTcp = false;
-    uint64_t rxBytes, rxPackets, txBytes, txPackets, tcpRxPackets, tcpTxPackets;
-
-    while (fgets(buffer, sizeof(buffer), fp) != NULL) {
-        int matched = sscanf(buffer, "%31s %" SCNu64 " %" SCNu64 " %" SCNu64
-                " %" SCNu64 " " "%*u %" SCNu64 " %*u %*u %*u %*u "
-                "%*u %" SCNu64 " %*u %*u %*u %*u", cur_iface, &rxBytes,
-                &rxPackets, &txBytes, &txPackets, &tcpRxPackets, &tcpTxPackets);
-        if (matched >= 5) {
-            if (matched == 7) {
-                foundTcp = true;
-            }
-            if (!iface || !strcmp(iface, cur_iface)) {
-                stats->rxBytes += rxBytes;
-                stats->rxPackets += rxPackets;
-                stats->txBytes += txBytes;
-                stats->txPackets += txPackets;
-                if (matched == 7) {
-                    stats->tcpRxPackets += tcpRxPackets;
-                    stats->tcpTxPackets += tcpTxPackets;
-                }
-            }
-        }
-    }
-
-    if (!foundTcp) {
-        stats->tcpRxPackets = UNKNOWN;
-        stats->tcpTxPackets = UNKNOWN;
-    }
-
-    if (fclose(fp) != 0) {
-        return -1;
-    }
-    return 0;
-}
-
-static int parseUidStats(const uint32_t uid, Stats* stats) {
-    FILE *fp = fopen(QTAGUID_UID_STATS, "r");
-    if (fp == NULL) {
-        return -1;
-    }
-
-    char buffer[384];
-    char iface[32];
-    uint32_t idx, cur_uid, set;
-    uint64_t tag, rxBytes, rxPackets, txBytes, txPackets;
-
-    while (fgets(buffer, sizeof(buffer), fp) != NULL) {
-        if (sscanf(buffer,
-                "%" SCNu32 " %31s 0x%" SCNx64 " %u %u %" SCNu64 " %" SCNu64
-                " %" SCNu64 " %" SCNu64 "",
-                &idx, iface, &tag, &cur_uid, &set, &rxBytes, &rxPackets,
-                &txBytes, &txPackets) == 9) {
-            if (uid == cur_uid && tag == 0L) {
-                stats->rxBytes += rxBytes;
-                stats->rxPackets += rxPackets;
-                stats->txBytes += txBytes;
-                stats->txPackets += txPackets;
-            }
-        }
-    }
-
-    if (fclose(fp) != 0) {
-        return -1;
-    }
-    return 0;
-}
-
-static jlong getTotalStat(JNIEnv* env, jclass clazz, jint type, jboolean useBpfStats) {
+static jlong getTotalStat(JNIEnv* env, jclass clazz, jint type) {
     Stats stats = {};
 
-    if (useBpfStats) {
-        if (bpfGetIfaceStats(NULL, &stats) == 0) {
-            return getStatsType(&stats, (StatsType) type);
-        } else {
-            return UNKNOWN;
-        }
-    }
-
-    if (parseIfaceStats(NULL, &stats) == 0) {
+    if (bpfGetIfaceStats(NULL, &stats) == 0) {
         return getStatsType(&stats, (StatsType) type);
     } else {
         return UNKNOWN;
     }
 }
 
-static jlong getIfaceStat(JNIEnv* env, jclass clazz, jstring iface, jint type,
-                          jboolean useBpfStats) {
+static jlong getIfaceStat(JNIEnv* env, jclass clazz, jstring iface, jint type) {
     ScopedUtfChars iface8(env, iface);
     if (iface8.c_str() == NULL) {
         return UNKNOWN;
@@ -175,33 +87,17 @@
 
     Stats stats = {};
 
-    if (useBpfStats) {
-        if (bpfGetIfaceStats(iface8.c_str(), &stats) == 0) {
-            return getStatsType(&stats, (StatsType) type);
-        } else {
-            return UNKNOWN;
-        }
-    }
-
-    if (parseIfaceStats(iface8.c_str(), &stats) == 0) {
+    if (bpfGetIfaceStats(iface8.c_str(), &stats) == 0) {
         return getStatsType(&stats, (StatsType) type);
     } else {
         return UNKNOWN;
     }
 }
 
-static jlong getUidStat(JNIEnv* env, jclass clazz, jint uid, jint type, jboolean useBpfStats) {
+static jlong getUidStat(JNIEnv* env, jclass clazz, jint uid, jint type) {
     Stats stats = {};
 
-    if (useBpfStats) {
-        if (bpfGetUidStats(uid, &stats) == 0) {
-            return getStatsType(&stats, (StatsType) type);
-        } else {
-            return UNKNOWN;
-        }
-    }
-
-    if (parseUidStats(uid, &stats) == 0) {
+    if (bpfGetUidStats(uid, &stats) == 0) {
         return getStatsType(&stats, (StatsType) type);
     } else {
         return UNKNOWN;
@@ -209,9 +105,9 @@
 }
 
 static const JNINativeMethod gMethods[] = {
-    {"nativeGetTotalStat", "(IZ)J", (void*) getTotalStat},
-    {"nativeGetIfaceStat", "(Ljava/lang/String;IZ)J", (void*) getIfaceStat},
-    {"nativeGetUidStat", "(IIZ)J", (void*) getUidStat},
+        {"nativeGetTotalStat", "(I)J", (void*)getTotalStat},
+        {"nativeGetIfaceStat", "(Ljava/lang/String;I)J", (void*)getIfaceStat},
+        {"nativeGetUidStat", "(II)J", (void*)getUidStat},
 };
 
 int register_android_server_net_NetworkStatsService(JNIEnv* env) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 727f265..3839a9f 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -8460,7 +8460,9 @@
     @Override
     public boolean hasDeviceOwner() {
         final CallerIdentity caller = getCallerIdentity();
-        Preconditions.checkCallAuthorization(isDeviceOwner(caller) || canManageUsers(caller));
+        Preconditions.checkCallAuthorization(isDeviceOwner(caller)
+                        || canManageUsers(caller)
+                        || hasCallingOrSelfPermission(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS));
         return mOwners.hasDeviceOwner();
     }
 
@@ -8640,7 +8642,8 @@
         if (!mHasFeature) {
             return null;
         }
-        Preconditions.checkCallAuthorization(canManageUsers(getCallerIdentity()));
+        Preconditions.checkCallAuthorization(canManageUsers(getCallerIdentity())
+                || hasCallingOrSelfPermission(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS));
 
         synchronized (getLockObject()) {
             if (!mOwners.hasDeviceOwner()) {
@@ -8986,7 +8989,8 @@
             return DevicePolicyManager.STATE_USER_UNMANAGED;
         }
         final CallerIdentity caller = getCallerIdentity();
-        Preconditions.checkCallAuthorization(canManageUsers(caller));
+        Preconditions.checkCallAuthorization(canManageUsers(caller)
+                || hasCallingOrSelfPermission(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS));
 
         return getUserProvisioningState(caller.getUserId());
     }
@@ -9240,7 +9244,8 @@
         if (!mHasFeature) {
             return null;
         }
-        Preconditions.checkCallAuthorization(canManageUsers(getCallerIdentity()));
+        Preconditions.checkCallAuthorization(canManageUsers(getCallerIdentity())
+                || hasCallingOrSelfPermission(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS));
         return getProfileOwnerNameUnchecked(userHandle);
     }
 
@@ -16466,7 +16471,8 @@
         if (!mHasFeature) {
             return false;
         }
-        Preconditions.checkCallAuthorization(canManageUsers(getCallerIdentity()));
+        Preconditions.checkCallAuthorization(canManageUsers(getCallerIdentity())
+                || hasCallingOrSelfPermission(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS));
 
         long id = mInjector.binderClearCallingIdentity();
         try {
@@ -16492,7 +16498,8 @@
         if (!mHasFeature) {
             return false;
         }
-        Preconditions.checkCallAuthorization(canManageUsers(getCallerIdentity()));
+        Preconditions.checkCallAuthorization(canManageUsers(getCallerIdentity())
+                || hasCallingOrSelfPermission(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS));
 
         return mInjector.binderWithCleanCallingIdentity(() -> isUnattendedManagedKioskUnchecked());
     }
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index accfdd3..2f9e334 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -267,6 +267,8 @@
             "com.android.server.stats.StatsCompanion$Lifecycle";
     private static final String STATS_PULL_ATOM_SERVICE_CLASS =
             "com.android.server.stats.pull.StatsPullAtomService";
+    private static final String STATS_BOOTSTRAP_ATOM_SERVICE_LIFECYCLE_CLASS =
+            "com.android.server.stats.bootstrap.StatsBootstrapAtomService$Lifecycle";
     private static final String USB_SERVICE_CLASS =
             "com.android.server.usb.UsbService$Lifecycle";
     private static final String MIDI_SERVICE_CLASS =
@@ -371,6 +373,8 @@
             "com.android.server.blob.BlobStoreManagerService";
     private static final String APP_SEARCH_MANAGER_SERVICE_CLASS =
             "com.android.server.appsearch.AppSearchManagerService";
+    private static final String ISOLATED_COMPILATION_SERVICE_CLASS =
+            "com.android.server.compos.IsolatedCompilationService";
     private static final String ROLLBACK_MANAGER_SERVICE_CLASS =
             "com.android.server.rollback.RollbackManagerService";
     private static final String ALARM_MANAGER_SERVICE_CLASS =
@@ -395,6 +399,11 @@
             "/apex/com.android.uwb/javalib/service-uwb.jar";
     private static final String UWB_SERVICE_CLASS = "com.android.server.uwb.UwbService";
 
+    private static final String SUPPLEMENTALPROCESS_APEX_PATH =
+            "/apex/com.android.supplementalprocess/javalib/service-supplementalprocess.jar";
+    private static final String SUPPLEMENTALPROCESS_SERVICE_CLASS =
+            "com.android.server.supplementalprocess.SupplementalProcessManagerService$Lifecycle";
+
     private static final String TETHERING_CONNECTOR_CLASS = "android.net.ITetheringConnector";
 
     private static final String PERSISTENT_DATA_BLOCK_PROP = "ro.frp.pst";
@@ -2474,11 +2483,9 @@
             t.traceEnd();
         }
 
-        if (!isWatch) {
-            t.traceBegin("StartMediaProjectionManager");
-            mSystemServiceManager.startService(MediaProjectionManagerService.class);
-            t.traceEnd();
-        }
+        t.traceBegin("StartMediaProjectionManager");
+        mSystemServiceManager.startService(MediaProjectionManagerService.class);
+        t.traceEnd();
 
        if (isWatch) {
             // Must be started before services that depend it, e.g. WearConnectivityService
@@ -2538,11 +2545,22 @@
         mSystemServiceManager.startService(STATS_PULL_ATOM_SERVICE_CLASS);
         t.traceEnd();
 
+        // Log atoms to statsd from bootstrap processes.
+        t.traceBegin("StatsBootstrapAtomService");
+        mSystemServiceManager.startService(STATS_BOOTSTRAP_ATOM_SERVICE_LIFECYCLE_CLASS);
+        t.traceEnd();
+
         // Incidentd and dumpstated helper
         t.traceBegin("StartIncidentCompanionService");
         mSystemServiceManager.startService(IncidentCompanionService.class);
         t.traceEnd();
 
+        // Supplemental Process
+        t.traceBegin("StartSupplementalProcessManagerService");
+        mSystemServiceManager.startServiceFromJar(SUPPLEMENTALPROCESS_SERVICE_CLASS,
+                SUPPLEMENTALPROCESS_APEX_PATH);
+        t.traceEnd();
+
         if (safeMode) {
             mActivityManagerService.enterSafeMode();
         }
@@ -2702,6 +2720,12 @@
         mSystemServiceManager.startService(APP_SEARCH_MANAGER_SERVICE_CLASS);
         t.traceEnd();
 
+        if (SystemProperties.getBoolean("ro.config.isolated_compilation_enabled", false)) {
+            t.traceBegin("IsolatedCompilationService");
+            mSystemServiceManager.startService(ISOLATED_COMPILATION_SERVICE_CLASS);
+            t.traceEnd();
+        }
+
         t.traceBegin("StartMediaCommunicationService");
         mSystemServiceManager.startService(MEDIA_COMMUNICATION_SERVICE_CLASS);
         t.traceEnd();
diff --git a/services/net/OWNERS b/services/net/OWNERS
index d3836d4..62c5737 100644
--- a/services/net/OWNERS
+++ b/services/net/OWNERS
@@ -1,8 +1,2 @@
 set noparent
-
-codewiz@google.com
-jchalard@google.com
-junyulai@google.com
-lorenzo@google.com
-reminv@google.com
-satk@google.com
+file:platform/packages/modules/Connectivity:master:/OWNERS_core_networking
diff --git a/services/people/java/com/android/server/people/data/CallLogQueryHelper.java b/services/people/java/com/android/server/people/data/CallLogQueryHelper.java
index 45e0aac..ff901af 100644
--- a/services/people/java/com/android/server/people/data/CallLogQueryHelper.java
+++ b/services/people/java/com/android/server/people/data/CallLogQueryHelper.java
@@ -93,6 +93,9 @@
                     hasResults = true;
                 }
             }
+        } catch (SecurityException ex) {
+            Slog.e(TAG, "Query call log failed: " + ex);
+            return false;
         }
         return hasResults;
     }
diff --git a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
index 8369319..62a16f7 100644
--- a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
+++ b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
@@ -91,10 +91,12 @@
             if (mIProfcollect == null) {
                 return;
             }
-            if (serviceHasSupportedTraceProvider()) {
-                registerObservers();
-            }
-            ProfcollectBGJobService.schedule(getContext());
+            BackgroundThread.get().getThreadHandler().post(() -> {
+                if (serviceHasSupportedTraceProvider()) {
+                    registerObservers();
+                    ProfcollectBGJobService.schedule(getContext());
+                }
+            });
         }
     }
 
@@ -234,14 +236,16 @@
                 "applaunch_trace_freq", 2);
         int randomNum = ThreadLocalRandom.current().nextInt(100);
         if (randomNum < traceFrequency) {
-            try {
-                if (DEBUG) {
-                    Log.d(LOG_TAG, "Tracing on app launch event: " + packageName);
-                }
-                mIProfcollect.trace_once("applaunch");
-            } catch (RemoteException e) {
-                Log.e(LOG_TAG, e.getMessage());
+            if (DEBUG) {
+                Log.d(LOG_TAG, "Tracing on app launch event: " + packageName);
             }
+            BackgroundThread.get().getThreadHandler().post(() -> {
+                try {
+                    mIProfcollect.trace_once("applaunch");
+                } catch (RemoteException e) {
+                    Log.e(LOG_TAG, e.getMessage());
+                }
+            });
         }
     }
 
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
index 349eb22..dc93e53 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
@@ -223,6 +223,7 @@
         AndroidPackage::isVendor,
         AndroidPackage::isVisibleToInstantApps,
         AndroidPackage::isVmSafeMode,
+        AndroidPackage::isResetEnabledSettingsOnAppDataCleared,
         AndroidPackage::getMaxAspectRatio,
         AndroidPackage::getMinAspectRatio,
         AndroidPackage::hasPreserveLegacyExternalStorage,
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
index 284a754..1ef9d13 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
@@ -67,7 +67,6 @@
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.anyBoolean;
 import static org.mockito.Mockito.anyInt;
-import static org.mockito.Mockito.anyLong;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doCallRealMethod;
 import static org.mockito.Mockito.doNothing;
@@ -2180,7 +2179,7 @@
         record.addConnection(binder, cr);
         client.mServices.addConnection(cr);
         binding.connections.add(cr);
-        doNothing().when(cr).trackProcState(anyInt(), anyInt(), anyLong());
+        doNothing().when(cr).trackProcState(anyInt(), anyInt());
         return record;
     }
 
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceHibernationTests.kt b/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceHibernationTests.kt
index bbfa461..cfc81e6 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceHibernationTests.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceHibernationTests.kt
@@ -29,6 +29,7 @@
 import com.android.server.apphibernation.AppHibernationService
 import com.android.server.extendedtestutils.wheneverStatic
 import com.android.server.testutils.whenever
+import org.junit.Assert
 import org.junit.Assert.assertFalse
 import org.junit.Assert.assertTrue
 import org.junit.Before
@@ -36,7 +37,6 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.Mock
-import org.mockito.Mockito
 import org.mockito.Mockito.verify
 import org.mockito.MockitoAnnotations
 
@@ -102,9 +102,10 @@
         val pm = createPackageManagerService()
         rule.system().validateFinalState()
 
-        pm.setPackageStoppedState(TEST_PACKAGE_NAME, true, TEST_USER_ID)
         TestableLooper.get(this).processAllMessages()
-        Mockito.clearInvocations(appHibernationManager)
+
+        whenever(appHibernationManager.isHibernatingForUser(TEST_PACKAGE_NAME, TEST_USER_ID))
+            .thenReturn(true)
 
         pm.setPackageStoppedState(TEST_PACKAGE_NAME, false, TEST_USER_ID)
 
@@ -115,6 +116,31 @@
     }
 
     @Test
+    fun testExitForceStop_nonExistingAppHibernationManager_doesNotThrowException() {
+        whenever(rule.mocks().injector.getLocalService(AppHibernationManagerInternal::class.java))
+            .thenReturn(null)
+
+        rule.system().stageScanExistingPackage(
+            TEST_PACKAGE_NAME,
+            1L,
+            rule.system().dataAppDirectory)
+        val pm = createPackageManagerService()
+        rule.system().validateFinalState()
+
+        TestableLooper.get(this).processAllMessages()
+
+        whenever(appHibernationManager.isHibernatingForUser(TEST_PACKAGE_NAME, TEST_USER_ID))
+            .thenReturn(true)
+
+        try {
+            pm.setPackageStoppedState(TEST_PACKAGE_NAME, false, TEST_USER_ID)
+            TestableLooper.get(this).processAllMessages()
+        } catch (e: Exception) {
+            Assert.fail("Method throws exception when AppHibernationManager is not ready.\n$e")
+        }
+    }
+
+    @Test
     fun testGetOptimizablePackages_ExcludesGloballyHibernatingPackages() {
         rule.system().stageScanExistingPackage(
             TEST_PACKAGE_NAME,
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/PackageSessionVerifierTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/PackageSessionVerifierTest.java
index 1e399ff..cf5967e 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/PackageSessionVerifierTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/PackageSessionVerifierTest.java
@@ -21,6 +21,7 @@
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -77,18 +78,26 @@
     public void checkRollbacks() throws Exception {
         StagingManager.StagedSession session1 = createStagedSession(111, "com.foo", 1);
         StagingManager.StagedSession session2 = createStagedSession(222, "com.bar", 2);
+        StagingManager.StagedSession session3 = createStagedSession(333, "com.baz", 3);
         session2.sessionParams().setInstallReason(PackageManager.INSTALL_REASON_ROLLBACK);
+        session3.sessionParams().setInstallReason(PackageManager.INSTALL_REASON_ROLLBACK);
+        when(session2.isDestroyed()).thenReturn(true);
         mSessionVerifier.storeSession(session1);
         mSessionVerifier.storeSession(session2);
+        mSessionVerifier.storeSession(session3);
+
+        // Non-rollback session shouldn't be failed by a destroyed session
+        mSessionVerifier.checkRollbacks(session2);
+        verify(session1, never()).setSessionFailed(anyInt(), anyString());
 
         // Non-rollback session should fail
-        mSessionVerifier.checkRollbacks(session2);
+        mSessionVerifier.checkRollbacks(session3);
         verify(session1, times(1)).setSessionFailed(anyInt(), anyString());
 
         // Yet another non-rollback session should fail
-        StagingManager.StagedSession session3 = createStagedSession(333, "com.baz", 3);
+        StagingManager.StagedSession session4 = createStagedSession(444, "com.fur", 4);
         assertThrows(PackageManagerException.class,
-                () -> mSessionVerifier.checkRollbacks(session3));
+                () -> mSessionVerifier.checkRollbacks(session4));
     }
 
     @Test
@@ -105,6 +114,11 @@
         StagingManager.StagedSession session3 = createStagedSession(333, "com.foo", 3);
         assertThrows(PackageManagerException.class,
                 () -> mSessionVerifier.checkOverlaps(session3, session3));
+        // session4 is earlier than session1, but it shouldn't fail session1
+        StagingManager.StagedSession session4 = createStagedSession(444, "com.foo", 0);
+        when(session4.isDestroyed()).thenReturn(true);
+        mSessionVerifier.checkOverlaps(session4, session4);
+        verify(session1, never()).setSessionFailed(anyInt(), anyString());
     }
 
     private PackageInstallerSession createSession(boolean isStaged, boolean isApex,
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index ba580ec..e3c60fd 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -108,6 +108,7 @@
 
     data: [
         ":JobTestApp",
+        ":StubTestApp",
     ],
 
     java_resources: [
diff --git a/services/tests/servicestests/AndroidTest.xml b/services/tests/servicestests/AndroidTest.xml
index 5a0f1ee..4c638d6 100644
--- a/services/tests/servicestests/AndroidTest.xml
+++ b/services/tests/servicestests/AndroidTest.xml
@@ -28,6 +28,17 @@
         <option name="test-file-name" value="SimpleServiceTestApp3.apk" />
     </target_preparer>
 
+    <!-- Create place to store apks -->
+    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+        <option name="run-command" value="mkdir -p /data/local/tmp/servicestests" />
+        <option name="teardown-command" value="rm -rf /data/local/tmp/servicestests"/>
+    </target_preparer>
+
+    <!-- Load additional APKs onto device -->
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+        <option name="push" value="StubTestApp.apk->/data/local/tmp/servicestests/StubTestApp.apk"/>
+    </target_preparer>
+
     <option name="test-tag" value="FrameworksServicesTests" />
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="com.android.frameworks.servicestests" />
diff --git a/services/tests/servicestests/src/com/android/server/BluetoothAirplaneModeListenerTest.java b/services/tests/servicestests/src/com/android/server/BluetoothAirplaneModeListenerTest.java
index 3ace3f4..a1d4c20 100644
--- a/services/tests/servicestests/src/com/android/server/BluetoothAirplaneModeListenerTest.java
+++ b/services/tests/servicestests/src/com/android/server/BluetoothAirplaneModeListenerTest.java
@@ -66,7 +66,7 @@
         when(mHelper.isBluetoothOn()).thenReturn(true);
         Assert.assertFalse(mBluetoothAirplaneModeListener.shouldSkipAirplaneModeChange());
 
-        when(mHelper.isA2dpOrHearingAidConnected()).thenReturn(true);
+        when(mHelper.isMediaProfileConnected()).thenReturn(true);
         Assert.assertFalse(mBluetoothAirplaneModeListener.shouldSkipAirplaneModeChange());
 
         when(mHelper.isAirplaneModeOn()).thenReturn(true);
@@ -83,7 +83,7 @@
     public void testHandleAirplaneModeChange_NotInvokeAirplaneModeChanged_NotPopToast() {
         mBluetoothAirplaneModeListener.mToastCount = BluetoothAirplaneModeListener.MAX_TOAST_COUNT;
         when(mHelper.isBluetoothOn()).thenReturn(true);
-        when(mHelper.isA2dpOrHearingAidConnected()).thenReturn(true);
+        when(mHelper.isMediaProfileConnected()).thenReturn(true);
         when(mHelper.isAirplaneModeOn()).thenReturn(true);
         mBluetoothAirplaneModeListener.handleAirplaneModeChange();
 
@@ -97,7 +97,7 @@
     public void testHandleAirplaneModeChange_NotInvokeAirplaneModeChanged_PopToast() {
         mBluetoothAirplaneModeListener.mToastCount = 0;
         when(mHelper.isBluetoothOn()).thenReturn(true);
-        when(mHelper.isA2dpOrHearingAidConnected()).thenReturn(true);
+        when(mHelper.isMediaProfileConnected()).thenReturn(true);
         when(mHelper.isAirplaneModeOn()).thenReturn(true);
         mBluetoothAirplaneModeListener.handleAirplaneModeChange();
 
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java
index 086e3c0..a83d51b 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java
@@ -68,6 +68,7 @@
 import android.accessibilityservice.AccessibilityServiceInfo;
 import android.accessibilityservice.AccessibilityTrace;
 import android.accessibilityservice.IAccessibilityServiceClient;
+import android.accessibilityservice.MagnificationConfig;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
@@ -650,8 +651,12 @@
         final float scale = 1.8f;
         final float centerX = 50.5f;
         final float centerY = 100.5f;
-        when(mMockMagnificationProcessor.setScaleAndCenter(displayId,
-                scale, centerX, centerY, true, SERVICE_ID)).thenReturn(true);
+        MagnificationConfig config = new MagnificationConfig.Builder()
+                .setScale(scale)
+                .setCenterX(centerX)
+                .setCenterY(centerY).build();
+        when(mMockMagnificationProcessor.setMagnificationConfig(displayId, config, true,
+                SERVICE_ID)).thenReturn(true);
         when(mMockSecurityPolicy.canControlMagnification(mServiceConnection)).thenReturn(false);
 
         final boolean result = mServiceConnection.setMagnificationScaleAndCenter(
@@ -665,8 +670,12 @@
         final float scale = 1.8f;
         final float centerX = 50.5f;
         final float centerY = 100.5f;
-        when(mMockMagnificationProcessor.setScaleAndCenter(displayId,
-                scale, centerX, centerY, true, SERVICE_ID)).thenReturn(true);
+        MagnificationConfig config = new MagnificationConfig.Builder()
+                .setScale(scale)
+                .setCenterX(centerX)
+                .setCenterY(centerY).build();
+        when(mMockMagnificationProcessor.setMagnificationConfig(displayId, config, true,
+                SERVICE_ID)).thenReturn(true);
         when(mMockSystemSupport.getCurrentUserIdLocked()).thenReturn(USER_ID2);
 
         final boolean result = mServiceConnection.setMagnificationScaleAndCenter(
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/MagnificationProcessorTest.java b/services/tests/servicestests/src/com/android/server/accessibility/MagnificationProcessorTest.java
index c412b94..2fd2816 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/MagnificationProcessorTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/MagnificationProcessorTest.java
@@ -16,25 +16,32 @@
 
 package com.android.server.accessibility;
 
+import static android.accessibilityservice.MagnificationConfig.FULLSCREEN_MODE;
+import static android.accessibilityservice.MagnificationConfig.WINDOW_MODE;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyFloat;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.accessibilityservice.MagnificationConfig;
 import android.graphics.Region;
 
 import com.android.server.accessibility.magnification.FullScreenMagnificationController;
 import com.android.server.accessibility.magnification.MagnificationController;
 import com.android.server.accessibility.magnification.MagnificationProcessor;
+import com.android.server.accessibility.magnification.WindowMagnificationManager;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.Mock;
+import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
-
+import org.mockito.stubbing.Answer;
 
 /**
  * Tests for the {@link MagnificationProcessor}
@@ -42,57 +49,115 @@
 public class MagnificationProcessorTest {
 
     private static final int TEST_DISPLAY = 0;
-
+    private static final int SERVICE_ID = 42;
+    private static final float TEST_SCALE = 1.8f;
+    private static final float TEST_CENTER_X = 50.5f;
+    private static final float TEST_CENTER_Y = 100.5f;
     private MagnificationProcessor mMagnificationProcessor;
     @Mock
     private MagnificationController mMockMagnificationController;
     @Mock
     private FullScreenMagnificationController mMockFullScreenMagnificationController;
+    @Mock
+    private WindowMagnificationManager mMockWindowMagnificationManager;
+    FullScreenMagnificationControllerStub mFullScreenMagnificationControllerStub;
+    WindowMagnificationManagerStub mWindowMagnificationManagerStub;
 
     @Before
+
     public void setup() {
         MockitoAnnotations.initMocks(this);
-
+        mFullScreenMagnificationControllerStub = new FullScreenMagnificationControllerStub(
+                mMockFullScreenMagnificationController);
+        mWindowMagnificationManagerStub = new WindowMagnificationManagerStub(
+                mMockWindowMagnificationManager);
         when(mMockMagnificationController.getFullScreenMagnificationController()).thenReturn(
                 mMockFullScreenMagnificationController);
+        when(mMockMagnificationController.getWindowMagnificationMgr()).thenReturn(
+                mMockWindowMagnificationManager);
         mMagnificationProcessor = new MagnificationProcessor(mMockMagnificationController);
     }
 
     @Test
-    public void getScale() {
-        final float result = 2;
-        when(mMockFullScreenMagnificationController.getScale(TEST_DISPLAY)).thenReturn(result);
+    public void getScale_fullscreenMode_expectedValue() {
+        final MagnificationConfig config = new MagnificationConfig.Builder()
+                .setMode(FULLSCREEN_MODE)
+                .setScale(TEST_SCALE).build();
+        setMagnificationActivated(TEST_DISPLAY, config);
 
         float scale = mMagnificationProcessor.getScale(TEST_DISPLAY);
 
-        assertEquals(scale, result, 0);
+        assertEquals(scale, TEST_SCALE, 0);
     }
 
     @Test
-    public void getCenterX_canControlMagnification_returnCenterX() {
-        final float result = 200;
-        when(mMockFullScreenMagnificationController.getCenterX(TEST_DISPLAY)).thenReturn(result);
+    public void getScale_windowMode_expectedValue() {
+        final MagnificationConfig config = new MagnificationConfig.Builder()
+                .setMode(WINDOW_MODE)
+                .setScale(TEST_SCALE).build();
+        setMagnificationActivated(TEST_DISPLAY, config);
+
+        float scale = mMagnificationProcessor.getScale(TEST_DISPLAY);
+
+        assertEquals(scale, TEST_SCALE, 0);
+    }
+
+    @Test
+    public void getCenterX_canControlFullscreenMagnification_returnCenterX() {
+        final MagnificationConfig config = new MagnificationConfig.Builder()
+                .setMode(FULLSCREEN_MODE)
+                .setCenterX(TEST_CENTER_X).build();
+        setMagnificationActivated(TEST_DISPLAY, config);
 
         float centerX = mMagnificationProcessor.getCenterX(
                 TEST_DISPLAY,  /* canControlMagnification= */true);
 
-        assertEquals(centerX, result, 0);
+        assertEquals(centerX, TEST_CENTER_X, 0);
     }
 
     @Test
-    public void getCenterY_canControlMagnification_returnCenterY() {
-        final float result = 300;
-        when(mMockFullScreenMagnificationController.getCenterY(TEST_DISPLAY)).thenReturn(result);
+    public void getCenterX_canControlWindowMagnification_returnCenterX() {
+        final MagnificationConfig config = new MagnificationConfig.Builder()
+                .setMode(WINDOW_MODE)
+                .setCenterX(TEST_CENTER_X).build();
+        setMagnificationActivated(TEST_DISPLAY, config);
+
+        float centerX = mMagnificationProcessor.getCenterX(
+                TEST_DISPLAY,  /* canControlMagnification= */true);
+
+        assertEquals(centerX, TEST_CENTER_X, 0);
+    }
+
+    @Test
+    public void getCenterY_canControlFullscreenMagnification_returnCenterY() {
+        final MagnificationConfig config = new MagnificationConfig.Builder()
+                .setMode(FULLSCREEN_MODE)
+                .setCenterY(TEST_CENTER_Y).build();
+        setMagnificationActivated(TEST_DISPLAY, config);
 
         float centerY = mMagnificationProcessor.getCenterY(
                 TEST_DISPLAY,  /* canControlMagnification= */false);
 
-        assertEquals(centerY, result, 0);
+        assertEquals(centerY, TEST_CENTER_Y, 0);
     }
 
     @Test
-    public void getMagnificationRegion_canControlMagnification_returnRegion() {
+    public void getCenterY_canControlWindowMagnification_returnCenterY() {
+        final MagnificationConfig config = new MagnificationConfig.Builder()
+                .setMode(WINDOW_MODE)
+                .setCenterY(TEST_CENTER_Y).build();
+        setMagnificationActivated(TEST_DISPLAY, config);
+
+        float centerY = mMagnificationProcessor.getCenterY(
+                TEST_DISPLAY,  /* canControlMagnification= */false);
+
+        assertEquals(centerY, TEST_CENTER_Y, 0);
+    }
+
+    @Test
+    public void getMagnificationRegion_canControlFullscreenMagnification_returnRegion() {
         final Region region = new Region(10, 20, 100, 200);
+        setMagnificationActivated(TEST_DISPLAY, FULLSCREEN_MODE);
         mMagnificationProcessor.getMagnificationRegion(TEST_DISPLAY,
                 region,  /* canControlMagnification= */true);
 
@@ -101,14 +166,25 @@
     }
 
     @Test
-    public void getMagnificationRegion_notRegistered_shouldRegisterThenUnregister() {
+    public void getMagnificationRegion_canControlWindowMagnification_returnRegion() {
         final Region region = new Region(10, 20, 100, 200);
+        setMagnificationActivated(TEST_DISPLAY, WINDOW_MODE);
+        mMagnificationProcessor.getMagnificationRegion(TEST_DISPLAY,
+                region,  /* canControlMagnification= */true);
+
+        verify(mMockWindowMagnificationManager).getMagnificationSourceBounds(eq(TEST_DISPLAY),
+                eq(region));
+    }
+
+    @Test
+    public void getMagnificationRegion_fullscreenModeNotRegistered_shouldRegisterThenUnregister() {
+        final Region region = new Region(10, 20, 100, 200);
+        setMagnificationActivated(TEST_DISPLAY, FULLSCREEN_MODE);
         doAnswer((invocation) -> {
             ((Region) invocation.getArguments()[1]).set(region);
             return null;
         }).when(mMockFullScreenMagnificationController).getMagnificationRegion(eq(TEST_DISPLAY),
                 any());
-        when(mMockFullScreenMagnificationController.isRegistered(TEST_DISPLAY)).thenReturn(false);
 
         final Region result = new Region();
         mMagnificationProcessor.getMagnificationRegion(TEST_DISPLAY,
@@ -119,44 +195,242 @@
     }
 
     @Test
-    public void getMagnificationCenterX_notRegistered_shouldRegisterThenUnregister() {
-        final float centerX = 480.0f;
-        when(mMockFullScreenMagnificationController.getCenterX(TEST_DISPLAY)).thenReturn(centerX);
-        when(mMockFullScreenMagnificationController.isRegistered(TEST_DISPLAY)).thenReturn(false);
+    public void getMagnificationCenterX_fullscreenModeNotRegistered_shouldRegisterThenUnregister() {
+        final MagnificationConfig config = new MagnificationConfig.Builder()
+                .setMode(FULLSCREEN_MODE)
+                .setCenterX(TEST_CENTER_X).build();
+        setMagnificationActivated(TEST_DISPLAY, config);
 
         final float result = mMagnificationProcessor.getCenterX(
                 TEST_DISPLAY,  /* canControlMagnification= */ true);
-        assertEquals(centerX, result, 0);
+        assertEquals(TEST_CENTER_X, result, 0);
         verify(mMockFullScreenMagnificationController).register(TEST_DISPLAY);
         verify(mMockFullScreenMagnificationController).unregister(TEST_DISPLAY);
     }
 
     @Test
-    public void getMagnificationCenterY_notRegistered_shouldRegisterThenUnregister() {
-        final float centerY = 640.0f;
-        when(mMockFullScreenMagnificationController.getCenterY(TEST_DISPLAY)).thenReturn(centerY);
-        when(mMockFullScreenMagnificationController.isRegistered(TEST_DISPLAY)).thenReturn(false);
+    public void getMagnificationCenterY_fullscreenModeNotRegistered_shouldRegisterThenUnregister() {
+        final MagnificationConfig config = new MagnificationConfig.Builder()
+                .setMode(FULLSCREEN_MODE)
+                .setCenterY(TEST_CENTER_Y).build();
+        setMagnificationActivated(TEST_DISPLAY, config);
 
         final float result = mMagnificationProcessor.getCenterY(
                 TEST_DISPLAY,  /* canControlMagnification= */ true);
-        assertEquals(centerY, result, 0);
+        assertEquals(TEST_CENTER_Y, result, 0);
         verify(mMockFullScreenMagnificationController).register(TEST_DISPLAY);
         verify(mMockFullScreenMagnificationController).unregister(TEST_DISPLAY);
     }
 
     @Test
-    public void setMagnificationScaleAndCenter_notRegistered_shouldRegister() {
-        final int serviceId = 42;
-        final float scale = 1.8f;
-        final float centerX = 50.5f;
-        final float centerY = 100.5f;
-        when(mMockFullScreenMagnificationController.setScaleAndCenter(TEST_DISPLAY,
-                scale, centerX, centerY, true, serviceId)).thenReturn(true);
-        when(mMockFullScreenMagnificationController.isRegistered(TEST_DISPLAY)).thenReturn(false);
+    public void getCurrentMode_configDefaultMode_returnActivatedMode() {
+        final int targetMode = WINDOW_MODE;
+        setMagnificationActivated(TEST_DISPLAY, targetMode);
 
-        final boolean result = mMagnificationProcessor.setScaleAndCenter(
-                TEST_DISPLAY, scale, centerX, centerY, true, serviceId);
+        int currentMode = mMagnificationProcessor.getControllingMode(TEST_DISPLAY);
+
+        assertEquals(WINDOW_MODE, currentMode);
+    }
+
+    @Test
+    public void reset_fullscreenMagnificationActivated() {
+        setMagnificationActivated(TEST_DISPLAY, FULLSCREEN_MODE);
+
+        mMagnificationProcessor.reset(TEST_DISPLAY, /* animate= */false);
+
+        verify(mMockFullScreenMagnificationController).reset(TEST_DISPLAY, false);
+    }
+
+    @Test
+    public void reset_windowMagnificationActivated() {
+        setMagnificationActivated(TEST_DISPLAY, WINDOW_MODE);
+
+        mMagnificationProcessor.reset(TEST_DISPLAY, /* animate= */false);
+
+        verify(mMockWindowMagnificationManager).reset(TEST_DISPLAY);
+    }
+
+    @Test
+    public void setMagnificationConfig_fullscreenModeNotRegistered_shouldRegister() {
+        final MagnificationConfig config = new MagnificationConfig.Builder()
+                .setMode(FULLSCREEN_MODE)
+                .setScale(TEST_SCALE)
+                .setCenterX(TEST_CENTER_X)
+                .setCenterY(TEST_CENTER_Y).build();
+        setMagnificationActivated(TEST_DISPLAY, config);
+
+        final boolean result = mMagnificationProcessor.setMagnificationConfig(
+                TEST_DISPLAY, config, true, SERVICE_ID);
         assertTrue(result);
         verify(mMockFullScreenMagnificationController).register(TEST_DISPLAY);
     }
+
+    @Test
+    public void setMagnificationConfig_windowMode_enableMagnification() {
+        final MagnificationConfig config = new MagnificationConfig.Builder()
+                .setMode(WINDOW_MODE)
+                .setScale(TEST_SCALE)
+                .setCenterX(TEST_CENTER_X)
+                .setCenterY(TEST_CENTER_Y).build();
+        setMagnificationActivated(TEST_DISPLAY, config);
+
+        final boolean result = mMagnificationProcessor.setMagnificationConfig(
+                TEST_DISPLAY, config, true, SERVICE_ID);
+
+        assertTrue(result);
+    }
+
+    @Test
+    public void setMagnificationConfig_fullscreenEnabled_expectedConfigValues() {
+        final MagnificationConfig config = new MagnificationConfig.Builder()
+                .setMode(FULLSCREEN_MODE)
+                .setScale(TEST_SCALE)
+                .setCenterX(TEST_CENTER_X)
+                .setCenterY(TEST_CENTER_Y).build();
+        setMagnificationActivated(TEST_DISPLAY, config);
+     //   mMockFullScreenMagnificationController.unregister(TEST_DISPLAY);
+        mMagnificationProcessor.setMagnificationConfig(
+                TEST_DISPLAY, config, true, SERVICE_ID);
+
+        final MagnificationConfig result = mMagnificationProcessor.getMagnificationConfig(
+                TEST_DISPLAY);
+
+        assertConfigEquals(config, result);
+    }
+
+    @Test
+    public void setMagnificationConfig_windowEnabled_expectedConfigValues() {
+        final MagnificationConfig config = new MagnificationConfig.Builder()
+                .setMode(WINDOW_MODE)
+                .setScale(TEST_SCALE)
+                .setCenterX(TEST_CENTER_X)
+                .setCenterY(TEST_CENTER_Y).build();
+        setMagnificationActivated(TEST_DISPLAY, config);
+
+        mMagnificationProcessor.setMagnificationConfig(
+                TEST_DISPLAY, config, true, SERVICE_ID);
+
+        final MagnificationConfig result = mMagnificationProcessor.getMagnificationConfig(
+                TEST_DISPLAY);
+
+        assertConfigEquals(config, result);
+    }
+
+    private void setMagnificationActivated(int displayId, int configMode) {
+        setMagnificationActivated(displayId,
+                new MagnificationConfig.Builder().setMode(configMode).build());
+    }
+
+    private void setMagnificationActivated(int displayId, MagnificationConfig config) {
+        when(mMockMagnificationController.isActivated(displayId, config.getMode())).thenReturn(
+                true);
+        mMagnificationProcessor.setMagnificationConfig(displayId, config, false, SERVICE_ID);
+        if (config.getMode() == FULLSCREEN_MODE) {
+            when(mMockMagnificationController.isActivated(displayId, WINDOW_MODE)).thenReturn(
+                    false);
+            mFullScreenMagnificationControllerStub.resetAndStubMethods();
+            mMockFullScreenMagnificationController.setScaleAndCenter(displayId, config.getScale(),
+                    config.getCenterX(), config.getCenterY(), true, SERVICE_ID);
+        } else if (config.getMode() == WINDOW_MODE) {
+            when(mMockMagnificationController.isActivated(displayId, FULLSCREEN_MODE)).thenReturn(
+                    false);
+            mWindowMagnificationManagerStub.resetAndStubMethods();
+            mMockWindowMagnificationManager.enableWindowMagnification(displayId, config.getScale(),
+                    config.getCenterX(), config.getCenterY());
+        }
+    }
+
+    private void assertConfigEquals(MagnificationConfig expected, MagnificationConfig actual) {
+        assertEquals(expected.getMode(), actual.getMode());
+        assertEquals(expected.getScale(), actual.getScale(), 0);
+        assertEquals(expected.getCenterX(), actual.getCenterX(), 0);
+        assertEquals(expected.getCenterY(), actual.getCenterY(), 0);
+    }
+
+    private static class FullScreenMagnificationControllerStub {
+        private final FullScreenMagnificationController mScreenMagnificationController;
+        private float mScale = 1.0f;
+        private float mCenterX = 0;
+        private float mCenterY = 0;
+        private boolean mIsRegistered = false;
+
+        FullScreenMagnificationControllerStub(
+                FullScreenMagnificationController screenMagnificationController) {
+            mScreenMagnificationController = screenMagnificationController;
+        }
+
+        private void stubMethods() {
+            doAnswer(invocation -> mScale).when(mScreenMagnificationController).getScale(
+                    TEST_DISPLAY);
+            doAnswer(invocation -> mCenterX).when(mScreenMagnificationController).getCenterX(
+                    TEST_DISPLAY);
+            doAnswer(invocation -> mCenterY).when(mScreenMagnificationController).getCenterY(
+                    TEST_DISPLAY);
+            doAnswer(invocation -> mIsRegistered).when(mScreenMagnificationController).isRegistered(
+                    TEST_DISPLAY);
+            Answer enableMagnificationStubAnswer = invocation -> {
+                mScale = invocation.getArgument(1);
+                mCenterX = invocation.getArgument(2);
+                mCenterY = invocation.getArgument(3);
+                return true;
+            };
+            doAnswer(enableMagnificationStubAnswer).when(
+                    mScreenMagnificationController).setScaleAndCenter(eq(TEST_DISPLAY), anyFloat(),
+                    anyFloat(), anyFloat(), eq(true), eq(SERVICE_ID));
+
+            Answer registerStubAnswer = invocation -> {
+                mIsRegistered = true;
+                return true;
+            };
+            doAnswer(registerStubAnswer).when(
+                    mScreenMagnificationController).register(eq(TEST_DISPLAY));
+
+            Answer unregisterStubAnswer = invocation -> {
+                mIsRegistered = false;
+                return true;
+            };
+            doAnswer(unregisterStubAnswer).when(
+                    mScreenMagnificationController).unregister(eq(TEST_DISPLAY));
+        }
+
+        public void resetAndStubMethods() {
+            Mockito.reset(mScreenMagnificationController);
+            stubMethods();
+        }
+    }
+
+    private static class WindowMagnificationManagerStub {
+        private final WindowMagnificationManager mWindowMagnificationManager;
+        private float mScale = 1.0f;
+        private float mCenterX = 0;
+        private float mCenterY = 0;
+
+        WindowMagnificationManagerStub(
+                WindowMagnificationManager windowMagnificationManager) {
+            mWindowMagnificationManager = windowMagnificationManager;
+        }
+
+        private void stubMethods() {
+            doAnswer(invocation -> mScale).when(mWindowMagnificationManager).getScale(
+                    TEST_DISPLAY);
+            doAnswer(invocation -> mCenterX).when(mWindowMagnificationManager).getCenterX(
+                    TEST_DISPLAY);
+            doAnswer(invocation -> mCenterY).when(mWindowMagnificationManager).getCenterY(
+                    TEST_DISPLAY);
+            Answer enableWindowMagnificationStubAnswer = invocation -> {
+                mScale = invocation.getArgument(1);
+                mCenterX = invocation.getArgument(2);
+                mCenterY = invocation.getArgument(3);
+                return true;
+            };
+            doAnswer(enableWindowMagnificationStubAnswer).when(
+                    mWindowMagnificationManager).enableWindowMagnification(eq(TEST_DISPLAY),
+                    anyFloat(), anyFloat(), anyFloat());
+        }
+
+        public void resetAndStubMethods() {
+            Mockito.reset(mWindowMagnificationManager);
+            stubMethods();
+        }
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java
index 15ba358..02c0aca 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java
@@ -377,6 +377,17 @@
     }
 
     @Test
+    public void resetMagnification_enabled_windowMagnifierDisabled() {
+        mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
+        mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 3f, NaN, NaN);
+        assertTrue(mWindowMagnificationManager.isWindowMagnifierEnabled(TEST_DISPLAY));
+
+        mWindowMagnificationManager.reset(TEST_DISPLAY);
+
+        assertFalse(mWindowMagnificationManager.isWindowMagnifierEnabled(TEST_DISPLAY));
+    }
+
+    @Test
     public void onScreenOff_windowMagnifierIsEnabled_removeButtonAndDisableWindowMagnification()
             throws RemoteException {
         mWindowMagnificationManager.requestConnection(true);
diff --git a/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java b/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
index bf621b1..f664517 100644
--- a/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
@@ -56,12 +56,9 @@
     private static final int DARKENING_LIGHT_DEBOUNCE_CONFIG = 0;
     private static final float DOZE_SCALE_FACTOR = 0.0f;
     private static final boolean RESET_AMBIENT_LUX_AFTER_WARMUP_CONFIG = false;
-    private static final int DISPLAY_ID = 0;
-    private static final int LAYER_STACK = 0;
     private static final int LIGHT_SENSOR_WARMUP_TIME = 0;
 
     private Context mContext;
-    private LogicalDisplay mLogicalDisplay;
     private AutomaticBrightnessController mController;
 
     @Mock SensorManager mSensorManager;
@@ -69,7 +66,6 @@
     @Mock HysteresisLevels mAmbientBrightnessThresholds;
     @Mock HysteresisLevels mScreenBrightnessThresholds;
     @Mock Handler mNoOpHandler;
-    @Mock DisplayDevice mDisplayDevice;
     @Mock HighBrightnessModeController mHbmController;
 
     @Before
@@ -79,7 +75,6 @@
         MockitoAnnotations.initMocks(this);
 
         mContext = InstrumentationRegistry.getContext();
-        mLogicalDisplay = new LogicalDisplay(DISPLAY_ID, LAYER_STACK, mDisplayDevice);
     }
 
     @After
@@ -104,7 +99,7 @@
                 BRIGHTNESS_MAX_FLOAT, DOZE_SCALE_FACTOR, LIGHT_SENSOR_RATE,
                 INITIAL_LIGHT_SENSOR_RATE, BRIGHTENING_LIGHT_DEBOUNCE_CONFIG,
                 DARKENING_LIGHT_DEBOUNCE_CONFIG, RESET_AMBIENT_LUX_AFTER_WARMUP_CONFIG,
-                mAmbientBrightnessThresholds, mScreenBrightnessThresholds, mLogicalDisplay,
+                mAmbientBrightnessThresholds, mScreenBrightnessThresholds,
                 mContext, mHbmController
         );
 
diff --git a/services/tests/servicestests/src/com/android/server/health/HealthServiceWrapperTest.java b/services/tests/servicestests/src/com/android/server/health/HealthServiceWrapperTest.java
index c97a67b..16d97a4 100644
--- a/services/tests/servicestests/src/com/android/server/health/HealthServiceWrapperTest.java
+++ b/services/tests/servicestests/src/com/android/server/health/HealthServiceWrapperTest.java
@@ -19,11 +19,12 @@
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.fail;
 
+import static org.mockito.AdditionalMatchers.not;
 import static org.mockito.Mockito.*;
 
-import android.hardware.health.V2_0.IHealth;
 import android.hidl.manager.V1_0.IServiceManager;
 import android.hidl.manager.V1_0.IServiceNotification;
+import android.os.IServiceCallback;
 import android.os.RemoteException;
 
 import androidx.test.filters.SmallTest;
@@ -44,28 +45,47 @@
 
 @RunWith(AndroidJUnit4.class)
 public class HealthServiceWrapperTest {
-
     @Mock IServiceManager mMockedManager;
-    @Mock IHealth mMockedHal;
-    @Mock IHealth mMockedHal2;
+    @Mock android.hardware.health.V2_0.IHealth mMockedHal;
+    @Mock android.hardware.health.V2_0.IHealth mMockedHal2;
 
     @Mock HealthServiceWrapperHidl.Callback mCallback;
     @Mock HealthServiceWrapperHidl.IServiceManagerSupplier mManagerSupplier;
     @Mock HealthServiceWrapperHidl.IHealthSupplier mHealthServiceSupplier;
+
+    @Mock android.hardware.health.IHealth.Stub mMockedAidlHal;
+    @Mock android.hardware.health.IHealth.Stub mMockedAidlHal2;
+    @Mock HealthServiceWrapperAidl.ServiceManagerStub mMockedAidlManager;
+    @Mock HealthRegCallbackAidl mRegCallbackAidl;
+
     HealthServiceWrapper mWrapper;
 
     private static final String VENDOR = HealthServiceWrapperHidl.INSTANCE_VENDOR;
+    private static final String AIDL_SERVICE_NAME = HealthServiceWrapperAidl.SERVICE_NAME;
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
+
+        // Mocks the conversion between IHealth and IBinder.
+        when(mMockedAidlHal.asBinder()).thenCallRealMethod(); // returns mMockedAidlHal
+        when(mMockedAidlHal2.asBinder()).thenCallRealMethod(); // returns mMockedAidlHal2
+        when(mMockedAidlHal.queryLocalInterface(android.hardware.health.IHealth.DESCRIPTOR))
+                .thenReturn(mMockedAidlHal);
+        when(mMockedAidlHal2.queryLocalInterface(android.hardware.health.IHealth.DESCRIPTOR))
+                .thenReturn(mMockedAidlHal2);
     }
 
     @After
     public void tearDown() {
+        validateMockitoUsage();
         if (mWrapper != null) mWrapper.getHandlerThread().quitSafely();
     }
 
+    public static <T> ArgumentMatcher<T> isOneOf(T[] collection) {
+        return isOneOf(Arrays.asList(collection));
+    }
+
     public static <T> ArgumentMatcher<T> isOneOf(Collection<T> collection) {
         return new ArgumentMatcher<T>() {
             @Override
@@ -75,13 +95,39 @@
 
             @Override
             public String toString() {
-                return collection.toString();
+                return "is one of " + collection.toString();
             }
         };
     }
 
-    private void initForInstances(String... instanceNamesArr) throws Exception {
-        final Collection<String> instanceNames = Arrays.asList(instanceNamesArr);
+    /**
+     * Set up mock objects to pretend that the given AIDL and HIDL instances exists.
+     *
+     * <p>Also, when registering service notifications, the mocked service managers immediately
+     * sends 3 registration notifications, including 2 referring to the original HAL and 1 referring
+     * to the new HAL.
+     *
+     * @param aidlInstances e.g. {"android.hardware.health.IHealth/default"}
+     * @param hidlInstances e.g. {"default", "backup"}
+     * @throws Exception
+     */
+    private void initForInstances(String[] aidlInstances, String[] hidlInstances) throws Exception {
+        doAnswer(
+                (invocation) -> {
+                    sendAidlRegCallback(invocation, mMockedAidlHal);
+                    sendAidlRegCallback(invocation, mMockedAidlHal);
+                    sendAidlRegCallback(invocation, mMockedAidlHal2);
+                    return null;
+                })
+                .when(mMockedAidlManager)
+                .registerForNotifications(
+                        argThat(isOneOf(aidlInstances)), any(IServiceCallback.class));
+        when(mMockedAidlManager.waitForDeclaredService(argThat(isOneOf(aidlInstances))))
+                .thenReturn(mMockedAidlHal)
+                .thenThrow(new RuntimeException("waitForDeclaredService called more than once"));
+        when(mMockedAidlManager.waitForDeclaredService(not(argThat(isOneOf(aidlInstances)))))
+                .thenReturn(null);
+
         doAnswer(
                 (invocation) -> {
                     // technically, preexisting is ignored by
@@ -93,8 +139,8 @@
                 })
                 .when(mMockedManager)
                 .registerForNotifications(
-                        eq(IHealth.kInterfaceName),
-                        argThat(isOneOf(instanceNames)),
+                        eq(android.hardware.health.V2_0.IHealth.kInterfaceName),
+                        argThat(isOneOf(hidlInstances)),
                         any(IServiceNotification.class));
 
         doReturn(mMockedManager).when(mManagerSupplier).get();
@@ -104,7 +150,7 @@
                 .doReturn(mMockedHal2) // notification 3
                 .doThrow(new RuntimeException("Should not call getService for more than 4 times"))
                 .when(mHealthServiceSupplier)
-                .get(argThat(isOneOf(instanceNames)));
+                .get(argThat(isOneOf(hidlInstances)));
     }
 
     private void waitHandlerThreadFinish() throws Exception {
@@ -121,19 +167,62 @@
             throws Exception {
         ((IServiceNotification) invocation.getArguments()[2])
                 .onRegistration(
-                        IHealth.kInterfaceName, (String) invocation.getArguments()[1], preexisting);
+                        android.hardware.health.V2_0.IHealth.kInterfaceName,
+                        (String) invocation.getArguments()[1],
+                        preexisting);
+    }
+
+    private static void sendAidlRegCallback(
+            InvocationOnMock invocation, android.hardware.health.IHealth service) throws Exception {
+        ((IServiceCallback) invocation.getArguments()[1])
+                .onRegistration((String) invocation.getArguments()[0], service.asBinder());
     }
 
     private void createWrapper() throws RemoteException {
-        mWrapper = HealthServiceWrapper.create(mCallback, mManagerSupplier, mHealthServiceSupplier);
+        mWrapper =
+                HealthServiceWrapper.create(
+                        mRegCallbackAidl,
+                        mMockedAidlManager,
+                        mCallback,
+                        mManagerSupplier,
+                        mHealthServiceSupplier);
     }
 
     @SmallTest
     @Test
-    public void testWrapPreferVendor() throws Exception {
-        initForInstances(VENDOR);
+    public void testWrapAidlOnly() throws Exception {
+        initForInstances(new String[] {AIDL_SERVICE_NAME}, new String[0]);
         createWrapper();
         waitHandlerThreadFinish();
+        verify(mRegCallbackAidl, times(1)).onRegistration(same(null), same(mMockedAidlHal));
+        verify(mRegCallbackAidl, never())
+                .onRegistration(same(mMockedAidlHal), same(mMockedAidlHal));
+        verify(mRegCallbackAidl, times(1))
+                .onRegistration(same(mMockedAidlHal), same(mMockedAidlHal2));
+        verify(mCallback, never()).onRegistration(any(), any(), anyString());
+    }
+
+    @SmallTest
+    @Test
+    public void testWrapPreferAidl() throws Exception {
+        initForInstances(new String[] {AIDL_SERVICE_NAME}, new String[] {VENDOR});
+        createWrapper();
+        waitHandlerThreadFinish();
+        verify(mRegCallbackAidl, times(1)).onRegistration(same(null), same(mMockedAidlHal));
+        verify(mRegCallbackAidl, never())
+                .onRegistration(same(mMockedAidlHal), same(mMockedAidlHal));
+        verify(mRegCallbackAidl, times(1))
+                .onRegistration(same(mMockedAidlHal), same(mMockedAidlHal2));
+        verify(mCallback, never()).onRegistration(any(), any(), anyString());
+    }
+
+    @SmallTest
+    @Test
+    public void testWrapFallbackHidl() throws Exception {
+        initForInstances(new String[0], new String[] {VENDOR});
+        createWrapper();
+        waitHandlerThreadFinish();
+        verify(mRegCallbackAidl, never()).onRegistration(any(), any());
         verify(mCallback, times(1)).onRegistration(same(null), same(mMockedHal), eq(VENDOR));
         verify(mCallback, never()).onRegistration(same(mMockedHal), same(mMockedHal), anyString());
         verify(mCallback, times(1)).onRegistration(same(mMockedHal), same(mMockedHal2), eq(VENDOR));
@@ -142,7 +231,7 @@
     @SmallTest
     @Test
     public void testNoService() throws Exception {
-        initForInstances("unrelated");
+        initForInstances(new String[0], new String[] {"unrelated"});
         try {
             createWrapper();
             fail("Expect NoSuchElementException");
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
index 734fdba..6a85c8b 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
@@ -16,6 +16,8 @@
 
 package com.android.server.pm;
 
+import static com.android.compatibility.common.util.ShellUtils.runShellCommand;
+
 import static com.google.common.truth.Truth.assertWithMessage;
 
 import static org.junit.Assert.fail;
@@ -27,11 +29,17 @@
 import static java.lang.reflect.Modifier.isStatic;
 
 import android.annotation.Nullable;
+import android.app.AppGlobals;
 import android.content.IIntentReceiver;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
 import android.os.Bundle;
+import android.os.UserHandle;
+import android.os.UserManager;
 import android.util.SparseArray;
 
+import androidx.test.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.internal.util.HexDump;
@@ -42,6 +50,7 @@
 
 import org.junit.After;
 import org.junit.Assert;
+import org.junit.Assume;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -62,6 +71,11 @@
 // bit FrameworksServicesTests:com.android.server.pm.PackageManagerServiceTest
 @RunWith(AndroidJUnit4.class)
 public class PackageManagerServiceTest {
+
+    private static final String TEST_DATA_PATH = "/data/local/tmp/servicestests/";
+    private static final String TEST_APP_APK = "StubTestApp.apk";
+    private static final String TEST_PKG_NAME = "com.android.servicestests.apps.stubapp";
+
     @Before
     public void setUp() throws Exception {
     }
@@ -509,6 +523,11 @@
         for (Method m : coreMethods) {
             if (m != null) {
                 final String name = "ComputerEngine." + displayName(m);
+                if (name.contains(".lambda$static")) {
+                    // skip static lambda function
+                    continue;
+                }
+
                 final int modifiers = m.getModifiers();
                 if (isPrivate(modifiers)) {
                     // Okay
@@ -598,4 +617,119 @@
         Collections.sort(knownPackageIds);
         return knownPackageIds;
     }
+
+    @Test
+    public void testInstallReason_afterUpdate_keepUnchanged() throws Exception {
+        final IPackageManager pm = AppGlobals.getPackageManager();
+        final File testApk = new File(TEST_DATA_PATH, TEST_APP_APK);
+        try {
+            // Try to install test APK with reason INSTALL_REASON_POLICY
+            runShellCommand("pm install --install-reason 1 " + testApk);
+            assertWithMessage("The install reason of test APK is incorrect.").that(
+                    pm.getInstallReason(TEST_PKG_NAME, UserHandle.myUserId())).isEqualTo(
+                    PackageManager.INSTALL_REASON_POLICY);
+
+            // Try to update test APK with different reason INSTALL_REASON_USER
+            runShellCommand("pm install --install-reason 4 " + testApk);
+            assertWithMessage("The install reason should keep unchanged after update.").that(
+                    pm.getInstallReason(TEST_PKG_NAME, UserHandle.myUserId())).isEqualTo(
+                    PackageManager.INSTALL_REASON_POLICY);
+        } finally {
+            runShellCommand("pm uninstall " + TEST_PKG_NAME);
+        }
+    }
+
+    @Test
+    public void testInstallReason_userRemainsUninstalled_keepUnknown() throws Exception {
+        Assume.assumeTrue(UserManager.supportsMultipleUsers());
+        final IPackageManager pm = AppGlobals.getPackageManager();
+        final UserManager um = UserManager.get(
+                InstrumentationRegistry.getInstrumentation().getContext());
+        final File testApk = new File(TEST_DATA_PATH, TEST_APP_APK);
+        int userId = UserHandle.USER_NULL;
+        try {
+            // Try to install test APK with reason INSTALL_REASON_POLICY
+            runShellCommand("pm install --install-reason 1 " + testApk);
+            assertWithMessage("The install reason of test APK is incorrect.").that(
+                    pm.getInstallReason(TEST_PKG_NAME, UserHandle.myUserId())).isEqualTo(
+                    PackageManager.INSTALL_REASON_POLICY);
+
+            // Create and start the 2nd user.
+            userId = um.createUser("Test User", 0 /* flags */).getUserHandle().getIdentifier();
+            runShellCommand("am start-user -w " + userId);
+            // Since the test APK isn't installed on the 2nd user, the reason should be unknown.
+            assertWithMessage("The install reason in 2nd user should be unknown.").that(
+                    pm.getInstallReason(TEST_PKG_NAME, userId)).isEqualTo(
+                    PackageManager.INSTALL_REASON_UNKNOWN);
+
+            // Try to update test APK with different reason INSTALL_REASON_USER
+            runShellCommand("pm install --install-reason 4 " + testApk);
+            assertWithMessage("The install reason in 2nd user should keep unknown.").that(
+                    pm.getInstallReason(TEST_PKG_NAME, userId)).isEqualTo(
+                    PackageManager.INSTALL_REASON_UNKNOWN);
+        } finally {
+            runShellCommand("pm uninstall " + TEST_PKG_NAME);
+            if (userId != UserHandle.USER_NULL) {
+                um.removeUser(userId);
+            }
+        }
+    }
+
+    @Test
+    public void testInstallReason_installForAllUsers_sameReason() throws Exception {
+        Assume.assumeTrue(UserManager.supportsMultipleUsers());
+        final IPackageManager pm = AppGlobals.getPackageManager();
+        final UserManager um = UserManager.get(
+                InstrumentationRegistry.getInstrumentation().getContext());
+        final File testApk = new File(TEST_DATA_PATH, TEST_APP_APK);
+        int userId = UserHandle.USER_NULL;
+        try {
+            // Create and start the 2nd user.
+            userId = um.createUser("Test User", 0 /* flags */).getUserHandle().getIdentifier();
+            runShellCommand("am start-user -w " + userId);
+
+            // Try to install test APK to all users with reason INSTALL_REASON_POLICY
+            runShellCommand("pm install --install-reason 1 " + testApk);
+            assertWithMessage("The install reason is inconsistent across users.").that(
+                    pm.getInstallReason(TEST_PKG_NAME, UserHandle.myUserId())).isEqualTo(
+                    pm.getInstallReason(TEST_PKG_NAME, userId));
+        } finally {
+            runShellCommand("pm uninstall " + TEST_PKG_NAME);
+            if (userId != UserHandle.USER_NULL) {
+                um.removeUser(userId);
+            }
+        }
+    }
+
+    @Test
+    public void testInstallReason_installSeparately_withSeparatedReason() throws Exception {
+        Assume.assumeTrue(UserManager.supportsMultipleUsers());
+        final IPackageManager pm = AppGlobals.getPackageManager();
+        final UserManager um = UserManager.get(
+                InstrumentationRegistry.getInstrumentation().getContext());
+        final File testApk = new File(TEST_DATA_PATH, TEST_APP_APK);
+        int userId = UserHandle.USER_NULL;
+        try {
+            // Create and start the 2nd user.
+            userId = um.createUser("Test User", 0 /* flags */).getUserHandle().getIdentifier();
+            runShellCommand("am start-user -w " + userId);
+
+            // Try to install test APK on the current user with reason INSTALL_REASON_POLICY
+            runShellCommand("pm install --user cur --install-reason 1 " + testApk);
+            assertWithMessage("The install reason on the current user is incorrect.").that(
+                    pm.getInstallReason(TEST_PKG_NAME, UserHandle.myUserId())).isEqualTo(
+                    PackageManager.INSTALL_REASON_POLICY);
+
+            // Try to install test APK on the 2nd user with reason INSTALL_REASON_USER
+            runShellCommand("pm install --user " + userId + " --install-reason 4 " + testApk);
+            assertWithMessage("The install reason on the 2nd user is incorrect.").that(
+                    pm.getInstallReason(TEST_PKG_NAME, userId)).isEqualTo(
+                    PackageManager.INSTALL_REASON_USER);
+        } finally {
+            runShellCommand("pm uninstall " + TEST_PKG_NAME);
+            if (userId != UserHandle.USER_NULL) {
+                um.removeUser(userId);
+            }
+        }
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
index 5d93e3d..ab37e9b 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -25,6 +25,7 @@
 import static android.content.pm.parsing.ParsingPackageUtils.parsePublicKey;
 import static android.content.res.Resources.ID_NULL;
 
+import static org.hamcrest.CoreMatchers.equalTo;
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.CoreMatchers.not;
 import static org.hamcrest.CoreMatchers.notNullValue;
@@ -86,7 +87,6 @@
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
-import java.util.Map;
 import java.util.Set;
 import java.util.UUID;
 import java.util.concurrent.CountDownLatch;
@@ -1004,6 +1004,13 @@
         }
     }
 
+    private void verifyKeySetData(PackageKeySetData originalData, PackageKeySetData testData) {
+        assertThat(originalData.getProperSigningKeySet(),
+                equalTo(testData.getProperSigningKeySet()));
+        assertThat(originalData.getUpgradeKeySets(), is(testData.getUpgradeKeySets()));
+        assertThat(originalData.getAliases(), is(testData.getAliases()));
+    }
+
     private void verifySettingCopy(PackageSetting origPkgSetting, PackageSetting testPkgSetting) {
         assertThat(origPkgSetting, is(not(testPkgSetting)));
         assertThat(origPkgSetting.getAppId(), is(testPkgSetting.getAppId()));
@@ -1018,8 +1025,7 @@
         assertSame(origPkgSetting.getInstallSource(), testPkgSetting.getInstallSource());
         assertThat(origPkgSetting.isInstallPermissionsFixed(),
                 is(testPkgSetting.isInstallPermissionsFixed()));
-        assertSame(origPkgSetting.getKeySetData(), testPkgSetting.getKeySetData());
-        assertThat(origPkgSetting.getKeySetData(), is(testPkgSetting.getKeySetData()));
+        verifyKeySetData(origPkgSetting.getKeySetData(), testPkgSetting.getKeySetData());
         assertThat(origPkgSetting.getLastUpdateTime(), is(testPkgSetting.getLastUpdateTime()));
         assertSame(origPkgSetting.getLegacyNativeLibraryPath(),
                 testPkgSetting.getLegacyNativeLibraryPath());
diff --git a/services/tests/servicestests/src/com/android/server/power/NotifierTest.java b/services/tests/servicestests/src/com/android/server/power/NotifierTest.java
index 6e3f754..a3223d6d 100644
--- a/services/tests/servicestests/src/com/android/server/power/NotifierTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/NotifierTest.java
@@ -34,6 +34,7 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.ServiceManager;
+import android.os.VibrationAttributes;
 import android.os.Vibrator;
 import android.os.test.TestLooper;
 import android.provider.Settings;
@@ -108,7 +109,7 @@
         mTestLooper.dispatchAll();
 
         // THEN the device vibrates once
-        verify(mVibrator, times(1)).vibrate(any(), any());
+        verify(mVibrator, times(1)).vibrate(any(), any(VibrationAttributes.class));
     }
 
     @Test
@@ -123,7 +124,7 @@
         mTestLooper.dispatchAll();
 
         // THEN the device doesn't vibrate
-        verify(mVibrator, never()).vibrate(any(), any());
+        verify(mVibrator, never()).vibrate(any(), any(VibrationAttributes.class));
     }
 
     @Test
@@ -138,7 +139,7 @@
         mTestLooper.dispatchAll();
 
         // THEN the device vibrates once
-        verify(mVibrator, times(1)).vibrate(any(), any());
+        verify(mVibrator, times(1)).vibrate(any(), any(VibrationAttributes.class));
     }
 
     @Test
@@ -153,7 +154,7 @@
         mTestLooper.dispatchAll();
 
         // THEN the device doesn't vibrate
-        verify(mVibrator, never()).vibrate(any(), any());
+        verify(mVibrator, never()).vibrate(any(), any(VibrationAttributes.class));
     }
 
     @Test
@@ -171,7 +172,7 @@
         mTestLooper.dispatchAll();
 
         // THEN the device doesn't vibrate
-        verify(mVibrator, never()).vibrate(any(), any());
+        verify(mVibrator, never()).vibrate(any(), any(VibrationAttributes.class));
     }
 
     @Test
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/ConfigurationInternalTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/ConfigurationInternalTest.java
index 117680b..809b2f9 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/ConfigurationInternalTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/ConfigurationInternalTest.java
@@ -48,13 +48,13 @@
                 .setUserConfigAllowed(true)
                 .setTelephonyDetectionFeatureSupported(true)
                 .setGeoDetectionFeatureSupported(true)
-                .setAutoDetectionEnabled(true)
-                .setLocationEnabled(true)
-                .setGeoDetectionEnabled(true)
+                .setAutoDetectionEnabledSetting(true)
+                .setLocationEnabledSetting(true)
+                .setGeoDetectionEnabledSetting(true)
                 .build();
         {
             ConfigurationInternal autoOnConfig = new ConfigurationInternal.Builder(baseConfig)
-                    .setAutoDetectionEnabled(true)
+                    .setAutoDetectionEnabledSetting(true)
                     .build();
             assertTrue(autoOnConfig.getAutoDetectionEnabledSetting());
             assertTrue(autoOnConfig.getGeoDetectionEnabledSetting());
@@ -79,7 +79,7 @@
 
         {
             ConfigurationInternal autoOffConfig = new ConfigurationInternal.Builder(baseConfig)
-                    .setAutoDetectionEnabled(false)
+                    .setAutoDetectionEnabledSetting(false)
                     .build();
             assertFalse(autoOffConfig.getAutoDetectionEnabledSetting());
             assertTrue(autoOffConfig.getGeoDetectionEnabledSetting());
@@ -110,13 +110,13 @@
                 .setUserConfigAllowed(false)
                 .setTelephonyDetectionFeatureSupported(true)
                 .setGeoDetectionFeatureSupported(true)
-                .setAutoDetectionEnabled(true)
-                .setLocationEnabled(true)
-                .setGeoDetectionEnabled(true)
+                .setAutoDetectionEnabledSetting(true)
+                .setLocationEnabledSetting(true)
+                .setGeoDetectionEnabledSetting(true)
                 .build();
         {
             ConfigurationInternal autoOnConfig = new ConfigurationInternal.Builder(baseConfig)
-                    .setAutoDetectionEnabled(true)
+                    .setAutoDetectionEnabledSetting(true)
                     .build();
             assertTrue(autoOnConfig.getAutoDetectionEnabledSetting());
             assertTrue(autoOnConfig.getGeoDetectionEnabledSetting());
@@ -142,7 +142,7 @@
 
         {
             ConfigurationInternal autoOffConfig = new ConfigurationInternal.Builder(baseConfig)
-                    .setAutoDetectionEnabled(false)
+                    .setAutoDetectionEnabledSetting(false)
                     .build();
             assertFalse(autoOffConfig.getAutoDetectionEnabledSetting());
             assertTrue(autoOffConfig.getGeoDetectionEnabledSetting());
@@ -174,13 +174,13 @@
                 .setUserConfigAllowed(true)
                 .setTelephonyDetectionFeatureSupported(false)
                 .setGeoDetectionFeatureSupported(false)
-                .setAutoDetectionEnabled(true)
-                .setLocationEnabled(true)
-                .setGeoDetectionEnabled(true)
+                .setAutoDetectionEnabledSetting(true)
+                .setLocationEnabledSetting(true)
+                .setGeoDetectionEnabledSetting(true)
                 .build();
         {
             ConfigurationInternal autoOnConfig = new ConfigurationInternal.Builder(baseConfig)
-                    .setAutoDetectionEnabled(true)
+                    .setAutoDetectionEnabledSetting(true)
                     .build();
             assertTrue(autoOnConfig.getAutoDetectionEnabledSetting());
             assertTrue(autoOnConfig.getGeoDetectionEnabledSetting());
@@ -203,7 +203,7 @@
         }
         {
             ConfigurationInternal autoOffConfig = new ConfigurationInternal.Builder(baseConfig)
-                    .setAutoDetectionEnabled(false)
+                    .setAutoDetectionEnabledSetting(false)
                     .build();
             assertFalse(autoOffConfig.getAutoDetectionEnabledSetting());
             assertTrue(autoOffConfig.getGeoDetectionEnabledSetting());
@@ -236,13 +236,13 @@
                 .setUserConfigAllowed(true)
                 .setTelephonyDetectionFeatureSupported(true)
                 .setGeoDetectionFeatureSupported(false)
-                .setAutoDetectionEnabled(true)
-                .setLocationEnabled(true)
-                .setGeoDetectionEnabled(true)
+                .setAutoDetectionEnabledSetting(true)
+                .setLocationEnabledSetting(true)
+                .setGeoDetectionEnabledSetting(true)
                 .build();
         {
             ConfigurationInternal autoOnConfig = new ConfigurationInternal.Builder(baseConfig)
-                    .setAutoDetectionEnabled(true)
+                    .setAutoDetectionEnabledSetting(true)
                     .build();
             assertTrue(autoOnConfig.getAutoDetectionEnabledSetting());
             assertTrue(autoOnConfig.getGeoDetectionEnabledSetting());
@@ -266,7 +266,7 @@
         }
         {
             ConfigurationInternal autoOffConfig = new ConfigurationInternal.Builder(baseConfig)
-                    .setAutoDetectionEnabled(false)
+                    .setAutoDetectionEnabledSetting(false)
                     .build();
             assertFalse(autoOffConfig.getAutoDetectionEnabledSetting());
             assertTrue(autoOffConfig.getGeoDetectionEnabledSetting());
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/FakeServiceConfigAccessor.java b/services/tests/servicestests/src/com/android/server/timezonedetector/FakeServiceConfigAccessor.java
new file mode 100644
index 0000000..9d1c74b
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/FakeServiceConfigAccessor.java
@@ -0,0 +1,213 @@
+/*
+ * 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.assertNotNull;
+import static org.junit.Assert.fail;
+
+import android.annotation.NonNull;
+import android.annotation.UserIdInt;
+import android.app.time.TimeZoneCapabilities;
+import android.app.time.TimeZoneCapabilitiesAndConfig;
+import android.app.time.TimeZoneConfiguration;
+
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+
+/** A partially implemented, fake implementation of ServiceConfigAccessor for tests. */
+class FakeServiceConfigAccessor implements ServiceConfigAccessor {
+
+    private final List<ConfigurationChangeListener> mConfigurationInternalChangeListeners =
+            new ArrayList<>();
+    private ConfigurationInternal mConfigurationInternal;
+
+    @Override
+    public void addConfigurationInternalChangeListener(ConfigurationChangeListener listener) {
+        mConfigurationInternalChangeListeners.add(listener);
+    }
+
+    @Override
+    public void removeConfigurationInternalChangeListener(ConfigurationChangeListener listener) {
+        mConfigurationInternalChangeListeners.remove(listener);
+    }
+
+    @Override
+    public ConfigurationInternal getCurrentUserConfigurationInternal() {
+        return mConfigurationInternal;
+    }
+
+    @Override
+    public boolean updateConfiguration(
+            @UserIdInt int userID, @NonNull TimeZoneConfiguration requestedChanges) {
+        assertNotNull(mConfigurationInternal);
+        assertNotNull(requestedChanges);
+
+        // Simulate the real strategy's behavior: the new configuration will be updated to be the
+        // old configuration merged with the new if the user has the capability to up the settings.
+        // Then, if the configuration changed, the change listener is invoked.
+        TimeZoneCapabilitiesAndConfig capabilitiesAndConfig =
+                mConfigurationInternal.createCapabilitiesAndConfig();
+        TimeZoneCapabilities capabilities = capabilitiesAndConfig.getCapabilities();
+        TimeZoneConfiguration configuration = capabilitiesAndConfig.getConfiguration();
+        TimeZoneConfiguration newConfiguration =
+                capabilities.tryApplyConfigChanges(configuration, requestedChanges);
+        if (newConfiguration == null) {
+            return false;
+        }
+
+        if (!newConfiguration.equals(capabilitiesAndConfig.getConfiguration())) {
+            mConfigurationInternal = mConfigurationInternal.merge(newConfiguration);
+
+            // Note: Unlike the real strategy, the listeners are invoked synchronously.
+            simulateConfigurationChangeForTests();
+        }
+        return true;
+    }
+
+    void initializeConfiguration(ConfigurationInternal configurationInternal) {
+        mConfigurationInternal = configurationInternal;
+    }
+
+    void simulateConfigurationChangeForTests() {
+        for (ConfigurationChangeListener listener : mConfigurationInternalChangeListeners) {
+            listener.onChange();
+        }
+    }
+
+    @Override
+    public ConfigurationInternal getConfigurationInternal(int userId) {
+        assertEquals("Multi-user testing not supported currently",
+                userId, mConfigurationInternal.getUserId());
+        return mConfigurationInternal;
+    }
+
+    @Override
+    public void addLocationTimeZoneManagerConfigListener(ConfigurationChangeListener listener) {
+        failUnimplemented();
+    }
+
+    @Override
+    public boolean isTelephonyTimeZoneDetectionFeatureSupported() {
+        return failUnimplemented();
+    }
+
+    @Override
+    public boolean isGeoTimeZoneDetectionFeatureSupportedInConfig() {
+        return failUnimplemented();
+    }
+
+    @Override
+    public boolean isGeoTimeZoneDetectionFeatureSupported() {
+        return failUnimplemented();
+    }
+
+    @Override
+    public String getPrimaryLocationTimeZoneProviderPackageName() {
+        return failUnimplemented();
+    }
+
+    @Override
+    public void setTestPrimaryLocationTimeZoneProviderPackageName(
+            String testPrimaryLocationTimeZoneProviderPackageName) {
+        failUnimplemented();
+    }
+
+    @Override
+    public boolean isTestPrimaryLocationTimeZoneProvider() {
+        return failUnimplemented();
+    }
+
+    @Override
+    public String getSecondaryLocationTimeZoneProviderPackageName() {
+        return failUnimplemented();
+    }
+
+    @Override
+    public void setTestSecondaryLocationTimeZoneProviderPackageName(
+            String testSecondaryLocationTimeZoneProviderPackageName) {
+        failUnimplemented();
+    }
+
+    @Override
+    public boolean isTestSecondaryLocationTimeZoneProvider() {
+        return failUnimplemented();
+    }
+
+    @Override
+    public void setRecordProviderStateChanges(boolean enabled) {
+        failUnimplemented();
+    }
+
+    @Override
+    public boolean getRecordProviderStateChanges() {
+        return failUnimplemented();
+    }
+
+    @Override
+    public @ProviderMode String getPrimaryLocationTimeZoneProviderMode() {
+        return failUnimplemented();
+    }
+
+    @Override
+    public @ProviderMode String getSecondaryLocationTimeZoneProviderMode() {
+        return failUnimplemented();
+    }
+
+    @Override
+    public boolean isGeoDetectionEnabledForUsersByDefault() {
+        return failUnimplemented();
+    }
+
+    @Override
+    public Optional<Boolean> getGeoDetectionSettingEnabledOverride() {
+        return failUnimplemented();
+    }
+
+    @Override
+    public Duration getLocationTimeZoneProviderInitializationTimeout() {
+        return failUnimplemented();
+    }
+
+    @Override
+    public Duration getLocationTimeZoneProviderInitializationTimeoutFuzz() {
+        return failUnimplemented();
+    }
+
+    @Override
+    public Duration getLocationTimeZoneUncertaintyDelay() {
+        return failUnimplemented();
+    }
+
+    @Override
+    public Duration getLocationTimeZoneProviderEventFilteringAgeThreshold() {
+        return failUnimplemented();
+    }
+
+    @Override
+    public void resetVolatileTestConfig() {
+        failUnimplemented();
+    }
+
+    @SuppressWarnings("UnusedReturnValue")
+    private static <T> T failUnimplemented() {
+        fail("Unimplemented");
+        return 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 11d5f3f..ee3195e 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/FakeTimeZoneDetectorStrategy.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/FakeTimeZoneDetectorStrategy.java
@@ -16,26 +16,16 @@
 package com.android.server.timezonedetector;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
 
 import android.annotation.NonNull;
 import android.annotation.UserIdInt;
-import android.app.time.TimeZoneCapabilities;
-import android.app.time.TimeZoneCapabilitiesAndConfig;
-import android.app.time.TimeZoneConfiguration;
 import android.app.timezonedetector.ManualTimeZoneSuggestion;
 import android.app.timezonedetector.TelephonyTimeZoneSuggestion;
 import android.util.IndentingPrintWriter;
 
 class FakeTimeZoneDetectorStrategy implements TimeZoneDetectorStrategy {
 
-    private ConfigurationChangeListener mConfigurationChangeListener;
-
-    // Fake state
-    private ConfigurationInternal mConfigurationInternal;
-
     // Call tracking.
     private GeolocationTimeZoneSuggestion mLastGeolocationSuggestion;
     private ManualTimeZoneSuggestion mLastManualSuggestion;
@@ -43,59 +33,6 @@
     private boolean mDumpCalled;
 
     @Override
-    public void addConfigChangeListener(@NonNull ConfigurationChangeListener listener) {
-        if (mConfigurationChangeListener != null) {
-            fail("Fake only supports one listener");
-        }
-        mConfigurationChangeListener = listener;
-    }
-
-    @Override
-    public ConfigurationInternal getConfigurationInternal(int userId) {
-        if (mConfigurationInternal.getUserId() != userId) {
-            fail("Fake only supports one user");
-        }
-        return mConfigurationInternal;
-    }
-
-    @Override
-    public ConfigurationInternal getCurrentUserConfigurationInternal() {
-        return mConfigurationInternal;
-    }
-
-    @Override
-    public boolean updateConfiguration(
-            @UserIdInt int userID, @NonNull TimeZoneConfiguration requestedChanges) {
-        assertNotNull(mConfigurationInternal);
-        assertNotNull(requestedChanges);
-
-        // Simulate the real strategy's behavior: the new configuration will be updated to be the
-        // old configuration merged with the new if the user has the capability to up the settings.
-        // Then, if the configuration changed, the change listener is invoked.
-        TimeZoneCapabilitiesAndConfig capabilitiesAndConfig =
-                mConfigurationInternal.createCapabilitiesAndConfig();
-        TimeZoneCapabilities capabilities = capabilitiesAndConfig.getCapabilities();
-        TimeZoneConfiguration configuration = capabilitiesAndConfig.getConfiguration();
-        TimeZoneConfiguration newConfiguration =
-                capabilities.tryApplyConfigChanges(configuration, requestedChanges);
-        if (newConfiguration == null) {
-            return false;
-        }
-
-        if (!newConfiguration.equals(capabilitiesAndConfig.getConfiguration())) {
-            mConfigurationInternal = mConfigurationInternal.merge(newConfiguration);
-
-            // Note: Unlike the real strategy, the listeners is invoked synchronously.
-            mConfigurationChangeListener.onChange();
-        }
-        return true;
-    }
-
-    public void simulateConfigurationChangeForTests() {
-        mConfigurationChangeListener.onChange();
-    }
-
-    @Override
     public void suggestGeolocationTimeZone(GeolocationTimeZoneSuggestion timeZoneSuggestion) {
         mLastGeolocationSuggestion = timeZoneSuggestion;
     }
@@ -123,10 +60,6 @@
         mDumpCalled = true;
     }
 
-    void initializeConfiguration(ConfigurationInternal configurationInternal) {
-        mConfigurationInternal = configurationInternal;
-    }
-
     void resetCallTracking() {
         mLastGeolocationSuggestion = null;
         mLastManualSuggestion = null;
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorInternalImplTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorInternalImplTest.java
index 45c5b6c..c5bab76 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorInternalImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorInternalImplTest.java
@@ -16,7 +16,6 @@
 
 package com.android.server.timezonedetector;
 
-import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.mock;
 
 import android.content.Context;
@@ -77,18 +76,6 @@
         mFakeTimeZoneDetectorStrategy.verifySuggestGeolocationTimeZoneCalled(timeZoneSuggestion);
     }
 
-    @Test
-    public void testAddConfigurationListener() throws Exception {
-        boolean[] changeCalled = new boolean[2];
-        mTimeZoneDetectorInternal.addConfigurationListener(() -> changeCalled[0] = true);
-        mTimeZoneDetectorInternal.addConfigurationListener(() -> changeCalled[1] = true);
-
-        mFakeTimeZoneDetectorStrategy.simulateConfigurationChangeForTests();
-
-        assertTrue(changeCalled[0]);
-        assertTrue(changeCalled[1]);
-    }
-
     private static GeolocationTimeZoneSuggestion createGeolocationTimeZoneSuggestion() {
         return GeolocationTimeZoneSuggestion.createCertainSuggestion(
                 ARBITRARY_ELAPSED_REALTIME_MILLIS, ARBITRARY_ZONE_IDS);
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java
index 1e55c7b..ce3b78e 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java
@@ -65,6 +65,7 @@
     private HandlerThread mHandlerThread;
     private TestHandler mTestHandler;
     private TestCallerIdentityInjector mTestCallerIdentityInjector;
+    private FakeServiceConfigAccessor mFakeServiceConfigAccessor;
     private FakeTimeZoneDetectorStrategy mFakeTimeZoneDetectorStrategy;
 
 
@@ -81,10 +82,11 @@
         mTestCallerIdentityInjector.initializeCallingUserId(ARBITRARY_USER_ID);
 
         mFakeTimeZoneDetectorStrategy = new FakeTimeZoneDetectorStrategy();
+        mFakeServiceConfigAccessor = new FakeServiceConfigAccessor();
 
         mTimeZoneDetectorService = new TimeZoneDetectorService(
                 mMockContext, mTestHandler, mTestCallerIdentityInjector,
-                mFakeTimeZoneDetectorStrategy);
+                mFakeServiceConfigAccessor, mFakeTimeZoneDetectorStrategy);
     }
 
     @After
@@ -114,7 +116,7 @@
 
         ConfigurationInternal configuration =
                 createConfigurationInternal(true /* autoDetectionEnabled*/);
-        mFakeTimeZoneDetectorStrategy.initializeConfiguration(configuration);
+        mFakeServiceConfigAccessor.initializeConfiguration(configuration);
 
         assertEquals(configuration.createCapabilitiesAndConfig(),
                 mTimeZoneDetectorService.getCapabilitiesAndConfig());
@@ -160,7 +162,7 @@
     public void testListenerRegistrationAndCallbacks() throws Exception {
         ConfigurationInternal initialConfiguration =
                 createConfigurationInternal(false /* autoDetectionEnabled */);
-        mFakeTimeZoneDetectorStrategy.initializeConfiguration(initialConfiguration);
+        mFakeServiceConfigAccessor.initializeConfiguration(initialConfiguration);
 
         IBinder mockListenerBinder = mock(IBinder.class);
         ITimeZoneDetectorListener mockListener = mock(ITimeZoneDetectorListener.class);
@@ -367,16 +369,16 @@
     }
 
     private static ConfigurationInternal createConfigurationInternal(boolean autoDetectionEnabled) {
-        // Default geo detection settings from auto detection settings - they are not important to
-        // the tests.
+        // Default geo detection settings from the auto detection setting - they are not important
+        // to the tests.
         final boolean geoDetectionEnabled = autoDetectionEnabled;
         return new ConfigurationInternal.Builder(ARBITRARY_USER_ID)
                 .setTelephonyDetectionFeatureSupported(true)
                 .setGeoDetectionFeatureSupported(true)
                 .setUserConfigAllowed(true)
-                .setAutoDetectionEnabled(autoDetectionEnabled)
-                .setLocationEnabled(geoDetectionEnabled)
-                .setGeoDetectionEnabled(geoDetectionEnabled)
+                .setAutoDetectionEnabledSetting(autoDetectionEnabled)
+                .setLocationEnabledSetting(geoDetectionEnabled)
+                .setGeoDetectionEnabledSetting(geoDetectionEnabled)
                 .build();
     }
 
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 1826812..91e8d16 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java
@@ -32,17 +32,13 @@
 import static com.android.server.timezonedetector.TimeZoneDetectorStrategyImpl.TELEPHONY_SCORE_USAGE_THRESHOLD;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
 
 import android.annotation.ElapsedRealtimeLong;
 import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.annotation.UserIdInt;
-import android.app.time.TimeZoneConfiguration;
 import android.app.timezonedetector.ManualTimeZoneSuggestion;
 import android.app.timezonedetector.TelephonyTimeZoneSuggestion;
 import android.app.timezonedetector.TelephonyTimeZoneSuggestion.MatchType;
@@ -88,88 +84,68 @@
                     TELEPHONY_SCORE_HIGHEST),
     };
 
-    private static final ConfigurationInternal CONFIG_INT_USER_RESTRICTED_AUTO_DISABLED =
+    private static final ConfigurationInternal CONFIG_USER_RESTRICTED_AUTO_DISABLED =
             new ConfigurationInternal.Builder(USER_ID)
                     .setUserConfigAllowed(false)
                     .setTelephonyDetectionFeatureSupported(true)
                     .setGeoDetectionFeatureSupported(true)
-                    .setAutoDetectionEnabled(false)
-                    .setLocationEnabled(true)
-                    .setGeoDetectionEnabled(false)
+                    .setAutoDetectionEnabledSetting(false)
+                    .setLocationEnabledSetting(true)
+                    .setGeoDetectionEnabledSetting(false)
                     .build();
 
-    private static final ConfigurationInternal CONFIG_INT_USER_RESTRICTED_AUTO_ENABLED =
+    private static final ConfigurationInternal CONFIG_USER_RESTRICTED_AUTO_ENABLED =
             new ConfigurationInternal.Builder(USER_ID)
                     .setUserConfigAllowed(false)
                     .setTelephonyDetectionFeatureSupported(true)
                     .setGeoDetectionFeatureSupported(true)
-                    .setAutoDetectionEnabled(true)
-                    .setLocationEnabled(true)
-                    .setGeoDetectionEnabled(true)
+                    .setAutoDetectionEnabledSetting(true)
+                    .setLocationEnabledSetting(true)
+                    .setGeoDetectionEnabledSetting(true)
                     .build();
 
-    private static final ConfigurationInternal CONFIG_INT_AUTO_DETECT_NOT_SUPPORTED =
+    private static final ConfigurationInternal CONFIG_AUTO_DETECT_NOT_SUPPORTED =
             new ConfigurationInternal.Builder(USER_ID)
                     .setUserConfigAllowed(true)
                     .setTelephonyDetectionFeatureSupported(false)
                     .setGeoDetectionFeatureSupported(false)
-                    .setAutoDetectionEnabled(false)
-                    .setLocationEnabled(true)
-                    .setGeoDetectionEnabled(false)
+                    .setAutoDetectionEnabledSetting(false)
+                    .setLocationEnabledSetting(true)
+                    .setGeoDetectionEnabledSetting(false)
                     .build();
 
-    private static final ConfigurationInternal CONFIG_INT_TELEPHONY_SUPPORTED_GEO_NOT_SUPPORTED =
-            new ConfigurationInternal.Builder(USER_ID)
-                    .setUserConfigAllowed(true)
-                    .setTelephonyDetectionFeatureSupported(true)
-                    .setGeoDetectionFeatureSupported(false)
-                    .setAutoDetectionEnabled(true)
-                    .setLocationEnabled(true)
-                    .setGeoDetectionEnabled(true)
-                    .build();
-
-    private static final ConfigurationInternal CONFIG_INT_AUTO_DISABLED_GEO_DISABLED =
+    private static final ConfigurationInternal CONFIG_AUTO_DISABLED_GEO_DISABLED =
             new ConfigurationInternal.Builder(USER_ID)
                     .setUserConfigAllowed(true)
                     .setTelephonyDetectionFeatureSupported(true)
                     .setGeoDetectionFeatureSupported(true)
-                    .setAutoDetectionEnabled(false)
-                    .setLocationEnabled(true)
-                    .setGeoDetectionEnabled(false)
+                    .setAutoDetectionEnabledSetting(false)
+                    .setLocationEnabledSetting(true)
+                    .setGeoDetectionEnabledSetting(false)
                     .build();
 
-    private static final ConfigurationInternal CONFIG_INT_AUTO_ENABLED_GEO_DISABLED =
+    private static final ConfigurationInternal CONFIG_AUTO_ENABLED_GEO_DISABLED =
             new ConfigurationInternal.Builder(USER_ID)
                     .setTelephonyDetectionFeatureSupported(true)
                     .setGeoDetectionFeatureSupported(true)
                     .setUserConfigAllowed(true)
-                    .setAutoDetectionEnabled(true)
-                    .setLocationEnabled(true)
-                    .setGeoDetectionEnabled(false)
+                    .setAutoDetectionEnabledSetting(true)
+                    .setLocationEnabledSetting(true)
+                    .setGeoDetectionEnabledSetting(false)
                     .build();
 
-    private static final ConfigurationInternal CONFIG_INT_AUTO_ENABLED_GEO_ENABLED =
+    private static final ConfigurationInternal CONFIG_AUTO_ENABLED_GEO_ENABLED =
             new ConfigurationInternal.Builder(USER_ID)
                     .setTelephonyDetectionFeatureSupported(true)
                     .setGeoDetectionFeatureSupported(true)
                     .setUserConfigAllowed(true)
-                    .setAutoDetectionEnabled(true)
-                    .setLocationEnabled(true)
-                    .setGeoDetectionEnabled(true)
+                    .setAutoDetectionEnabledSetting(true)
+                    .setLocationEnabledSetting(true)
+                    .setGeoDetectionEnabledSetting(true)
                     .build();
 
-    private static final TimeZoneConfiguration CONFIG_AUTO_DISABLED =
-            createConfig(false /* autoDetection */, null);
-    private static final TimeZoneConfiguration CONFIG_AUTO_ENABLED =
-            createConfig(true /* autoDetection */, null);
-    private static final TimeZoneConfiguration CONFIG_GEO_DETECTION_ENABLED =
-            createConfig(null, true /* geoDetection */);
-    private static final TimeZoneConfiguration CONFIG_GEO_DETECTION_DISABLED =
-            createConfig(null, false /* geoDetection */);
-
     private TimeZoneDetectorStrategyImpl mTimeZoneDetectorStrategy;
     private FakeEnvironment mFakeEnvironment;
-    private MockConfigChangeListener mMockConfigChangeListener;
 
     // A fake source of time for suggestions. This will typically be incremented after every use.
     @ElapsedRealtimeLong private long mElapsedRealtimeMillis;
@@ -177,132 +153,8 @@
     @Before
     public void setUp() {
         mFakeEnvironment = new FakeEnvironment();
-        mMockConfigChangeListener = new MockConfigChangeListener();
+        mFakeEnvironment.initializeConfig(CONFIG_AUTO_DISABLED_GEO_DISABLED);
         mTimeZoneDetectorStrategy = new TimeZoneDetectorStrategyImpl(mFakeEnvironment);
-        mTimeZoneDetectorStrategy.addConfigChangeListener(mMockConfigChangeListener);
-    }
-
-    @Test
-    public void testGetCurrentUserConfiguration() {
-        new Script().initializeConfig(CONFIG_INT_AUTO_ENABLED_GEO_DISABLED);
-        ConfigurationInternal expectedConfiguration =
-                mFakeEnvironment.getConfigurationInternal(USER_ID);
-        assertEquals(expectedConfiguration,
-                mTimeZoneDetectorStrategy.getCurrentUserConfigurationInternal());
-    }
-
-    @Test
-    public void testUpdateConfiguration_unrestricted() {
-        Script script = new Script().initializeConfig(CONFIG_INT_AUTO_ENABLED_GEO_DISABLED);
-
-        // Set the configuration with auto detection enabled.
-        script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */);
-
-        // Nothing should have happened: it was initialized in this state.
-        script.verifyConfigurationNotChanged();
-
-        // Update the configuration with auto detection disabled.
-        script.simulateUpdateConfiguration(
-                USER_ID, CONFIG_AUTO_DISABLED, true /* expectedResult */);
-
-        // The settings should have been changed and the StrategyListener onChange() called.
-        script.verifyConfigurationChangedAndReset(CONFIG_INT_AUTO_DISABLED_GEO_DISABLED);
-
-        // Update the configuration with auto detection enabled.
-        script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */);
-
-        // The settings should have been changed and the StrategyListener onChange() called.
-        script.verifyConfigurationChangedAndReset(CONFIG_INT_AUTO_ENABLED_GEO_DISABLED);
-
-        // Update the configuration to enable geolocation time zone detection.
-        script.simulateUpdateConfiguration(
-                USER_ID, CONFIG_GEO_DETECTION_ENABLED,  true /* expectedResult */);
-
-        // The settings should have been changed and the StrategyListener onChange() called.
-        script.verifyConfigurationChangedAndReset(CONFIG_INT_AUTO_ENABLED_GEO_ENABLED);
-    }
-
-    @Test
-    public void testUpdateConfiguration_restricted() {
-        Script script = new Script().initializeConfig(CONFIG_INT_USER_RESTRICTED_AUTO_ENABLED);
-
-        // Try to update the configuration with auto detection disabled.
-        script.simulateUpdateConfiguration(
-                USER_ID, CONFIG_AUTO_DISABLED, false /* expectedResult */);
-
-        // The settings should not have been changed: user shouldn't have the capabilities.
-        script.verifyConfigurationNotChanged();
-
-        // Try to update the configuration with auto detection enabled.
-        script.simulateUpdateConfiguration(
-                USER_ID, CONFIG_AUTO_ENABLED,  false /* expectedResult */);
-
-        // The settings should not have been changed: user shouldn't have the capabilities.
-        script.verifyConfigurationNotChanged();
-
-        // Try to update the configuration to enable geolocation time zone detection: this should
-        // succeed, the geolocation time zone detection setting is not covered by the restriction).
-        script.simulateUpdateConfiguration(
-                USER_ID, CONFIG_GEO_DETECTION_DISABLED,  true /* expectedResult */);
-
-        // The settings should have been changed.
-        ConfigurationInternal expectedConfig = new ConfigurationInternal.Builder(
-                CONFIG_INT_USER_RESTRICTED_AUTO_ENABLED)
-                .setGeoDetectionEnabled(false)
-                .build();
-        script.verifyConfigurationChangedAndReset(expectedConfig);
-    }
-
-    @Test
-    public void testUpdateConfiguration_autoDetectNotSupported() {
-        Script script = new Script().initializeConfig(CONFIG_INT_AUTO_DETECT_NOT_SUPPORTED);
-
-        // Try to update the configuration with auto detection disabled.
-        script.simulateUpdateConfiguration(
-                USER_ID, CONFIG_AUTO_DISABLED, false /* expectedResult */);
-
-        // The settings should not have been changed: user shouldn't have the capabilities.
-        script.verifyConfigurationNotChanged();
-
-        // Try to update the configuration with auto detection enabled.
-        script.simulateUpdateConfiguration(
-                USER_ID, CONFIG_AUTO_ENABLED, false /* expectedResult */);
-
-        // The settings should not have been changed: user shouldn't have the capabilities.
-        script.verifyConfigurationNotChanged();
-    }
-
-    @Test
-    public void testUpdateConfiguration_autoDetectSupportedGeoNotSupported() {
-        Script script = new Script().initializeConfig(
-                CONFIG_INT_TELEPHONY_SUPPORTED_GEO_NOT_SUPPORTED);
-
-        // Update the configuration with auto detection disabled.
-        script.simulateUpdateConfiguration(
-                USER_ID, CONFIG_AUTO_DISABLED, true /* expectedResult */);
-
-        // The settings should have been changed and the StrategyListener onChange() called.
-        ConfigurationInternal expectedConfig =
-                new ConfigurationInternal.Builder(CONFIG_INT_TELEPHONY_SUPPORTED_GEO_NOT_SUPPORTED)
-                        .setAutoDetectionEnabled(false)
-                        .build();
-        script.verifyConfigurationChangedAndReset(expectedConfig);
-
-        // Try to update the configuration with geo detection disabled.
-        script.simulateUpdateConfiguration(
-                USER_ID, CONFIG_GEO_DETECTION_DISABLED, false /* expectedResult */);
-
-        // The settings should not have been changed: user shouldn't have the capability to modify
-        // the setting when the feature is disabled.
-        script.verifyConfigurationNotChanged();
-
-        // Try to update the configuration with geo detection enabled.
-        script.simulateUpdateConfiguration(
-                USER_ID, CONFIG_GEO_DETECTION_ENABLED, false /* expectedResult */);
-
-        // The settings should not have been changed: user shouldn't have the capability to modify
-        // the setting when the feature is disabled.
-        script.verifyConfigurationNotChanged();
     }
 
     @Test
@@ -312,8 +164,9 @@
         TelephonyTimeZoneSuggestion slotIndex2TimeZoneSuggestion =
                 createEmptySlotIndex2Suggestion();
         Script script = new Script()
-                .initializeConfig(CONFIG_INT_AUTO_ENABLED_GEO_DISABLED)
-                .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
+                .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID)
+                .simulateConfigurationInternalChange(CONFIG_AUTO_ENABLED_GEO_DISABLED)
+                .resetConfigurationTracking();
 
         script.simulateTelephonyTimeZoneSuggestion(slotIndex1TimeZoneSuggestion)
                 .verifyTimeZoneNotChanged();
@@ -357,7 +210,9 @@
         TelephonyTestCase testCase2 = newTelephonyTestCase(MATCH_TYPE_NETWORK_COUNTRY_ONLY,
                 QUALITY_SINGLE_ZONE, TELEPHONY_SCORE_HIGH);
 
-        Script script = new Script().initializeConfig(CONFIG_INT_AUTO_ENABLED_GEO_DISABLED);
+        Script script = new Script()
+                .simulateConfigurationInternalChange(CONFIG_AUTO_ENABLED_GEO_DISABLED)
+                .resetConfigurationTracking();
 
         // A low quality suggestions will not be taken: The device time zone setting is left
         // uninitialized.
@@ -422,8 +277,9 @@
 
         for (TelephonyTestCase testCase : TELEPHONY_TEST_CASES) {
             // Start with the device in a known state.
-            script.initializeConfig(CONFIG_INT_AUTO_DISABLED_GEO_DISABLED)
-                    .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
+            script.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID)
+                    .simulateConfigurationInternalChange(CONFIG_AUTO_DISABLED_GEO_DISABLED)
+                    .resetConfigurationTracking();
 
             TelephonyTimeZoneSuggestion suggestion =
                     testCase.createSuggestion(SLOT_INDEX1, "Europe/London");
@@ -442,8 +298,7 @@
                     mTimeZoneDetectorStrategy.findBestTelephonySuggestionForTests());
 
             // Toggling the time zone setting on should cause the device setting to be set.
-            script.simulateUpdateConfiguration(
-                    USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */);
+            script.simulateSetAutoMode(true);
 
             // When time zone detection is already enabled the suggestion (if it scores highly
             // enough) should be set immediately.
@@ -460,8 +315,7 @@
                     mTimeZoneDetectorStrategy.findBestTelephonySuggestionForTests());
 
             // Toggling the time zone setting should off should do nothing.
-            script.simulateUpdateConfiguration(
-                    USER_ID, CONFIG_AUTO_DISABLED, true /* expectedResult */)
+            script.simulateSetAutoMode(false)
                     .verifyTimeZoneNotChanged();
 
             // Assert internal service state.
@@ -475,8 +329,9 @@
     @Test
     public void testTelephonySuggestionsSingleSlotId() {
         Script script = new Script()
-                .initializeConfig(CONFIG_INT_AUTO_ENABLED_GEO_DISABLED)
-                .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
+                .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID)
+                .simulateConfigurationInternalChange(CONFIG_AUTO_ENABLED_GEO_DISABLED)
+                .resetConfigurationTracking();
 
         for (TelephonyTestCase testCase : TELEPHONY_TEST_CASES) {
             makeSlotIndex1SuggestionAndCheckState(script, testCase);
@@ -540,8 +395,10 @@
                         TELEPHONY_SCORE_NONE);
 
         Script script = new Script()
-                .initializeConfig(CONFIG_INT_AUTO_ENABLED_GEO_DISABLED)
                 .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID)
+                .simulateConfigurationInternalChange(CONFIG_AUTO_ENABLED_GEO_DISABLED)
+                .resetConfigurationTracking()
+
                 // Initialize the latest suggestions as empty so we don't need to worry about nulls
                 // below for the first loop.
                 .simulateTelephonyTimeZoneSuggestion(emptySlotIndex1Suggestion)
@@ -625,7 +482,9 @@
      */
     @Test
     public void testTelephonySuggestionStrategyDoesNotAssumeCurrentSetting_autoTelephony() {
-        Script script = new Script().initializeConfig(CONFIG_INT_AUTO_ENABLED_GEO_DISABLED);
+        Script script = new Script()
+                .simulateConfigurationInternalChange(CONFIG_AUTO_ENABLED_GEO_DISABLED)
+                .resetConfigurationTracking();
 
         TelephonyTestCase testCase = newTelephonyTestCase(
                 MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET, QUALITY_SINGLE_ZONE, TELEPHONY_SCORE_HIGH);
@@ -643,20 +502,18 @@
 
         // Toggling time zone detection should set the device time zone only if the current setting
         // value is different from the most recent telephony suggestion.
-        script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_DISABLED, true /* expectedResult */)
+        script.simulateSetAutoMode(false)
                 .verifyTimeZoneNotChanged()
-                .simulateUpdateConfiguration(
-                        USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */)
+                .simulateSetAutoMode(true)
                 .verifyTimeZoneNotChanged();
 
         // Simulate a user turning auto detection off, a new suggestion being made while auto
         // detection is off, and the user turning it on again.
-        script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_DISABLED, true /* expectedResult */)
+        script.simulateSetAutoMode(false)
                 .simulateTelephonyTimeZoneSuggestion(newYorkSuggestion)
                 .verifyTimeZoneNotChanged();
         // Latest suggestion should be used.
-        script.simulateUpdateConfiguration(
-                USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */)
+        script.simulateSetAutoMode(true)
                 .verifyTimeZoneChangedAndReset(newYorkSuggestion);
     }
 
@@ -673,12 +530,13 @@
     private void checkManualSuggestion_unrestricted_autoDetectionEnabled(
             boolean geoDetectionEnabled) {
         ConfigurationInternal geoTzEnabledConfig =
-                new ConfigurationInternal.Builder(CONFIG_INT_AUTO_ENABLED_GEO_DISABLED)
-                        .setGeoDetectionEnabled(geoDetectionEnabled)
+                new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED_GEO_DISABLED)
+                        .setGeoDetectionEnabledSetting(geoDetectionEnabled)
                         .build();
         Script script = new Script()
-                .initializeConfig(geoTzEnabledConfig)
-                .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
+                .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID)
+                .simulateConfigurationInternalChange(geoTzEnabledConfig)
+                .resetConfigurationTracking();
 
         // Auto time zone detection is enabled so the manual suggestion should be ignored.
         script.simulateManualTimeZoneSuggestion(
@@ -691,8 +549,9 @@
     @Test
     public void testManualSuggestion_restricted_simulateAutoTimeZoneEnabled() {
         Script script = new Script()
-                .initializeConfig(CONFIG_INT_USER_RESTRICTED_AUTO_ENABLED)
-                .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
+                .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID)
+                .simulateConfigurationInternalChange(CONFIG_USER_RESTRICTED_AUTO_ENABLED)
+                .resetConfigurationTracking();
 
         // User is restricted so the manual suggestion should be ignored.
         script.simulateManualTimeZoneSuggestion(
@@ -705,8 +564,9 @@
     @Test
     public void testManualSuggestion_unrestricted_autoTimeZoneDetectionDisabled() {
         Script script = new Script()
-                .initializeConfig(CONFIG_INT_AUTO_DISABLED_GEO_DISABLED)
-                .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
+                .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID)
+                .simulateConfigurationInternalChange(CONFIG_AUTO_DISABLED_GEO_DISABLED)
+                .resetConfigurationTracking();
 
         // Auto time zone detection is disabled so the manual suggestion should be used.
         ManualTimeZoneSuggestion manualSuggestion = createManualSuggestion("Europe/Paris");
@@ -720,8 +580,9 @@
     @Test
     public void testManualSuggestion_restricted_autoTimeZoneDetectionDisabled() {
         Script script = new Script()
-                .initializeConfig(CONFIG_INT_USER_RESTRICTED_AUTO_DISABLED)
-                .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
+                .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID)
+                .simulateConfigurationInternalChange(CONFIG_USER_RESTRICTED_AUTO_DISABLED)
+                .resetConfigurationTracking();
 
         // Restricted users do not have the capability.
         ManualTimeZoneSuggestion manualSuggestion = createManualSuggestion("Europe/Paris");
@@ -735,8 +596,9 @@
     @Test
     public void testManualSuggestion_autoDetectNotSupported() {
         Script script = new Script()
-                .initializeConfig(CONFIG_INT_AUTO_DETECT_NOT_SUPPORTED)
-                .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
+                .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID)
+                .simulateConfigurationInternalChange(CONFIG_AUTO_DETECT_NOT_SUPPORTED)
+                .resetConfigurationTracking();
 
         // Unrestricted users have the capability.
         ManualTimeZoneSuggestion manualSuggestion = createManualSuggestion("Europe/Paris");
@@ -749,8 +611,10 @@
 
     @Test
     public void testGeoSuggestion_uncertain() {
-        Script script = new Script().initializeConfig(CONFIG_INT_AUTO_ENABLED_GEO_ENABLED)
-                .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
+        Script script = new Script()
+                .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID)
+                .simulateConfigurationInternalChange(CONFIG_AUTO_ENABLED_GEO_ENABLED)
+                .resetConfigurationTracking();
 
         GeolocationTimeZoneSuggestion uncertainSuggestion = createUncertainGeolocationSuggestion();
 
@@ -765,8 +629,9 @@
     @Test
     public void testGeoSuggestion_noZones() {
         Script script = new Script()
-                .initializeConfig(CONFIG_INT_AUTO_ENABLED_GEO_ENABLED)
-                .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
+                .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID)
+                .simulateConfigurationInternalChange(CONFIG_AUTO_ENABLED_GEO_ENABLED)
+                .resetConfigurationTracking();
 
         GeolocationTimeZoneSuggestion noZonesSuggestion = createCertainGeolocationSuggestion();
 
@@ -783,8 +648,9 @@
                 createCertainGeolocationSuggestion("Europe/London");
 
         Script script = new Script()
-                .initializeConfig(CONFIG_INT_AUTO_ENABLED_GEO_ENABLED)
-                .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
+                .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID)
+                .simulateConfigurationInternalChange(CONFIG_AUTO_ENABLED_GEO_ENABLED)
+                .resetConfigurationTracking();
 
         script.simulateGeolocationTimeZoneSuggestion(suggestion)
                 .verifyTimeZoneChangedAndReset(suggestion);
@@ -808,8 +674,9 @@
                 createCertainGeolocationSuggestion("Europe/Paris");
 
         Script script = new Script()
-                .initializeConfig(CONFIG_INT_AUTO_ENABLED_GEO_ENABLED)
-                .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
+                .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID)
+                .simulateConfigurationInternalChange(CONFIG_AUTO_ENABLED_GEO_ENABLED)
+                .resetConfigurationTracking();
 
         script.simulateGeolocationTimeZoneSuggestion(londonOnlySuggestion)
                 .verifyTimeZoneChangedAndReset(londonOnlySuggestion);
@@ -848,8 +715,9 @@
                 "Europe/Paris");
 
         Script script = new Script()
-                .initializeConfig(CONFIG_INT_AUTO_DISABLED_GEO_DISABLED)
-                .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
+                .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID)
+                .simulateConfigurationInternalChange(CONFIG_AUTO_DISABLED_GEO_DISABLED)
+                .resetConfigurationTracking();
 
         // Add suggestions. Nothing should happen as time zone detection is disabled.
         script.simulateGeolocationTimeZoneSuggestion(geolocationSuggestion)
@@ -867,19 +735,17 @@
         // Toggling the time zone detection enabled setting on should cause the device setting to be
         // set from the telephony signal, as we've started with geolocation time zone detection
         // disabled.
-        script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */)
+        script.simulateSetAutoMode(true)
                 .verifyTimeZoneChangedAndReset(telephonySuggestion);
 
         // Changing the detection to enable geo detection will cause the device tz setting to
         // change to use the latest geolocation suggestion.
-        script.simulateUpdateConfiguration(
-                USER_ID, CONFIG_GEO_DETECTION_ENABLED, true /* expectedResult */)
+        script.simulateSetGeoDetectionEnabled(true)
                 .verifyTimeZoneChangedAndReset(geolocationSuggestion);
 
         // Changing the detection to disable geo detection should cause the device tz setting to
         // change to the telephony suggestion.
-        script.simulateUpdateConfiguration(
-                USER_ID, CONFIG_GEO_DETECTION_DISABLED, true /* expectedResult */)
+        script.simulateSetGeoDetectionEnabled(false)
                 .verifyTimeZoneChangedAndReset(telephonySuggestion);
 
         assertEquals(geolocationSuggestion,
@@ -888,12 +754,13 @@
 
     @Test
     public void testGenerateMetricsState() {
-        ConfigurationInternal expectedInternalConfig = CONFIG_INT_AUTO_DISABLED_GEO_DISABLED;
+        ConfigurationInternal expectedInternalConfig = CONFIG_AUTO_DISABLED_GEO_DISABLED;
         String expectedDeviceTimeZoneId = "InitialZoneId";
 
         Script script = new Script()
-                .initializeConfig(expectedInternalConfig)
-                .initializeTimeZoneSetting(expectedDeviceTimeZoneId);
+                .initializeTimeZoneSetting(expectedDeviceTimeZoneId)
+                .simulateConfigurationInternalChange(expectedInternalConfig)
+                .resetConfigurationTracking();
 
         assertMetricsState(expectedInternalConfig, expectedDeviceTimeZoneId, null, null,
                 null, MetricsTimeZoneDetectorState.DETECTION_MODE_MANUAL);
@@ -908,9 +775,7 @@
                 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.
+        // With time zone auto detection off, telephony and geo suggestions will be recorded.
         TelephonyTimeZoneSuggestion telephonySuggestion =
                 createTelephonySuggestion(0 /* slotIndex */, MATCH_TYPE_NETWORK_COUNTRY_ONLY,
                         QUALITY_SINGLE_ZONE, "Zone2");
@@ -926,15 +791,13 @@
                 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)
+                .setAutoDetectionEnabledSetting(true)
+                .setGeoDetectionEnabledSetting(true)
                 .build();
 
         expectedDeviceTimeZoneId = geolocationTimeZoneSuggestion.getZoneIds().get(0);
-        script.simulateUpdateConfiguration(USER_ID, configUpdate, true /* expectedResult */)
+        script.simulateConfigurationInternalChange(expectedInternalConfig)
                 .verifyTimeZoneChangedAndReset(expectedDeviceTimeZoneId);
         assertMetricsState(expectedInternalConfig, expectedDeviceTimeZoneId,
                 manualSuggestion, telephonySuggestion, geolocationTimeZoneSuggestion,
@@ -1016,26 +879,14 @@
         return suggestion;
     }
 
-    private static TimeZoneConfiguration createConfig(
-            @Nullable Boolean autoDetection, @Nullable Boolean geoDetection) {
-        TimeZoneConfiguration.Builder builder = new TimeZoneConfiguration.Builder();
-        if (autoDetection != null) {
-            builder.setAutoDetectionEnabled(autoDetection);
-        }
-        if (geoDetection != null) {
-            builder.setGeoDetectionEnabled(geoDetection);
-        }
-        return builder.build();
-    }
-
     static class FakeEnvironment implements TimeZoneDetectorStrategyImpl.Environment {
 
-        private final TestState<ConfigurationInternal> mConfigurationInternal = new TestState<>();
         private final TestState<String> mTimeZoneId = new TestState<>();
-        private ConfigurationChangeListener mConfigChangeListener;
+        private ConfigurationInternal mConfigurationInternal;
+        private ConfigurationChangeListener mConfigurationInternalChangeListener;
 
         void initializeConfig(ConfigurationInternal configurationInternal) {
-            mConfigurationInternal.init(configurationInternal);
+            mConfigurationInternal = configurationInternal;
         }
 
         void initializeTimeZoneSetting(String zoneId) {
@@ -1043,22 +894,13 @@
         }
 
         @Override
-        public void setConfigChangeListener(ConfigurationChangeListener listener) {
-            mConfigChangeListener = listener;
+        public void setConfigurationInternalChangeListener(ConfigurationChangeListener listener) {
+            mConfigurationInternalChangeListener = listener;
         }
 
         @Override
-        public ConfigurationInternal getConfigurationInternal(int userId) {
-            ConfigurationInternal configuration = mConfigurationInternal.getLatest();
-            if (userId != configuration.getUserId()) {
-                fail("FakeCallback does not support multiple users.");
-            }
-            return configuration;
-        }
-
-        @Override
-        public int getCurrentUserId() {
-            return mConfigurationInternal.getLatest().getUserId();
+        public ConfigurationInternal getCurrentUserConfigurationInternal() {
+            return mConfigurationInternal;
         }
 
         @Override
@@ -1076,26 +918,9 @@
             mTimeZoneId.set(zoneId);
         }
 
-        @Override
-        public void storeConfiguration(
-                @UserIdInt int userId, TimeZoneConfiguration newConfiguration) {
-            ConfigurationInternal oldConfiguration = mConfigurationInternal.getLatest();
-            if (userId != oldConfiguration.getUserId()) {
-                fail("FakeCallback does not support multiple users");
-            }
-
-            ConfigurationInternal mergedConfiguration = oldConfiguration.merge(newConfiguration);
-            if (!mergedConfiguration.equals(oldConfiguration)) {
-                mConfigurationInternal.set(mergedConfiguration);
-
-                // Note: Unlike the real callback impl, the listener is invoked synchronously.
-                mConfigChangeListener.onChange();
-            }
-        }
-
-        void assertKnownUser(int userId) {
-            assertEquals("FakeCallback does not support multiple users",
-                    mConfigurationInternal.getLatest().getUserId(), userId);
+        void simulateConfigurationInternalChange(ConfigurationInternal configurationInternal) {
+            mConfigurationInternal = configurationInternal;
+            mConfigurationInternalChangeListener.onChange();
         }
 
         void assertTimeZoneNotChanged() {
@@ -1110,7 +935,6 @@
 
         void commitAllChanges() {
             mTimeZoneId.commitLatest();
-            mConfigurationInternal.commitLatest();
         }
     }
 
@@ -1120,24 +944,40 @@
      */
     private class Script {
 
-        Script initializeConfig(ConfigurationInternal configuration) {
-            mFakeEnvironment.initializeConfig(configuration);
-            return this;
-        }
-
         Script initializeTimeZoneSetting(String zoneId) {
             mFakeEnvironment.initializeTimeZoneSetting(zoneId);
             return this;
         }
 
         /**
-         * Simulates the time zone detection strategy receiving an updated configuration and checks
-         * the return value.
+         * Simulates the user / user's configuration changing.
          */
-        Script simulateUpdateConfiguration(
-                int userId, TimeZoneConfiguration configuration, boolean expectedResult) {
-            assertEquals(expectedResult,
-                    mTimeZoneDetectorStrategy.updateConfiguration(userId, configuration));
+        Script simulateConfigurationInternalChange(ConfigurationInternal configurationInternal) {
+            mFakeEnvironment.simulateConfigurationInternalChange(configurationInternal);
+            return this;
+        }
+
+        /**
+         * Simulates automatic time zone detection being set to the specified value.
+         */
+        Script simulateSetAutoMode(boolean autoDetectionEnabled) {
+            ConfigurationInternal newConfig = new ConfigurationInternal.Builder(
+                    mFakeEnvironment.getCurrentUserConfigurationInternal())
+                    .setAutoDetectionEnabledSetting(autoDetectionEnabled)
+                    .build();
+            simulateConfigurationInternalChange(newConfig);
+            return this;
+        }
+
+        /**
+         * Simulates automatic geolocation time zone detection being set to the specified value.
+         */
+        Script simulateSetGeoDetectionEnabled(boolean geoDetectionEnabled) {
+            ConfigurationInternal newConfig = new ConfigurationInternal.Builder(
+                    mFakeEnvironment.getCurrentUserConfigurationInternal())
+                    .setGeoDetectionEnabledSetting(geoDetectionEnabled)
+                    .build();
+            simulateConfigurationInternalChange(newConfig);
             return this;
         }
 
@@ -1154,7 +994,6 @@
         Script simulateManualTimeZoneSuggestion(
                 @UserIdInt int userId, ManualTimeZoneSuggestion manualTimeZoneSuggestion,
                 boolean expectedResult) {
-            mFakeEnvironment.assertKnownUser(userId);
             boolean actualResult = mTimeZoneDetectorStrategy.suggestManualTimeZone(
                     userId, manualTimeZoneSuggestion);
             assertEquals(expectedResult, actualResult);
@@ -1205,32 +1044,6 @@
             return this;
         }
 
-        /**
-         * Verifies that the configuration has been changed to the expected value.
-         */
-        Script verifyConfigurationChangedAndReset(ConfigurationInternal expected) {
-            mFakeEnvironment.mConfigurationInternal.assertHasBeenSet();
-            assertEquals(expected, mFakeEnvironment.mConfigurationInternal.getLatest());
-            mFakeEnvironment.commitAllChanges();
-
-            // Also confirm the listener triggered.
-            mMockConfigChangeListener.verifyOnChangeCalled();
-            mMockConfigChangeListener.reset();
-            return this;
-        }
-
-        /**
-         * Verifies that no underlying settings associated with the properties from the
-         * {@link TimeZoneConfiguration} have been changed.
-         */
-        Script verifyConfigurationNotChanged() {
-            mFakeEnvironment.mConfigurationInternal.assertHasNotBeenSet();
-
-            // Also confirm the listener did not trigger.
-            mMockConfigChangeListener.verifyOnChangeNotCalled();
-            return this;
-        }
-
         Script resetConfigurationTracking() {
             mFakeEnvironment.commitAllChanges();
             return this;
@@ -1261,25 +1074,4 @@
             @MatchType int matchType, @Quality int quality, int expectedScore) {
         return new TelephonyTestCase(matchType, quality, expectedScore);
     }
-
-    private static class MockConfigChangeListener implements ConfigurationChangeListener {
-        private boolean mOnChangeCalled;
-
-        @Override
-        public void onChange() {
-            mOnChangeCalled = true;
-        }
-
-        void verifyOnChangeCalled() {
-            assertTrue(mOnChangeCalled);
-        }
-
-        void verifyOnChangeNotCalled() {
-            assertFalse(mOnChangeCalled);
-        }
-
-        void reset() {
-            mOnChangeCalled = false;
-        }
-    }
 }
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 7d6772e..463ac52 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
@@ -1202,7 +1202,7 @@
             if (Objects.equals(oldConfig, newConfig)) {
                 fail("Bad test? No config change when one was expected");
             }
-            mController.onConfigChanged();
+            mController.onConfigurationInternalChanged();
         }
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/location/TestSupport.java b/services/tests/servicestests/src/com/android/server/timezonedetector/location/TestSupport.java
index 16ac1d6..e3da90e 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/location/TestSupport.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/location/TestSupport.java
@@ -41,14 +41,14 @@
     }
 
     private static ConfigurationInternal createUserConfig(
-            @UserIdInt int userId, boolean geoDetectionEnabled) {
+            @UserIdInt int userId, boolean geoDetectionEnabledSetting) {
         return new ConfigurationInternal.Builder(userId)
                 .setUserConfigAllowed(true)
                 .setTelephonyDetectionFeatureSupported(true)
                 .setGeoDetectionFeatureSupported(true)
-                .setAutoDetectionEnabled(true)
-                .setLocationEnabled(true)
-                .setGeoDetectionEnabled(geoDetectionEnabled)
+                .setAutoDetectionEnabledSetting(true)
+                .setLocationEnabledSetting(true)
+                .setGeoDetectionEnabledSetting(geoDetectionEnabledSetting)
                 .build();
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/FakeVibrator.java b/services/tests/servicestests/src/com/android/server/vibrator/FakeVibrator.java
index e739a76..e2a348e 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/FakeVibrator.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/FakeVibrator.java
@@ -16,12 +16,11 @@
 
 package com.android.server.vibrator;
 
+import android.annotation.NonNull;
 import android.os.VibrationAttributes;
 import android.os.VibrationEffect;
 import android.os.Vibrator;
 
-import androidx.annotation.NonNull;
-
 /** Fake implementation of {@link Vibrator} for service tests. */
 final class FakeVibrator extends Vibrator {
 
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java
index 7d24a2f..a9cbad2 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java
@@ -16,6 +16,19 @@
 
 package com.android.server.vibrator;
 
+import static android.os.VibrationAttributes.USAGE_ALARM;
+import static android.os.VibrationAttributes.USAGE_COMMUNICATION_REQUEST;
+import static android.os.VibrationAttributes.USAGE_HARDWARE_FEEDBACK;
+import static android.os.VibrationAttributes.USAGE_NOTIFICATION;
+import static android.os.VibrationAttributes.USAGE_PHYSICAL_EMULATION;
+import static android.os.VibrationAttributes.USAGE_RINGTONE;
+import static android.os.VibrationAttributes.USAGE_TOUCH;
+import static android.os.VibrationAttributes.USAGE_UNKNOWN;
+import static android.os.Vibrator.VIBRATION_INTENSITY_HIGH;
+import static android.os.Vibrator.VIBRATION_INTENSITY_LOW;
+import static android.os.Vibrator.VIBRATION_INTENSITY_MEDIUM;
+import static android.os.Vibrator.VIBRATION_INTENSITY_OFF;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
@@ -39,9 +52,7 @@
 import android.os.PowerManagerInternal;
 import android.os.PowerSaveState;
 import android.os.UserHandle;
-import android.os.VibrationAttributes;
 import android.os.VibrationEffect;
-import android.os.Vibrator;
 import android.os.test.TestLooper;
 import android.platform.test.annotations.Presubmit;
 import android.provider.Settings;
@@ -70,16 +81,19 @@
 public class VibrationSettingsTest {
 
     private static final int UID = 1;
-    private static final int USER_OPERATION_TIMEOUT_MILLIS = 60_000; // 1 min
     private static final PowerSaveState NORMAL_POWER_STATE = new PowerSaveState.Builder().build();
     private static final PowerSaveState LOW_POWER_STATE = new PowerSaveState.Builder()
             .setBatterySaverEnabled(true).build();
 
-    @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule();
-    @Rule public FakeSettingsProviderRule mSettingsProviderRule = FakeSettingsProvider.rule();
+    @Rule
+    public MockitoRule mMockitoRule = MockitoJUnit.rule();
+    @Rule
+    public FakeSettingsProviderRule mSettingsProviderRule = FakeSettingsProvider.rule();
 
-    @Mock private VibrationSettings.OnVibratorSettingsChanged mListenerMock;
-    @Mock private PowerManagerInternal mPowerManagerInternalMock;
+    @Mock
+    private VibrationSettings.OnVibratorSettingsChanged mListenerMock;
+    @Mock
+    private PowerManagerInternal mPowerManagerInternalMock;
 
     private TestLooper mTestLooper;
     private ContextWrapper mContextSpy;
@@ -129,14 +143,12 @@
         setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 0);
         setGlobalSetting(Settings.Global.APPLY_RAMPING_RINGER, 0);
         setGlobalSetting(Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_ALARMS);
-        setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
-                Vibrator.VIBRATION_INTENSITY_OFF);
-        setUserSetting(Settings.System.RING_VIBRATION_INTENSITY,
-                Vibrator.VIBRATION_INTENSITY_OFF);
-        setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY,
-                Vibrator.VIBRATION_INTENSITY_OFF);
+        setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY, VIBRATION_INTENSITY_OFF);
+        setUserSetting(Settings.System.RING_VIBRATION_INTENSITY, VIBRATION_INTENSITY_OFF);
+        setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_OFF);
+        setUserSetting(Settings.System.HARDWARE_HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_OFF);
 
-        verify(mListenerMock, times(7)).onChange();
+        verify(mListenerMock, times(8)).onChange();
     }
 
     @Test
@@ -171,89 +183,83 @@
         VibrationSettings vibrationSettings = new VibrationSettings(mContextSpy,
                 new Handler(mTestLooper.getLooper()));
 
-        assertFalse(vibrationSettings.shouldVibrateForRingerMode(
-                VibrationAttributes.USAGE_RINGTONE));
-        assertTrue(mVibrationSettings.shouldVibrateForRingerMode(VibrationAttributes.USAGE_ALARM));
-        assertTrue(mVibrationSettings.shouldVibrateForRingerMode(VibrationAttributes.USAGE_TOUCH));
-        assertTrue(mVibrationSettings.shouldVibrateForRingerMode(
-                VibrationAttributes.USAGE_NOTIFICATION));
-        assertTrue(mVibrationSettings.shouldVibrateForRingerMode(
-                VibrationAttributes.USAGE_COMMUNICATION_REQUEST));
+        assertFalse(vibrationSettings.shouldVibrateForRingerMode(USAGE_RINGTONE));
+        assertTrue(mVibrationSettings.shouldVibrateForRingerMode(USAGE_ALARM));
+        assertTrue(mVibrationSettings.shouldVibrateForRingerMode(USAGE_TOUCH));
+        assertTrue(mVibrationSettings.shouldVibrateForRingerMode(USAGE_NOTIFICATION));
+        assertTrue(mVibrationSettings.shouldVibrateForRingerMode(USAGE_COMMUNICATION_REQUEST));
+        assertTrue(mVibrationSettings.shouldVibrateForRingerMode(USAGE_HARDWARE_FEEDBACK));
     }
 
     @Test
     public void shouldVibrateForRingerMode_withoutRingtoneUsage_returnsTrue() {
-        assertTrue(mVibrationSettings.shouldVibrateForRingerMode(VibrationAttributes.USAGE_ALARM));
-        assertTrue(mVibrationSettings.shouldVibrateForRingerMode(VibrationAttributes.USAGE_TOUCH));
-        assertTrue(mVibrationSettings.shouldVibrateForRingerMode(
-                VibrationAttributes.USAGE_NOTIFICATION));
-        assertTrue(mVibrationSettings.shouldVibrateForRingerMode(
-                VibrationAttributes.USAGE_COMMUNICATION_REQUEST));
+        assertTrue(mVibrationSettings.shouldVibrateForRingerMode(USAGE_ALARM));
+        assertTrue(mVibrationSettings.shouldVibrateForRingerMode(USAGE_TOUCH));
+        assertTrue(mVibrationSettings.shouldVibrateForRingerMode(USAGE_NOTIFICATION));
+        assertTrue(mVibrationSettings.shouldVibrateForRingerMode(USAGE_COMMUNICATION_REQUEST));
+        assertTrue(mVibrationSettings.shouldVibrateForRingerMode(USAGE_HARDWARE_FEEDBACK));
     }
 
     @Test
     public void shouldVibrateForRingerMode_withVibrateWhenRinging_ignoreSettingsForSilentMode() {
-        int usageRingtone = VibrationAttributes.USAGE_RINGTONE;
         setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 1);
 
         setRingerMode(AudioManager.RINGER_MODE_SILENT);
-        assertFalse(mVibrationSettings.shouldVibrateForRingerMode(usageRingtone));
+        assertFalse(mVibrationSettings.shouldVibrateForRingerMode(USAGE_RINGTONE));
 
         setRingerMode(AudioManager.RINGER_MODE_MAX);
-        assertTrue(mVibrationSettings.shouldVibrateForRingerMode(usageRingtone));
+        assertTrue(mVibrationSettings.shouldVibrateForRingerMode(USAGE_RINGTONE));
 
         setRingerMode(AudioManager.RINGER_MODE_NORMAL);
-        assertTrue(mVibrationSettings.shouldVibrateForRingerMode(usageRingtone));
+        assertTrue(mVibrationSettings.shouldVibrateForRingerMode(USAGE_RINGTONE));
 
         setRingerMode(AudioManager.RINGER_MODE_VIBRATE);
-        assertTrue(mVibrationSettings.shouldVibrateForRingerMode(usageRingtone));
+        assertTrue(mVibrationSettings.shouldVibrateForRingerMode(USAGE_RINGTONE));
     }
 
     @Test
     public void shouldVibrateForRingerMode_withApplyRampingRinger_ignoreSettingsForSilentMode() {
-        int usageRingtone = VibrationAttributes.USAGE_RINGTONE;
         setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 0);
         setGlobalSetting(Settings.Global.APPLY_RAMPING_RINGER, 1);
 
         setRingerMode(AudioManager.RINGER_MODE_SILENT);
-        assertFalse(mVibrationSettings.shouldVibrateForRingerMode(usageRingtone));
+        assertFalse(mVibrationSettings.shouldVibrateForRingerMode(USAGE_RINGTONE));
 
         setRingerMode(AudioManager.RINGER_MODE_MAX);
-        assertTrue(mVibrationSettings.shouldVibrateForRingerMode(usageRingtone));
+        assertTrue(mVibrationSettings.shouldVibrateForRingerMode(USAGE_RINGTONE));
 
         setRingerMode(AudioManager.RINGER_MODE_NORMAL);
-        assertTrue(mVibrationSettings.shouldVibrateForRingerMode(usageRingtone));
+        assertTrue(mVibrationSettings.shouldVibrateForRingerMode(USAGE_RINGTONE));
 
         setRingerMode(AudioManager.RINGER_MODE_VIBRATE);
-        assertTrue(mVibrationSettings.shouldVibrateForRingerMode(usageRingtone));
+        assertTrue(mVibrationSettings.shouldVibrateForRingerMode(USAGE_RINGTONE));
     }
 
     @Test
     public void shouldVibrateForRingerMode_withAllSettingsOff_onlyVibratesForVibrateMode() {
-        int usageRingtone = VibrationAttributes.USAGE_RINGTONE;
         setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 0);
         setGlobalSetting(Settings.Global.APPLY_RAMPING_RINGER, 0);
 
         setRingerMode(AudioManager.RINGER_MODE_VIBRATE);
-        assertTrue(mVibrationSettings.shouldVibrateForRingerMode(usageRingtone));
+        assertTrue(mVibrationSettings.shouldVibrateForRingerMode(USAGE_RINGTONE));
 
         setRingerMode(AudioManager.RINGER_MODE_SILENT);
-        assertFalse(mVibrationSettings.shouldVibrateForRingerMode(usageRingtone));
+        assertFalse(mVibrationSettings.shouldVibrateForRingerMode(USAGE_RINGTONE));
 
         setRingerMode(AudioManager.RINGER_MODE_MAX);
-        assertFalse(mVibrationSettings.shouldVibrateForRingerMode(usageRingtone));
+        assertFalse(mVibrationSettings.shouldVibrateForRingerMode(USAGE_RINGTONE));
 
         setRingerMode(AudioManager.RINGER_MODE_NORMAL);
-        assertFalse(mVibrationSettings.shouldVibrateForRingerMode(usageRingtone));
+        assertFalse(mVibrationSettings.shouldVibrateForRingerMode(USAGE_RINGTONE));
     }
 
     @Test
     public void shouldVibrateForUid_withForegroundOnlyUsage_returnsTrueWhInForeground() {
-        assertTrue(mVibrationSettings.shouldVibrateForUid(UID, VibrationAttributes.USAGE_TOUCH));
+        assertTrue(mVibrationSettings.shouldVibrateForUid(UID, USAGE_TOUCH));
 
         mVibrationSettings.mUidObserver.onUidStateChanged(
                 UID, ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND, 0, 0);
-        assertFalse(mVibrationSettings.shouldVibrateForUid(UID, VibrationAttributes.USAGE_TOUCH));
+        assertFalse(mVibrationSettings.shouldVibrateForUid(UID, USAGE_TOUCH));
     }
 
     @Test
@@ -261,38 +267,32 @@
         mVibrationSettings.mUidObserver.onUidStateChanged(
                 UID, ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND, 0, 0);
 
-        assertTrue(mVibrationSettings.shouldVibrateForUid(UID, VibrationAttributes.USAGE_ALARM));
-        assertTrue(mVibrationSettings.shouldVibrateForUid(UID,
-                VibrationAttributes.USAGE_COMMUNICATION_REQUEST));
-        assertTrue(mVibrationSettings.shouldVibrateForUid(UID,
-                VibrationAttributes.USAGE_NOTIFICATION));
-        assertTrue(mVibrationSettings.shouldVibrateForUid(UID, VibrationAttributes.USAGE_RINGTONE));
+        assertTrue(mVibrationSettings.shouldVibrateForUid(UID, USAGE_ALARM));
+        assertTrue(mVibrationSettings.shouldVibrateForUid(UID, USAGE_COMMUNICATION_REQUEST));
+        assertTrue(mVibrationSettings.shouldVibrateForUid(UID, USAGE_NOTIFICATION));
+        assertTrue(mVibrationSettings.shouldVibrateForUid(UID, USAGE_RINGTONE));
     }
 
     @Test
     public void shouldVibrateForPowerMode_withLowPowerAndAllowedUsage_returnTrue() {
         mRegisteredPowerModeListener.onLowPowerModeChanged(LOW_POWER_STATE);
 
-        assertTrue(mVibrationSettings.shouldVibrateForPowerMode(VibrationAttributes.USAGE_ALARM));
-        assertTrue(mVibrationSettings.shouldVibrateForPowerMode(
-                VibrationAttributes.USAGE_RINGTONE));
-        assertTrue(mVibrationSettings.shouldVibrateForPowerMode(
-                VibrationAttributes.USAGE_COMMUNICATION_REQUEST));
+        assertTrue(mVibrationSettings.shouldVibrateForPowerMode(USAGE_ALARM));
+        assertTrue(mVibrationSettings.shouldVibrateForPowerMode(USAGE_RINGTONE));
+        assertTrue(mVibrationSettings.shouldVibrateForPowerMode(USAGE_COMMUNICATION_REQUEST));
     }
 
     @Test
     public void shouldVibrateForPowerMode_withRestrictedUsage_returnsFalseWhileInLowPowerMode() {
         mRegisteredPowerModeListener.onLowPowerModeChanged(NORMAL_POWER_STATE);
 
-        assertTrue(mVibrationSettings.shouldVibrateForPowerMode(VibrationAttributes.USAGE_TOUCH));
-        assertTrue(mVibrationSettings.shouldVibrateForPowerMode(
-                VibrationAttributes.USAGE_NOTIFICATION));
+        assertTrue(mVibrationSettings.shouldVibrateForPowerMode(USAGE_TOUCH));
+        assertTrue(mVibrationSettings.shouldVibrateForPowerMode(USAGE_NOTIFICATION));
 
         mRegisteredPowerModeListener.onLowPowerModeChanged(LOW_POWER_STATE);
 
-        assertFalse(mVibrationSettings.shouldVibrateForPowerMode(VibrationAttributes.USAGE_TOUCH));
-        assertFalse(mVibrationSettings.shouldVibrateForPowerMode(
-                VibrationAttributes.USAGE_NOTIFICATION));
+        assertFalse(mVibrationSettings.shouldVibrateForPowerMode(USAGE_TOUCH));
+        assertFalse(mVibrationSettings.shouldVibrateForPowerMode(USAGE_NOTIFICATION));
     }
 
     @Test
@@ -324,108 +324,128 @@
 
     @Test
     public void getDefaultIntensity_beforeSystemReady_returnsMediumToAllExceptAlarm() {
-        mFakeVibrator.setDefaultHapticFeedbackIntensity(Vibrator.VIBRATION_INTENSITY_HIGH);
-        mFakeVibrator.setDefaultNotificationVibrationIntensity(Vibrator.VIBRATION_INTENSITY_HIGH);
-        mFakeVibrator.setDefaultRingVibrationIntensity(Vibrator.VIBRATION_INTENSITY_HIGH);
+        mFakeVibrator.setDefaultHapticFeedbackIntensity(VIBRATION_INTENSITY_HIGH);
+        mFakeVibrator.setDefaultNotificationVibrationIntensity(VIBRATION_INTENSITY_HIGH);
+        mFakeVibrator.setDefaultRingVibrationIntensity(VIBRATION_INTENSITY_HIGH);
 
-        setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
-                Vibrator.VIBRATION_INTENSITY_OFF);
-        setUserSetting(Settings.System.RING_VIBRATION_INTENSITY,
-                Vibrator.VIBRATION_INTENSITY_OFF);
-        setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY,
-                Vibrator.VIBRATION_INTENSITY_OFF);
+        setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY, VIBRATION_INTENSITY_OFF);
+        setUserSetting(Settings.System.RING_VIBRATION_INTENSITY, VIBRATION_INTENSITY_OFF);
+        setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_OFF);
+        setUserSetting(Settings.System.HARDWARE_HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_OFF);
 
         VibrationSettings vibrationSettings = new VibrationSettings(mContextSpy,
                 new Handler(mTestLooper.getLooper()));
 
-        assertEquals(Vibrator.VIBRATION_INTENSITY_HIGH,
-                vibrationSettings.getDefaultIntensity(VibrationAttributes.USAGE_ALARM));
-        assertEquals(Vibrator.VIBRATION_INTENSITY_MEDIUM,
-                vibrationSettings.getDefaultIntensity(VibrationAttributes.USAGE_TOUCH));
-        assertEquals(Vibrator.VIBRATION_INTENSITY_MEDIUM,
-                vibrationSettings.getDefaultIntensity(VibrationAttributes.USAGE_NOTIFICATION));
-        assertEquals(Vibrator.VIBRATION_INTENSITY_MEDIUM,
-                vibrationSettings.getDefaultIntensity(VibrationAttributes.USAGE_UNKNOWN));
-        assertEquals(Vibrator.VIBRATION_INTENSITY_MEDIUM,
-                vibrationSettings.getDefaultIntensity(
-                        VibrationAttributes.USAGE_PHYSICAL_EMULATION));
-        assertEquals(Vibrator.VIBRATION_INTENSITY_MEDIUM,
-                vibrationSettings.getDefaultIntensity(VibrationAttributes.USAGE_RINGTONE));
+        assertEquals(VIBRATION_INTENSITY_HIGH,
+                vibrationSettings.getDefaultIntensity(USAGE_ALARM));
+        assertEquals(VIBRATION_INTENSITY_MEDIUM,
+                vibrationSettings.getDefaultIntensity(USAGE_TOUCH));
+        assertEquals(VIBRATION_INTENSITY_MEDIUM,
+                vibrationSettings.getDefaultIntensity(USAGE_HARDWARE_FEEDBACK));
+        assertEquals(VIBRATION_INTENSITY_MEDIUM,
+                vibrationSettings.getDefaultIntensity(USAGE_PHYSICAL_EMULATION));
+        assertEquals(VIBRATION_INTENSITY_MEDIUM,
+                vibrationSettings.getDefaultIntensity(USAGE_NOTIFICATION));
+        assertEquals(VIBRATION_INTENSITY_MEDIUM,
+                vibrationSettings.getDefaultIntensity(USAGE_UNKNOWN));
+        assertEquals(VIBRATION_INTENSITY_MEDIUM,
+                vibrationSettings.getDefaultIntensity(USAGE_RINGTONE));
     }
 
     @Test
     public void getDefaultIntensity_returnsIntensityFromVibratorService() {
-        mFakeVibrator.setDefaultHapticFeedbackIntensity(Vibrator.VIBRATION_INTENSITY_HIGH);
-        mFakeVibrator.setDefaultNotificationVibrationIntensity(Vibrator.VIBRATION_INTENSITY_MEDIUM);
-        mFakeVibrator.setDefaultRingVibrationIntensity(Vibrator.VIBRATION_INTENSITY_LOW);
+        mFakeVibrator.setDefaultHapticFeedbackIntensity(VIBRATION_INTENSITY_HIGH);
+        mFakeVibrator.setDefaultNotificationVibrationIntensity(VIBRATION_INTENSITY_MEDIUM);
+        mFakeVibrator.setDefaultRingVibrationIntensity(VIBRATION_INTENSITY_LOW);
 
-        setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
-                Vibrator.VIBRATION_INTENSITY_OFF);
-        setUserSetting(Settings.System.RING_VIBRATION_INTENSITY,
-                Vibrator.VIBRATION_INTENSITY_OFF);
-        setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY,
-                Vibrator.VIBRATION_INTENSITY_OFF);
+        setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY, VIBRATION_INTENSITY_OFF);
+        setUserSetting(Settings.System.RING_VIBRATION_INTENSITY, VIBRATION_INTENSITY_OFF);
+        setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_OFF);
 
-        assertEquals(Vibrator.VIBRATION_INTENSITY_HIGH,
-                mVibrationSettings.getDefaultIntensity(VibrationAttributes.USAGE_ALARM));
-        assertEquals(Vibrator.VIBRATION_INTENSITY_HIGH,
-                mVibrationSettings.getDefaultIntensity(VibrationAttributes.USAGE_TOUCH));
-        assertEquals(Vibrator.VIBRATION_INTENSITY_MEDIUM,
-                mVibrationSettings.getDefaultIntensity(VibrationAttributes.USAGE_NOTIFICATION));
-        assertEquals(Vibrator.VIBRATION_INTENSITY_MEDIUM,
-                mVibrationSettings.getDefaultIntensity(VibrationAttributes.USAGE_UNKNOWN));
-        assertEquals(Vibrator.VIBRATION_INTENSITY_MEDIUM,
-                mVibrationSettings.getDefaultIntensity(
-                        VibrationAttributes.USAGE_PHYSICAL_EMULATION));
-        assertEquals(Vibrator.VIBRATION_INTENSITY_LOW,
-                mVibrationSettings.getDefaultIntensity(VibrationAttributes.USAGE_RINGTONE));
+        assertEquals(VIBRATION_INTENSITY_HIGH,
+                mVibrationSettings.getDefaultIntensity(USAGE_ALARM));
+        assertEquals(VIBRATION_INTENSITY_HIGH,
+                mVibrationSettings.getDefaultIntensity(USAGE_TOUCH));
+        assertEquals(VIBRATION_INTENSITY_HIGH,
+                mVibrationSettings.getDefaultIntensity(USAGE_HARDWARE_FEEDBACK));
+        assertEquals(VIBRATION_INTENSITY_HIGH,
+                mVibrationSettings.getDefaultIntensity(USAGE_PHYSICAL_EMULATION));
+        assertEquals(VIBRATION_INTENSITY_MEDIUM,
+                mVibrationSettings.getDefaultIntensity(USAGE_NOTIFICATION));
+        assertEquals(VIBRATION_INTENSITY_MEDIUM,
+                mVibrationSettings.getDefaultIntensity(USAGE_UNKNOWN));
+        assertEquals(VIBRATION_INTENSITY_LOW,
+                mVibrationSettings.getDefaultIntensity(USAGE_RINGTONE));
     }
 
     @Test
     public void getCurrentIntensity_returnsIntensityFromSettings() {
-        mFakeVibrator.setDefaultHapticFeedbackIntensity(Vibrator.VIBRATION_INTENSITY_OFF);
-        mFakeVibrator.setDefaultNotificationVibrationIntensity(Vibrator.VIBRATION_INTENSITY_OFF);
-        mFakeVibrator.setDefaultRingVibrationIntensity(Vibrator.VIBRATION_INTENSITY_OFF);
+        mFakeVibrator.setDefaultHapticFeedbackIntensity(VIBRATION_INTENSITY_OFF);
+        mFakeVibrator.setDefaultNotificationVibrationIntensity(VIBRATION_INTENSITY_OFF);
+        mFakeVibrator.setDefaultRingVibrationIntensity(VIBRATION_INTENSITY_OFF);
 
-        setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY,
-                Vibrator.VIBRATION_INTENSITY_HIGH);
+        setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_HIGH);
+        setUserSetting(Settings.System.HARDWARE_HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_LOW);
         setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
-                Vibrator.VIBRATION_INTENSITY_MEDIUM);
-        setUserSetting(Settings.System.RING_VIBRATION_INTENSITY,
-                Vibrator.VIBRATION_INTENSITY_LOW);
+                VIBRATION_INTENSITY_MEDIUM);
+        setUserSetting(Settings.System.RING_VIBRATION_INTENSITY, VIBRATION_INTENSITY_LOW);
 
-        assertEquals(Vibrator.VIBRATION_INTENSITY_HIGH,
-                mVibrationSettings.getCurrentIntensity(VibrationAttributes.USAGE_ALARM));
-        assertEquals(Vibrator.VIBRATION_INTENSITY_HIGH,
-                mVibrationSettings.getCurrentIntensity(VibrationAttributes.USAGE_TOUCH));
-        assertEquals(Vibrator.VIBRATION_INTENSITY_MEDIUM,
-                mVibrationSettings.getCurrentIntensity(VibrationAttributes.USAGE_NOTIFICATION));
-        assertEquals(Vibrator.VIBRATION_INTENSITY_MEDIUM,
-                mVibrationSettings.getCurrentIntensity(VibrationAttributes.USAGE_UNKNOWN));
-        assertEquals(Vibrator.VIBRATION_INTENSITY_MEDIUM,
-                mVibrationSettings.getCurrentIntensity(
-                        VibrationAttributes.USAGE_PHYSICAL_EMULATION));
-        assertEquals(Vibrator.VIBRATION_INTENSITY_LOW,
-                mVibrationSettings.getCurrentIntensity(VibrationAttributes.USAGE_RINGTONE));
+        assertEquals(VIBRATION_INTENSITY_HIGH, mVibrationSettings.getCurrentIntensity(USAGE_ALARM));
+        assertEquals(VIBRATION_INTENSITY_HIGH, mVibrationSettings.getCurrentIntensity(USAGE_TOUCH));
+        assertEquals(VIBRATION_INTENSITY_LOW,
+                mVibrationSettings.getCurrentIntensity(USAGE_HARDWARE_FEEDBACK));
+        assertEquals(VIBRATION_INTENSITY_LOW,
+                mVibrationSettings.getCurrentIntensity(USAGE_PHYSICAL_EMULATION));
+        assertEquals(VIBRATION_INTENSITY_MEDIUM,
+                mVibrationSettings.getCurrentIntensity(USAGE_NOTIFICATION));
+        assertEquals(VIBRATION_INTENSITY_MEDIUM,
+                mVibrationSettings.getCurrentIntensity(USAGE_UNKNOWN));
+        assertEquals(VIBRATION_INTENSITY_LOW,
+                mVibrationSettings.getCurrentIntensity(USAGE_RINGTONE));
     }
 
     @Test
     public void getCurrentIntensity_updateTriggeredAfterUserSwitched() {
-        mFakeVibrator.setDefaultRingVibrationIntensity(Vibrator.VIBRATION_INTENSITY_OFF);
-        setUserSetting(Settings.System.RING_VIBRATION_INTENSITY,
-                Vibrator.VIBRATION_INTENSITY_HIGH);
-        assertEquals(Vibrator.VIBRATION_INTENSITY_HIGH,
-                mVibrationSettings.getCurrentIntensity(VibrationAttributes.USAGE_RINGTONE));
+        mFakeVibrator.setDefaultRingVibrationIntensity(VIBRATION_INTENSITY_OFF);
+        setUserSetting(Settings.System.RING_VIBRATION_INTENSITY, VIBRATION_INTENSITY_HIGH);
+        assertEquals(VIBRATION_INTENSITY_HIGH,
+                mVibrationSettings.getCurrentIntensity(USAGE_RINGTONE));
 
         // Switching user is not working with FakeSettingsProvider.
         // Testing the broadcast flow manually.
         Settings.System.putIntForUser(mContextSpy.getContentResolver(),
-                Settings.System.RING_VIBRATION_INTENSITY, Vibrator.VIBRATION_INTENSITY_LOW,
+                Settings.System.RING_VIBRATION_INTENSITY, VIBRATION_INTENSITY_LOW,
                 UserHandle.USER_CURRENT);
         mVibrationSettings.mUserReceiver.onReceive(mContextSpy,
                 new Intent(Intent.ACTION_USER_SWITCHED));
-        assertEquals(Vibrator.VIBRATION_INTENSITY_LOW,
-                mVibrationSettings.getCurrentIntensity(VibrationAttributes.USAGE_RINGTONE));
+        assertEquals(VIBRATION_INTENSITY_LOW,
+                mVibrationSettings.getCurrentIntensity(USAGE_RINGTONE));
+    }
+
+    @Test
+    public void getCurrentIntensity_noHardwareFeedbackValueUsesHapticFeedbackValue() {
+        mFakeVibrator.setDefaultHapticFeedbackIntensity(VIBRATION_INTENSITY_MEDIUM);
+        setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_OFF);
+        assertEquals(VIBRATION_INTENSITY_OFF, mVibrationSettings.getCurrentIntensity(USAGE_TOUCH));
+        // If haptic feedback is off, fallback to default value.
+        assertEquals(VIBRATION_INTENSITY_MEDIUM,
+                mVibrationSettings.getCurrentIntensity(USAGE_HARDWARE_FEEDBACK));
+        assertEquals(VIBRATION_INTENSITY_MEDIUM,
+                mVibrationSettings.getCurrentIntensity(USAGE_PHYSICAL_EMULATION));
+
+        // Switching user is not working with FakeSettingsProvider.
+        // Testing the broadcast flow manually.
+        Settings.System.putIntForUser(mContextSpy.getContentResolver(),
+                Settings.System.HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_HIGH,
+                UserHandle.USER_CURRENT);
+        mVibrationSettings.mUserReceiver.onReceive(mContextSpy,
+                new Intent(Intent.ACTION_USER_SWITCHED));
+        assertEquals(VIBRATION_INTENSITY_HIGH,
+                mVibrationSettings.getCurrentIntensity(USAGE_TOUCH));
+        assertEquals(VIBRATION_INTENSITY_HIGH,
+                mVibrationSettings.getCurrentIntensity(USAGE_HARDWARE_FEEDBACK));
+        assertEquals(VIBRATION_INTENSITY_HIGH,
+                mVibrationSettings.getCurrentIntensity(USAGE_PHYSICAL_EMULATION));
     }
 
     @Test
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 6118169..be83efb 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java
@@ -118,8 +118,7 @@
     private static final VibrationAttributes ALARM_ATTRS =
             new VibrationAttributes.Builder().setUsage(VibrationAttributes.USAGE_ALARM).build();
     private static final VibrationAttributes HAPTIC_FEEDBACK_ATTRS =
-            new VibrationAttributes.Builder().setUsage(
-                    VibrationAttributes.USAGE_TOUCH).build();
+            new VibrationAttributes.Builder().setUsage(VibrationAttributes.USAGE_TOUCH).build();
     private static final VibrationAttributes NOTIFICATION_ATTRS =
             new VibrationAttributes.Builder().setUsage(
                     VibrationAttributes.USAGE_NOTIFICATION).build();
@@ -658,8 +657,7 @@
                 service, TEST_TIMEOUT_MILLIS));
 
         vibrate(service, VibrationEffect.get(VibrationEffect.EFFECT_CLICK),
-                new VibrationAttributes.Builder().setUsage(
-                        VibrationAttributes.USAGE_TOUCH).build());
+                HAPTIC_FEEDBACK_ATTRS);
 
         // Wait before checking it never played a second effect.
         assertFalse(waitUntil(s -> mVibratorProviders.get(1).getEffectSegments().size() > 1,
@@ -682,8 +680,7 @@
                 service, TEST_TIMEOUT_MILLIS));
 
         vibrate(service, VibrationEffect.get(VibrationEffect.EFFECT_CLICK),
-                new VibrationAttributes.Builder().setUsage(
-                        VibrationAttributes.USAGE_TOUCH).build());
+                HAPTIC_FEEDBACK_ATTRS);
 
         // Wait before checking it never played a second effect.
         assertFalse(waitUntil(s -> mVibratorProviders.get(1).getEffectSegments().size() > 1,
diff --git a/packages/overlays/OneHandedModeGesturalOverlay/Android.bp b/services/tests/servicestests/test-apps/StubApp/Android.bp
similarity index 73%
rename from packages/overlays/OneHandedModeGesturalOverlay/Android.bp
rename to services/tests/servicestests/test-apps/StubApp/Android.bp
index 468069d..99deb3f 100644
--- a/packages/overlays/OneHandedModeGesturalOverlay/Android.bp
+++ b/services/tests/servicestests/test-apps/StubApp/Android.bp
@@ -1,18 +1,16 @@
-//
-//  Copyright 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.
 // You may obtain a copy of the License at
 //
-//     http://www.apache.org/licenses/LICENSE-2.0
+//      http://www.apache.org/licenses/LICENSE-2.0
 //
 // Unless required by applicable law or agreed to in writing, software
 // distributed under the License is distributed on an "AS IS" BASIS,
 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 // See the License for the specific language governing permissions and
 // limitations under the License.
-//
 
 package {
     // See: http://go/android-license-faq
@@ -23,8 +21,17 @@
     default_applicable_licenses: ["frameworks_base_license"],
 }
 
-runtime_resource_overlay {
-    name: "OneHandedModeGesturalOverlay",
-    theme: "OneHandedModeGestural",
-    product_specific: true,
+android_test_helper_app {
+    name: "StubTestApp",
+
+    sdk_version: "current",
+
+    srcs: ["**/*.java"],
+
+    dex_preopt: {
+        enabled: false,
+    },
+    optimize: {
+        enabled: false,
+    },
 }
diff --git a/services/tests/servicestests/test-apps/StubApp/AndroidManifest.xml b/services/tests/servicestests/test-apps/StubApp/AndroidManifest.xml
new file mode 100644
index 0000000..90172e7
--- /dev/null
+++ b/services/tests/servicestests/test-apps/StubApp/AndroidManifest.xml
@@ -0,0 +1,25 @@
+<?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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.android.servicestests.apps.stubapp">
+
+    <application android:label="StubTestApp">
+        <activity android:name=".TestActivity"
+                  android:exported="true" />
+    </application>
+
+</manifest>
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FlagWriter.kt b/services/tests/servicestests/test-apps/StubApp/src/com/android/servicestests/apps/stubapp/TestActivity.java
similarity index 82%
copy from packages/SystemUI/src/com/android/systemui/flags/FlagWriter.kt
copy to services/tests/servicestests/test-apps/StubApp/src/com/android/servicestests/apps/stubapp/TestActivity.java
index bacc66b..0d94676 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FlagWriter.kt
+++ b/services/tests/servicestests/test-apps/StubApp/src/com/android/servicestests/apps/stubapp/TestActivity.java
@@ -14,8 +14,9 @@
  * limitations under the License.
  */
 
-package com.android.systemui.flags
+package com.android.servicestests.apps.stubapp;
 
-interface FlagWriter {
-    fun setEnabled(key: Int, value: Boolean) {}
-}
\ No newline at end of file
+import android.app.Activity;
+
+public class TestActivity extends Activity {
+}
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 d593e80..911fb6a 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
@@ -422,7 +422,7 @@
 
     private void verifyNeverVibrate() {
         verify(mVibrator, never()).vibrate(anyInt(), anyString(), any(), anyString(),
-                any(AudioAttributes.class));
+                any(VibrationAttributes.class));
     }
 
     private void verifyVibrate() {
@@ -448,17 +448,18 @@
 
     private void verifyDelayedNeverVibrate() {
         verify(mVibrator, after(MAX_VIBRATION_DELAY).never()).vibrate(anyInt(), anyString(), any(),
-                anyString(), any(AudioAttributes.class));
+                anyString(), any(VibrationAttributes.class));
     }
 
     private void verifyVibrate(ArgumentMatcher<VibrationEffect> effectMatcher,
             VerificationMode verification) {
-        ArgumentCaptor<AudioAttributes> captor = ArgumentCaptor.forClass(AudioAttributes.class);
+        ArgumentCaptor<VibrationAttributes> captor =
+                ArgumentCaptor.forClass(VibrationAttributes.class);
         verify(mVibrator, verification).vibrate(eq(Process.SYSTEM_UID),
                 eq(PackageManagerService.PLATFORM_PACKAGE_NAME), argThat(effectMatcher),
                 anyString(), captor.capture());
-        assertEquals(0, (captor.getValue().getAllFlags()
-                & AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY));
+        assertEquals(0, (captor.getValue().getFlags()
+                & VibrationAttributes.FLAG_BYPASS_INTERRUPTION_POLICY));
     }
 
     private void verifyStopVibrate() {
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
index c337ccd..cdb7230 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
@@ -1362,6 +1362,66 @@
     }
 
     @Test
+    public void testSetComponentState() throws Exception {
+        Context context = mock(Context.class);
+        PackageManager pm = mock(PackageManager.class);
+        ApplicationInfo ai = new ApplicationInfo();
+        ai.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT;
+
+        when(context.getPackageName()).thenReturn(mContext.getPackageName());
+        when(context.getUserId()).thenReturn(mContext.getUserId());
+        when(context.getPackageManager()).thenReturn(pm);
+        when(pm.getApplicationInfo(anyString(), anyInt())).thenReturn(ai);
+
+        ManagedServices service = new TestManagedServices(context, mLock, mUserProfiles, mIpm,
+                APPROVAL_BY_COMPONENT);
+        ComponentName cn = ComponentName.unflattenFromString("a/a");
+
+        service.registerSystemService(cn, 0);
+        when(context.bindServiceAsUser(any(), any(), anyInt(), any())).thenAnswer(invocation -> {
+            Object[] args = invocation.getArguments();
+            ServiceConnection sc = (ServiceConnection) args[1];
+            sc.onServiceConnected(cn, mock(IBinder.class));
+            return true;
+        });
+
+        service.registerSystemService(cn, mZero.id);
+
+        service.setComponentState(cn, mZero.id, false);
+        verify(context).unbindService(any());
+    }
+
+    @Test
+    public void testSetComponentState_workProfile() throws Exception {
+        Context context = mock(Context.class);
+        PackageManager pm = mock(PackageManager.class);
+        ApplicationInfo ai = new ApplicationInfo();
+        ai.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT;
+
+        when(context.getPackageName()).thenReturn(mContext.getPackageName());
+        when(context.getUserId()).thenReturn(mContext.getUserId());
+        when(context.getPackageManager()).thenReturn(pm);
+        when(pm.getApplicationInfo(anyString(), anyInt())).thenReturn(ai);
+
+        ManagedServices service = new TestManagedServices(context, mLock, mUserProfiles, mIpm,
+                APPROVAL_BY_COMPONENT);
+        ComponentName cn = ComponentName.unflattenFromString("a/a");
+
+        service.registerSystemService(cn, 0);
+        when(context.bindServiceAsUser(any(), any(), anyInt(), any())).thenAnswer(invocation -> {
+            Object[] args = invocation.getArguments();
+            ServiceConnection sc = (ServiceConnection) args[1];
+            sc.onServiceConnected(cn, mock(IBinder.class));
+            return true;
+        });
+
+        service.registerSystemService(cn, mZero.id);
+
+        service.setComponentState(cn, mTen.id, false);
+        verify(context, never()).unbindService(any());
+    }
+
+    @Test
     public void testOnPackagesChanged_nullValuesPassed_noNullPointers() {
         for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) {
             ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles,
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 31e7ad0..ea3a4cd 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -3859,6 +3859,19 @@
     }
 
     @Test
+    public void testTextChangedSet_forNewNotifs() throws Exception {
+        NotificationRecord original = generateNotificationRecord(mTestNotificationChannel);
+        mService.addEnqueuedNotification(original);
+
+        NotificationManagerService.PostNotificationRunnable runnable =
+                mService.new PostNotificationRunnable(original.getKey());
+        runnable.run();
+        waitForIdle();
+
+        assertTrue(original.isTextChanged());
+    }
+
+    @Test
     public void testVisuallyInterruptive_notSeen() throws Exception {
         NotificationRecord original = generateNotificationRecord(mTestNotificationChannel);
         mService.addNotification(original);
@@ -8498,6 +8511,18 @@
         assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
                 r.getSbn().getId(), r.getSbn().getTag(), r, false)).isFalse();
 
+        // using the style, but incorrect type in session - blocked
+        nb.setStyle(new Notification.MediaStyle());
+        Bundle extras = new Bundle();
+        extras.putParcelable(Notification.EXTRA_MEDIA_SESSION, new Intent());
+        nb.addExtras(extras);
+        sbn = new StatusBarNotification(PKG, PKG, 8, "tag", mUid, 0,
+                nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
+        r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
+
+        assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
+                r.getSbn().getId(), r.getSbn().getTag(), r, false)).isFalse();
+
         // style + media session - bypasses block
         nb.setStyle(new Notification.MediaStyle().setMediaSession(mock(MediaSession.Token.class)));
         sbn = new StatusBarNotification(PKG, PKG, 8, "tag", mUid, 0,
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationPermissionMigrationTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationPermissionMigrationTest.java
index ea01963..29ef339 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationPermissionMigrationTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationPermissionMigrationTest.java
@@ -89,6 +89,7 @@
 import android.media.session.MediaSession;
 import android.os.Binder;
 import android.os.Build;
+import android.os.Bundle;
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Process;
@@ -746,6 +747,18 @@
         assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
                 r.getSbn().getId(), r.getSbn().getTag(), r, false)).isFalse();
 
+        // using the style, but incorrect type in session - blocked
+        nb.setStyle(new Notification.MediaStyle());
+        Bundle extras = new Bundle();
+        extras.putParcelable(Notification.EXTRA_MEDIA_SESSION, new Intent());
+        nb.addExtras(extras);
+        sbn = new StatusBarNotification(PKG, PKG, 8, "tag", mUid, 0,
+                nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
+        r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
+
+        assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
+                r.getSbn().getId(), r.getSbn().getTag(), r, false)).isFalse();
+
         // style + media session - bypasses block
         nb.setStyle(new Notification.MediaStyle().setMediaSession(mock(MediaSession.Token.class)));
         sbn = new StatusBarNotification(PKG, PKG, 8, "tag", mUid, 0,
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
index 1266b2e..afc2b87 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
@@ -854,12 +854,19 @@
         ActivityTaskManagerInternal.PackageConfigurationUpdater packageConfigUpdater =
                 mAtm.mInternal.createPackageConfigurationUpdater(DEFAULT_PACKAGE_NAME,
                         DEFAULT_USER_ID);
+
+        // committing empty locales, when no config is set should return false.
+        assertFalse(packageConfigUpdater.setLocales(LocaleList.getEmptyLocaleList()).commit());
+
         // committing new configuration returns true;
         assertTrue(packageConfigUpdater.setLocales(LocaleList.forLanguageTags("en-XA,ar-XB"))
                 .commit());
         // applying the same configuration returns false.
         assertFalse(packageConfigUpdater.setLocales(LocaleList.forLanguageTags("en-XA,ar-XB"))
                 .commit());
+
+        // committing empty locales and undefined nightMode should return true (deletes the
+        // pre-existing record) if some config was previously set.
         assertTrue(packageConfigUpdater.setLocales(LocaleList.getEmptyLocaleList())
                 .setNightMode(Configuration.UI_MODE_NIGHT_UNDEFINED).commit());
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
index 5d0e34a..6fa306b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
@@ -803,6 +803,7 @@
         final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(task, organizer);
         final ActivityRecord openingActivity = taskFragment.getTopMostActivity();
         openingActivity.allDrawn = true;
+        task.effectiveUid = openingActivity.getUid();
         spyOn(mDisplayContent.mAppTransition);
 
         // Prepare a transition.
@@ -879,6 +880,7 @@
         final ActivityRecord closingActivity = taskFragment.getTopMostActivity();
         closingActivity.allDrawn = true;
         closingActivity.info.applicationInfo.uid = 12345;
+        task.effectiveUid = closingActivity.getUid();
         // Opening non-embedded activity with different UID.
         final ActivityRecord openingActivity = createActivityRecord(task);
         openingActivity.info.applicationInfo.uid = 54321;
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 562e958..08be15e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -102,6 +102,7 @@
 import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doCallRealMethod;
+import static org.mockito.Mockito.when;
 
 import android.app.ActivityTaskManager;
 import android.app.WindowConfiguration;
@@ -134,6 +135,7 @@
 import android.view.SurfaceControl.Transaction;
 import android.view.View;
 import android.view.WindowManager;
+import android.window.IDisplayAreaOrganizer;
 import android.window.WindowContainerToken;
 
 import androidx.test.filters.SmallTest;
@@ -390,6 +392,32 @@
         assertNull("computeImeParent() should be null", mDisplayContent.computeImeParent());
     }
 
+    @Test
+    public void testUpdateImeParent_skipForOrganizedImeContainer() {
+        final DisplayArea.Tokens imeContainer = mDisplayContent.getImeContainer();
+        final ActivityRecord activity = createActivityRecord(mDisplayContent);
+
+        final WindowState startingWin = createWindow(null, TYPE_APPLICATION_STARTING, activity,
+                "startingWin");
+        startingWin.setHasSurface(true);
+        assertTrue(startingWin.canBeImeTarget());
+        final SurfaceControl imeSurfaceParent = mock(SurfaceControl.class);
+        doReturn(imeSurfaceParent).when(mDisplayContent).computeImeParent();
+
+        // Main precondition for this test: organize the ImeContainer.
+        final IDisplayAreaOrganizer mockImeOrganizer = mock(IDisplayAreaOrganizer.class);
+        when(mockImeOrganizer.asBinder()).thenReturn(new Binder());
+        imeContainer.setOrganizer(mockImeOrganizer);
+
+        mDisplayContent.updateImeParent();
+
+        assertNull("Don't reparent the surface of an organized ImeContainer.",
+                mDisplayContent.mInputMethodSurfaceParent);
+
+        // Clean up organizer.
+        imeContainer.setOrganizer(null);
+    }
+
     /**
      * This tests root task movement between displays and proper root task's, task's and app token's
      * display container references updates.
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
index 70aa2a2..8da8596 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
@@ -16,6 +16,7 @@
 
 package com.android.server.wm;
 
+import static android.view.InsetsState.ITYPE_EXTRA_NAVIGATION_BAR;
 import static android.view.InsetsState.ITYPE_IME;
 import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
 import static android.view.RoundedCorners.NO_ROUNDED_CORNERS;
@@ -251,28 +252,38 @@
 
     @Test
     public void testOverlappingWithNavBar() {
+        final InsetsSource navSource = new InsetsSource(ITYPE_NAVIGATION_BAR);
+        navSource.setFrame(new Rect(100, 200, 200, 300));
+        testOverlappingWithNavBarType(navSource);
+    }
+
+    @Test
+    public void testOverlappingWithExtraNavBar() {
+        final InsetsSource navSource = new InsetsSource(ITYPE_EXTRA_NAVIGATION_BAR);
+        navSource.setFrame(new Rect(100, 200, 200, 300));
+        testOverlappingWithNavBarType(navSource);
+    }
+
+    private void testOverlappingWithNavBarType(InsetsSource navSource) {
         final WindowState targetWin = createApplicationWindow();
         final WindowFrames winFrame = targetWin.getWindowFrames();
         winFrame.mFrame.set(new Rect(100, 100, 200, 200));
-
-        final WindowState navigationBar = createNavigationBarWindow();
-
-        navigationBar.getFrame().set(new Rect(100, 200, 200, 300));
+        targetWin.mAboveInsetsState.addSource(navSource);
 
         assertFalse("Freeform is overlapping with navigation bar",
-                DisplayPolicy.isOverlappingWithNavBar(targetWin, navigationBar));
+                DisplayPolicy.isOverlappingWithNavBar(targetWin));
 
         winFrame.mFrame.set(new Rect(100, 101, 200, 201));
         assertTrue("Freeform should be overlapping with navigation bar (bottom)",
-                DisplayPolicy.isOverlappingWithNavBar(targetWin, navigationBar));
+                DisplayPolicy.isOverlappingWithNavBar(targetWin));
 
         winFrame.mFrame.set(new Rect(99, 200, 199, 300));
         assertTrue("Freeform should be overlapping with navigation bar (right)",
-                DisplayPolicy.isOverlappingWithNavBar(targetWin, navigationBar));
+                DisplayPolicy.isOverlappingWithNavBar(targetWin));
 
         winFrame.mFrame.set(new Rect(199, 200, 299, 300));
         assertTrue("Freeform should be overlapping with navigation bar (left)",
-                DisplayPolicy.isOverlappingWithNavBar(targetWin, navigationBar));
+                DisplayPolicy.isOverlappingWithNavBar(targetWin));
     }
 
     private WindowState createNavigationBarWindow() {
diff --git a/services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java
index 4509ff4..dbb7fae 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java
@@ -41,14 +41,17 @@
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.os.Binder;
 import android.platform.test.annotations.Presubmit;
 import android.view.Display;
+import android.window.IDisplayAreaOrganizer;
 
 import androidx.test.filters.SmallTest;
 
@@ -346,6 +349,39 @@
     }
 
     @Test
+    public void testPlaceImeContainer_skipReparentForOrganizedImeContainer() {
+        setupImeWindow();
+        final DisplayArea.Tokens imeContainer = mDisplay.getImeContainer();
+        final WindowToken imeToken = tokenOfType(TYPE_INPUT_METHOD);
+
+        // By default, the ime container is attached to DC as defined in DAPolicy.
+        assertThat(imeContainer.getRootDisplayArea()).isEqualTo(mDisplay);
+        assertThat(mDisplay.findAreaForTokenInLayer(imeToken)).isEqualTo(imeContainer);
+
+        final WindowState firstActivityWin =
+                createWindow(null /* parent */, TYPE_APPLICATION_STARTING, mFirstActivity,
+                        "firstActivityWin");
+        spyOn(firstActivityWin);
+        // firstActivityWin should be the target
+        doReturn(true).when(firstActivityWin).canBeImeTarget();
+
+        // Main precondition for this test: organize the ImeContainer.
+        final IDisplayAreaOrganizer mockImeOrganizer = mock(IDisplayAreaOrganizer.class);
+        when(mockImeOrganizer.asBinder()).thenReturn(new Binder());
+        imeContainer.setOrganizer(mockImeOrganizer);
+
+        WindowState imeTarget = mDisplay.computeImeTarget(true /* updateImeTarget */);
+
+        // The IME target must be updated but the don't reparent organized ImeContainers.
+        // See DisplayAreaOrganizer#FEATURE_IME.
+        assertThat(imeTarget).isEqualTo(firstActivityWin);
+        verify(mFirstRoot, never()).placeImeContainer(imeContainer);
+
+        // Clean up organizer.
+        imeContainer.setOrganizer(null);
+    }
+
+    @Test
     public void testResizableFixedOrientationApp_fixedOrientationLetterboxing() {
         mFirstRoot.setIgnoreOrientationRequest(false /* ignoreOrientationRequest */);
         mSecondRoot.setIgnoreOrientationRequest(false /* ignoreOrientationRequest */);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
index d89d64a..a5c6dc0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
@@ -21,6 +21,7 @@
 import static com.android.server.wm.testing.Assert.assertThrows;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.any;
@@ -352,28 +353,66 @@
     }
 
     @Test
-    public void testApplyTransaction_enforceHierarchyChange_createTaskFragment() {
+    public void testApplyTransaction_enforceHierarchyChange_createTaskFragment()
+            throws RemoteException {
+        mController.registerOrganizer(mIOrganizer);
+        final ActivityRecord activity = createActivityRecord(mDisplayContent);
+        final int uid = Binder.getCallingUid();
+        activity.info.applicationInfo.uid = uid;
+        activity.getTask().effectiveUid = uid;
+        final IBinder fragmentToken = new Binder();
+        final TaskFragmentCreationParams params = new TaskFragmentCreationParams.Builder(
+                mOrganizerToken, fragmentToken, activity.token).build();
         mOrganizer.applyTransaction(mTransaction);
 
         // Allow organizer to create TaskFragment and start/reparent activity to TaskFragment.
-        final TaskFragmentCreationParams mockParams = mock(TaskFragmentCreationParams.class);
-        doReturn(mOrganizerToken).when(mockParams).getOrganizer();
-        mTransaction.createTaskFragment(mockParams);
+        mTransaction.createTaskFragment(params);
         mTransaction.startActivityInTaskFragment(
                 mFragmentToken, null /* callerToken */, new Intent(), null /* activityOptions */);
         mTransaction.reparentActivityToTaskFragment(mFragmentToken, mock(IBinder.class));
         mTransaction.setAdjacentTaskFragments(mFragmentToken, mock(IBinder.class),
                 null /* options */);
+        mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
 
-        // It is expected to fail for the mock TaskFragmentCreationParams. It is ok as we are
-        // testing the security check here.
-        assertThrows(IllegalArgumentException.class, () -> {
-            try {
-                mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
-            } catch (RemoteException e) {
-                fail();
-            }
-        });
+        // Successfully created a TaskFragment.
+        final TaskFragment taskFragment = mAtm.mWindowOrganizerController
+                .getTaskFragment(fragmentToken);
+        assertNotNull(taskFragment);
+        assertEquals(activity.getTask(), taskFragment.getTask());
+    }
+
+    @Test
+    public void testApplyTransaction_createTaskFragment_failForDifferentUid()
+            throws RemoteException {
+        mController.registerOrganizer(mIOrganizer);
+        final ActivityRecord activity = createActivityRecord(mDisplayContent);
+        final int uid = Binder.getCallingUid();
+        final IBinder fragmentToken = new Binder();
+        final TaskFragmentCreationParams params = new TaskFragmentCreationParams.Builder(
+                mOrganizerToken, fragmentToken, activity.token).build();
+        mOrganizer.applyTransaction(mTransaction);
+        mTransaction.createTaskFragment(params);
+
+        // Fail to create TaskFragment when the task uid is different from caller.
+        activity.info.applicationInfo.uid = uid;
+        activity.getTask().effectiveUid = uid + 1;
+        mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
+
+        assertNull(mAtm.mWindowOrganizerController.getTaskFragment(fragmentToken));
+
+        // Fail to create TaskFragment when the task uid is different from owner activity.
+        activity.info.applicationInfo.uid = uid + 1;
+        activity.getTask().effectiveUid = uid;
+        mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
+
+        assertNull(mAtm.mWindowOrganizerController.getTaskFragment(fragmentToken));
+
+        // Successfully created a TaskFragment for same uid.
+        activity.info.applicationInfo.uid = uid;
+        activity.getTask().effectiveUid = uid;
+        mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
+
+        assertNotNull(mAtm.mWindowOrganizerController.getTaskFragment(fragmentToken));
     }
 
     @Test
@@ -424,4 +463,26 @@
 
         verify(mAtm.mRootWindowContainer).resumeFocusedTasksTopActivities();
     }
+
+    @Test
+    public void testDeferPendingTaskFragmentEventsOfInvisibleTask() {
+        // Task - TaskFragment - Activity.
+        final Task task = createTask(mDisplayContent);
+        final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm)
+                .setParentTask(task)
+                .setOrganizer(mOrganizer)
+                .build();
+
+        // Mock the task to invisible
+        doReturn(false).when(task).shouldBeVisible(any());
+
+        // Sending events
+        mController.registerOrganizer(mIOrganizer);
+        taskFragment.mTaskFragmentAppearedSent = true;
+        mController.onTaskFragmentInfoChanged(mIOrganizer, taskFragment);
+        mController.dispatchPendingEvents();
+
+        // Verifies that event was not sent
+        verify(mOrganizer, never()).onTaskFragmentInfoChanged(any());
+    }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java b/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java
index c742e56..7dfb5ae 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java
@@ -69,10 +69,6 @@
     }
 
     @Override
-    public void windowFocusChanged(boolean hasFocus) throws RemoteException {
-    }
-
-    @Override
     public void closeSystemDialogs(String reason) throws RemoteException {
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
index f366f57..caaf4e4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
@@ -54,7 +54,6 @@
 import android.view.Surface;
 import android.view.SurfaceControl;
 import android.view.WindowManager;
-import android.window.ITransitionPlayer;
 
 import androidx.test.filters.SmallTest;
 
@@ -313,11 +312,7 @@
         wallpaperWindow.setHasSurface(true);
 
         // Set-up mock shell transitions
-        final IBinder mockBinder = mock(IBinder.class);
-        final ITransitionPlayer mockPlayer = mock(ITransitionPlayer.class);
-        doReturn(mockBinder).when(mockPlayer).asBinder();
-        mWm.mAtmService.getTransitionController().registerTransitionPlayer(mockPlayer,
-                null /* appThread */);
+        registerTestTransitionPlayer();
 
         Transition transit =
                 mWm.mAtmService.getTransitionController().createTransition(TRANSIT_OPEN);
@@ -338,10 +333,21 @@
         assertFalse(token.isVisibleRequested());
         assertTrue(token.isVisible());
 
-        transit.onTransactionReady(transit.getSyncId(), mock(SurfaceControl.Transaction.class));
-        transit.finishTransition();
+        final SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class);
+        token.finishSync(t, false /* cancel */);
+        transit.onTransactionReady(transit.getSyncId(), t);
+        dc.mTransitionController.finishTransition(transit);
         assertFalse(wallpaperWindow.isVisible());
         assertFalse(token.isVisible());
+
+        // Assume wallpaper was visible. When transaction is ready without wallpaper target,
+        // wallpaper should be requested to be invisible.
+        token.setVisibility(true);
+        transit = dc.mTransitionController.createTransition(TRANSIT_CLOSE);
+        dc.mTransitionController.collect(token);
+        transit.onTransactionReady(transit.getSyncId(), t);
+        assertFalse(token.isVisibleRequested());
+        assertTrue(token.isVisible());
     }
 
     private WindowState createWallpaperTargetWindow(DisplayContent dc) {
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
index f05dd63..e19ea47 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
@@ -841,7 +841,7 @@
             try {
                 return mContext.bindIsolatedService(
                         mIntent,
-                        Context.BIND_AUTO_CREATE | mBindingFlags,
+                        Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE | mBindingFlags,
                         "hotword_detector_" + mInstanceNumber,
                         mExecutor,
                         serviceConnection);
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index f4f06fd..96c78bc 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -191,7 +191,7 @@
         IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
         mContext.registerReceiver(mBroadcastReceiver, filter, null, handler,
-                Context.RECEIVER_NOT_EXPORTED);
+                Context.RECEIVER_EXPORTED);
     }
 
     public boolean showSessionLocked(Bundle args, int flags,
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index abbce1c..98f619f 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -1687,7 +1687,11 @@
      *
      * @param accountHandle The handle for the account retrieve a number for.
      * @return A string representation of the line 1 phone number.
+     * @deprecated use {@link SubscriptionManager#getPhoneNumber(int)} instead, which takes a
+     *             Telephony Subscription ID that can be retrieved with the {@code accountHandle}
+     *             from {@link TelephonyManager#getSubscriptionId(PhoneAccountHandle)}.
      */
+    @Deprecated
     @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges or default SMS app
     @RequiresPermission(anyOf = {
             android.Manifest.permission.READ_PHONE_STATE,
diff --git a/telephony/common/Android.bp b/telephony/common/Android.bp
index 1cacc03..b0a812b 100644
--- a/telephony/common/Android.bp
+++ b/telephony/common/Android.bp
@@ -21,7 +21,10 @@
 
 filegroup {
     name: "framework-mms-shared-srcs",
-    visibility: ["//packages/apps/Bluetooth"],
+    visibility: [
+        "//packages/apps/Bluetooth",
+	"//packages/modules/Bluetooth/android/app",
+    ],
     srcs: [
         "com/google/android/mms/**/*.java",
     ],
diff --git a/telephony/java/android/service/euicc/EuiccService.java b/telephony/java/android/service/euicc/EuiccService.java
index fcbb008..fabe612 100644
--- a/telephony/java/android/service/euicc/EuiccService.java
+++ b/telephony/java/android/service/euicc/EuiccService.java
@@ -255,6 +255,12 @@
     public static final String EXTRA_RESOLUTION_CARD_ID =
             "android.service.euicc.extra.RESOLUTION_CARD_ID";
 
+    /**
+     * Intent extra set for resolution requests containing an int indicating the current port index.
+     */
+    public static final String EXTRA_RESOLUTION_PORT_INDEX =
+            "android.service.euicc.extra.RESOLUTION_PORT_INDEX";
+
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(prefix = { "RESULT_" }, value = {
@@ -579,9 +585,32 @@
      * @return the result of the switch operation. May be one of the predefined {@code RESULT_}
      *     constants or any implementation-specific code starting with {@link #RESULT_FIRST_USER}.
      * @see android.telephony.euicc.EuiccManager#switchToSubscription
+     *
+     * @deprecated prefer {@link #onSwitchToSubscriptionWithPort(int, int, String, boolean)}
      */
-    public abstract @Result int onSwitchToSubscription(int slotId, @Nullable String iccid,
-            boolean forceDeactivateSim);
+    @Deprecated public abstract @Result int onSwitchToSubscription(int slotId,
+            @Nullable String iccid, boolean forceDeactivateSim);
+
+    /**
+     * Switch to the given subscription.
+     *
+     * @param slotId ID of the SIM slot to use for the operation.
+     * @param portIndex which port on the eUICC to use
+     * @param iccid the ICCID of the subscription to enable. May be null, in which case the current
+     *     profile should be deactivated and no profile should be activated to replace it - this is
+     *     equivalent to a physical SIM being ejected.
+     * @param forceDeactivateSim If true, and if an active SIM must be deactivated to access the
+     *     eUICC, perform this action automatically. Otherwise, {@link #RESULT_MUST_DEACTIVATE_SIM}
+     *     should be returned to allow the user to consent to this operation first.
+     * @return the result of the switch operation. May be one of the predefined {@code RESULT_}
+     *     constants or any implementation-specific code starting with {@link #RESULT_FIRST_USER}.
+     * @see android.telephony.euicc.EuiccManager#switchToSubscription
+     */
+    public @Result int onSwitchToSubscriptionWithPort(int slotId, int portIndex,
+            @Nullable String iccid, boolean forceDeactivateSim) {
+        // stub implementation, LPA needs to implement this
+        throw new UnsupportedOperationException("LPA must override onSwitchToSubscriptionWithPort");
+    }
 
     /**
      * Update the nickname of the given subscription.
@@ -821,13 +850,13 @@
                 }
             });
         }
-
         @Override
-        public void switchToSubscription(int slotId, String iccid, boolean forceDeactivateSim,
-                ISwitchToSubscriptionCallback callback) {
+        public void switchToSubscription(int slotId, int portIndex, String iccid,
+                boolean forceDeactivateSim, ISwitchToSubscriptionCallback callback) {
             mExecutor.execute(new Runnable() {
                 @Override
                 public void run() {
+                    // TODO(b/207392528: use portIndex API once implemented)
                     int result =
                             EuiccService.this.onSwitchToSubscription(
                                     slotId, iccid, forceDeactivateSim);
diff --git a/telephony/java/android/service/euicc/IEuiccService.aidl b/telephony/java/android/service/euicc/IEuiccService.aidl
index bb7b569..aa30c9e 100644
--- a/telephony/java/android/service/euicc/IEuiccService.aidl
+++ b/telephony/java/android/service/euicc/IEuiccService.aidl
@@ -48,7 +48,7 @@
             in IGetDefaultDownloadableSubscriptionListCallback callback);
     void getEuiccInfo(int slotId, in IGetEuiccInfoCallback callback);
     void deleteSubscription(int slotId, String iccid, in IDeleteSubscriptionCallback callback);
-    void switchToSubscription(int slotId, String iccid, boolean forceDeactivateSim,
+    void switchToSubscription(int slotId, int portIndex, String iccid, boolean forceDeactivateSim,
             in ISwitchToSubscriptionCallback callback);
     void updateSubscriptionNickname(int slotId, String iccid, String nickname,
             in IUpdateSubscriptionNicknameCallback callback);
diff --git a/telephony/java/android/telephony/Annotation.java b/telephony/java/android/telephony/Annotation.java
index 23cf511..e88106c 100644
--- a/telephony/java/android/telephony/Annotation.java
+++ b/telephony/java/android/telephony/Annotation.java
@@ -1,6 +1,8 @@
 package android.telephony;
 
 import android.annotation.IntDef;
+import android.net.NetworkAgent;
+import android.net.NetworkCapabilities;
 import android.telecom.Connection;
 import android.telephony.data.ApnSetting;
 
@@ -664,4 +666,59 @@
         TelephonyManager.THERMAL_MITIGATION_RESULT_INVALID_STATE,
         TelephonyManager.THERMAL_MITIGATION_RESULT_UNKNOWN_ERROR})
     public @interface ThermalMitigationResult {}
+
+    /**
+     * Per Android API guideline 8.15, annotation can't be public APIs. So duplicate
+     * android.net.NetworkCapabilities.NetCapability here. Must update here when new capabilities
+     * are added in {@link NetworkCapabilities}.
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = { "NET_CAPABILITY_" }, value = {
+            NetworkCapabilities.NET_CAPABILITY_MMS,
+            NetworkCapabilities.NET_CAPABILITY_SUPL,
+            NetworkCapabilities.NET_CAPABILITY_DUN,
+            NetworkCapabilities.NET_CAPABILITY_FOTA,
+            NetworkCapabilities.NET_CAPABILITY_IMS,
+            NetworkCapabilities.NET_CAPABILITY_CBS,
+            NetworkCapabilities.NET_CAPABILITY_WIFI_P2P,
+            NetworkCapabilities.NET_CAPABILITY_IA,
+            NetworkCapabilities.NET_CAPABILITY_RCS,
+            NetworkCapabilities.NET_CAPABILITY_XCAP,
+            NetworkCapabilities.NET_CAPABILITY_EIMS,
+            NetworkCapabilities.NET_CAPABILITY_NOT_METERED,
+            NetworkCapabilities.NET_CAPABILITY_INTERNET,
+            NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED,
+            NetworkCapabilities.NET_CAPABILITY_TRUSTED,
+            NetworkCapabilities.NET_CAPABILITY_NOT_VPN,
+            NetworkCapabilities.NET_CAPABILITY_VALIDATED,
+            NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL,
+            NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING,
+            NetworkCapabilities.NET_CAPABILITY_FOREGROUND,
+            NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED,
+            NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED,
+            NetworkCapabilities.NET_CAPABILITY_OEM_PAID,
+            NetworkCapabilities.NET_CAPABILITY_MCX,
+            NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY,
+            NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED,
+            NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE,
+            NetworkCapabilities.NET_CAPABILITY_VEHICLE_INTERNAL,
+            NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED,
+            NetworkCapabilities.NET_CAPABILITY_ENTERPRISE,
+            NetworkCapabilities.NET_CAPABILITY_VSIM,
+            NetworkCapabilities.NET_CAPABILITY_BIP,
+            NetworkCapabilities.NET_CAPABILITY_HEAD_UNIT,
+    })
+    public @interface NetCapability { }
+
+    /**
+     * Per Android API guideline 8.15, annotation can't be public APIs. So duplicate
+     * android.net.NetworkAgent.ValidationStatus here. Must update here when new validation status
+     * are added in {@link NetworkAgent}.
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = { "VALIDATION_STATUS_" }, value = {
+            NetworkAgent.VALIDATION_STATUS_VALID,
+            NetworkAgent.VALIDATION_STATUS_NOT_VALID
+    })
+    public @interface ValidationStatus {}
 }
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index f700d79..c7e5aaf 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -5207,16 +5207,6 @@
             "call_composer_picture_server_url_string";
 
     /**
-     * For Android 11, provide a temporary solution for OEMs to use the lower of the two MTU values
-     * for IPv4 and IPv6 if both are sent.
-     * TODO: remove in later release
-     *
-     * @hide
-     */
-    public static final String KEY_USE_LOWER_MTU_VALUE_IF_BOTH_RECEIVED =
-            "use_lower_mtu_value_if_both_received";
-
-    /**
      * Determines the default RTT mode.
      *
      * Upon first boot, when the user has not yet set a value for their preferred RTT mode,
@@ -5961,16 +5951,15 @@
                         "capabilities=eims, retry_interval=1000, maximum_retries=20",
                         "fail_causes=8|27|28|29|30|32|33|35|50|51|111|-5|-6|65537|65538|-3|2253|"
                                 + "2254, maximum_retries=0", // No retry for those causes
+                        "capabilities=mms|supl|cbs, retry_interval=2000",
                         "capabilities=internet|enterprise|dun|ims|fota, retry_interval=2000, "
                                 + "backoff=true, maximum_retries=13",
-                        "capabilities=mms|supl|cbs, retry_interval=2000"
                 });
         sDefaults.putStringArray(KEY_MISSED_INCOMING_CALL_SMS_PATTERN_STRING_ARRAY, new String[0]);
         sDefaults.putBoolean(KEY_DISABLE_DUN_APN_WHILE_ROAMING_WITH_PRESET_APN_BOOL, false);
         sDefaults.putString(KEY_DEFAULT_PREFERRED_APN_NAME_STRING, "");
         sDefaults.putBoolean(KEY_SUPPORTS_CALL_COMPOSER_BOOL, false);
         sDefaults.putString(KEY_CALL_COMPOSER_PICTURE_SERVER_URL_STRING, "");
-        sDefaults.putBoolean(KEY_USE_LOWER_MTU_VALUE_IF_BOTH_RECEIVED, false);
         sDefaults.putBoolean(KEY_USE_ACS_FOR_RCS_BOOL, false);
         sDefaults.putBoolean(KEY_NETWORK_TEMP_NOT_METERED_SUPPORTED_BOOL, true);
         sDefaults.putInt(KEY_DEFAULT_RTT_MODE_INT, 0);
diff --git a/telephony/java/android/telephony/DataFailCause.java b/telephony/java/android/telephony/DataFailCause.java
index 88efe1f..56bf303 100644
--- a/telephony/java/android/telephony/DataFailCause.java
+++ b/telephony/java/android/telephony/DataFailCause.java
@@ -1076,6 +1076,13 @@
      */
     public static final int SERVICE_TEMPORARILY_UNAVAILABLE = 0x10009;
 
+    /**
+     * The request is not supported by the vendor.
+     *
+     * @hide
+     */
+    public static final int REQUEST_NOT_SUPPORTED = 0x1000A;
+
     private static final Map<Integer, String> sFailCauseMap;
     static {
         sFailCauseMap = new HashMap<>();
diff --git a/telephony/java/android/telephony/SignalStrengthUpdateRequest.java b/telephony/java/android/telephony/SignalStrengthUpdateRequest.java
index 2ff4ac5..9cb80f1 100644
--- a/telephony/java/android/telephony/SignalStrengthUpdateRequest.java
+++ b/telephony/java/android/telephony/SignalStrengthUpdateRequest.java
@@ -71,12 +71,7 @@
             @Nullable List<SignalThresholdInfo> signalThresholdInfos,
             boolean isReportingRequestedWhileIdle,
             boolean isSystemThresholdReportingRequestedWhileIdle) {
-        // System app (like Bluetooth) can specify the request to report system thresholds while
-        // device is idle (with permission protection). In this case, the request doesn't need to
-        // provide a non-empty list of SignalThresholdInfo which is only asked for public apps.
-        if (!isSystemThresholdReportingRequestedWhileIdle) {
-            validate(signalThresholdInfos);
-        }
+        validate(signalThresholdInfos, isSystemThresholdReportingRequestedWhileIdle);
 
         mSignalThresholdInfos = signalThresholdInfos;
         mIsReportingRequestedWhileIdle = isReportingRequestedWhileIdle;
@@ -274,8 +269,12 @@
      * Throw IAE if SignalThresholdInfo collection is null or empty,
      * or the SignalMeasurementType for the same RAN in the collection is not unique.
      */
-    private static void validate(Collection<SignalThresholdInfo> infos) {
-        if (infos == null || infos.isEmpty()) {
+    private static void validate(Collection<SignalThresholdInfo> infos,
+            boolean isSystemThresholdReportingRequestedWhileIdle) {
+        // System app (like Bluetooth) can specify the request to report system thresholds while
+        // device is idle (with permission protection). In this case, the request doesn't need to
+        // provide a non-empty list of SignalThresholdInfo which is only asked for public apps.
+        if (infos == null || (infos.isEmpty() && !isSystemThresholdReportingRequestedWhileIdle)) {
             throw new IllegalArgumentException("SignalThresholdInfo collection is null or empty");
         }
 
diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java
index d6d6775..d11ad91 100644
--- a/telephony/java/android/telephony/SubscriptionInfo.java
+++ b/telephony/java/android/telephony/SubscriptionInfo.java
@@ -498,7 +498,10 @@
      *
      * @return the number of this subscription, or an empty string if one of these requirements is
      * not met
+     * @deprecated use {@link SubscriptionManager#getPhoneNumber(int)} instead, which takes a
+     *             {@link #getSubscriptionId() subscription ID}.
      */
+    @Deprecated
     public String getNumber() {
         return mNumber;
     }
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 04e7b7c..88b21e0 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -4791,7 +4791,10 @@
      *     for any API level.
      *     {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
      *     for apps targeting SDK API level 29 and below.
+     *
+     * @deprecated use {@link SubscriptionManager#getPhoneNumber(int)} instead.
      */
+    @Deprecated
     @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges or default SMS app
     @RequiresPermission(anyOf = {
             android.Manifest.permission.READ_PHONE_STATE,
@@ -4864,7 +4867,9 @@
      * @param alphaTag alpha-tagging of the dailing nubmer
      * @param number The dialing number
      * @return true if the operation was executed correctly.
+     * @deprecated use {@link SubscriptionManager#setCarrierPhoneNumber(int, String)} instead.
      */
+    @Deprecated
     public boolean setLine1NumberForDisplay(String alphaTag, String number) {
         return setLine1NumberForDisplay(getSubId(), alphaTag, number);
     }
@@ -4885,6 +4890,10 @@
      */
     public boolean setLine1NumberForDisplay(int subId, String alphaTag, String number) {
         try {
+            // This API is deprecated; call the new API to allow smooth migartion.
+            // The new API doesn't accept null so convert null to empty string.
+            mSubscriptionManager.setCarrierPhoneNumber(subId, (number == null ? "" : number));
+
             ITelephony telephony = getITelephony();
             if (telephony != null)
                 return telephony.setLine1NumberForDisplayForSubscriber(subId, alphaTag, number);
diff --git a/telephony/java/android/telephony/UiccCardInfo.java b/telephony/java/android/telephony/UiccCardInfo.java
index 7dfe450..0dfab18 100644
--- a/telephony/java/android/telephony/UiccCardInfo.java
+++ b/telephony/java/android/telephony/UiccCardInfo.java
@@ -156,9 +156,11 @@
     @Nullable
     @Deprecated
     public String getIccId() {
-        if (mIccIdAccessRestricted) {
-            throw new UnsupportedOperationException("getIccId from UiccPortInfo");
-        }
+        // Temporarily bypassing exception
+        // TODO: add exception once refactoring completed.
+        //if (mIccIdAccessRestricted) {
+        //    throw new UnsupportedOperationException("getIccId from UiccPortInfo");
+        //}
         //always return ICCID from first port.
         return getPorts().stream().findFirst().get().getIccId();
     }
diff --git a/telephony/java/android/telephony/UiccSlotInfo.java b/telephony/java/android/telephony/UiccSlotInfo.java
index 2b1c8c8..a8668e7 100644
--- a/telephony/java/android/telephony/UiccSlotInfo.java
+++ b/telephony/java/android/telephony/UiccSlotInfo.java
@@ -159,9 +159,11 @@
      */
     @Deprecated
     public boolean getIsActive() {
-        if (mLogicalSlotAccessRestricted) {
-            throw new UnsupportedOperationException("get port status from UiccPortInfo");
-        }
+        // Temporarily bypassing exception
+        // TODO: add exception once refactoring completed.
+        //if (mLogicalSlotAccessRestricted) {
+        //    throw new UnsupportedOperationException("get port status from UiccPortInfo");
+        //}
         //always return status from first port.
         return getPorts().stream().findFirst().get().isActive();
     }
@@ -196,9 +198,11 @@
      */
     @Deprecated
     public int getLogicalSlotIdx() {
-        if (mLogicalSlotAccessRestricted) {
-            throw new UnsupportedOperationException("get logical slot index from UiccPortInfo");
-        }
+        // Temporarily bypassing exception
+        // TODO: add exception once refactoring completed.
+        //if (mLogicalSlotAccessRestricted) {
+        //    throw new UnsupportedOperationException("get logical slot index from UiccPortInfo");
+        //}
         //always return logical slot index from first port.
         //portList always have at least one element.
         return getPorts().stream().findFirst().get().getLogicalSlotIndex();
diff --git a/telephony/java/android/telephony/data/DataProfile.java b/telephony/java/android/telephony/data/DataProfile.java
index 93903d2..43ad982 100644
--- a/telephony/java/android/telephony/data/DataProfile.java
+++ b/telephony/java/android/telephony/data/DataProfile.java
@@ -22,9 +22,11 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
+import android.net.NetworkCapabilities;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.telephony.Annotation.ApnType;
+import android.telephony.Annotation.NetCapability;
 import android.telephony.TelephonyManager;
 import android.telephony.TelephonyManager.NetworkTypeBitMask;
 import android.telephony.data.ApnSetting.AuthType;
@@ -66,7 +68,7 @@
 
     private final @Nullable TrafficDescriptor mTrafficDescriptor;
 
-    private final boolean mPreferred;
+    private boolean mPreferred;
 
     private DataProfile(@NonNull Builder builder) {
         mApnSetting = builder.mApnSetting;
@@ -291,6 +293,16 @@
     }
 
     /**
+     * Set the preferred flag for the data profile.
+     *
+     * @param preferred {@code true} if this data profile is preferred for internet.
+     * @hide
+     */
+    public void setPreferred(boolean preferred) {
+        mPreferred = preferred;
+    }
+
+    /**
      * @return {@code true} if this data profile was used to bring up the last default
      * (i.e internet) data connection successfully, or the one chosen by the user in Settings'
      * APN editor. For one carrier there can be only one profiled preferred.
@@ -315,6 +327,76 @@
         return mTrafficDescriptor;
     }
 
+    /**
+     * Check if this data profile can satisfy certain network capabilities
+     *
+     * @param networkCapabilities The network capabilities. Note that the non-APN-type capabilities
+     * will be ignored.
+     *
+     * @return {@code true} if this data profile can satisfy the given network capabilities.
+     * @hide
+     */
+    public boolean canSatisfy(@NonNull @NetCapability int[] networkCapabilities) {
+        if (mApnSetting != null) {
+            for (int netCap : networkCapabilities) {
+                if (!canSatisfy(netCap)) {
+                    return false;
+                }
+            }
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Check if this data profile can satisfy a certain network capability.
+     *
+     * @param networkCapability The network capability. Note that the non-APN-type capability
+     * will always be satisfied.
+     * @return {@code true} if this data profile can satisfy the given network capability.
+     * @hide
+     */
+    public boolean canSatisfy(@NetCapability int networkCapability) {
+        return mApnSetting != null && mApnSetting.canHandleType(
+                networkCapabilityToApnType(networkCapability));
+    }
+
+    /**
+     * Convert network capability into APN type.
+     *
+     * @param networkCapability Network capability.
+     * @return APN type.
+     * @hide
+     */
+    private static @ApnType int networkCapabilityToApnType(@NetCapability int networkCapability) {
+        switch (networkCapability) {
+            case NetworkCapabilities.NET_CAPABILITY_MMS:
+                return ApnSetting.TYPE_MMS;
+            case NetworkCapabilities.NET_CAPABILITY_SUPL:
+                return ApnSetting.TYPE_SUPL;
+            case NetworkCapabilities.NET_CAPABILITY_DUN:
+                return ApnSetting.TYPE_DUN;
+            case NetworkCapabilities.NET_CAPABILITY_FOTA:
+                return ApnSetting.TYPE_FOTA;
+            case NetworkCapabilities.NET_CAPABILITY_IMS:
+                return ApnSetting.TYPE_IMS;
+            case NetworkCapabilities.NET_CAPABILITY_CBS:
+                return ApnSetting.TYPE_CBS;
+            case NetworkCapabilities.NET_CAPABILITY_XCAP:
+                return ApnSetting.TYPE_XCAP;
+            case NetworkCapabilities.NET_CAPABILITY_EIMS:
+                return ApnSetting.TYPE_EMERGENCY;
+            case NetworkCapabilities.NET_CAPABILITY_INTERNET:
+                return ApnSetting.TYPE_DEFAULT;
+            case NetworkCapabilities.NET_CAPABILITY_MCX:
+                return ApnSetting.TYPE_MCX;
+            case NetworkCapabilities.NET_CAPABILITY_IA:
+                return ApnSetting.TYPE_IA;
+            default:
+                return ApnSetting.TYPE_NONE;
+        }
+    }
+
     @Override
     public int describeContents() {
         return 0;
diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java
index 45022a6..aa514b9 100644
--- a/telephony/java/android/telephony/euicc/EuiccManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccManager.java
@@ -16,6 +16,7 @@
 package android.telephony.euicc;
 
 import android.Manifest;
+import android.annotation.CallbackExecutor;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -28,6 +29,7 @@
 import android.content.Intent;
 import android.content.IntentSender;
 import android.content.pm.PackageManager;
+import android.os.Binder;
 import android.os.Bundle;
 import android.os.RemoteException;
 import android.telephony.TelephonyFrameworkInitializer;
@@ -35,11 +37,13 @@
 import android.telephony.euicc.EuiccCardManager.ResetOption;
 
 import com.android.internal.telephony.euicc.IEuiccController;
+import com.android.internal.telephony.euicc.IResultCallback;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.Collections;
 import java.util.List;
+import java.util.concurrent.Executor;
 import java.util.stream.Collectors;
 
 /**
@@ -215,6 +219,20 @@
             "android.telephony.euicc.action.START_EUICC_ACTIVATION";
 
     /**
+     * Result codes passed to the ResultListener by
+     * {@link #switchToSubscription(int, int, Executor, ResultListener)}
+     *
+     * @hide
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"EMBEDDED_SUBSCRIPTION_RESULT_"}, value = {
+            EMBEDDED_SUBSCRIPTION_RESULT_OK,
+            EMBEDDED_SUBSCRIPTION_RESULT_ERROR,
+            EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR
+    })
+    public @interface ResultCode{}
+
+    /**
      * Result code for an operation indicating that the operation succeeded.
      */
     public static final int EMBEDDED_SUBSCRIPTION_RESULT_OK = 0;
@@ -1125,7 +1143,12 @@
      *     permission, or the calling app must be authorized to manage the active subscription on
      *     the target eUICC.
      * @param callbackIntent a PendingIntent to launch when the operation completes.
+     *
+     * @deprecated From T, callers should use
+     * {@link #switchToSubscription(int, int, Executor, ResultListener)} instead to specify a port
+     * index on the card to switch to.
      */
+    @Deprecated
     @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
     public void switchToSubscription(int subscriptionId, PendingIntent callbackIntent) {
         if (!isEnabled()) {
@@ -1141,6 +1164,71 @@
     }
 
     /**
+     * Switch to (enable) the given subscription.
+     *
+     * <p>Requires the {@code android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission,
+     * or the calling app must be authorized to manage both the currently-active subscription and
+     * the subscription to be enabled according to the subscription metadata. Without the former,
+     * an {@link #EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR} will be returned in the callback
+     * intent to prompt the user to accept the download.
+     *
+     * <p>On a multi-active SIM device, requires the
+     * {@code android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission, or a calling app
+     * only if the targeted eUICC does not currently have an active subscription or the calling app
+     * is authorized to manage the active subscription on the target eUICC, and the calling app is
+     * authorized to manage any active subscription on any SIM. Without it, an
+     * {@link #EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR} will be returned in the callback
+     * intent to prompt the user to accept the download. The caller should also be authorized to
+     * manage the subscription to be enabled.
+     *
+     * @param subscriptionId the ID of the subscription to enable. May be
+     *     {@link android.telephony.SubscriptionManager#INVALID_SUBSCRIPTION_ID} to deactivate the
+     *     current profile without activating another profile to replace it. If it's a disable
+     *     operation, requires the {@code android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS}
+     *     permission, or the calling app must be authorized to manage the active subscription on
+     *     the target eUICC.
+     * @param portIndex the index of the port to target for the enabled subscription
+     * @param executor an Executor on which to run the callback
+     * @param callback a {@link ResultListener} which will run when the operation completes
+     */
+    @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
+    public void switchToSubscription(int subscriptionId, int portIndex,
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull ResultListener callback) {
+        if (!isEnabled()) {
+            sendUnavailableErrorToCallback(executor, callback);
+            return;
+        }
+        try {
+            IResultCallback internalCallback = new IResultCallback.Stub() {
+                @Override
+                public void onComplete(int result, Intent resultIntent) {
+                    executor.execute(() -> Binder.withCleanCallingIdentity(
+                            () -> callback.onComplete(result, resultIntent)));
+                }
+            };
+            getIEuiccController().switchToSubscriptionWithPort(mCardId, portIndex,
+                    subscriptionId, mContext.getOpPackageName(), internalCallback);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Callback to receive the result of an EuiccManager API.
+     */
+    public interface ResultListener {
+        /**
+         * Called on completion of some operation.
+         * @param resultCode representing success or specific failure of the operation
+         *                   (See {@link ResultCode})
+         * @param resultIntent an intent used to start a resolution activity when an error
+         *                     occurs that can be resolved by the user
+         */
+        void onComplete(@ResultCode int resultCode, @Nullable Intent resultIntent);
+    }
+
+    /**
      * Update the nickname for the given subscription.
      *
      * <p>Requires that the calling app has carrier privileges according to the metadata of the
@@ -1411,6 +1499,13 @@
         }
     }
 
+    private static void sendUnavailableErrorToCallback(@NonNull Executor executor,
+            ResultListener callback) {
+        Integer result = EMBEDDED_SUBSCRIPTION_RESULT_ERROR;
+        executor.execute(() ->
+                Binder.withCleanCallingIdentity(() -> callback.onComplete(result, null)));
+    }
+
     private static IEuiccController getIEuiccController() {
         return IEuiccController.Stub.asInterface(
                 TelephonyFrameworkInitializer
diff --git a/telephony/java/android/telephony/ims/DelegateRegistrationState.java b/telephony/java/android/telephony/ims/DelegateRegistrationState.java
index c00c741..1b10404 100644
--- a/telephony/java/android/telephony/ims/DelegateRegistrationState.java
+++ b/telephony/java/android/telephony/ims/DelegateRegistrationState.java
@@ -117,6 +117,7 @@
     })
     public @interface DeregisteringReason {}
 
+    private ArraySet<String> mRegisteringTags = new ArraySet<>();
     private ArraySet<String> mRegisteredTags = new ArraySet<>();
     private final ArraySet<FeatureTagState> mDeregisteringTags = new ArraySet<>();
     private final ArraySet<FeatureTagState> mDeregisteredTags = new ArraySet<>();
@@ -134,6 +135,20 @@
         }
 
         /**
+         * Add the set of feature tags that are associated with this SipDelegate and
+         * the IMS stack is actively trying to register on the carrier network.
+         *
+         * The feature tags will either move to the registered or deregistered state
+         * depending on the result of the registration.
+         * @param featureTags The IMS media feature tags that are in the progress of registering.
+         * @return The in-progress Builder instance for RegistrationState. ]
+         */
+        public @NonNull Builder addRegisteringFeatureTags(@NonNull Set<String> featureTags) {
+            mState.mRegisteringTags.addAll(featureTags);
+            return this;
+        }
+
+        /**
          * Add a feature tag that is currently included in the current network IMS Registration.
          * @param featureTag The IMS media feature tag included in the current IMS registration.
          * @return The in-progress Builder instance for RegistrationState.
@@ -209,6 +224,17 @@
         mRegisteredTags = (ArraySet<String>) source.readArraySet(null);
         readStateFromParcel(source, mDeregisteringTags);
         readStateFromParcel(source, mDeregisteredTags);
+        mRegisteringTags = (ArraySet<String>) source.readArraySet(null);
+    }
+
+    /**
+     * Get the feature tags that are associated with this SipDelegate that the IMS stack is actively
+     * trying to register on the carrier network.
+     * @return A Set of feature tags associated with this SipDelegate that the IMS service is
+     * currently trying to register on the  carrier network.
+     */
+    public @NonNull Set<String> getRegisteringFeatureTags() {
+        return new ArraySet<>(mRegisteringTags);
     }
 
     /**
@@ -286,6 +312,7 @@
         dest.writeArraySet(mRegisteredTags);
         writeStateToParcel(dest, mDeregisteringTags);
         writeStateToParcel(dest, mDeregisteredTags);
+        dest.writeArraySet(mRegisteringTags);
     }
 
     private void writeStateToParcel(Parcel dest, Set<FeatureTagState> state) {
@@ -311,19 +338,22 @@
         if (this == o) return true;
         if (o == null || getClass() != o.getClass()) return false;
         DelegateRegistrationState that = (DelegateRegistrationState) o;
-        return mRegisteredTags.equals(that.mRegisteredTags)
+        return mRegisteringTags.equals(that.mRegisteringTags)
+                && mRegisteredTags.equals(that.mRegisteredTags)
                 && mDeregisteringTags.equals(that.mDeregisteringTags)
                 && mDeregisteredTags.equals(that.mDeregisteredTags);
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(mRegisteredTags, mDeregisteringTags, mDeregisteredTags);
+        return Objects.hash(mRegisteringTags, mRegisteredTags,
+                mDeregisteringTags, mDeregisteredTags);
     }
 
     @Override
     public String toString() {
         return "DelegateRegistrationState{ registered={" + mRegisteredTags
+                + "}, registering={" + mRegisteringTags
                 + "}, deregistering={" + mDeregisteringTags + "}, deregistered={"
                 + mDeregisteredTags + "}}";
     }
diff --git a/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl b/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl
index 944ce348..7f5982f 100644
--- a/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl
+++ b/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl
@@ -21,6 +21,9 @@
 import android.os.Bundle;
 import android.telephony.euicc.DownloadableSubscription;
 import android.telephony.euicc.EuiccInfo;
+
+import com.android.internal.telephony.euicc.IResultCallback;
+
 import java.util.List;
 
 /** @hide */
@@ -42,6 +45,8 @@
         in PendingIntent callbackIntent);
     oneway void switchToSubscription(int cardId, int subscriptionId, String callingPackage,
         in PendingIntent callbackIntent);
+    oneway void switchToSubscriptionWithPort(int cardId, int portIndex, int subscriptionId,
+        String callingPackage, in IResultCallback callback);
     oneway void updateSubscriptionNickname(int cardId, int subscriptionId, String nickname,
         String callingPackage, in PendingIntent callbackIntent);
     oneway void eraseSubscriptions(int cardId, in PendingIntent callbackIntent);
diff --git a/core/java/android/window/TaskFragmentAppearedInfo.aidl b/telephony/java/com/android/internal/telephony/euicc/IResultCallback.aidl
similarity index 76%
rename from core/java/android/window/TaskFragmentAppearedInfo.aidl
rename to telephony/java/com/android/internal/telephony/euicc/IResultCallback.aidl
index 3729c09..69f479c 100644
--- a/core/java/android/window/TaskFragmentAppearedInfo.aidl
+++ b/telephony/java/com/android/internal/telephony/euicc/IResultCallback.aidl
@@ -13,11 +13,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package com.android.internal.telephony.euicc;
 
-package android.window;
+import android.content.Intent;
 
-/**
- * Data object for the TaskFragment info provided when a TaskFragment is presented to an organizer.
- * @hide
- */
-parcelable TaskFragmentAppearedInfo;
+/** @hide */
+oneway interface IResultCallback {
+    void onComplete(int resultCode, in Intent resultIntent);
+}
diff --git a/tests/AttestationVerificationTest/OWNERS b/tests/AttestationVerificationTest/OWNERS
new file mode 100644
index 0000000..a7a6ef1
--- /dev/null
+++ b/tests/AttestationVerificationTest/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/security/attestationverification/OWNERS
diff --git a/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java b/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java
index e4e535d..da5468e 100644
--- a/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java
+++ b/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java
@@ -157,8 +157,18 @@
 
     @Test
     public void testStagedSessionShouldCleanUpOnVerificationFailure() throws Exception {
+        // APEX verification
         InstallUtils.commitExpectingFailure(AssertionError.class, "apexd verification failed",
                 Install.single(APEX_WRONG_SHA_V2).setStaged());
+        InstallUtils.commitExpectingFailure(AssertionError.class, "apexd verification failed",
+                Install.multi(APEX_WRONG_SHA_V2, TestApp.A1).setStaged());
+        // APK verification
+        Install.single(TestApp.A2).commit();
+        assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
+        InstallUtils.commitExpectingFailure(AssertionError.class, "Downgrade detected",
+                Install.single(TestApp.A1).setStaged());
+        InstallUtils.commitExpectingFailure(AssertionError.class, "Downgrade detected",
+                Install.multi(TestApp.A1, TestApp.B1).setStaged());
     }
 
     @Test
@@ -176,6 +186,12 @@
     }
 
     @Test
+    public void testStagedSessionShouldCleanUpOnOnSuccessMultiPackage_Commit() throws Exception {
+        int sessionId = Install.multi(TestApp.A1, TestApp.Apex2).setStaged().commit();
+        storeSessionId(sessionId);
+    }
+
+    @Test
     public void testStagedInstallationShouldCleanUpOnValidationFailure() throws Exception {
         InstallUtils.commitExpectingFailure(AssertionError.class, "INSTALL_FAILED_INVALID_APK",
                 Install.single(TestApp.AIncompleteSplit).setStaged());
diff --git a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
index 78cf9ac..926bf1b 100644
--- a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
+++ b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
@@ -301,6 +301,18 @@
     }
 
     @Test
+    @LargeTest
+    public void testStagedSessionShouldCleanUpOnOnSuccessMultiPackage() throws Exception {
+        List<String> before = getStagingDirectories();
+        runPhase("testStagedSessionShouldCleanUpOnOnSuccessMultiPackage_Commit");
+        assertThat(getStagingDirectories()).isNotEqualTo(before);
+        getDevice().reboot();
+        runPhase("testStagedSessionShouldCleanUpOnOnSuccess_Verify");
+        List<String> after = getStagingDirectories();
+        assertThat(after).isEqualTo(before);
+    }
+
+    @Test
     public void testStagedInstallationShouldCleanUpOnValidationFailure() throws Exception {
         List<String> before = getStagingDirectories();
         runPhase("testStagedInstallationShouldCleanUpOnValidationFailure");
diff --git a/tests/utils/hostutils/src/com/android/internal/util/test/SystemPreparer.java b/tests/utils/hostutils/src/com/android/internal/util/test/SystemPreparer.java
index 8444833..525a784 100644
--- a/tests/utils/hostutils/src/com/android/internal/util/test/SystemPreparer.java
+++ b/tests/utils/hostutils/src/com/android/internal/util/test/SystemPreparer.java
@@ -207,17 +207,6 @@
             default:
                 device.executeShellCommand("stop");
                 device.executeShellCommand("start");
-                ITestDevice.RecoveryMode cachedRecoveryMode = device.getRecoveryMode();
-                device.setRecoveryMode(ITestDevice.RecoveryMode.ONLINE);
-
-                if (device.isEncryptionSupported()) {
-                    if (device.isDeviceEncrypted()) {
-                        LogUtil.CLog.e("Device is encrypted after userspace reboot!");
-                        device.unlockDevice();
-                    }
-                }
-
-                device.setRecoveryMode(cachedRecoveryMode);
                 device.waitForDeviceAvailable();
                 break;
         }
diff --git a/tools/aosp/aosp_sha.sh b/tools/aosp/aosp_sha.sh
index ac23c3d..36bea57 100755
--- a/tools/aosp/aosp_sha.sh
+++ b/tools/aosp/aosp_sha.sh
@@ -1,7 +1,7 @@
 #!/bin/bash
 LOCAL_DIR="$( dirname "${BASH_SOURCE}" )"
 
-if git branch -vv | grep -q -P "^\*[^\[]+\[aosp/"; then
+if git branch -vv | grep -q -E "^\*[^\[]+\[aosp/"; then
     # Change appears to be in AOSP
     exit 0
 elif git log -n 1 --format='%B' $1 | grep -q -E "^Ignore-AOSP-First: .+" ; then