Merge "Update BTS Service to use push API instead of pull API in BIC" into main
diff --git a/AconfigFlags.bp b/AconfigFlags.bp
index bd1d3e2..e184704 100644
--- a/AconfigFlags.bp
+++ b/AconfigFlags.bp
@@ -373,6 +373,11 @@
     name: "android.security.flags-aconfig-java-export",
     aconfig_declarations: "android.security.flags-aconfig",
     mode: "exported",
+    min_sdk_version: "30",
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.wifi",
+    ],
     defaults: ["framework-minus-apex-aconfig-java-defaults"],
 }
 
diff --git a/core/api/current.txt b/core/api/current.txt
index a42a8de..5773d1f 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -1502,6 +1502,7 @@
     field public static final int shadowRadius = 16843108; // 0x1010164
     field public static final int shape = 16843162; // 0x101019a
     field public static final int shareInterpolator = 16843195; // 0x10101bb
+    field @FlaggedApi("android.nfc.nfc_associated_role_services") public static final int shareRolePriority;
     field @Deprecated public static final int sharedUserId = 16842763; // 0x101000b
     field @Deprecated public static final int sharedUserLabel = 16843361; // 0x1010261
     field public static final int sharedUserMaxSdkVersion = 16844365; // 0x101064d
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index e225bb4..caaab5f 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -34,6 +34,7 @@
     field public static final String ACCESS_VIBRATOR_STATE = "android.permission.ACCESS_VIBRATOR_STATE";
     field public static final String ACTIVITY_EMBEDDING = "android.permission.ACTIVITY_EMBEDDING";
     field public static final String ADD_ALWAYS_UNLOCKED_DISPLAY = "android.permission.ADD_ALWAYS_UNLOCKED_DISPLAY";
+    field @FlaggedApi("android.companion.virtualdevice.flags.enable_limited_vdm_role") public static final String ADD_MIRROR_DISPLAY = "android.permission.ADD_MIRROR_DISPLAY";
     field public static final String ADD_TRUSTED_DISPLAY = "android.permission.ADD_TRUSTED_DISPLAY";
     field public static final String ADJUST_RUNTIME_PERMISSIONS_POLICY = "android.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY";
     field public static final String ALLOCATE_AGGRESSIVE = "android.permission.ALLOCATE_AGGRESSIVE";
@@ -11110,6 +11111,7 @@
     method @FlaggedApi("android.nfc.enable_nfc_mainline") public void setDynamicAidGroup(@NonNull android.nfc.cardemulation.AidGroup);
     method @FlaggedApi("android.nfc.enable_nfc_mainline") public void setOffHostSecureElement(@NonNull String);
     method @FlaggedApi("android.nfc.nfc_observe_mode") public void setShouldDefaultToObserveMode(boolean);
+    method @FlaggedApi("android.nfc.nfc_associated_role_services") public boolean shareRolePriority();
     method @FlaggedApi("android.nfc.nfc_observe_mode") public boolean shouldDefaultToObserveMode();
     method @FlaggedApi("android.nfc.enable_nfc_mainline") public void writeToParcel(@NonNull android.os.Parcel, int);
     field @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public static final android.os.Parcelable.Creator<android.nfc.cardemulation.ApduServiceInfo> CREATOR;
@@ -12865,6 +12867,30 @@
 
 package android.security.intrusiondetection {
 
+  @FlaggedApi("android.security.afl_api") public final class IntrusionDetectionEvent implements android.os.Parcelable {
+    ctor public IntrusionDetectionEvent(@NonNull android.app.admin.SecurityLog.SecurityEvent);
+    ctor public IntrusionDetectionEvent(@NonNull android.app.admin.DnsEvent);
+    ctor public IntrusionDetectionEvent(@NonNull android.app.admin.ConnectEvent);
+    method @FlaggedApi("android.security.afl_api") public int describeContents();
+    method @NonNull public android.app.admin.ConnectEvent getConnectEvent();
+    method @NonNull public android.app.admin.DnsEvent getDnsEvent();
+    method @NonNull public android.app.admin.SecurityLog.SecurityEvent getSecurityEvent();
+    method @NonNull public int getType();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.security.intrusiondetection.IntrusionDetectionEvent> CREATOR;
+    field public static final int NETWORK_EVENT_CONNECT = 2; // 0x2
+    field public static final int NETWORK_EVENT_DNS = 1; // 0x1
+    field public static final int SECURITY_EVENT = 0; // 0x0
+  }
+
+  @FlaggedApi("android.security.afl_api") public class IntrusionDetectionEventTransport {
+    ctor public IntrusionDetectionEventTransport();
+    method public boolean addData(@NonNull java.util.List<android.security.intrusiondetection.IntrusionDetectionEvent>);
+    method @NonNull public android.os.IBinder getBinder();
+    method public boolean initialize();
+    method public boolean release();
+  }
+
   @FlaggedApi("android.security.afl_api") public class IntrusionDetectionManager {
     method @RequiresPermission(android.Manifest.permission.READ_INTRUSION_DETECTION_STATE) public void addStateCallback(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
     method @RequiresPermission(android.Manifest.permission.MANAGE_INTRUSION_DETECTION_STATE) public void disable(@NonNull java.util.concurrent.Executor, @NonNull android.security.intrusiondetection.IntrusionDetectionManager.CommandCallback);
@@ -16196,6 +16222,7 @@
     method @Nullable @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public android.content.ComponentName getAndUpdateDefaultRespondViaMessageApplication();
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getCallForwarding(int, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CallForwardingInfoCallback);
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getCallWaitingStatus(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
+    method @FlaggedApi("com.android.internal.telephony.flags.carrier_id_from_carrier_identifier") @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @WorkerThread public int getCarrierIdFromCarrierIdentifier(@NonNull android.service.carrier.CarrierIdentifier);
     method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.ImsiEncryptionInfo getCarrierInfoForImsiEncryption(int);
     method public java.util.List<java.lang.String> getCarrierPackageNamesForIntent(android.content.Intent);
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.List<java.lang.String> getCarrierPackageNamesForIntentAndPhone(android.content.Intent, int);
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index b84c91b..0e68cce 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -814,9 +814,9 @@
         if (Flags.notificationsRedesignTemplates()) {
             return switch (layoutId) {
                 case R.layout.notification_2025_template_collapsed_base,
+                     R.layout.notification_2025_template_expanded_base,
                      R.layout.notification_2025_template_heads_up_base,
                      R.layout.notification_2025_template_header,
-                     R.layout.notification_template_material_big_base,
                      R.layout.notification_template_material_big_picture,
                      R.layout.notification_template_material_big_text,
                      R.layout.notification_template_material_inbox,
@@ -3263,6 +3263,7 @@
     public boolean hasPromotableCharacteristics() {
         return isColorizedRequested()
                 && hasTitle()
+                && !isGroupSummary()
                 && !containsCustomViews()
                 && hasPromotableStyle();
     }
@@ -7545,7 +7546,11 @@
         }
 
         private int getBigBaseLayoutResource() {
-            return R.layout.notification_template_material_big_base;
+            if (Flags.notificationsRedesignTemplates()) {
+                return R.layout.notification_2025_template_expanded_base;
+            } else {
+                return R.layout.notification_template_material_big_base;
+            }
         }
 
         private int getBigPictureLayoutResource() {
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index e766ae2..42fa9e7 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -14453,7 +14453,7 @@
      * </ul>
      * <p>
      * The following methods are supported for the parent instance but can only be called by the
-     * profile owner of a managed profile that was created during the device provisioning flow:
+     * profile owner on an <a href="#organization-owned">organization owned</a> managed profile:
      * <ul>
      * <li>{@link #getPasswordComplexity}</li>
      * <li>{@link #setCameraDisabled}</li>
@@ -14461,11 +14461,6 @@
      * <li>{@link #setAccountManagementDisabled(ComponentName, String, boolean)}</li>
      * <li>{@link #setPermittedInputMethods}</li>
      * <li>{@link #getPermittedInputMethods}</li>
-     * </ul>
-     *
-     * <p>The following methods can be called by the profile owner of a managed profile
-     * on an organization-owned device:
-     * <ul>
      * <li>{@link #wipeData}</li>
      * </ul>
      *
@@ -18177,4 +18172,4 @@
         }
         return HEADLESS_DEVICE_OWNER_MODE_UNSUPPORTED;
     }
-}
\ No newline at end of file
+}
diff --git a/core/java/android/companion/virtual/IVirtualDevice.aidl b/core/java/android/companion/virtual/IVirtualDevice.aidl
index d3a1c25..367f1af 100644
--- a/core/java/android/companion/virtual/IVirtualDevice.aidl
+++ b/core/java/android/companion/virtual/IVirtualDevice.aidl
@@ -90,11 +90,6 @@
      */
     boolean hasCustomAudioInputSupport();
 
-    /**
-     * Returns whether this device is allowed to create mirror displays.
-     */
-    boolean canCreateMirrorDisplays();
-
     /*
      * Turns off all trusted non-mirror displays of the virtual device.
      */
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 3d2d487..02eed1a 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -7720,6 +7720,7 @@
     @IntDef(flag = true, prefix = { "EXTENDED_FLAG_" }, value = {
             EXTENDED_FLAG_FILTER_MISMATCH,
             EXTENDED_FLAG_MISSING_CREATOR_OR_INVALID_TOKEN,
+            EXTENDED_FLAG_NESTED_INTENT_KEYS_COLLECTED,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface ExtendedFlags {}
@@ -7740,6 +7741,13 @@
      */
     public static final int EXTENDED_FLAG_MISSING_CREATOR_OR_INVALID_TOKEN = 1 << 1;
 
+    /**
+     * This flag indicates this intent called {@link #collectExtraIntentKeys()}.
+     *
+     * @hide
+     */
+    public static final int EXTENDED_FLAG_NESTED_INTENT_KEYS_COLLECTED = 1 << 2;
+
     // ---------------------------------------------------------------------
     // ---------------------------------------------------------------------
     // toUri() and parseUri() options.
@@ -12328,7 +12336,8 @@
     }
 
     private void collectNestedIntentKeysRecur(Set<Intent> visited) {
-        if (mExtras != null && !mExtras.isParcelled() && !mExtras.isEmpty()) {
+        addExtendedFlags(EXTENDED_FLAG_NESTED_INTENT_KEYS_COLLECTED);
+        if (mExtras != null && !mExtras.isEmpty()) {
             for (String key : mExtras.keySet()) {
                 Object value = mExtras.get(key);
 
diff --git a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
index 7254203..18a45d8d 100644
--- a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
+++ b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
@@ -595,9 +595,6 @@
                                     /*allowDuplicates=*/ true);
                             break;
                         case TAG_USES_STATIC_LIBRARY:
-                            if (!android.content.pm.Flags.sdkDependencyInstaller()) {
-                                break;
-                            }
                             String usesStaticLibName = parser.getAttributeValue(
                                     ANDROID_RES_NAMESPACE, "name");
                             long usesStaticLibVersion = parser.getAttributeIntValue(
@@ -666,7 +663,7 @@
                                     SharedLibraryInfo.TYPE_SDK_PACKAGE));
                             break;
                         case TAG_STATIC_LIBRARY:
-                            isSdkLibrary = true;
+                            isStaticLibrary = true;
                             // Mirrors ParsingPackageUtils#parseStaticLibrary until lite and full
                             // parsing are combined
                             String staticLibName = parser.getAttributeValue(
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 23f7629..d5b5258 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -10999,6 +10999,25 @@
                 "emergency_gesture_ui_last_started_millis";
 
         /**
+         * Whether double tap the power button gesture is enabled.
+         *
+         * @hide
+         */
+        @Readable
+        public static final String DOUBLE_TAP_POWER_BUTTON_GESTURE_ENABLED =
+                "double_tap_power_button_gesture_enabled";
+
+        /**
+         * Double tap power button gesture behavior.
+         * 0 = Camera launch
+         * 1 = Wallet launch
+         * @hide
+         */
+        @Readable
+        public static final String DOUBLE_TAP_POWER_BUTTON_GESTURE =
+                "double_tap_power_button_gesture";
+
+        /**
          * Whether the camera launch gesture to double tap the power button when the screen is off
          * should be disabled.
          *
diff --git a/core/java/android/security/intrusiondetection/IIntrusionDetectionEventTransport.aidl b/core/java/android/security/intrusiondetection/IIntrusionDetectionEventTransport.aidl
index 8759f72..eab1c15 100644
--- a/core/java/android/security/intrusiondetection/IIntrusionDetectionEventTransport.aidl
+++ b/core/java/android/security/intrusiondetection/IIntrusionDetectionEventTransport.aidl
@@ -15,6 +15,7 @@
  */
 
 package android.security.intrusiondetection;
+
 import android.security.intrusiondetection.IntrusionDetectionEvent;
 
 import com.android.internal.infra.AndroidFuture;
@@ -24,18 +25,20 @@
     /**
      * Initialize the server side.
      */
-    void initialize(in AndroidFuture<int> resultFuture);
+    void initialize(in AndroidFuture<boolean> resultFuture);
 
     /**
-     * Send intrusiondetection logging data to the backup destination.
+     * Send intrusiondetection logging data to the transport destination.
      * The data is a list of IntrusionDetectionEvent.
      * The IntrusionDetectionEvent is an abstract class that represents
-     * different type of events.
+     * different types of events.
      */
-    void addData(in List<IntrusionDetectionEvent> events, in AndroidFuture<int> resultFuture);
+    void addData(
+        in List<IntrusionDetectionEvent> events,
+        in AndroidFuture<boolean> resultFuture);
 
     /**
      * Release the binder to the server.
      */
-    void release(in AndroidFuture<int> resultFuture);
+    void release(in AndroidFuture<boolean> resultFuture);
 }
diff --git a/core/java/android/security/intrusiondetection/IntrusionDetectionEvent.java b/core/java/android/security/intrusiondetection/IntrusionDetectionEvent.java
index 538acf9..b479ca7 100644
--- a/core/java/android/security/intrusiondetection/IntrusionDetectionEvent.java
+++ b/core/java/android/security/intrusiondetection/IntrusionDetectionEvent.java
@@ -22,6 +22,7 @@
 import android.app.admin.ConnectEvent;
 import android.app.admin.DnsEvent;
 import android.app.admin.SecurityLog.SecurityEvent;
+import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.security.Flags;
@@ -31,14 +32,36 @@
 
 /**
  * A class that represents a intrusiondetection event.
+ *
  * @hide
  */
+@SystemApi
 @FlaggedApi(Flags.FLAG_AFL_API)
 public final class IntrusionDetectionEvent implements Parcelable {
     private static final String TAG = "IntrusionDetectionEvent";
 
+    /**
+     * Event type representing a security-related event.
+     * This type is associated with a {@link SecurityEvent} object.
+     *
+     * @see SecurityEvent
+     */
     public static final int SECURITY_EVENT = 0;
+
+    /**
+     * Event type representing a network DNS event.
+     * This type is associated with a {@link DnsEvent} object.
+     *
+     * @see DnsEvent
+     */
     public static final int NETWORK_EVENT_DNS = 1;
+
+    /**
+     * Event type representing a network connection event.
+     * This type is associated with a {@link ConnectEvent} object.
+     *
+     * @see ConnectEvent
+     */
     public static final int NETWORK_EVENT_CONNECT = 2;
 
     /** @hide */
@@ -67,6 +90,12 @@
                 }
             };
 
+    /**
+     * Creates an IntrusionDetectionEvent object with a
+     * {@link SecurityEvent} object as the event source.
+     *
+     * @param securityEvent The SecurityEvent object.
+     */
     public IntrusionDetectionEvent(@NonNull SecurityEvent securityEvent) {
         mType = SECURITY_EVENT;
         mSecurityEvent = securityEvent;
@@ -74,6 +103,12 @@
         mNetworkEventConnect = null;
     }
 
+    /**
+     * Creates an IntrusionDetectionEvent object with a
+     * {@link DnsEvent} object as the event source.
+     *
+     * @param dnsEvent The DnsEvent object.
+     */
     public IntrusionDetectionEvent(@NonNull DnsEvent dnsEvent) {
         mType = NETWORK_EVENT_DNS;
         mNetworkEventDns = dnsEvent;
@@ -81,6 +116,12 @@
         mNetworkEventConnect = null;
     }
 
+    /**
+     * Creates an IntrusionDetectionEvent object with a
+     * {@link ConnectEvent} object as the event source.
+     *
+     * @param connectEvent The ConnectEvent object.
+     */
     public IntrusionDetectionEvent(@NonNull ConnectEvent connectEvent) {
         mType = NETWORK_EVENT_CONNECT;
         mNetworkEventConnect = connectEvent;
diff --git a/core/java/android/security/intrusiondetection/IntrusionDetectionEventTransport.java b/core/java/android/security/intrusiondetection/IntrusionDetectionEventTransport.java
new file mode 100644
index 0000000..2e2d0f7
--- /dev/null
+++ b/core/java/android/security/intrusiondetection/IntrusionDetectionEventTransport.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.security.intrusiondetection;
+
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.annotation.SuppressLint;
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.IBinder;
+import android.util.CloseGuard;
+
+import android.security.Flags;
+import android.security.intrusiondetection.IntrusionDetectionEvent;
+import android.security.intrusiondetection.IIntrusionDetectionEventTransport;
+
+import com.android.internal.infra.AndroidFuture;
+
+import java.lang.AutoCloseable;
+import java.util.List;
+
+/**
+ * A class that provides a stable API for transporting intrusion detection events
+ * to a transport location, such as a file or a network endpoint.
+ *
+ * This class acts as a bridge between the {@link IIntrusionDetectionEventTransport}
+ * interface and its implementations. It allows system components to add intrusion
+ * detection events ({@link IntrusionDetectionEvent}) to a transport queue,
+ * which will then be delivered to the specified location.
+ *
+ * Usage:
+ * 1. Obtain an instance of {@link IntrusionDetectionEventTransport} using the constructor.
+ * 2. Initialize the transport by calling {@link #initialize()}.
+ * 3. Add events to the transport queue using {@link #addData(List)}.
+ * 4. Release the transport when finished by calling {@link #release()}.
+ *
+ * Key Components:
+ * - {@link IIntrusionDetectionEventTransport}: The underlying AIDL interface
+ *     for interacting with transport implementations.
+ * - {@link IntrusionDetectionEvent}: Represents a single event.
+ *
+ * @hide
+ */
+@SystemApi
+@FlaggedApi(Flags.FLAG_AFL_API)
+@SuppressLint("NotCloseable")
+public class IntrusionDetectionEventTransport {
+    IIntrusionDetectionEventTransport mBinderImpl = new TransportImpl();
+
+    /**
+     * Returns the binder interface for this transport.
+     */
+    @NonNull
+    public IBinder getBinder() {
+        return mBinderImpl.asBinder();
+    }
+
+    /**
+     * Initializes the transport.
+     *
+     * @return whether the initialization was successful.
+     */
+    public boolean initialize() {
+        return false;
+    }
+
+    /**
+     * Adds data to the transport.
+     *
+     * @param events the events to add.
+     * @return whether the addition was successful.
+     */
+    public boolean addData(@NonNull List<IntrusionDetectionEvent> events) {
+        return false;
+    }
+
+    /**
+     * Releases the transport.
+     *
+     * The release() method is a callback implemented by the concrete transport
+     * endpoint.
+     * The "SuppressLint" annotation is used to allow the release() method to be
+     * included in the API without requiring the class to implement AutoCloseable.
+     *
+     * @return whether the release was successful.
+     */
+    public boolean release() {
+        return false;
+    }
+
+    /**
+     * Bridge between the actual IIntrusionDetectionEventTransport implementation
+     * and the stable API.  If the binder interface needs to change, we use this
+     * layer to translate so that we can decouple those framework-side changes
+     * from the IntrusionDetectionEventTransport implementations.
+     */
+    class TransportImpl extends IIntrusionDetectionEventTransport.Stub {
+        @Override
+        public void initialize(AndroidFuture<Boolean> resultFuture) {
+            try {
+                boolean result = IntrusionDetectionEventTransport.this.initialize();
+                resultFuture.complete(result);
+            } catch (RuntimeException e) {
+                resultFuture.cancel(/* mayInterruptIfRunning */ true);
+            }
+        }
+
+        @Override
+        public void addData(
+            List<IntrusionDetectionEvent> events,
+            AndroidFuture<Boolean> resultFuture) {
+            try {
+                boolean result = IntrusionDetectionEventTransport.this.addData(events);
+                resultFuture.complete(result);
+            } catch (RuntimeException e) {
+                resultFuture.cancel(/* mayInterruptIfRunning */ true);
+            }
+        }
+
+        @Override
+        public void release(AndroidFuture<Boolean> resultFuture) {
+            try {
+                boolean result = IntrusionDetectionEventTransport.this.release();
+                resultFuture.complete(result);
+            } catch (RuntimeException e) {
+                resultFuture.cancel(/* mayInterruptIfRunning */ true);
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/core/java/android/security/responsible_apis_flags.aconfig b/core/java/android/security/responsible_apis_flags.aconfig
index 6c92991..357aba3 100644
--- a/core/java/android/security/responsible_apis_flags.aconfig
+++ b/core/java/android/security/responsible_apis_flags.aconfig
@@ -96,6 +96,21 @@
 }
 
 flag {
+    name: "prevent_intent_redirect_throw_exception_if_nested_keys_not_collected"
+    namespace: "responsible_apis"
+    description: "Prevent intent redirect attacks by throwing exception if the intent does not collect nested keys"
+    bug: "361143368"
+}
+
+flag {
+    name: "prevent_intent_redirect_collect_nested_keys_on_server_if_not_collected"
+    namespace: "responsible_apis"
+    description: "Prevent intent redirect attacks by collecting nested keys on server if not yet collected"
+    bug: "361143368"
+    is_fixed_read_only: true
+}
+
+flag {
     name: "enable_intent_matching_flags"
     is_exported: true
     namespace: "permissions"
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index b4b0687..1e8cad6 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -1426,8 +1426,9 @@
             "android.window.PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_FULLSCREEN_OVERRIDE";
 
     /**
-     * Activity-level {@link android.content.pm.PackageManager.Property PackageManager.Property}
-     * that specifies whether this activity can declare or request
+     * Application or Activity level
+     * {@link android.content.pm.PackageManager.Property PackageManager.Property}
+     * that specifies whether this package or activity can declare or request
      * {@link android.R.attr#screenOrientation fixed orientation},
      * {@link android.R.attr#minAspectRatio max aspect ratio},
      * {@link android.R.attr#maxAspectRatio min aspect ratio}
@@ -1438,6 +1439,13 @@
      *
      * <p><b>Syntax:</b>
      * <pre>
+     * &lt;application&gt;
+     *   &lt;property
+     *     android:name="android.window.PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_FULLSCREEN_OVERRIDE"
+     *     android:value="false"/&gt;
+     * &lt;/application&gt;
+     * </pre>or
+     * <pre>
      * &lt;activity&gt;
      *   &lt;property
      *     android:name="android.window.PROPERTY_COMPAT_ALLOW_RESTRICTED_RESIZABILITY"
@@ -1446,7 +1454,7 @@
      * </pre>
      * @hide
      */
-    // TODO(b/357141415): Make this public API.
+    // TODO(b/357141415): Remove this from sdk 37
     String PROPERTY_COMPAT_ALLOW_RESTRICTED_RESIZABILITY =
             "android.window.PROPERTY_COMPAT_ALLOW_RESTRICTED_RESIZABILITY";
 
diff --git a/core/java/android/window/WindowTokenClient.java b/core/java/android/window/WindowTokenClient.java
index 15adc80..6e76d8d 100644
--- a/core/java/android/window/WindowTokenClient.java
+++ b/core/java/android/window/WindowTokenClient.java
@@ -19,6 +19,8 @@
 import static android.window.ConfigurationHelper.isDifferentDisplay;
 import static android.window.ConfigurationHelper.shouldUpdateResources;
 
+import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
+
 import android.annotation.AnyThread;
 import android.annotation.MainThread;
 import android.annotation.NonNull;
@@ -104,7 +106,7 @@
      * @param newConfig the updated {@link Configuration}
      * @param newDisplayId the updated {@link android.view.Display} ID
      */
-    @VisibleForTesting
+    @VisibleForTesting(visibility = PACKAGE)
     @MainThread
     public void onConfigurationChanged(Configuration newConfig, int newDisplayId) {
         onConfigurationChanged(newConfig, newDisplayId, true /* shouldReportConfigChange */);
@@ -113,7 +115,7 @@
     /**
      * Posts an {@link #onConfigurationChanged} to the main thread.
      */
-    @VisibleForTesting
+    @VisibleForTesting(visibility = PACKAGE)
     public void postOnConfigurationChanged(@NonNull Configuration newConfig, int newDisplayId) {
         mHandler.post(PooledLambda.obtainRunnable(this::onConfigurationChanged, newConfig,
                 newDisplayId, true /* shouldReportConfigChange */).recycleOnUse());
@@ -232,7 +234,7 @@
     /**
      * Called when the attached window is removed from the display.
      */
-    @VisibleForTesting
+    @VisibleForTesting(visibility = PACKAGE)
     @MainThread
     public void onWindowTokenRemoved() {
         final Context context = mContextRef.get();
diff --git a/core/java/android/window/WindowTokenClientController.java b/core/java/android/window/WindowTokenClientController.java
index abf7bb1..fa34595 100644
--- a/core/java/android/window/WindowTokenClientController.java
+++ b/core/java/android/window/WindowTokenClientController.java
@@ -28,7 +28,7 @@
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.RemoteException;
-import android.util.ArrayMap;
+import android.util.ArraySet;
 import android.util.Log;
 import android.view.IWindowManager;
 import android.view.WindowManagerGlobal;
@@ -50,9 +50,9 @@
     private final IApplicationThread mAppThread = ActivityThread.currentActivityThread()
             .getApplicationThread();
 
-    /** Mapping from a client defined token to the {@link WindowTokenClient} it represents. */
+    /** Attached {@link WindowTokenClient}. */
     @GuardedBy("mLock")
-    private final ArrayMap<IBinder, WindowTokenClient> mWindowTokenClientMap = new ArrayMap<>();
+    private final ArraySet<WindowTokenClient> mWindowTokenClients = new ArraySet<>();
 
     /** Gets the singleton controller. */
     @NonNull
@@ -85,11 +85,15 @@
     /** Gets the {@link WindowContext} instance for the token. */
     @Nullable
     public Context getWindowContext(@NonNull IBinder clientToken) {
-        final WindowTokenClient windowTokenClient;
-        synchronized (mLock) {
-            windowTokenClient = mWindowTokenClientMap.get(clientToken);
+        if (!(clientToken instanceof WindowTokenClient windowTokenClient)) {
+            return null;
         }
-        return windowTokenClient != null ? windowTokenClient.getContext() : null;
+        synchronized (mLock) {
+            if (!mWindowTokenClients.contains(windowTokenClient)) {
+                return null;
+            }
+        }
+        return windowTokenClient.getContext();
     }
 
     /**
@@ -126,8 +130,14 @@
      */
     public boolean attachToDisplayContent(@NonNull WindowTokenClient client, int displayId) {
         final IWindowManager wms = getWindowManagerService();
-        // #createSystemUiContext may call this method before WindowManagerService is initialized.
         if (wms == null) {
+            // #createSystemUiContext may call this method before WindowManagerService is
+            // initialized.
+            // Regardless of whether or not it is ready, keep track of the token so that when WMS
+            // is initialized later, the SystemUiContext will start reporting from
+            // DisplayContent#registerSystemUiContext, and WindowTokenClientController can report
+            // the Configuration to the correct client.
+            recordWindowContextToken(client);
             return false;
         }
         final WindowContextInfo info;
@@ -170,12 +180,18 @@
     /** Detaches a {@link WindowTokenClient} from associated WindowContainer if there's one. */
     public void detachIfNeeded(@NonNull WindowTokenClient client) {
         synchronized (mLock) {
-            if (mWindowTokenClientMap.remove(client) == null) {
+            if (!mWindowTokenClients.remove(client)) {
                 return;
             }
         }
+        final IWindowManager wms = getWindowManagerService();
+        if (wms == null) {
+            // #createSystemUiContext may call this method before WindowManagerService is
+            // initialized. If it is GC'ed before WMS is initialized, skip calling into WMS.
+            return;
+        }
         try {
-            getWindowManagerService().detachWindowContext(client);
+            wms.detachWindowContext(client);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -183,9 +199,7 @@
 
     private void onWindowContextTokenAttached(@NonNull WindowTokenClient client,
             @NonNull WindowContextInfo info, boolean shouldReportConfigChange) {
-        synchronized (mLock) {
-            mWindowTokenClientMap.put(client, client);
-        }
+        recordWindowContextToken(client);
         if (shouldReportConfigChange) {
             // Should trigger an #onConfigurationChanged callback to the WindowContext. Post the
             // dispatch in the next loop to prevent the callback from being dispatched before
@@ -199,10 +213,16 @@
         }
     }
 
+    private void recordWindowContextToken(@NonNull WindowTokenClient client) {
+        synchronized (mLock) {
+            mWindowTokenClients.add(client);
+        }
+    }
+
     /** Called when receives {@link WindowContextInfoChangeItem}. */
     public void onWindowContextInfoChanged(@NonNull IBinder clientToken,
             @NonNull WindowContextInfo info) {
-        final WindowTokenClient windowTokenClient = getWindowTokenClient(clientToken);
+        final WindowTokenClient windowTokenClient = getWindowTokenClientIfAttached(clientToken);
         if (windowTokenClient != null) {
             windowTokenClient.onConfigurationChanged(info.getConfiguration(), info.getDisplayId());
         }
@@ -210,20 +230,23 @@
 
     /** Called when receives {@link WindowContextWindowRemovalItem}. */
     public void onWindowContextWindowRemoved(@NonNull IBinder clientToken) {
-        final WindowTokenClient windowTokenClient = getWindowTokenClient(clientToken);
+        final WindowTokenClient windowTokenClient = getWindowTokenClientIfAttached(clientToken);
         if (windowTokenClient != null) {
             windowTokenClient.onWindowTokenRemoved();
         }
     }
 
     @Nullable
-    private WindowTokenClient getWindowTokenClient(@NonNull IBinder clientToken) {
-        final WindowTokenClient windowTokenClient;
-        synchronized (mLock) {
-            windowTokenClient = mWindowTokenClientMap.get(clientToken);
+    private WindowTokenClient getWindowTokenClientIfAttached(@NonNull IBinder clientToken) {
+        if (!(clientToken instanceof WindowTokenClient windowTokenClient)) {
+            Log.e(TAG, "getWindowTokenClient failed for non-window token " + clientToken);
+            return null;
         }
-        if (windowTokenClient == null) {
-            Log.w(TAG, "Can't find attached WindowTokenClient for " + clientToken);
+        synchronized (mLock) {
+            if (!mWindowTokenClients.contains(windowTokenClient)) {
+                Log.w(TAG, "Can't find attached WindowTokenClient for " + clientToken);
+                return null;
+            }
         }
         return windowTokenClient;
     }
diff --git a/core/java/android/window/flags/lse_desktop_experience.aconfig b/core/java/android/window/flags/lse_desktop_experience.aconfig
index eebdeadc..e23cb3f 100644
--- a/core/java/android/window/flags/lse_desktop_experience.aconfig
+++ b/core/java/android/window/flags/lse_desktop_experience.aconfig
@@ -242,6 +242,13 @@
 }
 
 flag {
+    name: "enable_desktop_windowing_app_handle_education_integration"
+    namespace: "lse_desktop_experience"
+    description: "Enables desktop windowing app handle education and integrates new APIs"
+    bug: "316006079"
+}
+
+flag {
     name: "enable_desktop_windowing_transitions"
     namespace: "lse_desktop_experience"
     description: "Enables desktop windowing transition & motion polish changes"
diff --git a/core/java/com/android/internal/vibrator/persistence/SerializedCompositionPrimitive.java b/core/java/com/android/internal/vibrator/persistence/SerializedCompositionPrimitive.java
index 862f7cb..5eedec6 100644
--- a/core/java/com/android/internal/vibrator/persistence/SerializedCompositionPrimitive.java
+++ b/core/java/com/android/internal/vibrator/persistence/SerializedCompositionPrimitive.java
@@ -17,6 +17,7 @@
 package com.android.internal.vibrator.persistence;
 
 import static com.android.internal.vibrator.persistence.XmlConstants.ATTRIBUTE_DELAY_MS;
+import static com.android.internal.vibrator.persistence.XmlConstants.ATTRIBUTE_DELAY_TYPE;
 import static com.android.internal.vibrator.persistence.XmlConstants.ATTRIBUTE_NAME;
 import static com.android.internal.vibrator.persistence.XmlConstants.ATTRIBUTE_SCALE;
 import static com.android.internal.vibrator.persistence.XmlConstants.NAMESPACE;
@@ -25,9 +26,11 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.os.VibrationEffect;
+import android.os.vibrator.Flags;
 import android.os.vibrator.PrimitiveSegment;
 
 import com.android.internal.vibrator.persistence.SerializedComposedEffect.SerializedSegment;
+import com.android.internal.vibrator.persistence.XmlConstants.PrimitiveDelayType;
 import com.android.internal.vibrator.persistence.XmlConstants.PrimitiveEffectName;
 import com.android.modules.utils.TypedXmlPullParser;
 import com.android.modules.utils.TypedXmlSerializer;
@@ -46,17 +49,26 @@
     private final PrimitiveEffectName mPrimitiveName;
     private final float mPrimitiveScale;
     private final int mPrimitiveDelayMs;
+    @Nullable
+    private final PrimitiveDelayType mDelayType;
 
-    SerializedCompositionPrimitive(PrimitiveEffectName primitiveName, float scale, int delayMs) {
+    SerializedCompositionPrimitive(PrimitiveEffectName primitiveName, float scale, int delayMs,
+            @Nullable PrimitiveDelayType delayType) {
         mPrimitiveName = primitiveName;
         mPrimitiveScale = scale;
         mPrimitiveDelayMs = delayMs;
+        mDelayType = delayType;
     }
 
     @Override
     public void deserializeIntoComposition(@NonNull VibrationEffect.Composition composition) {
-        composition.addPrimitive(mPrimitiveName.getPrimitiveId(), mPrimitiveScale,
-                mPrimitiveDelayMs);
+        if (Flags.primitiveCompositionAbsoluteDelay() && mDelayType != null) {
+            composition.addPrimitive(mPrimitiveName.getPrimitiveId(), mPrimitiveScale,
+                    mPrimitiveDelayMs, mDelayType.getDelayType());
+        } else {
+            composition.addPrimitive(mPrimitiveName.getPrimitiveId(), mPrimitiveScale,
+                    mPrimitiveDelayMs);
+        }
     }
 
     @Override
@@ -72,6 +84,12 @@
             serializer.attributeInt(NAMESPACE, ATTRIBUTE_DELAY_MS, mPrimitiveDelayMs);
         }
 
+        if (Flags.primitiveCompositionAbsoluteDelay() && mDelayType != null) {
+            if (mDelayType.getDelayType() != PrimitiveSegment.DEFAULT_DELAY_TYPE) {
+                serializer.attribute(NAMESPACE, ATTRIBUTE_DELAY_TYPE, mDelayType.toString());
+            }
+        }
+
         serializer.endTag(NAMESPACE, TAG_PRIMITIVE_EFFECT);
     }
 
@@ -81,6 +99,7 @@
                 + "name=" + mPrimitiveName
                 + ", scale=" + mPrimitiveScale
                 + ", delayMs=" + mPrimitiveDelayMs
+                + ", delayType=" + mDelayType
                 + '}';
     }
 
@@ -91,8 +110,14 @@
         static SerializedCompositionPrimitive parseNext(@NonNull TypedXmlPullParser parser)
                 throws XmlParserException, IOException {
             XmlValidator.checkStartTag(parser, TAG_PRIMITIVE_EFFECT);
-            XmlValidator.checkTagHasNoUnexpectedAttributes(parser,
-                    ATTRIBUTE_NAME, ATTRIBUTE_DELAY_MS, ATTRIBUTE_SCALE);
+
+            if (Flags.primitiveCompositionAbsoluteDelay()) {
+                XmlValidator.checkTagHasNoUnexpectedAttributes(parser,
+                        ATTRIBUTE_NAME, ATTRIBUTE_DELAY_MS, ATTRIBUTE_SCALE, ATTRIBUTE_DELAY_TYPE);
+            } else {
+                XmlValidator.checkTagHasNoUnexpectedAttributes(parser,
+                        ATTRIBUTE_NAME, ATTRIBUTE_DELAY_MS, ATTRIBUTE_SCALE);
+            }
 
             PrimitiveEffectName primitiveName = parsePrimitiveName(
                     parser.getAttributeValue(NAMESPACE, ATTRIBUTE_NAME));
@@ -100,11 +125,13 @@
                     parser, ATTRIBUTE_SCALE, 0, 1, PrimitiveSegment.DEFAULT_SCALE);
             int delayMs = XmlReader.readAttributeIntNonNegative(
                     parser, ATTRIBUTE_DELAY_MS, PrimitiveSegment.DEFAULT_DELAY_MILLIS);
+            PrimitiveDelayType delayType = parseDelayType(
+                    parser.getAttributeValue(NAMESPACE, ATTRIBUTE_DELAY_TYPE));
 
             // Consume tag
             XmlReader.readEndTag(parser);
 
-            return new SerializedCompositionPrimitive(primitiveName, scale, delayMs);
+            return new SerializedCompositionPrimitive(primitiveName, scale, delayMs, delayType);
         }
 
         @NonNull
@@ -119,5 +146,21 @@
             }
             return effectName;
         }
+
+        @Nullable
+        private static PrimitiveDelayType parseDelayType(@Nullable String name)
+                throws XmlParserException {
+            if (name == null) {
+                return null;
+            }
+            if (!Flags.primitiveCompositionAbsoluteDelay()) {
+                throw new XmlParserException("Unexpected primitive delay type " + name);
+            }
+            PrimitiveDelayType delayType = PrimitiveDelayType.findByName(name);
+            if (delayType == null) {
+                throw new XmlParserException("Unexpected primitive delay type " + name);
+            }
+            return delayType;
+        }
     }
 }
diff --git a/core/java/com/android/internal/vibrator/persistence/VibrationEffectXmlSerializer.java b/core/java/com/android/internal/vibrator/persistence/VibrationEffectXmlSerializer.java
index d74a23d..cb834a5 100644
--- a/core/java/com/android/internal/vibrator/persistence/VibrationEffectXmlSerializer.java
+++ b/core/java/com/android/internal/vibrator/persistence/VibrationEffectXmlSerializer.java
@@ -27,6 +27,7 @@
 
 import com.android.internal.vibrator.persistence.SerializedComposedEffect.SerializedSegment;
 import com.android.internal.vibrator.persistence.XmlConstants.PredefinedEffectName;
+import com.android.internal.vibrator.persistence.XmlConstants.PrimitiveDelayType;
 import com.android.internal.vibrator.persistence.XmlConstants.PrimitiveEffectName;
 
 import java.util.List;
@@ -170,8 +171,20 @@
         XmlValidator.checkSerializerCondition(primitiveName != null,
                 "Unsupported primitive effect id %s", primitive.getPrimitiveId());
 
+        PrimitiveDelayType delayType = null;
+
+        if (Flags.primitiveCompositionAbsoluteDelay()) {
+            delayType = PrimitiveDelayType.findByType(primitive.getDelayType());
+            XmlValidator.checkSerializerCondition(delayType != null,
+                    "Unsupported primitive delay type %s", primitive.getDelayType());
+        } else {
+            XmlValidator.checkSerializerCondition(
+                    primitive.getDelayType() == PrimitiveSegment.DEFAULT_DELAY_TYPE,
+                    "Unsupported primitive delay type %s", primitive.getDelayType());
+        }
+
         return new SerializedCompositionPrimitive(
-                primitiveName, primitive.getScale(), primitive.getDelay());
+                primitiveName, primitive.getScale(), primitive.getDelay(), delayType);
     }
 
     private static int toAmplitudeInt(float amplitude) {
diff --git a/core/java/com/android/internal/vibrator/persistence/XmlConstants.java b/core/java/com/android/internal/vibrator/persistence/XmlConstants.java
index 2a55d99..4122215 100644
--- a/core/java/com/android/internal/vibrator/persistence/XmlConstants.java
+++ b/core/java/com/android/internal/vibrator/persistence/XmlConstants.java
@@ -20,6 +20,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.os.VibrationEffect;
+import android.os.VibrationEffect.Composition.DelayType;
 import android.os.VibrationEffect.Composition.PrimitiveType;
 
 import java.lang.annotation.Retention;
@@ -51,6 +52,7 @@
     public static final String ATTRIBUTE_AMPLITUDE = "amplitude";
     public static final String ATTRIBUTE_SCALE = "scale";
     public static final String ATTRIBUTE_DELAY_MS = "delayMs";
+    public static final String ATTRIBUTE_DELAY_TYPE = "delayType";
 
     public static final String VALUE_AMPLITUDE_DEFAULT = "default";
 
@@ -87,7 +89,7 @@
 
         /**
          * Return the {@link PrimitiveEffectName} that represents given primitive id, or null if
-         * none of the available names maps to the given id.
+         * none of the available names map to the given id.
          */
         @Nullable
         public static PrimitiveEffectName findById(int primitiveId) {
@@ -200,4 +202,53 @@
             return name().toLowerCase(Locale.ROOT);
         }
     }
+
+    /** Represent supported values for attribute delay type in {@link #TAG_PRIMITIVE_EFFECT}  */
+    public enum PrimitiveDelayType {
+        PAUSE(VibrationEffect.Composition.DELAY_TYPE_PAUSE),
+        RELATIVE_START_OFFSET(VibrationEffect.Composition.DELAY_TYPE_RELATIVE_START_OFFSET);
+
+        @DelayType private final int mDelayType;
+
+        PrimitiveDelayType(@DelayType int type) {
+            mDelayType = type;
+        }
+
+        /**
+         * Return the {@link PrimitiveEffectName} that represents given primitive id, or null if
+         * none of the available names maps to the given id.
+         */
+        @Nullable
+        public static PrimitiveDelayType findByType(int delayType) {
+            for (PrimitiveDelayType type : PrimitiveDelayType.values()) {
+                if (type.mDelayType == delayType) {
+                    return type;
+                }
+            }
+            return null;
+        }
+
+        /**
+         * Return the {@link PrimitiveEffectName} that represents given primitive name, or null if
+         * none of the available names maps to the given name.
+         */
+        @Nullable
+        public static PrimitiveDelayType findByName(@NonNull String delayType) {
+            try {
+                return PrimitiveDelayType.valueOf(delayType.toUpperCase(Locale.ROOT));
+            } catch (IllegalArgumentException e) {
+                return null;
+            }
+        }
+
+        @DelayType
+        public int getDelayType() {
+            return mDelayType;
+        }
+
+        @Override
+        public String toString() {
+            return name().toLowerCase(Locale.ROOT);
+        }
+    }
 }
diff --git a/core/proto/android/providers/settings/secure.proto b/core/proto/android/providers/settings/secure.proto
index 6af742f..2e0fe9e 100644
--- a/core/proto/android/providers/settings/secure.proto
+++ b/core/proto/android/providers/settings/secure.proto
@@ -256,6 +256,12 @@
     }
     optional Display display = 100;
 
+    message DoubleTapPowerButton {
+        optional SettingProto gesture_enabled = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto gesture = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    }
+    optional DoubleTapPowerButton double_tap_power_button = 103;
+
     message Doze {
         option (android.msg_privacy).dest = DEST_EXPLICIT;
 
@@ -737,5 +743,5 @@
 
     // Please insert fields in alphabetical order and group them into messages
     // if possible (to avoid reaching the method limit).
-    // Next tag = 103;
+    // Next tag = 104;
 }
diff --git a/core/res/Android.bp b/core/res/Android.bp
index 8042b30..aacd869 100644
--- a/core/res/Android.bp
+++ b/core/res/Android.bp
@@ -160,6 +160,7 @@
         "android.app.contextualsearch.flags-aconfig",
         "android.app.flags-aconfig",
         "android.appwidget.flags-aconfig",
+        "android.companion.virtualdevice.flags-aconfig",
         "android.content.pm.flags-aconfig",
         "android.media.audio-aconfig",
         "android.provider.flags-aconfig",
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index cedcd2f..a13e334 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -8060,6 +8060,13 @@
     <permission android:name="android.permission.ADD_ALWAYS_UNLOCKED_DISPLAY"
                 android:protectionLevel="signature|role"/>
 
+    <!-- Allows an application to create displays that mirror other displays' content.
+         @FlaggedApi(android.companion.virtualdevice.flags.Flags.FLAG_ENABLE_LIMITED_VDM_ROLE)
+         @hide @SystemApi -->
+    <permission android:name="android.permission.ADD_MIRROR_DISPLAY"
+        android:protectionLevel="internal|role"
+        android:featureFlag="android.companion.virtualdevice.flags.enable_limited_vdm_role" />
+
     <!-- @hide @SystemApi Allows an application to access locusId events in the usage stats. -->
     <permission android:name="android.permission.ACCESS_LOCUS_ID_USAGE_STATS"
                 android:protectionLevel="signature|role" />
diff --git a/core/res/res/layout-sw600dp/preference_list_content_single.xml b/core/res/res/layout-sw600dp/preference_list_content_single.xml
index 88b1aa8..ebe4eca 100644
--- a/core/res/res/layout-sw600dp/preference_list_content_single.xml
+++ b/core/res/res/layout-sw600dp/preference_list_content_single.xml
@@ -19,6 +19,7 @@
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:orientation="vertical"
+    android:fitsSystemWindows="true"
     android:layout_height="match_parent"
     android:layout_width="match_parent">
 
diff --git a/core/res/res/layout/notification_2025_reply_container.xml b/core/res/res/layout/notification_2025_reply_container.xml
new file mode 100644
index 0000000..6923b59
--- /dev/null
+++ b/core/res/res/layout/notification_2025_reply_container.xml
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<!-- Note: this layout is included from a view stub; layout attributes will be overridden. -->
+<LinearLayout
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/notification_material_reply_container"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical"
+        android:paddingStart="@dimen/notification_2025_content_margin_start">
+
+    <ImageView
+            android:layout_width="match_parent"
+            android:layout_height="1dip"
+            android:id="@+id/action_divider"
+            android:layout_marginTop="@dimen/notification_content_margin"
+            android:layout_marginBottom="@dimen/notification_content_margin"
+            android:layout_marginEnd="@dimen/notification_content_margin_end"
+            android:background="@drawable/notification_template_divider" />
+
+    <TextView
+            android:id="@+id/notification_material_reply_text_3"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginEnd="@dimen/notification_content_margin_end"
+            android:visibility="gone"
+            android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Reply"
+            android:singleLine="true" />
+
+    <TextView
+            android:id="@+id/notification_material_reply_text_2"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginEnd="@dimen/notification_content_margin_end"
+            android:visibility="gone"
+            android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Reply"
+            android:singleLine="true" />
+
+    <LinearLayout
+            android:id="@+id/notification_material_reply_text_1_container"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal"
+            android:layout_marginEnd="@dimen/notification_content_margin_end">
+        <TextView
+                android:id="@+id/notification_material_reply_text_1"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_weight="1"
+                android:layout_marginEnd="@dimen/notification_content_margin_end"
+                android:layout_gravity="center"
+                android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Reply"
+                android:singleLine="true" />
+        <ProgressBar
+            android:id="@+id/notification_material_reply_progress"
+            android:layout_height="@dimen/messaging_group_sending_progress_size"
+            android:layout_width="@dimen/messaging_group_sending_progress_size"
+            android:layout_marginStart="@dimen/notification_2025_content_margin_start"
+            android:layout_gravity="center"
+            android:indeterminate="true"
+            style="?android:attr/progressBarStyleSmall" />
+    </LinearLayout>
+
+</LinearLayout>
diff --git a/core/res/res/layout/notification_2025_template_expanded_base.xml b/core/res/res/layout/notification_2025_template_expanded_base.xml
new file mode 100644
index 0000000..e480fe5
--- /dev/null
+++ b/core/res/res/layout/notification_2025_template_expanded_base.xml
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/status_bar_latest_event_content"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical"
+    android:clipChildren="false"
+    android:tag="big"
+    >
+
+    <LinearLayout
+        android:id="@+id/notification_action_list_margin_target"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginBottom="@dimen/notification_content_margin"
+        android:orientation="vertical"
+        >
+
+        <FrameLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:layout_gravity="top"
+            >
+
+            <include layout="@layout/notification_2025_template_header" />
+
+            <LinearLayout
+                android:id="@+id/notification_main_column"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginStart="@dimen/notification_2025_content_margin_start"
+                android:layout_marginEnd="@dimen/notification_content_margin_end"
+                android:layout_marginTop="@dimen/notification_content_margin_top"
+                android:orientation="vertical"
+                >
+
+                <include layout="@layout/notification_template_part_line1" />
+
+                <include layout="@layout/notification_template_text_multiline" />
+
+                <include
+                    android:layout_width="match_parent"
+                    android:layout_height="@dimen/notification_progress_bar_height"
+                    android:layout_marginTop="@dimen/notification_progress_margin_top"
+                    layout="@layout/notification_template_progress"
+                    />
+            </LinearLayout>
+
+            <include layout="@layout/notification_template_right_icon" />
+        </FrameLayout>
+
+        <ViewStub
+            android:layout="@layout/notification_2025_reply_container"
+            android:id="@+id/notification_material_reply_container"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            />
+
+        <include
+            layout="@layout/notification_template_smart_reply_container"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="@dimen/notification_2025_content_margin_start"
+            android:layout_marginEnd="@dimen/notification_content_margin_end"
+            android:layout_marginTop="@dimen/notification_content_margin"
+            />
+
+        <include layout="@layout/notification_material_action_list" />
+    </LinearLayout>
+</FrameLayout>
diff --git a/core/res/res/layout/preference_list_content.xml b/core/res/res/layout/preference_list_content.xml
index bed80ed..7a2fb0b 100644
--- a/core/res/res/layout/preference_list_content.xml
+++ b/core/res/res/layout/preference_list_content.xml
@@ -20,6 +20,7 @@
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:orientation="vertical"
+    android:fitsSystemWindows="true"
     android:layout_height="match_parent"
     android:layout_width="match_parent">
 
diff --git a/core/res/res/layout/preference_list_content_material.xml b/core/res/res/layout/preference_list_content_material.xml
index 37b4119..23c8250 100644
--- a/core/res/res/layout/preference_list_content_material.xml
+++ b/core/res/res/layout/preference_list_content_material.xml
@@ -20,6 +20,7 @@
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:orientation="vertical"
+    android:fitsSystemWindows="true"
     android:layout_height="match_parent"
     android:layout_width="match_parent">
 
diff --git a/core/res/res/layout/preference_list_content_single.xml b/core/res/res/layout/preference_list_content_single.xml
index 726ce78..4f072da 100644
--- a/core/res/res/layout/preference_list_content_single.xml
+++ b/core/res/res/layout/preference_list_content_single.xml
@@ -19,6 +19,7 @@
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:orientation="vertical"
+    android:fitsSystemWindows="true"
     android:layout_height="match_parent"
     android:layout_width="match_parent">
 
diff --git a/core/res/res/layout/preference_list_fragment.xml b/core/res/res/layout/preference_list_fragment.xml
index c43975e..44a5df9 100644
--- a/core/res/res/layout/preference_list_fragment.xml
+++ b/core/res/res/layout/preference_list_fragment.xml
@@ -19,6 +19,7 @@
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:orientation="vertical"
+    android:fitsSystemWindows="true"
     android:layout_height="match_parent"
     android:layout_width="match_parent"
     android:background="@android:color/transparent"
diff --git a/core/res/res/layout/preference_list_fragment_material.xml b/core/res/res/layout/preference_list_fragment_material.xml
index db2fe7d..4df7602 100644
--- a/core/res/res/layout/preference_list_fragment_material.xml
+++ b/core/res/res/layout/preference_list_fragment_material.xml
@@ -19,6 +19,7 @@
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:orientation="vertical"
+    android:fitsSystemWindows="true"
     android:layout_height="match_parent"
     android:layout_width="match_parent"
     android:background="@android:color/transparent"
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index f6590b1..8c46ccc 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -4808,6 +4808,12 @@
         <!-- Whether the device should default to observe mode when this service is
              default or in the foreground. -->
         <attr name="shouldDefaultToObserveMode" format="boolean"/>
+        <!-- Whether this service should share the same AID routing priority as the role
+             owner. This package and the role owner must have the same signature, and the
+             role owner must opt into this behavior by using the property named by
+             {@link android.nfc.cardemulation.CardEmulation.PROPERTY_ALLOW_SHARED_ROLE_PRIORITY }
+             in the <code>&lt;application&rt;</code> tag. -->
+        <attr name="shareRolePriority" format="boolean"/>
     </declare-styleable>
 
     <!-- Use <code>offhost-apdu-service</code> as the root tag of the XML resource that
@@ -4835,6 +4841,7 @@
         <!-- Whether the device should default to observe mode when this service is
              default or in the foreground. -->
         <attr name="shouldDefaultToObserveMode"/>
+        <attr name="shareRolePriority"/>
     </declare-styleable>
 
     <!-- Specify one or more <code>aid-group</code> elements inside a
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 7f2c816..38ebda7 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2731,6 +2731,8 @@
     </string-array>
     <!-- The list of supported dream complications -->
     <integer-array name="config_supportedDreamComplications">
+        <!-- COMPLICATION_TYPE_TIME -->
+        <item>1</item>
     </integer-array>
 
     <!-- Are we allowed to dream while not plugged in? -->
diff --git a/core/res/res/values/public-staging.xml b/core/res/res/values/public-staging.xml
index b0b87d1d..4c3fa4b 100644
--- a/core/res/res/values/public-staging.xml
+++ b/core/res/res/values/public-staging.xml
@@ -133,6 +133,8 @@
     <public name="alternateLauncherLabels"/>
     <!-- @FlaggedApi(android.content.pm.Flags.FLAG_APP_COMPAT_OPTION_16KB) -->
     <public name="pageSizeCompat" />
+    <!-- @FlaggedApi(android.nfc.Flags.FLAG_NFC_ASSOCIATED_ROLE_SERVICES) -->
+    <public name="shareRolePriority"/>
   </staging-public-group>
 
   <staging-public-group type="id" first-id="0x01b60000">
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index de71af0..94ffb48 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2390,6 +2390,7 @@
   <java-symbol type="layout" name="notification_material_action_list" />
   <java-symbol type="layout" name="notification_material_action_tombstone" />
   <java-symbol type="layout" name="notification_2025_template_collapsed_base" />
+  <java-symbol type="layout" name="notification_2025_template_expanded_base" />
   <java-symbol type="layout" name="notification_2025_template_heads_up_base" />
   <java-symbol type="layout" name="notification_2025_template_header" />
   <java-symbol type="layout" name="notification_template_material_base" />
diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp
index f39508d..4942557 100644
--- a/core/tests/coretests/Android.bp
+++ b/core/tests/coretests/Android.bp
@@ -152,6 +152,7 @@
         ":HelloWorldUsingSdkMalformedNegativeVersion",
         ":CtsStaticSharedLibConsumerApp1",
         ":CtsStaticSharedLibConsumerApp3",
+        ":CtsStaticSharedLibProviderApp1",
     ],
 }
 
diff --git a/core/tests/coretests/AndroidTest.xml b/core/tests/coretests/AndroidTest.xml
index 5d8ff87..bada751 100644
--- a/core/tests/coretests/AndroidTest.xml
+++ b/core/tests/coretests/AndroidTest.xml
@@ -43,6 +43,8 @@
             value="/data/local/tmp/tests/coretests/pm/CtsStaticSharedLibConsumerApp1.apk"/>
         <option name="push-file" key="CtsStaticSharedLibConsumerApp3.apk"
             value="/data/local/tmp/tests/coretests/pm/CtsStaticSharedLibConsumerApp3.apk"/>
+        <option name="push-file" key="CtsStaticSharedLibProviderApp1.apk"
+                value="/data/local/tmp/tests/coretests/pm/CtsStaticSharedLibProviderApp1.apk"/>
     </target_preparer>
 
     <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
diff --git a/core/tests/coretests/src/android/app/NotificationTest.java b/core/tests/coretests/src/android/app/NotificationTest.java
index 23a0985..63e678d 100644
--- a/core/tests/coretests/src/android/app/NotificationTest.java
+++ b/core/tests/coretests/src/android/app/NotificationTest.java
@@ -467,7 +467,6 @@
                 .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG"))
                 .setColor(Color.WHITE)
                 .setColorized(true)
-                .setFlag(FLAG_CAN_COLORIZE, true)
                 .build();
         assertThat(n.hasPromotableCharacteristics()).isTrue();
     }
@@ -481,7 +480,6 @@
                 .setContentTitle("TITLE")
                 .setColor(Color.WHITE)
                 .setColorized(true)
-                .setFlag(FLAG_CAN_COLORIZE, true)
                 .build();
         assertThat(n.hasPromotableCharacteristics()).isFalse();
     }
@@ -505,7 +503,20 @@
                 .setStyle(new Notification.BigTextStyle())
                 .setColor(Color.WHITE)
                 .setColorized(true)
-                .setFlag(FLAG_CAN_COLORIZE, true)
+                .build();
+        assertThat(n.hasPromotableCharacteristics()).isFalse();
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_UI_RICH_ONGOING)
+    public void testHasPromotableCharacteristics_groupSummary() {
+        Notification n = new Notification.Builder(mContext, "test")
+                .setSmallIcon(android.R.drawable.sym_def_app_icon)
+                .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG"))
+                .setColor(Color.WHITE)
+                .setColorized(true)
+                .setGroup("someGroup")
+                .setGroupSummary(true)
                 .build();
         assertThat(n.hasPromotableCharacteristics()).isFalse();
     }
diff --git a/core/tests/coretests/src/android/content/pm/parsing/ApkLiteParseUtilsTest.java b/core/tests/coretests/src/android/content/pm/parsing/ApkLiteParseUtilsTest.java
index ecacdb2..6d2dd53 100644
--- a/core/tests/coretests/src/android/content/pm/parsing/ApkLiteParseUtilsTest.java
+++ b/core/tests/coretests/src/android/content/pm/parsing/ApkLiteParseUtilsTest.java
@@ -73,6 +73,7 @@
     private static final String TEST_APP_USING_SDK1_AND_SDK1 = "HelloWorldUsingSdk1AndSdk1.apk";
     private static final String TEST_APP_USING_SDK_MALFORMED_VERSION =
             "HelloWorldUsingSdkMalformedNegativeVersion.apk";
+    private static final String TEST_STATIC_LIB_APP = "CtsStaticSharedLibProviderApp1.apk";
     private static final String TEST_APP_USING_STATIC_LIB = "CtsStaticSharedLibConsumerApp1.apk";
     private static final String TEST_APP_USING_STATIC_LIB_TWO_CERTS =
             "CtsStaticSharedLibConsumerApp3.apk";
@@ -207,6 +208,17 @@
         assertThat(liteCerts).isEqualTo(pkgCerts);
     }
 
+    @Test
+    public void testParseApkLite_isIsStaticLibrary() throws Exception {
+        File apkFile = copyApkToTmpDir(TEST_STATIC_LIB_APP);
+        ParseResult<ApkLite> result = ApkLiteParseUtils
+                .parseApkLite(ParseTypeImpl.forDefaultParsing().reset(), apkFile, 0);
+        assertThat(result.isError()).isFalse();
+        ApkLite baseApk = result.getResult();
+
+        assertThat(baseApk.isIsStaticLibrary()).isTrue();
+    }
+
     @SuppressLint("CheckResult")
     @Test
     public void testParseApkLite_malformedUsesSdkLibrary_duplicate() throws Exception {
diff --git a/core/tests/coretests/src/android/window/WindowTokenClientControllerTest.java b/core/tests/coretests/src/android/window/WindowTokenClientControllerTest.java
index a3725af..bb2fe1b 100644
--- a/core/tests/coretests/src/android/window/WindowTokenClientControllerTest.java
+++ b/core/tests/coretests/src/android/window/WindowTokenClientControllerTest.java
@@ -162,6 +162,22 @@
     }
 
     @Test
+    public void testAttachToDisplayContent_keepTrackWithoutWMS() {
+        // WMS is not initialized
+        doReturn(null).when(mController).getWindowManagerService();
+
+        assertFalse(mController.attachToDisplayContent(mWindowTokenClient, DEFAULT_DISPLAY));
+
+        // Can report config change
+        mController.onWindowContextInfoChanged(mWindowTokenClient, mWindowContextInfo);
+
+        verify(mWindowTokenClient).onConfigurationChanged(mConfiguration, DEFAULT_DISPLAY);
+
+        // No crash to detach even if WMS is not initialized.
+        mController.detachIfNeeded(mWindowTokenClient);
+    }
+
+    @Test
     public void testAttachToWindowToken() throws RemoteException {
         doReturn(null).when(mWindowManagerService).attachWindowContextToWindowToken(
                 any(), any(), any());
diff --git a/core/tests/vibrator/src/android/os/vibrator/persistence/VibrationEffectXmlSerializationTest.java b/core/tests/vibrator/src/android/os/vibrator/persistence/VibrationEffectXmlSerializationTest.java
index 1cc38de..4071057 100644
--- a/core/tests/vibrator/src/android/os/vibrator/persistence/VibrationEffectXmlSerializationTest.java
+++ b/core/tests/vibrator/src/android/os/vibrator/persistence/VibrationEffectXmlSerializationTest.java
@@ -16,6 +16,8 @@
 
 package android.os.vibrator.persistence;
 
+import static android.os.VibrationEffect.Composition.DELAY_TYPE_PAUSE;
+import static android.os.VibrationEffect.Composition.DELAY_TYPE_RELATIVE_START_OFFSET;
 import static android.os.VibrationEffect.Composition.PRIMITIVE_CLICK;
 import static android.os.VibrationEffect.Composition.PRIMITIVE_LOW_TICK;
 import static android.os.VibrationEffect.Composition.PRIMITIVE_SPIN;
@@ -31,6 +33,7 @@
 import android.os.VibrationEffect;
 import android.os.vibrator.Flags;
 import android.os.vibrator.PrebakedSegment;
+import android.os.vibrator.PrimitiveSegment;
 import android.platform.test.annotations.DisableFlags;
 import android.platform.test.annotations.EnableFlags;
 import android.platform.test.flag.junit.SetFlagsRule;
@@ -437,7 +440,7 @@
 
     @Test
     @EnableFlags(Flags.FLAG_VENDOR_VIBRATION_EFFECTS)
-    public void testVendorEffect_featureFlagEnabled_allSucceed() throws Exception {
+    public void testVendorEffect_allSucceed() throws Exception {
         PersistableBundle vendorData = new PersistableBundle();
         vendorData.putInt("id", 1);
         vendorData.putDouble("scale", 0.5);
@@ -476,7 +479,7 @@
 
     @Test
     @EnableFlags(Flags.FLAG_VENDOR_VIBRATION_EFFECTS)
-    public void testInvalidVendorEffect_featureFlagEnabled_allFail() throws IOException {
+    public void testInvalidVendorEffect_allFail() throws IOException {
         String emptyTag = "<vibration-effect><vendor-effect/></vibration-effect>";
         assertPublicApisParserFails(emptyTag);
         assertHiddenApisParserFails(emptyTag);
@@ -526,6 +529,81 @@
         assertHiddenApisSerializerFails(vendorEffect);
     }
 
+    @Test
+    @EnableFlags(Flags.FLAG_PRIMITIVE_COMPOSITION_ABSOLUTE_DELAY)
+    public void testPrimitiveDelayType_allSucceed() throws Exception {
+        VibrationEffect effect = VibrationEffect.startComposition()
+                .addPrimitive(PRIMITIVE_TICK, 1.0f, 0, DELAY_TYPE_RELATIVE_START_OFFSET)
+                .addPrimitive(PRIMITIVE_CLICK, 0.123f, 10, DELAY_TYPE_PAUSE)
+                .compose();
+        String xml = """
+                <vibration-effect>
+                    <primitive-effect name="tick" delayType="relative_start_offset"/>
+                    <primitive-effect name="click" scale="0.123" delayMs="10"/>
+                </vibration-effect>
+                """;
+
+        assertPublicApisParserSucceeds(xml, effect);
+        assertPublicApisSerializerSucceeds(effect, "tick", "click");
+        // Delay type pause is not serialized, as it's the default one
+        assertPublicApisSerializerSucceeds(effect, "relative_start_offset", "click");
+        assertPublicApisRoundTrip(effect);
+
+        assertHiddenApisParserSucceeds(xml, effect);
+        assertHiddenApisSerializerSucceeds(effect, "tick", "click");
+        assertHiddenApisRoundTrip(effect);
+
+        // Check PersistableBundle from round-trip
+        VibrationEffect.Composed parsedEffect = ((VibrationEffect.Composed) parseVibrationEffect(
+                serialize(effect), /* flags= */ 0));
+        assertThat(parsedEffect.getRepeatIndex()).isEqualTo(-1);
+        assertThat(parsedEffect.getSegments()).containsExactly(
+                new PrimitiveSegment(PRIMITIVE_TICK, 1.0f, 0, DELAY_TYPE_RELATIVE_START_OFFSET),
+                new PrimitiveSegment(PRIMITIVE_CLICK, 0.123f, 10, DELAY_TYPE_PAUSE))
+                .inOrder();
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_PRIMITIVE_COMPOSITION_ABSOLUTE_DELAY)
+    public void testPrimitiveInvalidDelayType_allFail() {
+        String emptyAttribute = """
+                <vibration-effect>
+                    <primitive-effect name="tick" delayType=""/>
+                </vibration-effect>
+                """;
+        assertPublicApisParserFails(emptyAttribute);
+        assertHiddenApisParserFails(emptyAttribute);
+
+        String invalidString = """
+                <vibration-effect>
+                    <primitive-effect name="tick" delayType="invalid"/>
+                </vibration-effect>
+                """;
+        assertPublicApisParserFails(invalidString);
+        assertHiddenApisParserFails(invalidString);
+    }
+
+    @Test
+    @DisableFlags(Flags.FLAG_PRIMITIVE_COMPOSITION_ABSOLUTE_DELAY)
+    public void testPrimitiveDelayType_featureFlagDisabled_allFail() {
+        VibrationEffect effect = VibrationEffect.startComposition()
+                .addPrimitive(PRIMITIVE_TICK, 1.0f, 0, DELAY_TYPE_RELATIVE_START_OFFSET)
+                .addPrimitive(PRIMITIVE_CLICK, 0.123f, 10, DELAY_TYPE_PAUSE)
+                .compose();
+        String xml = """
+                <vibration-effect>
+                    <primitive-effect name="tick" delayType="relative_start_offset"/>
+                    <primitive-effect name="click" scale="0.123" delayMs="10" delayType="pause"/>
+                </vibration-effect>
+                """;
+
+        assertPublicApisParserFails(xml);
+        assertPublicApisSerializerFails(effect);
+
+        assertHiddenApisParserFails(xml);
+        assertHiddenApisSerializerFails(effect);
+    }
+
     private void assertPublicApisParserFails(String xml) {
         assertThrows("Expected parseVibrationEffect to fail for " + xml,
                 VibrationXmlParser.ParseFailedException.class,
diff --git a/core/xsd/permission.xsd b/core/xsd/permission.xsd
index 0ec8f7d..0a0ca7c 100644
--- a/core/xsd/permission.xsd
+++ b/core/xsd/permission.xsd
@@ -43,6 +43,7 @@
                 <xs:element name="disabled-until-used-preinstalled-carrier-app" type="disabled-until-used-preinstalled-carrier-app"/>
                 <xs:element name="privapp-permissions" type="privapp-permissions"/>
                 <xs:element name="oem-permissions" type="oem-permissions"/>
+                <xs:element name="signature-permissions" type="signature-permissions"/>
                 <xs:element name="hidden-api-whitelisted-app" type="hidden-api-whitelisted-app"/>
                 <xs:element name="allow-association" type="allow-association"/>
                 <xs:element name="bugreport-whitelisted" type="bugreport-whitelisted"/>
@@ -156,6 +157,21 @@
         </xs:sequence>
         <xs:attribute name="package" type="xs:string"/>
     </xs:complexType>
+    <xs:complexType name="signature-permissions">
+        <xs:sequence>
+            <xs:element name="permission" minOccurs="0" maxOccurs="unbounded">
+                <xs:complexType>
+                    <xs:attribute name="name" type="xs:string"/>
+                </xs:complexType>
+            </xs:element>
+            <xs:element name="deny-permission" minOccurs="0" maxOccurs="unbounded">
+                <xs:complexType>
+                    <xs:attribute name="name" type="xs:string"/>
+                </xs:complexType>
+            </xs:element>
+        </xs:sequence>
+        <xs:attribute name="package" type="xs:string"/>
+    </xs:complexType>
     <xs:complexType name="hidden-api-whitelisted-app">
         <xs:attribute name="package" type="xs:string"/>
     </xs:complexType>
diff --git a/core/xsd/schema/current.txt b/core/xsd/schema/current.txt
index f3beea1..cdec6ab 100644
--- a/core/xsd/schema/current.txt
+++ b/core/xsd/schema/current.txt
@@ -183,6 +183,7 @@
     method public java.util.List<com.android.xml.permission.configfile.OemPermissions> getOemPermissions_optional();
     method public java.util.List<com.android.xml.permission.configfile.Permission> getPermission_optional();
     method public java.util.List<com.android.xml.permission.configfile.PrivappPermissions> getPrivappPermissions_optional();
+    method public java.util.List<com.android.xml.permission.configfile.SignaturePermissions> getSignaturePermissions_optional();
     method public java.util.List<com.android.xml.permission.configfile.SplitPermission> getSplitPermission_optional();
     method public java.util.List<com.android.xml.permission.configfile.SystemUserBlacklistedApp> getSystemUserBlacklistedApp_optional();
     method public java.util.List<com.android.xml.permission.configfile.SystemUserWhitelistedApp> getSystemUserWhitelistedApp_optional();
@@ -209,6 +210,26 @@
     method public void setName(String);
   }
 
+  public class SignaturePermissions {
+    ctor public SignaturePermissions();
+    method public java.util.List<com.android.xml.permission.configfile.SignaturePermissions.DenyPermission> getDenyPermission();
+    method public java.util.List<com.android.xml.permission.configfile.SignaturePermissions.Permission> getPermission();
+    method public String get_package();
+    method public void set_package(String);
+  }
+
+  public static class SignaturePermissions.DenyPermission {
+    ctor public SignaturePermissions.DenyPermission();
+    method public String getName();
+    method public void setName(String);
+  }
+
+  public static class SignaturePermissions.Permission {
+    ctor public SignaturePermissions.Permission();
+    method public String getName();
+    method public void setName(String);
+  }
+
   public class SplitPermission {
     ctor public SplitPermission();
     method public java.util.List<com.android.xml.permission.configfile.SplitPermission.Library> getLibrary();
diff --git a/core/xsd/vibrator/vibration/schema/current.txt b/core/xsd/vibrator/vibration/schema/current.txt
index 280b405..b4148d6 100644
--- a/core/xsd/vibrator/vibration/schema/current.txt
+++ b/core/xsd/vibrator/vibration/schema/current.txt
@@ -15,12 +15,20 @@
     enum_constant public static final com.android.internal.vibrator.persistence.PredefinedEffectName tick;
   }
 
+  public enum PrimitiveDelayType {
+    method public String getRawName();
+    enum_constant public static final com.android.internal.vibrator.persistence.PrimitiveDelayType pause;
+    enum_constant public static final com.android.internal.vibrator.persistence.PrimitiveDelayType relative_start_offset;
+  }
+
   public class PrimitiveEffect {
     ctor public PrimitiveEffect();
     method public java.math.BigInteger getDelayMs();
+    method public com.android.internal.vibrator.persistence.PrimitiveDelayType getDelayType();
     method public com.android.internal.vibrator.persistence.PrimitiveEffectName getName();
     method public float getScale();
     method public void setDelayMs(java.math.BigInteger);
+    method public void setDelayType(com.android.internal.vibrator.persistence.PrimitiveDelayType);
     method public void setName(com.android.internal.vibrator.persistence.PrimitiveEffectName);
     method public void setScale(float);
   }
diff --git a/core/xsd/vibrator/vibration/vibration-plus-hidden-apis.xsd b/core/xsd/vibrator/vibration/vibration-plus-hidden-apis.xsd
index 21a6fac..910a9b7 100644
--- a/core/xsd/vibrator/vibration/vibration-plus-hidden-apis.xsd
+++ b/core/xsd/vibrator/vibration/vibration-plus-hidden-apis.xsd
@@ -147,6 +147,7 @@
         <xs:attribute name="name" type="PrimitiveEffectName" use="required"/>
         <xs:attribute name="scale" type="PrimitiveScale"/>
         <xs:attribute name="delayMs" type="xs:nonNegativeInteger"/>
+        <xs:attribute name="delayType" type="PrimitiveDelayType"/>
     </xs:complexType>
 
     <!-- Primitive names as defined by VibrationEffect.Composition.PRIMITIVE_* -->
@@ -171,4 +172,12 @@
         </xs:restriction>
     </xs:simpleType>
 
+    <!-- Primitive delay types VibrationEffect.Composition.DELAY_TYPE_* -->
+    <xs:simpleType  name="PrimitiveDelayType">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="pause"/>
+            <xs:enumeration value="relative_start_offset"/>
+        </xs:restriction>
+    </xs:simpleType>
+
 </xs:schema>
diff --git a/core/xsd/vibrator/vibration/vibration.xsd b/core/xsd/vibrator/vibration/vibration.xsd
index d35d777..3c8e016 100644
--- a/core/xsd/vibrator/vibration/vibration.xsd
+++ b/core/xsd/vibrator/vibration/vibration.xsd
@@ -124,6 +124,7 @@
         <xs:attribute name="name" type="PrimitiveEffectName" use="required"/>
         <xs:attribute name="scale" type="PrimitiveScale"/>
         <xs:attribute name="delayMs" type="xs:nonNegativeInteger"/>
+        <xs:attribute name="delayType" type="PrimitiveDelayType"/>
     </xs:complexType>
 
     <!-- Primitive names as defined by VibrationEffect.Composition.PRIMITIVE_* -->
@@ -148,4 +149,12 @@
         </xs:restriction>
     </xs:simpleType>
 
+    <!-- Primitive delay types VibrationEffect.Composition.DELAY_TYPE_* -->
+    <xs:simpleType  name="PrimitiveDelayType">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="pause"/>
+            <xs:enumeration value="relative_start_offset"/>
+        </xs:restriction>
+    </xs:simpleType>
+
 </xs:schema>
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/common/DeviceStateManagerFoldingFeatureProducer.java b/libs/WindowManager/Jetpack/src/androidx/window/common/DeviceStateManagerFoldingFeatureProducer.java
index 0896138..5ea3843 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/common/DeviceStateManagerFoldingFeatureProducer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/common/DeviceStateManagerFoldingFeatureProducer.java
@@ -30,8 +30,6 @@
 import android.util.Log;
 import android.util.SparseIntArray;
 
-import androidx.annotation.BinderThread;
-import androidx.annotation.GuardedBy;
 import androidx.annotation.MainThread;
 import androidx.annotation.NonNull;
 import androidx.annotation.VisibleForTesting;
@@ -39,14 +37,12 @@
 import androidx.window.common.layout.DisplayFoldFeatureCommon;
 
 import com.android.internal.R;
-import com.android.window.flags.Flags;
 
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
 import java.util.Optional;
-import java.util.concurrent.Executor;
 import java.util.function.Consumer;
 
 /**
@@ -70,20 +66,8 @@
      * "rear display". Concurrent mode for example is activated via public API and can be active in
      * both the "open" and "half folded" device states.
      */
-    // TODO: b/337820752 - Add @GuardedBy("mCurrentDeviceStateLock") after flag cleanup.
     private DeviceState mCurrentDeviceState = INVALID_DEVICE_STATE;
 
-    /**
-     * Lock to synchronize access to {@link #mCurrentDeviceState}.
-     *
-     * <p>This lock is used to ensure thread-safety when accessing and modifying the
-     * {@link #mCurrentDeviceState} field. It is acquired by both the binder thread (if
-     * {@link Flags#wlinfoOncreate()} is enabled) and the main thread (if
-     * {@link Flags#wlinfoOncreate()} is disabled) to prevent race conditions and
-     * ensure data consistency.
-     */
-    private final Object mCurrentDeviceStateLock = new Object();
-
     @NonNull
     private final RawFoldingFeatureProducer mRawFoldSupplier;
 
@@ -95,15 +79,12 @@
         // The GuardedBy analysis is intra-procedural, meaning it doesn’t consider the getData()
         // implementation. See https://errorprone.info/bugpattern/GuardedBy for limitations.
         @SuppressWarnings("GuardedBy")
-        @BinderThread // When Flags.wlinfoOncreate() is enabled.
-        @MainThread // When Flags.wlinfoOncreate() is disabled.
+        @MainThread
         @Override
         public void onDeviceStateChanged(@NonNull DeviceState state) {
-            synchronized (mCurrentDeviceStateLock) {
-                mCurrentDeviceState = state;
-                mRawFoldSupplier.getData(DeviceStateManagerFoldingFeatureProducer.this
-                        ::notifyFoldingFeatureChangeLocked);
-            }
+            mCurrentDeviceState = state;
+            mRawFoldSupplier.getData(DeviceStateManagerFoldingFeatureProducer.this
+                    ::notifyFoldingFeatureChangeLocked);
         }
     };
 
@@ -115,10 +96,8 @@
                 new DeviceStateMapper(context, deviceStateManager.getSupportedDeviceStates());
 
         if (!mDeviceStateMapper.isDeviceStateToPostureMapEmpty()) {
-            final Executor executor =
-                    Flags.wlinfoOncreate() ? Runnable::run : context.getMainExecutor();
             Objects.requireNonNull(deviceStateManager)
-                    .registerCallback(executor, mDeviceStateCallback);
+                    .registerCallback(context.getMainExecutor(), mDeviceStateCallback);
         }
     }
 
@@ -145,21 +124,17 @@
     @Override
     protected void onListenersChanged() {
         super.onListenersChanged();
-        synchronized (mCurrentDeviceStateLock) {
-            if (hasListeners()) {
-                mRawFoldSupplier.addDataChangedCallback(this::notifyFoldingFeatureChangeLocked);
-            } else {
-                mCurrentDeviceState = INVALID_DEVICE_STATE;
-                mRawFoldSupplier.removeDataChangedCallback(this::notifyFoldingFeatureChangeLocked);
-            }
+        if (hasListeners()) {
+            mRawFoldSupplier.addDataChangedCallback(this::notifyFoldingFeatureChangeLocked);
+        } else {
+            mCurrentDeviceState = INVALID_DEVICE_STATE;
+            mRawFoldSupplier.removeDataChangedCallback(this::notifyFoldingFeatureChangeLocked);
         }
     }
 
     @NonNull
     private DeviceState getCurrentDeviceState() {
-        synchronized (mCurrentDeviceStateLock) {
-            return mCurrentDeviceState;
-        }
+        return mCurrentDeviceState;
     }
 
     @NonNull
@@ -231,7 +206,6 @@
         });
     }
 
-    @GuardedBy("mCurrentDeviceStateLock")
     private void notifyFoldingFeatureChangeLocked(String displayFeaturesString) {
         final DeviceState state = mCurrentDeviceState;
         if (!mDeviceStateMapper.isDeviceStateValid(state)) {
@@ -252,29 +226,16 @@
         return parseListFromString(displayFeaturesString, hingeState);
     }
 
-    /**
-     * Internal class to map device states to corresponding postures.
-     *
-     * <p>This class encapsulates the logic for mapping device states to postures. The mapping is
-     * immutable after initialization to ensure thread safety.
-     */
+    /** Internal class to map device states to corresponding postures. */
     private static class DeviceStateMapper {
         /**
          * Emulated device state
          * {@link DeviceStateManager.DeviceStateCallback#onDeviceStateChanged(DeviceState)} to
          * {@link CommonFoldingFeature.State} map.
-         *
-         * <p>This map must be immutable after initialization to ensure thread safety, as it may be
-         * accessed from multiple threads. Modifications should only occur during object
-         * construction.
          */
         private final SparseIntArray mDeviceStateToPostureMap = new SparseIntArray();
 
-        /**
-         * The list of device states that are supported.
-         *
-         * <p>This list must be immutable after initialization to ensure thread safety.
-         */
+        /** The list of device states that are supported. */
         @NonNull
         private final List<DeviceState> mSupportedStates;
 
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/common/DeviceStateManagerFoldingFeatureProducerTest.kt b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/common/DeviceStateManagerFoldingFeatureProducerTest.kt
index 90887a7..fb01cd8 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/common/DeviceStateManagerFoldingFeatureProducerTest.kt
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/common/DeviceStateManagerFoldingFeatureProducerTest.kt
@@ -20,9 +20,6 @@
 import android.content.res.Resources
 import android.hardware.devicestate.DeviceState
 import android.hardware.devicestate.DeviceStateManager
-import android.platform.test.annotations.DisableFlags
-import android.platform.test.annotations.EnableFlags
-import android.platform.test.flag.junit.SetFlagsRule
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.window.common.layout.CommonFoldingFeature
 import androidx.window.common.layout.CommonFoldingFeature.COMMON_STATE_FLAT
@@ -34,15 +31,11 @@
 import androidx.window.common.layout.DisplayFoldFeatureCommon.DISPLAY_FOLD_FEATURE_PROPERTY_SUPPORTS_HALF_OPENED
 import androidx.window.common.layout.DisplayFoldFeatureCommon.DISPLAY_FOLD_FEATURE_TYPE_SCREEN_FOLD_IN
 import com.android.internal.R
-import com.android.window.flags.Flags
 import com.google.common.truth.Truth.assertThat
 import java.util.Optional
-import java.util.concurrent.Executor
 import java.util.function.Consumer
-import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.mockito.ArgumentCaptor
 import org.mockito.kotlin.any
 import org.mockito.kotlin.doAnswer
 import org.mockito.kotlin.doReturn
@@ -60,9 +53,6 @@
  */
 @RunWith(AndroidJUnit4::class)
 class DeviceStateManagerFoldingFeatureProducerTest {
-    @get:Rule
-    val setFlagsRule: SetFlagsRule = SetFlagsRule()
-
     private val mMockDeviceStateManager = mock<DeviceStateManager>()
     private val mMockResources = mock<Resources> {
         on { getStringArray(R.array.config_device_state_postures) } doReturn DEVICE_STATE_POSTURES
@@ -79,8 +69,7 @@
     }
 
     @Test
-    @DisableFlags(Flags.FLAG_WLINFO_ONCREATE)
-    fun testRegisterCallback_whenWlinfoOncreateIsDisabled_usesMainExecutor() {
+    fun testRegisterCallback_usesMainExecutor() {
         DeviceStateManagerFoldingFeatureProducer(
             mMockContext,
             mRawFoldSupplier,
@@ -91,23 +80,6 @@
     }
 
     @Test
-    @EnableFlags(Flags.FLAG_WLINFO_ONCREATE)
-    fun testRegisterCallback_whenWlinfoOncreateIsEnabled_usesRunnableRun() {
-        val executorCaptor = ArgumentCaptor.forClass(Executor::class.java)
-        val runnable = mock<Runnable>()
-
-        DeviceStateManagerFoldingFeatureProducer(
-            mMockContext,
-            mRawFoldSupplier,
-            mMockDeviceStateManager,
-        )
-
-        verify(mMockDeviceStateManager).registerCallback(executorCaptor.capture(), any())
-        executorCaptor.value.execute(runnable)
-        verify(runnable).run()
-    }
-
-    @Test
     fun testGetCurrentData_validCurrentState_returnsFoldingFeatureWithState() {
         val ffp = DeviceStateManagerFoldingFeatureProducer(
             mMockContext,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityBackAnimation.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityBackAnimation.kt
index 3733930..7e5a82e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityBackAnimation.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityBackAnimation.kt
@@ -39,6 +39,8 @@
 import android.view.animation.Interpolator
 import android.view.animation.Transformation
 import android.window.BackEvent
+import android.window.BackEvent.EDGE_LEFT
+import android.window.BackEvent.EDGE_RIGHT
 import android.window.BackMotionEvent
 import android.window.BackNavigationInfo
 import android.window.BackProgressAnimator
@@ -50,6 +52,7 @@
 import com.android.internal.policy.ScreenDecorationsUtils
 import com.android.internal.policy.SystemBarUtils
 import com.android.internal.protolog.ProtoLog
+import com.android.window.flags.Flags.predictiveBackTimestampApi
 import com.android.wm.shell.R
 import com.android.wm.shell.RootTaskDisplayAreaOrganizer
 import com.android.wm.shell.protolog.ShellProtoLogGroup
@@ -118,7 +121,9 @@
     private val postCommitFlingSpring = SpringForce(SPRING_SCALE)
             .setStiffness(SpringForce.STIFFNESS_LOW)
             .setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY)
+    private var swipeEdge = EDGE_LEFT
     protected var gestureProgress = 0f
+    private val velocityTracker = ProgressVelocityTracker()
 
     /** Background color to be used during the animation, also see [getBackgroundColor] */
     protected var customizedBackgroundColor = 0
@@ -175,6 +180,7 @@
             )
             return
         }
+        swipeEdge = backMotionEvent.swipeEdge
         triggerBack = backMotionEvent.triggerBack
         initialTouchPos.set(backMotionEvent.touchX, backMotionEvent.touchY)
 
@@ -241,6 +247,9 @@
         )
         applyTransaction()
         background.customizeStatusBarAppearance(currentClosingRect.top.toInt())
+        if (predictiveBackTimestampApi()) {
+            velocityTracker.addPosition(backEvent.frameTimeMillis, progress)
+        }
     }
 
     private fun getYOffset(centeredRect: RectF, touchY: Float): Float {
@@ -272,10 +281,19 @@
 
         // kick off spring animation with the current velocity from the pre-commit phase, this
         // affects the scaling of the closing and/or opening activity during post-commit
-        val startVelocity =
-            if (gestureProgress < 0.1f) -DEFAULT_FLING_VELOCITY else -velocity * SPRING_SCALE
+
+        var startVelocity = if (predictiveBackTimestampApi()) {
+            // pronounce fling animation more for gestures
+            val velocityFactor = if (swipeEdge == EDGE_LEFT || swipeEdge == EDGE_RIGHT) 2f else 1f
+            velocity * SPRING_SCALE * (1f - MAX_SCALE) * velocityFactor
+        } else {
+            velocity * SPRING_SCALE
+        }
+        if (gestureProgress < 0.1f) {
+            startVelocity = startVelocity.coerceAtLeast(DEFAULT_FLING_VELOCITY)
+        }
         val flingAnimation = SpringAnimation(postCommitFlingScale, SPRING_SCALE)
-            .setStartVelocity(startVelocity.coerceIn(-MAX_FLING_VELOCITY, 0f))
+            .setStartVelocity(-startVelocity.coerceIn(0f, MAX_FLING_VELOCITY))
             .setStartValue(SPRING_SCALE)
             .setSpring(postCommitFlingSpring)
         flingAnimation.start()
@@ -338,6 +356,7 @@
         lastPostCommitFlingScale = SPRING_SCALE
         gestureProgress = 0f
         triggerBack = false
+        velocityTracker.resetTracking()
     }
 
     protected fun applyTransform(
@@ -520,7 +539,11 @@
         override fun onBackInvoked() {
             triggerBack = true
             progressAnimator.reset()
-            onGestureCommitted(progressAnimator.velocity)
+            if (predictiveBackTimestampApi()) {
+                onGestureCommitted(velocityTracker.calculateVelocity())
+            } else {
+                onGestureCommitted(progressAnimator.velocity)
+            }
         }
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossTaskBackAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossTaskBackAnimation.java
index dc50fdb..f48b3ff 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossTaskBackAnimation.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossTaskBackAnimation.java
@@ -16,7 +16,6 @@
 
 package com.android.wm.shell.back;
 
-import static android.view.MotionEvent.ACTION_MOVE;
 import static android.view.RemoteAnimationTarget.MODE_CLOSING;
 import static android.view.RemoteAnimationTarget.MODE_OPENING;
 import static android.window.BackEvent.EDGE_RIGHT;
@@ -43,10 +42,8 @@
 import android.view.Choreographer;
 import android.view.IRemoteAnimationFinishedCallback;
 import android.view.IRemoteAnimationRunner;
-import android.view.MotionEvent;
 import android.view.RemoteAnimationTarget;
 import android.view.SurfaceControl;
-import android.view.VelocityTracker;
 import android.view.animation.DecelerateInterpolator;
 import android.view.animation.Interpolator;
 import android.window.BackEvent;
@@ -132,9 +129,8 @@
     private final SpringForce mPostCommitFlingSpring = new SpringForce(SPRING_SCALE)
             .setStiffness(FLING_SPRING_STIFFNESS)
             .setDampingRatio(1f);
-    private final VelocityTracker mVelocityTracker = VelocityTracker.obtain();
+    private final ProgressVelocityTracker mVelocityTracker = new ProgressVelocityTracker();
     private float mGestureProgress = 0f;
-    private long mDownTime = 0L;
 
     @Inject
     public CrossTaskBackAnimation(Context context, BackAnimationBackground background,
@@ -316,8 +312,7 @@
         mClosingCurrentRect.setEmpty();
         mInitialTouchPos.set(0, 0);
         mGestureProgress = 0;
-        mDownTime = 0;
-        mVelocityTracker.clear();
+        mVelocityTracker.resetTracking();
 
         if (mFinishCallback != null) {
             try {
@@ -333,22 +328,13 @@
     private void onGestureProgress(@NonNull BackEvent backEvent) {
         if (!mBackInProgress) {
             mBackInProgress = true;
-            mDownTime = backEvent.getFrameTimeMillis();
         }
         float progress = backEvent.getProgress();
         mTouchPos.set(backEvent.getTouchX(), backEvent.getTouchY());
         float interpolatedProgress = getInterpolatedProgress(progress);
         if (predictiveBackTimestampApi()) {
-            mVelocityTracker.addMovement(
-                    MotionEvent.obtain(
-                            /* downTime */ mDownTime,
-                            /* eventTime */ backEvent.getFrameTimeMillis(),
-                            /* action */ ACTION_MOVE,
-                            /* x */ interpolatedProgress * SPRING_SCALE,
-                            /* y */ 0f,
-                            /* metaState */ 0
-                    )
-            );
+            mVelocityTracker.addPosition(backEvent.getFrameTimeMillis(),
+                    interpolatedProgress * SPRING_SCALE);
         }
         updateGestureBackProgress(interpolatedProgress, backEvent);
     }
@@ -362,9 +348,8 @@
         if (predictiveBackTimestampApi()) {
             // kick off spring animation with the current velocity from the pre-commit phase, this
             // affects the scaling of the closing and/or opening task during post-commit
-            mVelocityTracker.computeCurrentVelocity(1000);
             float startVelocity = mGestureProgress < 0.1f
-                    ? -DEFAULT_FLING_VELOCITY : -mVelocityTracker.getXVelocity();
+                    ? -DEFAULT_FLING_VELOCITY : -mVelocityTracker.calculateVelocity();
             SpringAnimation flingAnimation =
                     new SpringAnimation(mPostCommitFlingScale, SPRING_SCALE)
                     .setStartVelocity(Math.max(-MAX_FLING_VELOCITY, Math.min(0f, startVelocity)))
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/ProgressVelocityTracker.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/back/ProgressVelocityTracker.kt
new file mode 100644
index 0000000..6bbda0f
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/ProgressVelocityTracker.kt
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.back
+
+import android.view.MotionEvent
+import android.view.VelocityTracker
+
+internal class ProgressVelocityTracker {
+    private val velocityTracker: VelocityTracker = VelocityTracker.obtain()
+    private var downTime = -1L
+
+    fun addPosition(timeMillis: Long, position: Float) {
+        if (downTime == -1L) downTime = timeMillis
+        velocityTracker.addMovement(
+            MotionEvent.obtain(
+                /* downTime */ downTime,
+                /* eventTime */ timeMillis,
+                /* action */ MotionEvent.ACTION_MOVE,
+                /* x */ position,
+                /* y */ 0f,
+                /* metaState */0
+            )
+        )
+    }
+
+    /** calculates current velocity (unit: progress per second) */
+    fun calculateVelocity(): Float {
+        velocityTracker.computeCurrentVelocity(1000)
+        return velocityTracker.xVelocity
+    }
+
+    fun resetTracking() {
+        velocityTracker.clear()
+        downTime = -1L
+    }
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
index 2945691..dc2025b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
@@ -898,7 +898,10 @@
             Bubble oldest = mOverflowBubbles.get(mOverflowBubbles.size() - 1);
             ProtoLog.d(WM_SHELL_BUBBLES, "overflow full, remove=%s", oldest.getKey());
             mStateChange.bubbleRemoved(oldest, Bubbles.DISMISS_OVERFLOW_MAX_REACHED);
-            mLogger.log(bubble, BubbleLogger.Event.BUBBLE_OVERFLOW_REMOVE_MAX_REACHED);
+            if (!mPositioner.isShowingInBubbleBar()) {
+                // Only logged for bubbles in stack view
+                mLogger.log(bubble, BubbleLogger.Event.BUBBLE_OVERFLOW_REMOVE_MAX_REACHED);
+            }
             mOverflowBubbles.remove(oldest);
             mStateChange.removedOverflowBubble = oldest;
         }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java
index 9fe7a97..ed49417 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java
@@ -402,7 +402,7 @@
     }
 
     void animateExpansionWhenTaskViewVisible(Runnable animateExpansion) {
-        if (mVisibilityState == TaskViewVisibilityState.VISIBLE) {
+        if (mVisibilityState == TaskViewVisibilityState.VISIBLE || mIsOverflow) {
             animateExpansion.run();
         } else {
             mAnimateExpansion = animateExpansion;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
index 635531e..0f63658 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
@@ -703,6 +703,7 @@
             InputManager inputManager,
             FocusTransitionObserver focusTransitionObserver,
             DesktopModeEventLogger desktopModeEventLogger,
+            DesktopModeUiEventLogger desktopModeUiEventLogger,
             DesktopTilingDecorViewModel desktopTilingDecorViewModel) {
         return new DesktopTasksController(
                 context,
@@ -733,6 +734,7 @@
                 interactionJankMonitor,
                 mainHandler,
                 desktopModeEventLogger,
+                desktopModeUiEventLogger,
                 desktopTilingDecorViewModel);
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeEventLogger.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeEventLogger.kt
index b4eac7a..dc23128 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeEventLogger.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeEventLogger.kt
@@ -446,6 +446,7 @@
             val displayArea: Int?,
         )
 
+        @JvmStatic
         fun getInputMethodFromMotionEvent(e: MotionEvent?): InputMethod {
             if (e == null) return InputMethod.UNKNOWN_INPUT_METHOD
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandler.kt
index 114563a..6cb23b8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandler.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandler.kt
@@ -94,7 +94,7 @@
                     desktopTasksController.get().toggleDesktopTaskSize(
                         it,
                         ResizeTrigger.MAXIMIZE_MENU,
-                        null,
+                        DesktopModeEventLogger.Companion.InputMethod.KEYBOARD,
                     )
                 }
                 return true
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUiEventLogger.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUiEventLogger.kt
index 5801c6a..d0e0162 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUiEventLogger.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUiEventLogger.kt
@@ -106,7 +106,25 @@
         @UiEvent(doc = "Double tap on window header to maximize it in desktop windowing mode")
         DESKTOP_WINDOW_HEADER_DOUBLE_TAP_TO_MAXIMIZE(1724),
         @UiEvent(doc = "Tap on the window Handle to open the Handle Menu")
-        DESKTOP_WINDOW_APP_HANDLE_TAP(1998);
+        DESKTOP_WINDOW_APP_HANDLE_TAP(1998),
+        @UiEvent(doc = "Tap on the desktop mode option under app handle menu")
+        DESKTOP_WINDOW_APP_HANDLE_MENU_TAP_TO_DESKTOP_MODE(1999),
+        @UiEvent(doc = "Tap on the split screen option under app handle menu")
+        DESKTOP_WINDOW_APP_HANDLE_MENU_TAP_TO_SPLIT_SCREEN(2000),
+        @UiEvent(doc = "Tap on the full screen option under app handle menu")
+        DESKTOP_WINDOW_APP_HANDLE_MENU_TAP_TO_FULL_SCREEN(2001),
+        @UiEvent(doc = "When user successfully drags the app handle to desktop mode")
+        DESKTOP_WINDOW_APP_HANDLE_DRAG_TO_DESKTOP_MODE(2002),
+        @UiEvent(doc = "When user successfully drags the app handle to split screen")
+        DESKTOP_WINDOW_APP_HANDLE_DRAG_TO_SPLIT_SCREEN(2003),
+        @UiEvent(doc = "When user successfully drags the app handle to full screen")
+        DESKTOP_WINDOW_APP_HANDLE_DRAG_TO_FULL_SCREEN(2004),
+        @UiEvent(doc = "Drag the window header to the top to switch to full screen mode")
+        DESKTOP_WINDOW_APP_HEADER_DRAG_TO_FULL_SCREEN(2005),
+        @UiEvent(doc = "Drag the window header to an edge to tile it to the left side")
+        DESKTOP_WINDOW_APP_HEADER_DRAG_TO_TILE_TO_LEFT(2006),
+        @UiEvent(doc = "Drag the window header to an edge to tile it to the right side")
+        DESKTOP_WINDOW_APP_HEADER_DRAG_TO_TILE_TO_RIGHT(2007);
 
         override fun getId(): Int = mId
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
index ccbc920..3e3dd74 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
@@ -130,6 +130,7 @@
 import java.util.function.Consumer
 import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.InputMethod
 import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.ResizeTrigger
+import com.android.wm.shell.desktopmode.DesktopModeUiEventLogger.DesktopUiEventEnum
 import com.android.wm.shell.desktopmode.DragToDesktopTransitionHandler.Companion.DRAG_TO_DESKTOP_FINISH_ANIM_DURATION_MS
 import com.android.wm.shell.desktopmode.EnterDesktopTaskTransitionHandler.FREEFORM_ANIMATION_DURATION
 import com.android.wm.shell.desktopmode.ExitDesktopTaskTransitionHandler.FULLSCREEN_ANIMATION_DURATION
@@ -166,6 +167,7 @@
     private val interactionJankMonitor: InteractionJankMonitor,
     @ShellMainThread private val handler: Handler,
     private val desktopModeEventLogger: DesktopModeEventLogger,
+    private val desktopModeUiEventLogger: DesktopModeUiEventLogger,
     private val desktopTilingDecorViewModel: DesktopTilingDecorViewModel,
 ) :
     RemoteCallable<DesktopTasksController>,
@@ -819,12 +821,12 @@
     fun toggleDesktopTaskSize(
         taskInfo: RunningTaskInfo,
         resizeTrigger: ResizeTrigger,
-        motionEvent: MotionEvent?,
+        inputMethod: InputMethod,
     ) {
         val currentTaskBounds = taskInfo.configuration.windowConfiguration.bounds
         desktopModeEventLogger.logTaskResizingStarted(
             resizeTrigger,
-            DesktopModeEventLogger.getInputMethodFromMotionEvent(motionEvent),
+            inputMethod,
             taskInfo,
             currentTaskBounds.width(),
             currentTaskBounds.height(),
@@ -877,7 +879,7 @@
         taskbarDesktopTaskListener?.onTaskbarCornerRoundingUpdate(doesAnyTaskRequireTaskbarRounding)
         val wct = WindowContainerTransaction().setBounds(taskInfo.token, destinationBounds)
         desktopModeEventLogger.logTaskResizingEnded(
-            resizeTrigger, DesktopModeEventLogger.getInputMethodFromMotionEvent(motionEvent),
+            resizeTrigger, inputMethod,
             taskInfo, destinationBounds.width(),
             destinationBounds.height(), displayController
         )
@@ -909,7 +911,11 @@
             return
         }
 
-        toggleDesktopTaskSize(taskInfo, ResizeTrigger.DRAG_TO_TOP_RESIZE_TRIGGER, motionEvent)
+        toggleDesktopTaskSize(
+            taskInfo,
+            ResizeTrigger.DRAG_TO_TOP_RESIZE_TRIGGER,
+            DesktopModeEventLogger.getInputMethodFromMotionEvent(motionEvent)
+        )
     }
 
     private fun getMaximizeBounds(taskInfo: RunningTaskInfo, stableBounds: Rect): Rect {
@@ -2083,6 +2089,10 @@
                 if (DesktopModeStatus.shouldMaximizeWhenDragToTopEdge(context)) {
                     dragToMaximizeDesktopTask(taskInfo, taskSurface, currentDragBounds, motionEvent)
                 } else {
+                    desktopModeUiEventLogger.log(
+                        taskInfo,
+                        DesktopUiEventEnum.DESKTOP_WINDOW_APP_HEADER_DRAG_TO_FULL_SCREEN
+                    )
                     moveToFullscreenWithAnimation(
                         taskInfo,
                         position,
@@ -2091,6 +2101,10 @@
                 }
             }
             IndicatorType.TO_SPLIT_LEFT_INDICATOR -> {
+                desktopModeUiEventLogger.log(
+                    taskInfo,
+                    DesktopUiEventEnum.DESKTOP_WINDOW_APP_HEADER_DRAG_TO_TILE_TO_LEFT
+                )
                 handleSnapResizingTaskOnDrag(
                     taskInfo,
                     SnapPosition.LEFT,
@@ -2102,6 +2116,10 @@
                 )
             }
             IndicatorType.TO_SPLIT_RIGHT_INDICATOR -> {
+                desktopModeUiEventLogger.log(
+                    taskInfo,
+                    DesktopUiEventEnum.DESKTOP_WINDOW_APP_HEADER_DRAG_TO_TILE_TO_RIGHT
+                )
                 handleSnapResizingTaskOnDrag(
                     taskInfo,
                     SnapPosition.RIGHT,
@@ -2188,16 +2206,32 @@
                 // Start a new jank interaction for the drag release to desktop window animation.
                 interactionJankMonitor.begin(taskSurface, context, handler,
                     CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_RELEASE, "to_desktop")
+                desktopModeUiEventLogger.log(
+                    taskInfo,
+                    DesktopUiEventEnum.DESKTOP_WINDOW_APP_HANDLE_DRAG_TO_DESKTOP_MODE
+                )
                 finalizeDragToDesktop(taskInfo)
             }
             IndicatorType.NO_INDICATOR,
             IndicatorType.TO_FULLSCREEN_INDICATOR -> {
+                desktopModeUiEventLogger.log(
+                    taskInfo,
+                    DesktopUiEventEnum.DESKTOP_WINDOW_APP_HANDLE_DRAG_TO_FULL_SCREEN
+                )
                 cancelDragToDesktop(taskInfo)
             }
             IndicatorType.TO_SPLIT_LEFT_INDICATOR -> {
+                desktopModeUiEventLogger.log(
+                    taskInfo,
+                    DesktopUiEventEnum.DESKTOP_WINDOW_APP_HANDLE_DRAG_TO_SPLIT_SCREEN
+                )
                 requestSplit(taskInfo, leftOrTop = true)
             }
             IndicatorType.TO_SPLIT_RIGHT_INDICATOR -> {
+                desktopModeUiEventLogger.log(
+                    taskInfo,
+                    DesktopUiEventEnum.DESKTOP_WINDOW_APP_HANDLE_DRAG_TO_SPLIT_SCREEN
+                )
                 requestSplit(taskInfo, leftOrTop = false)
             }
         }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
index f7aed44..72c1ef0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
@@ -73,6 +73,7 @@
 import com.android.wm.shell.common.pip.PipDisplayLayoutState;
 import com.android.wm.shell.common.pip.PipMenuController;
 import com.android.wm.shell.common.pip.PipUtils;
+import com.android.wm.shell.common.split.SplitScreenUtils;
 import com.android.wm.shell.protolog.ShellProtoLogGroup;
 import com.android.wm.shell.shared.TransitionUtil;
 import com.android.wm.shell.shared.pip.PipContentOverlay;
@@ -1346,6 +1347,13 @@
         return true;
     }
 
+    @Override
+    public boolean isPackageActiveInPip(@Nullable String packageName) {
+        final TaskInfo inPipTask = mPipOrganizer.getTaskInfo();
+        return packageName != null && inPipTask != null && mPipOrganizer.isInPip()
+                && packageName.equals(SplitScreenUtils.getPackageName(inPipTask.baseIntent));
+    }
+
     private void updatePipForUnhandledTransition(@NonNull TransitionInfo.Change pipChange,
             @NonNull SurfaceControl.Transaction startTransaction,
             @NonNull SurfaceControl.Transaction finishTransaction) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
index 79a9ce5..a2738227 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
@@ -312,9 +312,8 @@
 
     /** Whether a particular package is same as current pip package. */
     public boolean isPackageActiveInPip(@Nullable String packageName) {
-        return packageName != null
-                && mPipBoundsState.getLastPipComponentName() != null
-                && packageName.equals(mPipBoundsState.getLastPipComponentName().getPackageName());
+        // No-op, to be handled differently in PIP1 and PIP2
+        return false;
     }
 
     /** Add PiP-related changes to `outWCT` for the given request. */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java
index 5e6b51e7..1ba29a2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java
@@ -915,4 +915,11 @@
                 break;
         }
     }
+
+    @Override
+    public boolean isPackageActiveInPip(@Nullable String packageName) {
+        return packageName != null
+                && mPipBoundsState.getLastPipComponentName() != null
+                && packageName.equals(mPipBoundsState.getLastPipComponentName().getPackageName());
+    }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
index 6caef36..1913e93 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
@@ -584,7 +584,7 @@
                 decoration.mTaskSurface, mContext, mMainHandler,
                 Cuj.CUJ_DESKTOP_MODE_MAXIMIZE_WINDOW, source);
         mDesktopTasksController.toggleDesktopTaskSize(decoration.mTaskInfo, resizeTrigger,
-                motionEvent);
+                DesktopModeEventLogger.getInputMethodFromMotionEvent(motionEvent));
         decoration.closeHandleMenu();
         decoration.closeMaximizeMenu();
     }
@@ -644,6 +644,11 @@
         decoration.addCaptionInset(wct);
         mDesktopTasksController.moveTaskToDesktop(taskId, wct, source);
         decoration.closeHandleMenu();
+
+        if (source == DesktopModeTransitionSource.APP_HANDLE_MENU_BUTTON) {
+            mDesktopModeUiEventLogger.log(decoration.mTaskInfo,
+                    DesktopUiEventEnum.DESKTOP_WINDOW_APP_HANDLE_MENU_TAP_TO_DESKTOP_MODE);
+        }
     }
 
     private void onToFullscreen(int taskId) {
@@ -659,6 +664,8 @@
             mDesktopTasksController.moveToFullscreen(taskId,
                     DesktopModeTransitionSource.APP_HANDLE_MENU_BUTTON);
         }
+        mDesktopModeUiEventLogger.log(decoration.mTaskInfo,
+                DesktopUiEventEnum.DESKTOP_WINDOW_APP_HANDLE_MENU_TAP_TO_FULL_SCREEN);
     }
 
     private void onToSplitScreen(int taskId) {
@@ -671,6 +678,8 @@
         // we shouldn't receive input for it any longer.
         decoration.disposeStatusBarInputLayer();
         mDesktopTasksController.requestSplit(decoration.mTaskInfo, false /* leftOrTop */);
+        mDesktopModeUiEventLogger.log(decoration.mTaskInfo,
+                DesktopUiEventEnum.DESKTOP_WINDOW_APP_HANDLE_MENU_TAP_TO_SPLIT_SCREEN);
     }
 
     private void onNewWindow(int taskId) {
@@ -1566,7 +1575,7 @@
 
         final DesktopModeTouchEventListener touchEventListener =
                 new DesktopModeTouchEventListener(taskInfo, taskPositioner);
-        InputMethod inputMethod = DesktopModeEventLogger.Companion.getInputMethodFromMotionEvent(
+        InputMethod inputMethod = DesktopModeEventLogger.getInputMethodFromMotionEvent(
                 touchEventListener.mMotionEvent);
         windowDecoration.setOnMaximizeOrRestoreClickListener(() -> {
             onMaximizeOrRestore(taskInfo.taskId, "maximize_menu", ResizeTrigger.MAXIMIZE_MENU,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
index b6fa059..d57044a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
@@ -1417,7 +1417,6 @@
         mHandleMenu.show(
                 /* onToDesktopClickListener= */ () -> {
                     mOnToDesktopClickListener.accept(APP_HANDLE_MENU_BUTTON);
-                    mOnToDesktopClickListener.accept(APP_HANDLE_MENU_BUTTON);
                     return Unit.INSTANCE;
                 },
                 /* onToFullscreenClickListener= */ mOnToFullscreenClickListener,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java
index b321399..a6d503d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java
@@ -460,7 +460,7 @@
                                 || ctrlType == CTRL_TYPE_RIGHT || ctrlType == CTRL_TYPE_LEFT)
                                 ? ResizeTrigger.EDGE : ResizeTrigger.CORNER;
                         mDesktopModeEventLogger.logTaskResizingStarted(mResizeTrigger,
-                                DesktopModeEventLogger.Companion.getInputMethodFromMotionEvent(e),
+                                DesktopModeEventLogger.getInputMethodFromMotionEvent(e),
                                 mTaskInfo, mDragStartTaskBounds.width(),
                                 mDragStartTaskBounds.height(), /* displayController= */ null,
                                 /* displayLayoutSize= */ mDisplayLayoutSizeSupplier.get());
@@ -514,7 +514,7 @@
                         }
 
                         mDesktopModeEventLogger.logTaskResizingEnded(mResizeTrigger,
-                                DesktopModeEventLogger.Companion.getInputMethodFromMotionEvent(
+                                DesktopModeEventLogger.getInputMethodFromMotionEvent(
                                         mLastMotionEventOnDown), mTaskInfo, taskBounds.width(),
                                 taskBounds.height(),
                                 /* displayController= */ null,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDividerWindowManager.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDividerWindowManager.kt
index 6cdc517c..5832822 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDividerWindowManager.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDividerWindowManager.kt
@@ -18,10 +18,12 @@
 
 import android.content.Context
 import android.content.res.Configuration
+import android.graphics.Path
 import android.graphics.PixelFormat
 import android.graphics.Rect
 import android.graphics.Region
 import android.os.Binder
+import android.util.Size
 import android.view.LayoutInflater
 import android.view.MotionEvent
 import android.view.RoundedCorner
@@ -40,7 +42,6 @@
 import android.view.WindowlessWindowManager
 import com.android.wm.shell.R
 import com.android.wm.shell.common.SyncTransactionQueue
-import com.android.wm.shell.desktopmode.DesktopModeEventLogger
 import java.util.function.Supplier
 
 /**
@@ -48,7 +49,7 @@
  * when two tasks are tiled on left and right to resize them simultaneously.
  */
 class DesktopTilingDividerWindowManager(
-    private val config: Configuration,
+    config: Configuration,
     private val windowName: String,
     private val context: Context,
     private val leash: SurfaceControl,
@@ -61,7 +62,11 @@
     private lateinit var viewHost: SurfaceControlViewHost
     private var tilingDividerView: TilingDividerView? = null
     private var dividerShown = false
-    private var handleRegionWidth: Int = -1
+    private var handleRegionSize: Size =
+        Size(
+            context.resources.getDimensionPixelSize(R.dimen.split_divider_handle_region_width),
+            context.resources.getDimensionPixelSize(R.dimen.split_divider_handle_region_height),
+        )
     private var setTouchRegion = true
     private val maxRoundedCornerRadius = getMaxRoundedCornerRadius()
 
@@ -74,9 +79,62 @@
         rect.set(dividerBounds)
     }
 
-    /** Sets the touch region for the SurfaceControlViewHost. */
-    fun setTouchRegion(region: Rect) {
-        setTouchRegion(viewHost.windowToken.asBinder(), Region(region))
+    /**
+     * Sets the touch region for the SurfaceControlViewHost.
+     *
+     * The region includes the area around the handle (for accessibility), the divider itself and
+     * the rounded corners (to prevent click reaching windows behind).
+     */
+    fun setTouchRegion(handle: Rect, divider: Rect, cornerRadius: Float) {
+        val path = Path()
+        path.fillType = Path.FillType.WINDING
+        // The UI starts on the top-left corner, the region will be:
+        //
+        //      cornerLeft     cornerRight
+        // c1Top        +--------+
+        //              |corners |
+        // c1Bottom     +--+  +--+
+        //                 |  |
+        //       handleLeft|  |  handleRight
+        // handleTop  +----+  +----+
+        //            |  handle    |
+        // handleBot  +----+  +----+
+        //                 |  |
+        //                 |  |
+        // c2Top        +--+  +--+
+        //              |corners |
+        // c2Bottom     +--------+
+        val cornerLeft = 0f
+        val centerX = cornerRadius + divider.width() / 2f
+        val centerY = divider.height()
+        val cornerRight = divider.width() + 2 * cornerRadius
+        val handleLeft = centerX - handle.width() / 2f
+        val handleRight = handleLeft + handle.width()
+        val dividerLeft = centerY - divider.width() / 2f
+        val dividerRight = dividerLeft + divider.width()
+
+        val c1Top = 0f
+        val c1Bottom = cornerRadius
+        val handleTop = centerY - handle.height() / 2f
+        val handleBottom = handleTop + handle.height()
+        val c2Top = divider.height() - cornerRadius
+        val c2Bottom = divider.height().toFloat()
+
+        // Top corners
+        path.addRect(cornerLeft, c1Top, cornerRight, c1Bottom, Path.Direction.CCW)
+        // Bottom corners
+        path.addRect(cornerLeft, c1Top, cornerRight, c2Bottom, Path.Direction.CCW)
+        // Handle
+        path.addRect(handleLeft, handleTop, handleRight, handleBottom, Path.Direction.CCW)
+        // Divider
+        path.addRect(dividerLeft, c2Top, dividerRight, c2Bottom, Path.Direction.CCW)
+
+        val clip = Rect(handleLeft.toInt(), c1Top.toInt(), handleRight.toInt(), c2Bottom.toInt())
+
+        val region = Region()
+        region.setPath(path, Region(clip))
+
+        setTouchRegion(viewHost.windowToken.asBinder(), region)
     }
 
     /**
@@ -96,7 +154,7 @@
         surfaceControlViewHost.setView(dividerView, lp)
         val tmpDividerBounds = Rect()
         getDividerBounds(tmpDividerBounds)
-        dividerView.setup(this, tmpDividerBounds)
+        dividerView.setup(this, tmpDividerBounds, handleRegionSize)
         t.setRelativeLayer(leash, relativeLeash, 1)
             .setPosition(
                 leash,
@@ -112,7 +170,7 @@
         viewHost = surfaceControlViewHost
         dividerView.addOnLayoutChangeListener(this)
         tilingDividerView = dividerView
-        handleRegionWidth = dividerView.handleRegionWidth
+        updateTouchRegion()
     }
 
     /** Hides the divider bar. */
@@ -176,8 +234,8 @@
     private fun getWindowManagerParams(): WindowManager.LayoutParams {
         val lp =
             WindowManager.LayoutParams(
-                dividerBounds.width() + 2 * maxRoundedCornerRadius,
-                dividerBounds.height(),
+                /* w= */ dividerBounds.width() + 2 * maxRoundedCornerRadius,
+                /* h= */ dividerBounds.height(),
                 TYPE_DOCK_DIVIDER,
                 FLAG_NOT_FOCUSABLE or
                     FLAG_NOT_TOUCH_MODAL or
@@ -216,13 +274,16 @@
     ) {
         if (!setTouchRegion) return
 
-        val startX = (dividerBounds.width() - handleRegionWidth) / 2
-        val startY = 0
-        val tempRect = Rect(startX, startY, startX + handleRegionWidth, dividerBounds.height())
-        setTouchRegion(tempRect)
+        updateTouchRegion()
         setTouchRegion = false
     }
 
+    private fun updateTouchRegion() {
+        val startX = -handleRegionSize.width / 2
+        val handle = Rect(startX, 0, startX + handleRegionSize.width, dividerBounds.height())
+        setTouchRegion(handle, dividerBounds, maxRoundedCornerRadius.toFloat())
+    }
+
     private fun setSlippery(slippery: Boolean) {
         val lp = tilingDividerView?.layoutParams as WindowManager.LayoutParams
         val isSlippery = (lp.flags and FLAG_SLIPPERY) != 0
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/TilingDividerView.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/TilingDividerView.kt
index 111e28e..b8e3b0f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/TilingDividerView.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/TilingDividerView.kt
@@ -21,8 +21,10 @@
 import android.graphics.Rect
 import android.provider.DeviceConfig
 import android.util.AttributeSet
+import android.util.Size
 import android.view.MotionEvent
 import android.view.PointerIcon
+import android.view.RoundedCorner
 import android.view.View
 import android.view.ViewConfiguration
 import android.widget.FrameLayout
@@ -42,6 +44,7 @@
     private lateinit var callback: DividerMoveCallback
     private lateinit var handle: DividerHandleView
     private lateinit var corners: DividerRoundedCorner
+    private var cornersRadius: Int = 0
     private var touchElevation = 0
 
     private var moving = false
@@ -49,8 +52,7 @@
     var handleRegionWidth: Int = 0
     private var handleRegionHeight = 0
     private var lastAcceptedPos = 0
-    @VisibleForTesting var handleStartY = 0
-    @VisibleForTesting var handleEndY = 0
+    @VisibleForTesting var handleY: IntRange = 0..0
     private var canResize = false
     private var resized = false
     /**
@@ -79,16 +81,19 @@
     ) : super(context, attrs, defStyleAttr, defStyleRes)
 
     /** Sets up essential dependencies of the divider bar. */
-    fun setup(dividerMoveCallback: DividerMoveCallback, dividerBounds: Rect) {
+    fun setup(
+        dividerMoveCallback: DividerMoveCallback,
+        dividerBounds: Rect,
+        handleRegionSize: Size,
+    ) {
         callback = dividerMoveCallback
         this.dividerBounds.set(dividerBounds)
         handle.setIsLeftRightSplit(true)
         corners.setIsLeftRightSplit(true)
-        handleRegionHeight =
-            resources.getDimensionPixelSize(R.dimen.split_divider_handle_region_width)
-
-        handleRegionWidth =
-            resources.getDimensionPixelSize(R.dimen.split_divider_handle_region_height)
+        handleRegionHeight = handleRegionSize.height
+        handleRegionWidth = handleRegionSize.width
+        cornersRadius =
+            context.display.getRoundedCorner(RoundedCorner.POSITION_TOP_LEFT)?.radius ?: 0
         initHandleYCoordinates()
         dragDetector =
             DragDetector(
@@ -241,17 +246,17 @@
         return true
     }
 
-    private fun isWithinHandleRegion(touchYPos: Int): Boolean {
-        return touchYPos in handleStartY..handleEndY
-    }
+    private fun isWithinHandleRegion(touchYPos: Int): Boolean = touchYPos in handleY
 
     private fun initHandleYCoordinates() {
-        handleStartY = (dividerBounds.height() - handleRegionHeight) / 2
-        handleEndY = handleStartY + handleRegionHeight
+        val handleStartY = (dividerBounds.height() - handleRegionHeight) / 2
+        val handleEndY = handleStartY + handleRegionHeight
+        handleY = handleStartY..handleEndY
     }
 
     companion object {
         const val TOUCH_ANIMATION_DURATION: Long = 150
         const val TOUCH_RELEASE_ANIMATION_DURATION: Long = 200
+        private val TAG = TilingDividerView::class.java.simpleName
     }
 }
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/DesktopModeFlickerScenarios.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/DesktopModeFlickerScenarios.kt
index 0cc8b0c..d9c36cc 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/DesktopModeFlickerScenarios.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/DesktopModeFlickerScenarios.kt
@@ -25,6 +25,7 @@
 import android.tools.flicker.assertors.assertions.AppLayerIsVisibleAtStart
 import android.tools.flicker.assertors.assertions.AppWindowAlignsWithOnlyOneDisplayCornerAtEnd
 import android.tools.flicker.assertors.assertions.AppWindowBecomesInvisible
+import android.tools.flicker.assertors.assertions.AppWindowBecomesPinned
 import android.tools.flicker.assertors.assertions.AppWindowBecomesTopWindow
 import android.tools.flicker.assertors.assertions.AppWindowBecomesVisible
 import android.tools.flicker.assertors.assertions.AppWindowCoversLeftHalfScreenAtEnd
@@ -465,5 +466,25 @@
                             AppWindowIsVisibleAlways(SIMPLE_APP)
                         ).associateBy({ it }, { AssertionInvocationGroup.BLOCKING }),
             )
+
+        val MINIMIZE_AUTO_PIP_APP =
+            FlickerConfigEntry(
+                scenarioId = ScenarioId("MINIMIZE_AUTO_PIP_APP"),
+                extractor =
+                ShellTransitionScenarioExtractor(
+                    transitionMatcher =
+                    object : ITransitionMatcher {
+                        override fun findAll(
+                            transitions: Collection<Transition>
+                        ): Collection<Transition> =
+                            transitions.filter { it.type == TransitionType.PIP }
+                    }
+                ),
+                assertions =
+                AssertionTemplates.COMMON_ASSERTIONS +
+                    listOf(
+                        AppWindowBecomesPinned(DESKTOP_MODE_APP),
+                    ).associateBy({ it }, { AssertionInvocationGroup.BLOCKING })
+            )
     }
 }
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/MinimizeAutoPipAppWindow.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/MinimizeAutoPipAppWindow.kt
new file mode 100644
index 0000000..b10db68
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/MinimizeAutoPipAppWindow.kt
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker
+
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.DesktopModeFlickerScenarios.Companion.MINIMIZE_AUTO_PIP_APP
+import com.android.wm.shell.scenarios.MinimizeAutoPipAppWindow
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class MinimizeAutoPipAppWindow : MinimizeAutoPipAppWindow() {
+    @ExpectedScenarios(["MINIMIZE_AUTO_PIP_APP"])
+    @Test
+    override fun minimizePipAppWindow() = super.minimizePipAppWindow()
+
+    companion object {
+        @JvmStatic
+        @FlickerConfigProvider
+        fun flickerConfigProvider(): FlickerConfig =
+            FlickerConfig().use(FlickerServiceConfig.DEFAULT).use(MINIMIZE_AUTO_PIP_APP)
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/DragAppWindowMultiWindowAndPip.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/DragAppWindowMultiWindowAndPip.kt
index c43a575..bb812ad 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/DragAppWindowMultiWindowAndPip.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/DragAppWindowMultiWindowAndPip.kt
@@ -45,9 +45,9 @@
     @Before
     fun setup() {
         Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet)
+        testApp.enterDesktopMode(wmHelper, device)
         // Set string extra to ensure the app is on PiP mode at launch
         pipApp.launchViaIntentAndWaitForPip(wmHelper, stringExtras = mapOf("enter_pip" to "true"))
-        testApp.enterDesktopMode(wmHelper, device)
         mailApp.launchViaIntent(wmHelper)
         newTasksApp.launchViaIntent(wmHelper)
         imeApp.launchViaIntent(wmHelper)
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppCornerMultiWindowAndPip.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppCornerMultiWindowAndPip.kt
index 0226eb3..41452c3 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppCornerMultiWindowAndPip.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppCornerMultiWindowAndPip.kt
@@ -63,9 +63,9 @@
         Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet)
         tapl.setEnableRotation(true)
         tapl.setExpectedRotation(rotation.value)
+        testApp.enterDesktopMode(wmHelper, device)
         // Set string extra to ensure the app is on PiP mode at launch
         pipApp.launchViaIntentAndWaitForPip(wmHelper, stringExtras = mapOf("enter_pip" to "true"))
-        testApp.enterDesktopMode(wmHelper, device)
         mailApp.launchViaIntent(wmHelper)
         newTasksApp.launchViaIntent(wmHelper)
         imeApp.launchViaIntent(wmHelper)
diff --git a/libs/WindowManager/Shell/tests/e2e/splitscreen/flicker-legacy/Android.bp b/libs/WindowManager/Shell/tests/e2e/splitscreen/flicker-legacy/Android.bp
index 176020f..6d12b00 100644
--- a/libs/WindowManager/Shell/tests/e2e/splitscreen/flicker-legacy/Android.bp
+++ b/libs/WindowManager/Shell/tests/e2e/splitscreen/flicker-legacy/Android.bp
@@ -49,6 +49,7 @@
         "wm-flicker-common-assertions",
         "launcher-helper-lib",
         "launcher-aosp-tapl",
+        "com_android_wm_shell_flags_lib",
     ],
 }
 
diff --git a/libs/WindowManager/Shell/tests/e2e/splitscreen/flicker-legacy/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByGoHome.kt b/libs/WindowManager/Shell/tests/e2e/splitscreen/flicker-legacy/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByGoHome.kt
index 6d396ea..9c71510 100644
--- a/libs/WindowManager/Shell/tests/e2e/splitscreen/flicker-legacy/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByGoHome.kt
+++ b/libs/WindowManager/Shell/tests/e2e/splitscreen/flicker-legacy/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByGoHome.kt
@@ -17,12 +17,16 @@
 package com.android.wm.shell.flicker.splitscreen
 
 import android.platform.test.annotations.Presubmit
+import android.platform.test.annotations.RequiresFlagsDisabled
+import android.platform.test.flag.junit.CheckFlagsRule
+import android.platform.test.flag.junit.DeviceFlagsValueProvider
 import android.tools.flicker.junit.FlickerParametersRunnerFactory
 import android.tools.flicker.legacy.FlickerBuilder
 import android.tools.flicker.legacy.LegacyFlickerTest
 import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.Flags
 import com.android.wm.shell.flicker.splitscreen.benchmark.DismissSplitScreenByGoHomeBenchmark
 import com.android.wm.shell.flicker.utils.ICommonAssertions
 import com.android.wm.shell.flicker.utils.appWindowBecomesInvisible
@@ -30,6 +34,7 @@
 import com.android.wm.shell.flicker.utils.splitAppLayerBoundsBecomesInvisible
 import com.android.wm.shell.flicker.utils.splitScreenDividerBecomesInvisible
 import org.junit.FixMethodOrder
+import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.MethodSorters
@@ -44,8 +49,13 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2)
 class DismissSplitScreenByGoHome(override val flicker: LegacyFlickerTest) :
     DismissSplitScreenByGoHomeBenchmark(flicker), ICommonAssertions {
+    @JvmField
+    @Rule
+    val checkFlagsRule: CheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule()
+
     override val transition: FlickerBuilder.() -> Unit
         get() = {
             defaultSetup(this)
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandlerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandlerTest.kt
index 7adc339..aecea2c 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandlerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandlerTest.kt
@@ -266,7 +266,7 @@
         verify(desktopTasksController).toggleDesktopTaskSize(
             task,
             ResizeTrigger.MAXIMIZE_MENU,
-            null
+            DesktopModeEventLogger.Companion.InputMethod.KEYBOARD
         )
     }
 
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
index a8cfef7..5fa90b78 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
@@ -220,6 +220,7 @@
   @Mock private lateinit var freeformTaskTransitionStarter: FreeformTaskTransitionStarter
   @Mock private lateinit var mockHandler: Handler
   @Mock private lateinit var desktopModeEventLogger: DesktopModeEventLogger
+  @Mock private lateinit var desktopModeUiEventLogger: DesktopModeUiEventLogger
   @Mock lateinit var persistentRepository: DesktopPersistentRepository
   @Mock lateinit var motionEvent: MotionEvent
   @Mock lateinit var repositoryInitializer: DesktopRepositoryInitializer
@@ -346,6 +347,7 @@
         mockInteractionJankMonitor,
         mockHandler,
         desktopModeEventLogger,
+        desktopModeUiEventLogger,
         desktopTilingDecorViewModel,
       )
   }
@@ -375,12 +377,12 @@
     val task1 = setUpFreeformTask()
 
     val argumentCaptor = ArgumentCaptor.forClass(Boolean::class.java)
-    controller.toggleDesktopTaskSize(task1, ResizeTrigger.MAXIMIZE_BUTTON, motionEvent)
+    controller.toggleDesktopTaskSize(task1, ResizeTrigger.MAXIMIZE_BUTTON, InputMethod.TOUCH)
 
     verify(taskbarDesktopTaskListener).onTaskbarCornerRoundingUpdate(argumentCaptor.capture())
     verify(desktopModeEventLogger, times(1)).logTaskResizingEnded(
       ResizeTrigger.MAXIMIZE_BUTTON,
-      InputMethod.UNKNOWN_INPUT_METHOD,
+      InputMethod.TOUCH,
       task1,
       STABLE_BOUNDS.width(),
       STABLE_BOUNDS.height(),
@@ -402,12 +404,12 @@
     val task1 = setUpFreeformTask(bounds = stableBounds, active = true)
 
     val argumentCaptor = ArgumentCaptor.forClass(Boolean::class.java)
-    controller.toggleDesktopTaskSize(task1, ResizeTrigger.MAXIMIZE_BUTTON, motionEvent)
+    controller.toggleDesktopTaskSize(task1, ResizeTrigger.MAXIMIZE_BUTTON, InputMethod.TOUCH)
 
     verify(taskbarDesktopTaskListener).onTaskbarCornerRoundingUpdate(argumentCaptor.capture())
     verify(desktopModeEventLogger, times(1)).logTaskResizingEnded(
       ResizeTrigger.MAXIMIZE_BUTTON,
-      InputMethod.UNKNOWN_INPUT_METHOD,
+      InputMethod.TOUCH,
       task1,
       0,
       0,
@@ -3357,14 +3359,14 @@
     val bounds = Rect(0, 0, 100, 100)
     val task = setUpFreeformTask(DEFAULT_DISPLAY, bounds)
 
-    controller.toggleDesktopTaskSize(task, ResizeTrigger.MAXIMIZE_BUTTON, motionEvent)
+    controller.toggleDesktopTaskSize(task, ResizeTrigger.MAXIMIZE_BUTTON, InputMethod.TOUCH)
 
     // Assert bounds set to stable bounds
     val wct = getLatestToggleResizeDesktopTaskWct()
     assertThat(findBoundsChange(wct, task)).isEqualTo(STABLE_BOUNDS)
     verify(desktopModeEventLogger, times(1)).logTaskResizingEnded(
       ResizeTrigger.MAXIMIZE_BUTTON,
-      InputMethod.UNKNOWN_INPUT_METHOD,
+      InputMethod.TOUCH,
       task,
       STABLE_BOUNDS.width(),
       STABLE_BOUNDS.height(),
@@ -3582,14 +3584,14 @@
     // Bounds should be 1000 x 500, vertically centered in the 1000 x 1000 stable bounds
     val expectedBounds = Rect(STABLE_BOUNDS.left, 250, STABLE_BOUNDS.right, 750)
 
-    controller.toggleDesktopTaskSize(task, ResizeTrigger.MAXIMIZE_BUTTON, motionEvent)
+    controller.toggleDesktopTaskSize(task, ResizeTrigger.MAXIMIZE_BUTTON, InputMethod.TOUCH)
 
     // Assert bounds set to stable bounds
     val wct = getLatestToggleResizeDesktopTaskWct()
     assertThat(findBoundsChange(wct, task)).isEqualTo(expectedBounds)
     verify(desktopModeEventLogger, times(1)).logTaskResizingEnded(
       ResizeTrigger.MAXIMIZE_BUTTON,
-      InputMethod.UNKNOWN_INPUT_METHOD,
+      InputMethod.TOUCH,
       task,
       expectedBounds.width(),
       expectedBounds.height(),
@@ -3602,7 +3604,7 @@
     val bounds = Rect(0, 0, 100, 100)
     val task = setUpFreeformTask(DEFAULT_DISPLAY, bounds)
 
-    controller.toggleDesktopTaskSize(task, ResizeTrigger.MAXIMIZE_BUTTON, motionEvent)
+    controller.toggleDesktopTaskSize(task, ResizeTrigger.MAXIMIZE_BUTTON, InputMethod.TOUCH)
     assertThat(taskRepository.removeBoundsBeforeMaximize(task.taskId)).isEqualTo(bounds)
     verify(desktopModeEventLogger, never()).logTaskResizingEnded(
       any(), any(), any(), any(),
@@ -3616,18 +3618,18 @@
     val task = setUpFreeformTask(DEFAULT_DISPLAY, boundsBeforeMaximize)
 
     // Maximize
-    controller.toggleDesktopTaskSize(task, ResizeTrigger.MAXIMIZE_BUTTON, motionEvent)
+    controller.toggleDesktopTaskSize(task, ResizeTrigger.MAXIMIZE_BUTTON, InputMethod.TOUCH)
     task.configuration.windowConfiguration.bounds.set(STABLE_BOUNDS)
 
     // Restore
-    controller.toggleDesktopTaskSize(task, ResizeTrigger.MAXIMIZE_BUTTON, motionEvent)
+    controller.toggleDesktopTaskSize(task, ResizeTrigger.MAXIMIZE_BUTTON, InputMethod.TOUCH)
 
     // Assert bounds set to last bounds before maximize
     val wct = getLatestToggleResizeDesktopTaskWct()
     assertThat(findBoundsChange(wct, task)).isEqualTo(boundsBeforeMaximize)
     verify(desktopModeEventLogger, times(1)).logTaskResizingEnded(
       ResizeTrigger.MAXIMIZE_BUTTON,
-      InputMethod.UNKNOWN_INPUT_METHOD,
+      InputMethod.TOUCH,
       task,
       boundsBeforeMaximize.width(),
       boundsBeforeMaximize.height(),
@@ -3643,19 +3645,19 @@
     }
 
     // Maximize
-    controller.toggleDesktopTaskSize(task, ResizeTrigger.MAXIMIZE_BUTTON, motionEvent)
+    controller.toggleDesktopTaskSize(task, ResizeTrigger.MAXIMIZE_BUTTON, InputMethod.TOUCH)
     task.configuration.windowConfiguration.bounds.set(STABLE_BOUNDS.left,
       boundsBeforeMaximize.top, STABLE_BOUNDS.right, boundsBeforeMaximize.bottom)
 
     // Restore
-    controller.toggleDesktopTaskSize(task, ResizeTrigger.MAXIMIZE_BUTTON, motionEvent)
+    controller.toggleDesktopTaskSize(task, ResizeTrigger.MAXIMIZE_BUTTON, InputMethod.TOUCH)
 
     // Assert bounds set to last bounds before maximize
     val wct = getLatestToggleResizeDesktopTaskWct()
     assertThat(findBoundsChange(wct, task)).isEqualTo(boundsBeforeMaximize)
     verify(desktopModeEventLogger, times(1)).logTaskResizingEnded(
       ResizeTrigger.MAXIMIZE_BUTTON,
-      InputMethod.UNKNOWN_INPUT_METHOD,
+      InputMethod.TOUCH,
       task,
       boundsBeforeMaximize.width(),
       boundsBeforeMaximize.height(),
@@ -3671,19 +3673,19 @@
     }
 
     // Maximize
-    controller.toggleDesktopTaskSize(task, ResizeTrigger.MAXIMIZE_BUTTON, motionEvent)
+    controller.toggleDesktopTaskSize(task, ResizeTrigger.MAXIMIZE_BUTTON, InputMethod.TOUCH)
     task.configuration.windowConfiguration.bounds.set(boundsBeforeMaximize.left,
       STABLE_BOUNDS.top, boundsBeforeMaximize.right, STABLE_BOUNDS.bottom)
 
     // Restore
-    controller.toggleDesktopTaskSize(task, ResizeTrigger.MAXIMIZE_BUTTON, motionEvent)
+    controller.toggleDesktopTaskSize(task, ResizeTrigger.MAXIMIZE_BUTTON, InputMethod.TOUCH)
 
     // Assert bounds set to last bounds before maximize
     val wct = getLatestToggleResizeDesktopTaskWct()
     assertThat(findBoundsChange(wct, task)).isEqualTo(boundsBeforeMaximize)
     verify(desktopModeEventLogger, times(1)).logTaskResizingEnded(
       ResizeTrigger.MAXIMIZE_BUTTON,
-      InputMethod.UNKNOWN_INPUT_METHOD,
+      InputMethod.TOUCH,
       task,
       boundsBeforeMaximize.width(),
       boundsBeforeMaximize.height(),
@@ -3697,17 +3699,17 @@
     val task = setUpFreeformTask(DEFAULT_DISPLAY, boundsBeforeMaximize)
 
     // Maximize
-    controller.toggleDesktopTaskSize(task, ResizeTrigger.MAXIMIZE_BUTTON, motionEvent)
+    controller.toggleDesktopTaskSize(task, ResizeTrigger.MAXIMIZE_BUTTON, InputMethod.TOUCH)
     task.configuration.windowConfiguration.bounds.set(STABLE_BOUNDS)
 
     // Restore
-    controller.toggleDesktopTaskSize(task, ResizeTrigger.MAXIMIZE_BUTTON, motionEvent)
+    controller.toggleDesktopTaskSize(task, ResizeTrigger.MAXIMIZE_BUTTON, InputMethod.TOUCH)
 
     // Assert last bounds before maximize removed after use
     assertThat(taskRepository.removeBoundsBeforeMaximize(task.taskId)).isNull()
     verify(desktopModeEventLogger, times(1)).logTaskResizingEnded(
       ResizeTrigger.MAXIMIZE_BUTTON,
-      InputMethod.UNKNOWN_INPUT_METHOD,
+      InputMethod.TOUCH,
       task,
       boundsBeforeMaximize.width(),
       boundsBeforeMaximize.height(),
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt
index 7bb8e891..b873162 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt
@@ -399,7 +399,7 @@
         verify(mockDesktopTasksController).toggleDesktopTaskSize(
             decor.mTaskInfo,
             ResizeTrigger.MAXIMIZE_MENU,
-            null
+            InputMethod.UNKNOWN_INPUT_METHOD
         )
     }
 
@@ -1033,7 +1033,11 @@
         onClickListenerCaptor.value.onClick(view)
 
         verify(mockDesktopTasksController)
-            .toggleDesktopTaskSize(decor.mTaskInfo, ResizeTrigger.MAXIMIZE_BUTTON, null)
+            .toggleDesktopTaskSize(
+                decor.mTaskInfo,
+                ResizeTrigger.MAXIMIZE_BUTTON,
+                InputMethod.UNKNOWN_INPUT_METHOD
+            )
     }
 
     @Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDividerWindowManagerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDividerWindowManagerTest.kt
index 3143946..121e0e9 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDividerWindowManagerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDividerWindowManagerTest.kt
@@ -122,6 +122,6 @@
 
     companion object {
         private val BOUNDS = Rect(1, 2, 3, 4)
-        private val CORNER_RADIUS = 28
+        private const val CORNER_RADIUS = 28
     }
 }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/TilingDividerViewTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/TilingDividerViewTest.kt
index 734815c..9a9d05a 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/TilingDividerViewTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/TilingDividerViewTest.kt
@@ -19,9 +19,12 @@
 import android.graphics.Rect
 import android.os.SystemClock
 import android.testing.AndroidTestingRunner
+import android.util.Size
+import android.view.Display
 import android.view.InputDevice
 import android.view.LayoutInflater
 import android.view.MotionEvent
+import android.view.RoundedCorner
 import android.view.View
 import androidx.test.annotation.UiThreadTest
 import androidx.test.filters.SmallTest
@@ -46,16 +49,19 @@
     private val dividerMoveCallbackMock = mock<DividerMoveCallback>()
 
     private val viewMock = mock<View>()
+    private val display = mock<Display>()
+    private val roundedCorner = mock<RoundedCorner>()
 
     @Before
     @UiThreadTest
     fun setUp() {
+        whenever(display.getRoundedCorner(any())).thenReturn(roundedCorner)
+        whenever(roundedCorner.radius).thenReturn(CORNER_RADIUS)
         tilingDividerView =
             LayoutInflater.from(mContext).inflate(R.layout.tiling_split_divider, /* root= */ null)
                 as TilingDividerView
-        tilingDividerView.setup(dividerMoveCallbackMock, BOUNDS)
-        tilingDividerView.handleStartY = 0
-        tilingDividerView.handleEndY = 1500
+        tilingDividerView.setup(dividerMoveCallbackMock, DIVIDER_BOUNDS, HANDLE_SIZE)
+        tilingDividerView.handleY = 0..1500
     }
 
     @Test
@@ -130,6 +136,8 @@
     }
 
     companion object {
-        private val BOUNDS = Rect(0, 0, 1500, 1500)
+        private val DIVIDER_BOUNDS = Rect(15, 0, 35, 1500)
+        private val HANDLE_SIZE = Size(800, 300)
+        private const val CORNER_RADIUS = 15
     }
 }
diff --git a/media/java/android/media/tv/extension/analog/IAnalogAttributeInterface.aidl b/media/java/android/media/tv/extension/analog/IAnalogAttributeInterface.aidl
new file mode 100644
index 0000000..550acba
--- /dev/null
+++ b/media/java/android/media/tv/extension/analog/IAnalogAttributeInterface.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.extension.analog;
+
+/**
+ * @hide
+ */
+interface IAnalogAttributeInterface {
+    int getVersion();
+    void setColorSystemCapability(in String[] list);
+    String[] getColorSystemCapability();
+}
diff --git a/media/java/android/media/tv/extension/clienttoken/IClientToken.aidl b/media/java/android/media/tv/extension/clienttoken/IClientToken.aidl
new file mode 100644
index 0000000..fa701b3
--- /dev/null
+++ b/media/java/android/media/tv/extension/clienttoken/IClientToken.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.extension.clienttoken;
+
+/**
+ * @hide
+ */
+interface IClientToken {
+    String generateClientToken();
+}
diff --git a/media/java/android/media/tv/extension/event/IEventDownload.aidl b/media/java/android/media/tv/extension/event/IEventDownload.aidl
new file mode 100644
index 0000000..29c7553
--- /dev/null
+++ b/media/java/android/media/tv/extension/event/IEventDownload.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.extension.event;
+
+import android.media.tv.extension.event.IEventDownloadListener;
+import android.os.Bundle;
+import android.os.IBinder;
+
+/**
+ * @hide
+ */
+interface IEventDownload {
+    // Create an event download session and return it as a Ibinder for DVB/DTMB
+    IBinder createSession(in Bundle eventDownloadParams, in IEventDownloadListener listener);
+}
diff --git a/media/java/android/media/tv/extension/event/IEventDownloadListener.aidl b/media/java/android/media/tv/extension/event/IEventDownloadListener.aidl
new file mode 100644
index 0000000..6d7d61f
--- /dev/null
+++ b/media/java/android/media/tv/extension/event/IEventDownloadListener.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.extension.event;
+
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+oneway interface IEventDownloadListener {
+    void onCompleted(in Bundle status);
+}
diff --git a/media/java/android/media/tv/extension/event/IEventDownloadSession.aidl b/media/java/android/media/tv/extension/event/IEventDownloadSession.aidl
new file mode 100644
index 0000000..fe7ee37
--- /dev/null
+++ b/media/java/android/media/tv/extension/event/IEventDownloadSession.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.extension.event;
+
+import android.net.Uri;
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+interface IEventDownloadSession {
+    // Determine to execute barker channel or silent tune flow for related service type
+    int isBarkerOrSequentialDownloadByServiceType(in Bundle eventDownloadParams);
+    // Determine whether to start barker channel or silent tune flow.
+    int isBarkerOrSequentialDownloadByServiceRecord(in Bundle eventDownloadParams);
+    // Start event download.
+    void startTuningMultiplex(in Uri channelUri);
+    // Set active window channels.
+    void setActiveWindowChannelInfo(in Uri[] activeWinChannelInfos);
+    // Cancel barker channel or silent tune flow.
+    void cancel();
+    // Release barker channel or silent tune flow.
+    void release();
+}
diff --git a/media/java/android/media/tv/extension/event/IEventMonitor.aidl b/media/java/android/media/tv/extension/event/IEventMonitor.aidl
new file mode 100644
index 0000000..f6e7bd1
--- /dev/null
+++ b/media/java/android/media/tv/extension/event/IEventMonitor.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.extension.event;
+
+import android.media.tv.extension.event.IEventMonitorListener;
+import android.net.Uri;
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+interface IEventMonitor {
+    // Get present event information.
+    Bundle getPresentEventInfo(long channelDbId);
+    // Add present event information listener.
+    void addPresentEventInfoListener(in IEventMonitorListener listener);
+    // Remove present event information listener.
+    void removePresentEventInfoListener(in IEventMonitorListener listener);
+    // Get following event information.
+    Bundle getFollowingEventInfo(long channelDbId);
+    // Add following event information listener.
+    void addFollowingEventInfoListener(in IEventMonitorListener listener);
+    // Remove following event information listener.
+    void removeFollowingEventInfoListener(in IEventMonitorListener listener);
+    // Get SDT guidance information.
+    Bundle getSdtGuidanceInfo(long channelDbId);
+    // Set Event Background channel list info.
+    void setBgmTuneChannelInfo(in Uri[] tuneChannelInfos);
+}
diff --git a/media/java/android/media/tv/extension/event/IEventMonitorListener.aidl b/media/java/android/media/tv/extension/event/IEventMonitorListener.aidl
new file mode 100644
index 0000000..a00e542
--- /dev/null
+++ b/media/java/android/media/tv/extension/event/IEventMonitorListener.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.extension.event;
+
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+oneway interface IEventMonitorListener {
+    void onInfoChanged(long channelDbId, in Bundle eventinfo);
+}
diff --git a/media/java/android/media/tv/extension/scanbsu/IScanBackgroundServiceUpdate.aidl b/media/java/android/media/tv/extension/scanbsu/IScanBackgroundServiceUpdate.aidl
new file mode 100644
index 0000000..bda60ed
--- /dev/null
+++ b/media/java/android/media/tv/extension/scanbsu/IScanBackgroundServiceUpdate.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.extension.scanbsu;
+
+import android.media.tv.extension.scanbsu.IScanBackgroundServiceUpdateListener;
+
+/**
+ * @hide
+ */
+interface IScanBackgroundServiceUpdate {
+    // Set the listener for background service update
+    // receives notifications for svl/tsl/nwl update during background service update.
+    void addBackgroundServiceUpdateListener(String clientToken,
+        in IScanBackgroundServiceUpdateListener listener);
+    // Remove the listener for background service update to stop receiving notifications
+    // for svl/tsl/nwl update during background service update.
+    void removeBackgroundServiceUpdateListener(in IScanBackgroundServiceUpdateListener listener);
+}
diff --git a/media/java/android/media/tv/extension/scanbsu/IScanBackgroundServiceUpdateListener.aidl b/media/java/android/media/tv/extension/scanbsu/IScanBackgroundServiceUpdateListener.aidl
new file mode 100644
index 0000000..d9bcbed
--- /dev/null
+++ b/media/java/android/media/tv/extension/scanbsu/IScanBackgroundServiceUpdateListener.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.extension.scanbsu;
+
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+interface IScanBackgroundServiceUpdateListener {
+    // On background service update add/delete/update svl records.
+    void onChannelListUpdate(String sessionToken, out Bundle[] updateInfos);
+    // On background service update add/delete/update nwl records.
+    void onNetworkListUpdate(String sessionToken, out Bundle[] updateInfos);
+    // On background service update add/delete/update tsl records.
+    void onTransportStreamingListUpdate(String sessionToken, out Bundle[] updateInfos);
+}
diff --git a/media/java/android/media/tv/extension/screenmode/IScreenModeSettings.aidl b/media/java/android/media/tv/extension/screenmode/IScreenModeSettings.aidl
new file mode 100644
index 0000000..57f3b4a
--- /dev/null
+++ b/media/java/android/media/tv/extension/screenmode/IScreenModeSettings.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.extension.screenmode;
+
+/**
+ * @hide
+ */
+interface IScreenModeSettings {
+    // Set screen mode information using a JSON string.
+    void setScreenModeSettings(String sessionToken, String setting);
+    // Get the overscan index which TIS session is applied.
+    int getOverScanIndex(String sessionToken);
+    // Get status that TIS session is support overscan or not.
+    boolean getSupportApplyOverScan(String sessionToken);
+}
diff --git a/media/java/android/media/tv/extension/servicedb/IChannelListTransfer.aidl b/media/java/android/media/tv/extension/servicedb/IChannelListTransfer.aidl
new file mode 100644
index 0000000..cb6aecc
--- /dev/null
+++ b/media/java/android/media/tv/extension/servicedb/IChannelListTransfer.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.extension.servicedb;
+
+import android.os.ParcelFileDescriptor;
+
+/**
+ * @hide
+ */
+interface IChannelListTransfer {
+    // Parse XML file and import Channels information.
+    void importChannelList(in ParcelFileDescriptor pfd);
+    // Get Channels information for export and create XML file.
+    void exportChannelList(in ParcelFileDescriptor pfd);
+}
diff --git a/media/java/android/media/tv/extension/servicedb/IServiceList.aidl b/media/java/android/media/tv/extension/servicedb/IServiceList.aidl
new file mode 100644
index 0000000..51daa80
--- /dev/null
+++ b/media/java/android/media/tv/extension/servicedb/IServiceList.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.extension.servicedb;
+
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+interface IServiceList {
+    // Get a list of the Service list IDs quivalent to COLUMN_CHANNEL_LIST_ID
+    // in the Channels table of TvProvider.
+    String[] getServiceListIds();
+    // Get the information associated with the Service list.
+    Bundle getServiceListInfo(String serviceListId, in String[] keys);
+}
diff --git a/media/java/android/media/tv/extension/servicedb/IServiceListEdit.aidl b/media/java/android/media/tv/extension/servicedb/IServiceListEdit.aidl
new file mode 100644
index 0000000..1b1577f
--- /dev/null
+++ b/media/java/android/media/tv/extension/servicedb/IServiceListEdit.aidl
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.extension.servicedb;
+
+import android.media.tv.extension.servicedb.IServiceListEditListener;
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+interface IServiceListEdit {
+    // Open in edit mode. Must call close() after edit is done.
+    int open(IServiceListEditListener listener);
+    // Method to close in edit mode.
+    int close();
+    // Method to commit changes made to service database.
+    int commit();
+    // Method to commit and close the changes.
+    int userEditCommit();
+
+    // Get a service/transportStream/Network/Satellite record information specified by
+    // serviceInfoId and keys from tvdb.
+    Bundle getServiceInfoFromDatabase(String serviceInfoId, in String[] keys);
+    // Get a list of all service records' information specified by serviceListId and keys from tvdb.
+    Bundle getServiceInfoListFromDatabase(String serviceListId, in String[] keys);
+    // Get a list of all service info IDs in the service list of serviceListId from tvdb.
+    String[] getServiceInfoIdsFromDatabase(String inServiceListId);
+    // Update a service information by the contents of serviceInfo;
+    int updateServiceInfoFromDatabase(in Bundle updateServiceInfo);
+    // Update all service information by the contents of serviceInfoList.
+    int updateServiceInfoByListFromDatabase(in Bundle[] updateServiceInfoList);
+    // Remove a service information of the serviceInfoId from the service list.
+    int removeServiceInfoFromDatabase(String serviceInfoId);
+    // Remove all service information of the serviceInfoId from the service list.
+    int removeServiceInfoByListFromDatabase(in String[] serviceInfoIdList);
+    // Get a list of the Service list IDs which is equivalent to COLUMN_CHANNEL_LIST_ID
+    // in Channels table from tv db.
+    String[] getServiceListChannelIds();
+    // Get the information associated with the Service list Channel id.
+    Bundle getServiceListInfoByChannelId(String serviceListChannelId, in String[] keys);
+
+    // Get a list of transportStream records' information specified by serviceListId and keys.
+    Bundle getTransportStreamInfoList(String serviceListId, in String[] keys);
+    // Get a list of transportStream records' information specified by serviceListId and keys
+    // from work db.
+    Bundle getTransportStreamInfoListForce(String serviceListId, in String[] keys);
+
+    // Get a list of network records' information specified by serviceListId and keys.
+    Bundle getNetworkInfoList(String serviceListId, in String[] keys);
+    // Get a list of satellite records' information specified by serviceListId and keys.
+    Bundle getSatelliteInfoList(String serviceListId, in String[] keys);
+
+    // Decompress whole bundle value of single service/transportStream/Network/Satellite record.
+    // RecordInfoBundle:a single record got from database by getServiceInfoFromDatabase()
+    String toRecordInfoByType(in Bundle recordInfoBundle, String recordType);
+    // Set channels(tv.db) modified result to middleware database(SVL/TSL/NWL/SATL).
+    int putRecordIdList(String serviceListId, in Bundle recordIdListBundle, int optType);
+
+    // Add predefined ServiceListInfo of Hotbird 13E in scan two satellite scene EU region
+    // following by commit().
+    String addPredefinedServiceListInfo(int broadcastType, String serviceListType,
+        String serviceListPrefix, String countryCode, int operatorId);
+    // Add predefined channels of Hotbird 13E in scan two satellite scene EU region.
+    int addPredefinedChannelList(String serviceListId, in Bundle[] predefinedListBundle);
+    // Add predefined satellite info of Hotbird 13E in scan two satellite scene EU region.
+    int addPredefinedSatInfo(String serviceListId, in Bundle predefinedSatInfoBundle);
+}
diff --git a/media/java/android/media/tv/extension/servicedb/IServiceListEditListener.aidl b/media/java/android/media/tv/extension/servicedb/IServiceListEditListener.aidl
new file mode 100644
index 0000000..e227eda
--- /dev/null
+++ b/media/java/android/media/tv/extension/servicedb/IServiceListEditListener.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.extension.servicedb;
+
+/**
+ * @hide
+ */
+oneway interface IServiceListEditListener {
+    void onCompleted(int requestId, int result);
+}
diff --git a/media/java/android/media/tv/extension/servicedb/IServiceListExportListener.aidl b/media/java/android/media/tv/extension/servicedb/IServiceListExportListener.aidl
new file mode 100644
index 0000000..c57e8f9
--- /dev/null
+++ b/media/java/android/media/tv/extension/servicedb/IServiceListExportListener.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.extension.servicedb;
+
+/**
+ * @hide
+ */
+oneway interface IServiceListExportListener {
+    void onExported(int exportResult);
+}
diff --git a/media/java/android/media/tv/extension/servicedb/IServiceListExportSession.aidl b/media/java/android/media/tv/extension/servicedb/IServiceListExportSession.aidl
new file mode 100644
index 0000000..fcde581
--- /dev/null
+++ b/media/java/android/media/tv/extension/servicedb/IServiceListExportSession.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.extension.servicedb;
+
+import android.os.Bundle;
+import android.os.ParcelFileDescriptor;
+
+/**
+ * @hide
+ */
+interface IServiceListExportSession {
+    // Start export service list with reserved parameters.
+    int exportServiceList(in ParcelFileDescriptor pfd, in Bundle exportParams);
+    // Release export resources.
+    int release();
+}
diff --git a/media/java/android/media/tv/extension/servicedb/IServiceListImportListener.aidl b/media/java/android/media/tv/extension/servicedb/IServiceListImportListener.aidl
new file mode 100644
index 0000000..abd8320
--- /dev/null
+++ b/media/java/android/media/tv/extension/servicedb/IServiceListImportListener.aidl
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.extension.servicedb;
+
+/**
+ * @hide
+ */
+interface IServiceListImportListener {
+    void onImported(int importResult);
+    void onPreloaded(int preloadResult);
+}
\ No newline at end of file
diff --git a/media/java/android/media/tv/extension/servicedb/IServiceListImportSession.aidl b/media/java/android/media/tv/extension/servicedb/IServiceListImportSession.aidl
new file mode 100644
index 0000000..1f1ae01
--- /dev/null
+++ b/media/java/android/media/tv/extension/servicedb/IServiceListImportSession.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.extension.servicedb;
+
+import android.os.Bundle;
+import android.os.ParcelFileDescriptor;
+
+/**
+ * @hide
+ */
+interface IServiceListImportSession {
+    // Start import service list. Should call after preload and before release.
+    int importServiceList(in ParcelFileDescriptor pfd, in Bundle importParams);
+    // Preparing for import.
+    int preload(in ParcelFileDescriptor pfd);
+    // Release import resources.
+    int release();
+}
diff --git a/media/java/android/media/tv/extension/servicedb/IServiceListSetChannelListListener.aidl b/media/java/android/media/tv/extension/servicedb/IServiceListSetChannelListListener.aidl
new file mode 100644
index 0000000..7c9c5c8
--- /dev/null
+++ b/media/java/android/media/tv/extension/servicedb/IServiceListSetChannelListListener.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.extension.servicedb;
+
+/**
+ * @hide
+ */
+oneway interface IServiceListSetChannelListListener {
+    void onCompleted(int setChannelListResult);
+}
diff --git a/media/java/android/media/tv/extension/servicedb/IServiceListSetChannelListSession.aidl b/media/java/android/media/tv/extension/servicedb/IServiceListSetChannelListSession.aidl
new file mode 100644
index 0000000..b0527b3
--- /dev/null
+++ b/media/java/android/media/tv/extension/servicedb/IServiceListSetChannelListSession.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.extension.servicedb;
+
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+interface IServiceListSetChannelListSession {
+    // Set channelList with channelinfo bundles, serviceListInfo, and operation type.
+    int setChannelList(in Bundle[] channelsInfo, in Bundle ServiceListInfoBundle, int optType);
+    // Release set channellist resources.
+    int release();
+}
diff --git a/media/java/android/media/tv/extension/servicedb/IServiceListTransferInterface.aidl b/media/java/android/media/tv/extension/servicedb/IServiceListTransferInterface.aidl
new file mode 100644
index 0000000..91fb157
--- /dev/null
+++ b/media/java/android/media/tv/extension/servicedb/IServiceListTransferInterface.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.extension.servicedb;
+
+import android.media.tv.extension.servicedb.IServiceListExportListener;
+import android.media.tv.extension.servicedb.IServiceListImportListener;
+import android.media.tv.extension.servicedb.IServiceListSetChannelListListener;
+import android.os.IBinder;
+
+/**
+ * @hide
+ */
+interface IServiceListTransferInterface {
+    IBinder createExportSession(in IServiceListExportListener listener);
+    IBinder createImportSession(in IServiceListImportListener listener);
+    IBinder createSetChannelListSession(in IServiceListSetChannelListListener listener);
+}
diff --git a/media/java/android/media/tv/extension/teletext/IDataServiceSignalInfo.aidl b/media/java/android/media/tv/extension/teletext/IDataServiceSignalInfo.aidl
new file mode 100644
index 0000000..a3725e4
--- /dev/null
+++ b/media/java/android/media/tv/extension/teletext/IDataServiceSignalInfo.aidl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.extension.teletext;
+
+import android.media.tv.extension.teletext.IDataServiceSignalInfoListener;
+import android.os.Bundle;
+
+
+/**
+ * @hide
+ */
+interface IDataServiceSignalInfo {
+     // Get Teletext data service signal information.
+     Bundle getDataServiceSignalInfo(String sessionToken);
+     // Add a listener that receives notifications of teletext running information.
+     void addDataServiceSignalInfoListener(String clientToken,
+        IDataServiceSignalInfoListener listener);
+     // Remove a listener that receives notifications of Teletext running information.
+     void removeDataServiceSignalInfoListener(String clientToken,
+        IDataServiceSignalInfoListener listener);
+}
diff --git a/media/java/android/media/tv/extension/teletext/IDataServiceSignalInfoListener.aidl b/media/java/android/media/tv/extension/teletext/IDataServiceSignalInfoListener.aidl
new file mode 100644
index 0000000..0e99bf5
--- /dev/null
+++ b/media/java/android/media/tv/extension/teletext/IDataServiceSignalInfoListener.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.extension.teletext;
+
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+oneway interface IDataServiceSignalInfoListener {
+    void onDataServiceSignalInfoChanged (String sessionToken, in Bundle changedSignalInfo);
+}
diff --git a/media/java/android/media/tv/extension/teletext/ITeletextPageSubCode.aidl b/media/java/android/media/tv/extension/teletext/ITeletextPageSubCode.aidl
new file mode 100644
index 0000000..c96ffc0
--- /dev/null
+++ b/media/java/android/media/tv/extension/teletext/ITeletextPageSubCode.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.extension.teletext;
+
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+interface ITeletextPageSubCode {
+    // Get Teletext page number
+    Bundle getTeletextPageNumber(String sessionToken);
+    // Set Teletext page number.
+    void setTeleltextPageNumber(String sessionToken, int pageNumber);
+    // Get Teletext sub page number.
+    Bundle getTeletextPageSubCode(String sessionToken);
+    // Set Teletext sub page number.
+    void setTeletextPageSubCode(String sessionToken, int pageSubCode);
+    // Get Teletext TopInfo.
+    Bundle getTeletextHasTopInfo(String sessionToken);
+    // Get Teletext TopBlockList.
+    Bundle getTeletextTopBlockList(String sessionToken);
+    // Get Teletext TopGroupList.
+    Bundle getTeletextTopGroupList(String sessionToken, int indexGroup);
+    // Get Teletext TopPageList.
+    Bundle getTeletextTopPageList(String sessionToken, int indexPage);
+}
diff --git a/media/java/android/media/tv/extension/tune/IChannelTunedInterface.aidl b/media/java/android/media/tv/extension/tune/IChannelTunedInterface.aidl
new file mode 100644
index 0000000..88e5084
--- /dev/null
+++ b/media/java/android/media/tv/extension/tune/IChannelTunedInterface.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.extension.tune;
+
+import android.media.tv.extension.tune.IChannelTunedListener;
+
+/*
+* @hide
+*/
+interface IChannelTunedInterface {
+    void addChannelTunedListener(in IChannelTunedListener listener);
+    void removeChannelTunedListener(in IChannelTunedListener listener);
+}
diff --git a/media/java/android/media/tv/extension/tune/IChannelTunedListener.aidl b/media/java/android/media/tv/extension/tune/IChannelTunedListener.aidl
new file mode 100644
index 0000000..4687546
--- /dev/null
+++ b/media/java/android/media/tv/extension/tune/IChannelTunedListener.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.extension.tune;
+
+import android.os.Bundle;
+
+/*
+* @hide
+*/
+oneway interface IChannelTunedListener {
+    void onChannelTuned(String sessionToken, in Bundle channelTunedInfo);
+}
diff --git a/media/java/android/media/tv/extension/tune/IMuxTune.aidl b/media/java/android/media/tv/extension/tune/IMuxTune.aidl
new file mode 100644
index 0000000..4e9dbda
--- /dev/null
+++ b/media/java/android/media/tv/extension/tune/IMuxTune.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.extension.tune;
+
+import android.media.tv.extension.tune.IMuxTuneSession;
+
+/**
+* @hide
+*/
+interface IMuxTune {
+    IMuxTuneSession createSession(int broadcastType, String clientToken);
+}
diff --git a/media/java/android/media/tv/extension/tune/IMuxTuneSession.aidl b/media/java/android/media/tv/extension/tune/IMuxTuneSession.aidl
new file mode 100644
index 0000000..5ad72b4
--- /dev/null
+++ b/media/java/android/media/tv/extension/tune/IMuxTuneSession.aidl
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.extension.tune;
+
+import android.os.Bundle;
+
+/**
+* @hide
+*/
+interface IMuxTuneSession {
+    // Start mux tune with tune params.
+    void start(int broadcastType, int frequency, int brandwith, in Bundle muxTuneParams);
+    // Stop mux tune.
+    void stop();
+    // Release muxtune resources.
+    void release();
+    // Get the session token created by TIS to identify different sessions.
+    String getSessionToken();
+}
diff --git a/nfc/api/current.txt b/nfc/api/current.txt
index 2aa73db..0ee81cb 100644
--- a/nfc/api/current.txt
+++ b/nfc/api/current.txt
@@ -233,6 +233,7 @@
     field @FlaggedApi("android.nfc.nfc_event_listener") public static final int NFC_INTERNAL_ERROR_NFC_CRASH_RESTART = 1; // 0x1
     field @FlaggedApi("android.nfc.nfc_event_listener") public static final int NFC_INTERNAL_ERROR_NFC_HARDWARE_ERROR = 2; // 0x2
     field @FlaggedApi("android.nfc.nfc_event_listener") public static final int NFC_INTERNAL_ERROR_UNKNOWN = 0; // 0x0
+    field @FlaggedApi("android.nfc.nfc_associated_role_services") public static final String PROPERTY_ALLOW_SHARED_ROLE_PRIORITY = "android.nfc.cardemulation.PROPERTY_ALLOW_SHARED_ROLE_PRIORITY";
     field @FlaggedApi("android.nfc.nfc_override_recover_routing_table") public static final int PROTOCOL_AND_TECHNOLOGY_ROUTE_DEFAULT = 3; // 0x3
     field @FlaggedApi("android.nfc.nfc_override_recover_routing_table") public static final int PROTOCOL_AND_TECHNOLOGY_ROUTE_DH = 0; // 0x0
     field @FlaggedApi("android.nfc.nfc_override_recover_routing_table") public static final int PROTOCOL_AND_TECHNOLOGY_ROUTE_ESE = 1; // 0x1
diff --git a/nfc/api/system-current.txt b/nfc/api/system-current.txt
index 9ada14b..031ed73 100644
--- a/nfc/api/system-current.txt
+++ b/nfc/api/system-current.txt
@@ -57,17 +57,18 @@
   @FlaggedApi("android.nfc.nfc_oem_extension") public final class NfcOemExtension {
     method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void clearPreference();
     method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public int forceRoutingTableCommit();
-    method @FlaggedApi("android.nfc.nfc_oem_extension") @NonNull public java.util.List<java.lang.String> getActiveNfceeList();
+    method @FlaggedApi("android.nfc.nfc_oem_extension") @NonNull public java.util.Map<java.lang.String,java.lang.Integer> getActiveNfceeList();
     method @FlaggedApi("android.nfc.nfc_oem_extension") @NonNull @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public android.nfc.RoutingStatus getRoutingStatus();
     method @FlaggedApi("android.nfc.nfc_oem_extension") @NonNull @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public java.util.List<android.nfc.NfcRoutingTableEntry> getRoutingTable();
+    method @FlaggedApi("android.nfc.nfc_oem_extension") @NonNull public android.nfc.T4tNdefNfcee getT4tNdefNfcee();
     method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean hasUserEnabledNfc();
     method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean isAutoChangeEnabled();
     method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean isTagPresent();
     method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void maybeTriggerFirmwareUpdate();
     method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void overwriteRoutingTable(int, int, int, int);
-    method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void pausePolling(int);
+    method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public int pausePolling(int);
     method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void registerCallback(@NonNull java.util.concurrent.Executor, @NonNull android.nfc.NfcOemExtension.Callback);
-    method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void resumePolling();
+    method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public int resumePolling();
     method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void setAutoChangeEnabled(boolean);
     method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public void setControllerAlwaysOnMode(int);
     method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void synchronizeScreenState();
@@ -83,6 +84,8 @@
     field public static final int HCE_ACTIVATE = 1; // 0x1
     field public static final int HCE_DATA_TRANSFERRED = 2; // 0x2
     field public static final int HCE_DEACTIVATE = 3; // 0x3
+    field public static final int POLLING_STATE_CHANGE_ALREADY_IN_REQUESTED_STATE = 2; // 0x2
+    field public static final int POLLING_STATE_CHANGE_SUCCEEDED = 1; // 0x1
     field public static final int STATUS_OK = 0; // 0x0
     field public static final int STATUS_UNKNOWN_ERROR = 1; // 0x1
   }
@@ -120,6 +123,11 @@
 
   @FlaggedApi("android.nfc.nfc_oem_extension") public abstract class NfcRoutingTableEntry {
     method public int getNfceeId();
+    method public int getType();
+    field public static final int TYPE_AID = 0; // 0x0
+    field public static final int TYPE_PROTOCOL = 1; // 0x1
+    field public static final int TYPE_SYSTEM_CODE = 3; // 0x3
+    field public static final int TYPE_TECHNOLOGY = 2; // 0x2
   }
 
   @FlaggedApi("android.nfc.nfc_oem_extension") public final class OemLogItems implements android.os.Parcelable {
@@ -179,6 +187,47 @@
     field @FlaggedApi("android.nfc.nfc_oem_extension") public static final int TECHNOLOGY_V = 3; // 0x3
   }
 
+  @FlaggedApi("android.nfc.nfc_oem_extension") public final class T4tNdefNfcee {
+    method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) @WorkerThread public int clearData();
+    method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean isOperationOngoing();
+    method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean isSupported();
+    method @Nullable @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) @WorkerThread public android.nfc.T4tNdefNfceeCcFileInfo readCcfile();
+    method @NonNull @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) @WorkerThread public byte[] readData(@IntRange(from=0, to=65535) int);
+    method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) @WorkerThread public int writeData(@IntRange(from=0, to=65535) int, @NonNull byte[]);
+    field public static final int CLEAR_DATA_FAILED_INTERNAL = 0; // 0x0
+    field public static final int CLEAR_DATA_SUCCESS = 1; // 0x1
+    field public static final int WRITE_DATA_ERROR_CONNECTION_FAILED = -6; // 0xfffffffa
+    field public static final int WRITE_DATA_ERROR_EMPTY_PAYLOAD = -7; // 0xfffffff9
+    field public static final int WRITE_DATA_ERROR_INTERNAL = -1; // 0xffffffff
+    field public static final int WRITE_DATA_ERROR_INVALID_FILE_ID = -4; // 0xfffffffc
+    field public static final int WRITE_DATA_ERROR_INVALID_LENGTH = -5; // 0xfffffffb
+    field public static final int WRITE_DATA_ERROR_NDEF_VALIDATION_FAILED = -8; // 0xfffffff8
+    field public static final int WRITE_DATA_ERROR_NFC_NOT_ON = -3; // 0xfffffffd
+    field public static final int WRITE_DATA_ERROR_RF_ACTIVATED = -2; // 0xfffffffe
+    field public static final int WRITE_DATA_SUCCESS = 0; // 0x0
+  }
+
+  @FlaggedApi("android.nfc.nfc_oem_extension") public final class T4tNdefNfceeCcFileInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method @IntRange(from=15, to=32767) public int getCcFileLength();
+    method @IntRange(from=0xffffffff, to=65535) public int getFileId();
+    method @IntRange(from=15, to=65535) public int getMaxReadLength();
+    method @IntRange(from=5, to=32767) public int getMaxSize();
+    method @IntRange(from=13, to=65535) public int getMaxWriteLength();
+    method public int getReadAccess();
+    method public int getVersion();
+    method public int getWriteAccess();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.nfc.T4tNdefNfceeCcFileInfo> CREATOR;
+    field public static final int READ_ACCESS_GRANTED_RESTRICTED = 128; // 0x80
+    field public static final int READ_ACCESS_GRANTED_UNRESTRICTED = 0; // 0x0
+    field public static final int VERSION_2_0 = 32; // 0x20
+    field public static final int VERSION_3_0 = 48; // 0x30
+    field public static final int WRITE_ACCESS_GRANTED_RESTRICTED = 128; // 0x80
+    field public static final int WRITE_ACCESS_GRANTED_UNRESTRICTED = 0; // 0x0
+    field public static final int WRITE_ACCESS_NOT_GRANTED = 255; // 0xff
+  }
+
 }
 
 package android.nfc.cardemulation {
diff --git a/nfc/java/android/nfc/INfcAdapter.aidl b/nfc/java/android/nfc/INfcAdapter.aidl
index a08b55f..5ae1be2 100644
--- a/nfc/java/android/nfc/INfcAdapter.aidl
+++ b/nfc/java/android/nfc/INfcAdapter.aidl
@@ -31,6 +31,7 @@
 import android.nfc.INfcFCardEmulation;
 import android.nfc.INfcOemExtensionCallback;
 import android.nfc.INfcUnlockHandler;
+import android.nfc.IT4tNdefNfcee;
 import android.nfc.ITagRemovedCallback;
 import android.nfc.INfcDta;
 import android.nfc.INfcWlcStateListener;
@@ -52,8 +53,8 @@
     int getState();
     boolean disable(boolean saveState, in String pkg);
     boolean enable(in String pkg);
-    void pausePolling(int timeoutInMs);
-    void resumePolling();
+    int pausePolling(int timeoutInMs);
+    int resumePolling();
 
     void setForegroundDispatch(in PendingIntent intent,
             in IntentFilter[] filters, in TechListParcel techLists);
@@ -114,7 +115,7 @@
     void clearPreference();
     void setScreenState();
     void checkFirmware();
-    List<String> fetchActiveNfceeList();
+    Map fetchActiveNfceeList();
     void triggerInitialization();
     boolean getSettingStatus();
     boolean isTagPresent();
@@ -122,4 +123,5 @@
     void indicateDataMigration(boolean inProgress, String pkg);
     int commitRouting();
     boolean isTagIntentAllowed(in String pkg, in int Userid);
+    IT4tNdefNfcee getT4tNdefNfceeInterface();
 }
diff --git a/nfc/java/android/nfc/IT4tNdefNfcee.aidl b/nfc/java/android/nfc/IT4tNdefNfcee.aidl
new file mode 100644
index 0000000..b4cda5b
--- /dev/null
+++ b/nfc/java/android/nfc/IT4tNdefNfcee.aidl
@@ -0,0 +1,33 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2024 The Android Open Source Project.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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.nfc;
+
+import android.nfc.T4tNdefNfceeCcFileInfo;
+
+/**
+ * @hide
+ */
+interface IT4tNdefNfcee {
+    int writeData(in int fileId, in byte[] data);
+    byte[] readData(in int fileId);
+    int clearNdefData();
+    boolean isNdefOperationOngoing();
+    boolean isNdefNfceeEmulationSupported();
+    T4tNdefNfceeCcFileInfo readCcfile();
+}
diff --git a/nfc/java/android/nfc/NfcAdapter.java b/nfc/java/android/nfc/NfcAdapter.java
index 056844f..89ce423 100644
--- a/nfc/java/android/nfc/NfcAdapter.java
+++ b/nfc/java/android/nfc/NfcAdapter.java
@@ -589,6 +589,7 @@
     static INfcTag sTagService;
     static INfcCardEmulation sCardEmulationService;
     static INfcFCardEmulation sNfcFCardEmulationService;
+    static IT4tNdefNfcee sNdefNfceeService;
 
     /**
      * The NfcAdapter object for each application context.
@@ -827,7 +828,13 @@
                     throw new UnsupportedOperationException();
                 }
             }
-
+            try {
+                sNdefNfceeService = sService.getT4tNdefNfceeInterface();
+            } catch (RemoteException e) {
+                sNdefNfceeService = null;
+                Log.e(TAG, "could not retrieve NDEF NFCEE service");
+                throw new UnsupportedOperationException();
+            }
             sIsInitialized = true;
         }
         NfcAdapter adapter = sNfcAdapters.get(context);
diff --git a/nfc/java/android/nfc/NfcOemExtension.java b/nfc/java/android/nfc/NfcOemExtension.java
index 9ed678f..f1198ed 100644
--- a/nfc/java/android/nfc/NfcOemExtension.java
+++ b/nfc/java/android/nfc/NfcOemExtension.java
@@ -39,6 +39,7 @@
 import android.os.Bundle;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
+import android.se.omapi.Reader;
 import android.util.Log;
 
 import java.lang.annotation.Retention;
@@ -148,6 +149,48 @@
     public @interface ControllerMode{}
 
     /**
+     * Technology Type for {@link #getActiveNfceeList()}.
+     * @hide
+     */
+    @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
+    public static final int NFCEE_TECH_NONE = 0;
+
+    /**
+     * Technology Type for {@link #getActiveNfceeList()}.
+     * @hide
+     */
+    @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
+    public static final int NFCEE_TECH_A = 1;
+
+    /**
+     * Technology Type for {@link #getActiveNfceeList()}.
+     * @hide
+     */
+    @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
+    public static final int NFCEE_TECH_B = 1 << 1;
+
+    /**
+     * Technology Type for {@link #getActiveNfceeList()}.
+     * @hide
+     */
+    @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
+    public static final int NFCEE_TECH_F = 1 << 2;
+
+    /**
+     * Nfc technology flags for {@link #getActiveNfceeList()}.
+     *
+     * @hide
+     */
+    @IntDef(flag = true, value = {
+        NFCEE_TECH_NONE,
+        NFCEE_TECH_A,
+        NFCEE_TECH_B,
+        NFCEE_TECH_F,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface NfceeTechnology {}
+
+    /**
      * Event that Host Card Emulation is activated.
      */
     public static final int HCE_ACTIVATE = 1;
@@ -173,6 +216,31 @@
     public @interface HostCardEmulationAction {}
 
     /**
+     * Status code returned when the polling state change request succeeded.
+     * @see #pausePolling()
+     * @see #resumePolling()
+     */
+    public static final int POLLING_STATE_CHANGE_SUCCEEDED = 1;
+    /**
+     * Status code returned when the polling state change request is already in
+     * required state.
+     * @see #pausePolling()
+     * @see #resumePolling()
+     */
+    public static final int POLLING_STATE_CHANGE_ALREADY_IN_REQUESTED_STATE = 2;
+    /**
+     * Possible status codes for {@link #pausePolling()} and
+     * {@link #resumePolling()}.
+     * @hide
+     */
+    @IntDef(value = {
+            POLLING_STATE_CHANGE_SUCCEEDED,
+            POLLING_STATE_CHANGE_ALREADY_IN_REQUESTED_STATE,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface PollingStateChangeStatusCode {}
+
+    /**
      * Status OK
      */
     public static final int STATUS_OK = 0;
@@ -467,6 +535,28 @@
     }
 
     /**
+     * Get an instance of {@link T4tNdefNfcee} object for performing T4T (Type-4 Tag)
+     * NDEF (NFC Data Exchange Format) NFCEE (NFC Execution Environment) operations.
+     * This can be used to write NDEF data to emulate a T4T tag in an NFCEE
+     * (NFC Execution Environment - eSE, SIM, etc). Refer to the NFC forum specification
+     * "NFCForum-TS-NCI-2.3 section 10.4" and "NFCForum-TS-T4T-1.1 section 4.2" for more details.
+     *
+     * This is a singleton object which shall be used by OEM extension module to do NDEF-NFCEE
+     * read/write operations.
+     *
+     * <p>Returns {@link T4tNdefNfcee}
+     * <p>Does not cause any RF activity and does not block.
+     * @return NFC Data Exchange Format (NDEF) NFC Execution Environment (NFCEE) object
+     * @hide
+     */
+    @SystemApi
+    @NonNull
+    @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
+    public T4tNdefNfcee getT4tNdefNfcee() {
+        return T4tNdefNfcee.getInstance();
+    }
+
+    /**
      * Register an {@link Callback} to listen for NFC oem extension callbacks
      * Multiple clients can register and callbacks will be invoked asynchronously.
      *
@@ -580,14 +670,18 @@
     /**
      * Get the Active NFCEE (NFC Execution Environment) List
      *
-     * @return List of activated secure elements on success
-     *         which can contain "eSE" and "UICC", otherwise empty list.
+     * @see Reader#getName() for the list of possible NFCEE names.
+     *
+     * @return Map< String, @NfceeTechnology Integer >
+     *         A HashMap where keys are activated secure elements and
+     *         the values are bitmap of technologies supported by each secure element
+     *         on success keys can contain "eSE" and "UICC", otherwise empty map.
      */
     @NonNull
     @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
-    public List<String> getActiveNfceeList() {
+    public Map<String, Integer> getActiveNfceeList() {
         return NfcAdapter.callServiceReturn(() ->
-            NfcAdapter.sService.fetchActiveNfceeList(), new ArrayList<String>());
+            NfcAdapter.sService.fetchActiveNfceeList(), new HashMap<String, Integer>());
     }
 
     /**
@@ -653,24 +747,32 @@
 
     /**
      * Pauses NFC tag reader mode polling for a {@code timeoutInMs} millisecond.
-     * In case of {@code timeoutInMs} is zero or invalid polling will be stopped indefinitely
-     * use {@link #resumePolling()} to resume the polling.
+     * In case of {@code timeoutInMs} is zero or invalid polling will be stopped indefinitely.
+     * Use {@link #resumePolling() to resume the polling.
      * @param timeoutInMs the pause polling duration in millisecond, ranging from 0 to 40000.
+     * @return status of the operation
+     * @throws IllegalArgumentException if timeoutInMs value is invalid
+     *         (0 < timeoutInMs < max).
      */
     @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
     @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
-    public void pausePolling(@DurationMillisLong int timeoutInMs) {
-        NfcAdapter.callService(() -> NfcAdapter.sService.pausePolling(timeoutInMs));
+    public @PollingStateChangeStatusCode int pausePolling(@DurationMillisLong int timeoutInMs) {
+        return NfcAdapter.callServiceReturn(() ->
+                NfcAdapter.sService.pausePolling(timeoutInMs),
+                POLLING_STATE_CHANGE_ALREADY_IN_REQUESTED_STATE);
     }
 
     /**
      * Resumes default NFC tag reader mode polling for the current device state if polling is
      * paused. Calling this while already in polling is a no-op.
+     * @return status of the operation
      */
     @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
     @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
-    public void resumePolling() {
-        NfcAdapter.callService(() -> NfcAdapter.sService.resumePolling());
+    public @PollingStateChangeStatusCode int resumePolling() {
+        return NfcAdapter.callServiceReturn(() ->
+                NfcAdapter.sService.resumePolling(),
+                POLLING_STATE_CHANGE_ALREADY_IN_REQUESTED_STATE);
     }
 
     /**
diff --git a/nfc/java/android/nfc/NfcRoutingTableEntry.java b/nfc/java/android/nfc/NfcRoutingTableEntry.java
index 4e91377..c2cbbed 100644
--- a/nfc/java/android/nfc/NfcRoutingTableEntry.java
+++ b/nfc/java/android/nfc/NfcRoutingTableEntry.java
@@ -17,8 +17,12 @@
 
 
 import android.annotation.FlaggedApi;
+import android.annotation.IntDef;
 import android.annotation.SystemApi;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 /**
  * Class to represent an entry of routing table. This class is abstract and extended by
  * {@link RoutingTableTechnologyEntry}, {@link RoutingTableProtocolEntry},
@@ -30,10 +34,42 @@
 @SystemApi
 public abstract class NfcRoutingTableEntry {
     private final int mNfceeId;
+    private final int mType;
+
+    /**
+     * AID routing table type.
+     */
+    public static final int TYPE_AID = 0;
+    /**
+     * Protocol routing table type.
+     */
+    public static final int TYPE_PROTOCOL = 1;
+    /**
+     * Technology routing table type.
+     */
+    public static final int TYPE_TECHNOLOGY = 2;
+    /**
+     * System Code routing table type.
+     */
+    public static final int TYPE_SYSTEM_CODE = 3;
+
+    /**
+     * Possible type of this routing table entry.
+     * @hide
+     */
+    @IntDef(prefix = "TYPE_", value = {
+            TYPE_AID,
+            TYPE_PROTOCOL,
+            TYPE_TECHNOLOGY,
+            TYPE_SYSTEM_CODE
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface RoutingTableType {}
 
     /** @hide */
-    protected NfcRoutingTableEntry(int nfceeId) {
+    protected NfcRoutingTableEntry(int nfceeId, @RoutingTableType int type) {
         mNfceeId = nfceeId;
+        mType = type;
     }
 
     /**
@@ -43,4 +79,13 @@
     public int getNfceeId() {
         return mNfceeId;
     }
+
+    /**
+     * Get the type of this entry.
+     * @return an integer defined in {@link RoutingTableType}
+     */
+    @RoutingTableType
+    public int getType() {
+        return mType;
+    }
 }
diff --git a/nfc/java/android/nfc/RoutingTableAidEntry.java b/nfc/java/android/nfc/RoutingTableAidEntry.java
index 7634fe3..bf697d6 100644
--- a/nfc/java/android/nfc/RoutingTableAidEntry.java
+++ b/nfc/java/android/nfc/RoutingTableAidEntry.java
@@ -20,7 +20,7 @@
 import android.annotation.SystemApi;
 
 /**
- * Represents an AID entry in current routing table.
+ * Represents an Application ID (AID) entry in current routing table.
  * @hide
  */
 @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
@@ -30,7 +30,7 @@
 
     /** @hide */
     public RoutingTableAidEntry(int nfceeId, String value) {
-        super(nfceeId);
+        super(nfceeId, TYPE_AID);
         this.mValue = value;
     }
 
diff --git a/nfc/java/android/nfc/RoutingTableProtocolEntry.java b/nfc/java/android/nfc/RoutingTableProtocolEntry.java
index 0c5be7d..536de4d 100644
--- a/nfc/java/android/nfc/RoutingTableProtocolEntry.java
+++ b/nfc/java/android/nfc/RoutingTableProtocolEntry.java
@@ -97,7 +97,7 @@
 
     /** @hide */
     public RoutingTableProtocolEntry(int nfceeId, @ProtocolValue int value) {
-        super(nfceeId);
+        super(nfceeId, TYPE_PROTOCOL);
         this.mValue = value;
     }
 
diff --git a/nfc/java/android/nfc/RoutingTableSystemCodeEntry.java b/nfc/java/android/nfc/RoutingTableSystemCodeEntry.java
index f87ad5f..f61892d 100644
--- a/nfc/java/android/nfc/RoutingTableSystemCodeEntry.java
+++ b/nfc/java/android/nfc/RoutingTableSystemCodeEntry.java
@@ -20,7 +20,9 @@
 import android.annotation.SystemApi;
 
 /**
- * Represents a system code entry in current routing table.
+ * Represents a system code entry in current routing table, where system codes are two-byte values
+ * used in NFC-F technology (a type of NFC communication) to identify specific
+ * device configurations.
  * @hide
  */
 @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
@@ -30,7 +32,7 @@
 
     /** @hide */
     public RoutingTableSystemCodeEntry(int nfceeId, byte[] value) {
-        super(nfceeId);
+        super(nfceeId, TYPE_SYSTEM_CODE);
         this.mValue = value;
     }
 
diff --git a/nfc/java/android/nfc/RoutingTableTechnologyEntry.java b/nfc/java/android/nfc/RoutingTableTechnologyEntry.java
index f51a529..2dbc942 100644
--- a/nfc/java/android/nfc/RoutingTableTechnologyEntry.java
+++ b/nfc/java/android/nfc/RoutingTableTechnologyEntry.java
@@ -30,22 +30,27 @@
 @SystemApi
 public class RoutingTableTechnologyEntry extends NfcRoutingTableEntry {
     /**
-     * Technology-A
+     * Technology-A.
+     * <p>Tech-A is mostly used for payment and ticketing applications. It supports various
+     * Tag platforms including Type 1, Type 2 and Type 4A tags. </p>
      */
     @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
     public static final int TECHNOLOGY_A = 0;
     /**
-     * Technology-B
+     * Technology-B which is based on ISO/IEC 14443-3 standard.
      */
     @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
     public static final int TECHNOLOGY_B = 1;
     /**
-     * Technology-F
+     * Technology-F.
+     * <p>Tech-F is a standard which supports Type 3 Tags and NFC-DEP protocol etc.</p>
      */
     @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
     public static final int TECHNOLOGY_F = 2;
     /**
-     * Technology-V
+     * Technology-V.
+     * <p>Tech-V is an NFC technology used for communication with passive tags that operate
+     * at a longer range than other NFC technologies. </p>
      */
     @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
     public static final int TECHNOLOGY_V = 3;
@@ -73,7 +78,7 @@
 
     /** @hide */
     public RoutingTableTechnologyEntry(int nfceeId, @TechnologyValue int value) {
-        super(nfceeId);
+        super(nfceeId, TYPE_TECHNOLOGY);
         this.mValue = value;
     }
 
diff --git a/nfc/java/android/nfc/T4tNdefNfcee.java b/nfc/java/android/nfc/T4tNdefNfcee.java
new file mode 100644
index 0000000..06d02c5
--- /dev/null
+++ b/nfc/java/android/nfc/T4tNdefNfcee.java
@@ -0,0 +1,258 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.nfc;
+
+import android.annotation.FlaggedApi;
+import android.annotation.IntDef;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
+import android.annotation.WorkerThread;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * This class is used for performing T4T (Type-4 Tag) NDEF (NFC Data Exchange Format)
+ * NFCEE (NFC Execution Environment) operations.
+ * This can be used to write NDEF data to emulate a T4T tag in an NFCEE
+ * (NFC Execution Environment - eSE, SIM, etc). Refer to the NFC forum specification
+ * "NFCForum-TS-NCI-2.3 section 10.4" and "NFCForum-TS-T4T-1.1 section 4.2" for more details.
+ * @hide
+ */
+@FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
+@SystemApi
+public final class T4tNdefNfcee {
+    private static final String TAG = "NdefNfcee";
+    static T4tNdefNfcee sNdefNfcee;
+
+    private T4tNdefNfcee() {
+    }
+
+    /**
+     * Helper to get an instance of this class.
+     *
+     * @return
+     * @hide
+     */
+    @NonNull
+    public static T4tNdefNfcee getInstance() {
+        if (sNdefNfcee == null) {
+            sNdefNfcee = new T4tNdefNfcee();
+        }
+        return sNdefNfcee;
+    }
+
+    /**
+     * Return flag for {@link #writeData(int, byte[])}.
+     * It indicates write data is successful.
+     */
+    public static final int WRITE_DATA_SUCCESS = 0;
+    /**
+     * Return flag for {@link #writeData(int, byte[])}.
+     * It indicates write data fail due to unknown reasons.
+     */
+    public static final int WRITE_DATA_ERROR_INTERNAL = -1;
+    /**
+     * Return flag for {@link #writeData(int, byte[])}.
+     * It indicates write data fail due to ongoing rf activity.
+     */
+    public static final int WRITE_DATA_ERROR_RF_ACTIVATED = -2;
+    /**
+     * Return flag for {@link #writeData(int, byte[])}.
+     * It indicates write data fail due to Nfc off.
+     */
+    public static final int WRITE_DATA_ERROR_NFC_NOT_ON = -3;
+    /**
+     * Return flag for {@link #writeData(int, byte[])}.
+     * It indicates write data fail due to invalid file id.
+     */
+    public static final int WRITE_DATA_ERROR_INVALID_FILE_ID = -4;
+    /**
+     * Return flag for {@link #writeData(int, byte[])}.
+     * It indicates write data fail due to invalid length.
+     */
+    public static final int WRITE_DATA_ERROR_INVALID_LENGTH = -5;
+    /**
+     * Return flag for {@link #writeData(int, byte[])}.
+     * It indicates write data fail due to core connection create failure.
+     */
+    public static final int WRITE_DATA_ERROR_CONNECTION_FAILED = -6;
+    /**
+     * Return flag for {@link #writeData(int, byte[])}.
+     * It indicates write data fail due to empty payload.
+     */
+    public static final int WRITE_DATA_ERROR_EMPTY_PAYLOAD = -7;
+    /**
+     * Returns flag for {@link #writeData(int, byte[])}.
+     * It idicates write data fail due to invalid ndef format.
+     */
+    public static final int WRITE_DATA_ERROR_NDEF_VALIDATION_FAILED = -8;
+
+    /**
+     * Possible return values for {@link #writeData(int, byte[])}.
+     *
+     * @hide
+     */
+    @IntDef(prefix = { "WRITE_DATA_" }, value = {
+        WRITE_DATA_SUCCESS,
+        WRITE_DATA_ERROR_INTERNAL,
+        WRITE_DATA_ERROR_RF_ACTIVATED,
+        WRITE_DATA_ERROR_NFC_NOT_ON,
+        WRITE_DATA_ERROR_INVALID_FILE_ID,
+        WRITE_DATA_ERROR_INVALID_LENGTH,
+        WRITE_DATA_ERROR_CONNECTION_FAILED,
+        WRITE_DATA_ERROR_EMPTY_PAYLOAD,
+        WRITE_DATA_ERROR_NDEF_VALIDATION_FAILED,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface WriteDataStatus{}
+
+    /**
+     * This API performs writes of T4T data to NFCEE.
+     *
+     * <p>This is an I/O operation and will block until complete. It must
+     * not be called from the main application thread.</p>
+     *
+     * @param fileId File id (Refer NFC Forum Type 4 Tag Specification
+     *               Section 4.2 File Identifiers and Access Conditions
+     *               for more information) to which to write.
+     * @param data   This should be valid Ndef Message format.
+     *               Refer to Nfc forum NDEF specification NDEF Message section
+     * @return status of the operation.
+     * @hide
+     */
+    @SystemApi
+    @WorkerThread
+    @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
+    public @WriteDataStatus int writeData(@IntRange(from = 0, to = 65535) int fileId,
+            @NonNull byte[] data) {
+        return NfcAdapter.callServiceReturn(() ->
+                NfcAdapter.sNdefNfceeService.writeData(fileId, data), WRITE_DATA_ERROR_INTERNAL);
+    }
+
+    /**
+     * This API performs reading of T4T content of Nfcee.
+     *
+     * <p>This is an I/O operation and will block until complete. It must
+     * not be called from the main application thread.</p>
+     *
+     * @param fileId File Id (Refer
+     *               Section 4.2 File Identifiers and Access Conditions
+     *               for more information) from which to read.
+     * @return - Returns Ndef message if success
+     *           Refer to Nfc forum NDEF specification NDEF Message section
+     * @throws IllegalStateException if read fails because the fileId is invalid.
+     * @hide
+     */
+    @SystemApi
+    @WorkerThread
+    @NonNull
+    @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
+    public byte[] readData(@IntRange(from = 0, to = 65535) int fileId) {
+        return NfcAdapter.callServiceReturn(() ->
+            NfcAdapter.sNdefNfceeService.readData(fileId), null);
+    }
+
+    /**
+     * Return flag for {@link #clearNdefData()}.
+     * It indicates clear data is successful.
+     */
+    public static final int CLEAR_DATA_SUCCESS = 1;
+     /**
+     * Return flag for {@link #clearNdefData()}.
+     * It indicates clear data failed due to internal error while processing the clear.
+     */
+    public static final int CLEAR_DATA_FAILED_INTERNAL = 0;
+
+    /**
+     * Possible return values for {@link #clearNdefData()}.
+     *
+     * @hide
+     */
+    @IntDef(prefix = { "CLEAR_DATA_" }, value = {
+        CLEAR_DATA_SUCCESS,
+        CLEAR_DATA_FAILED_INTERNAL,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ClearDataStatus{}
+
+    /**
+     * This API will set all the T4T NDEF NFCEE data to zero.
+     *
+     * <p>This is an I/O operation and will block until complete. It must
+     * not be called from the main application thread.
+     *
+     * <p>This API can be called regardless of NDEF file lock state.
+     * </p>
+     * @return status of the operation
+     *
+     * @hide
+     */
+    @SystemApi
+    @WorkerThread
+    @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
+    public @ClearDataStatus int clearData() {
+        return NfcAdapter.callServiceReturn(() ->
+            NfcAdapter.sNdefNfceeService.clearNdefData(), CLEAR_DATA_FAILED_INTERNAL);
+    }
+
+    /**
+     * Returns whether NDEF NFCEE operation is ongoing or not.
+     *
+     * @return true if NDEF NFCEE operation is ongoing, else false.
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
+    public boolean isOperationOngoing() {
+        return NfcAdapter.callServiceReturn(() ->
+            NfcAdapter.sNdefNfceeService.isNdefOperationOngoing(), false);
+    }
+
+    /**
+     * This Api is to check the status of NDEF NFCEE emulation feature is
+     * supported or not.
+     *
+     * @return true if NDEF NFCEE emulation feature is supported, else false.
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
+    public boolean isSupported() {
+        return NfcAdapter.callServiceReturn(() ->
+            NfcAdapter.sNdefNfceeService.isNdefNfceeEmulationSupported(), false);
+    }
+
+    /**
+     * This API performs reading of T4T NDEF NFCEE CC file content.
+     *
+     * Refer to the NFC forum specification "NFCForum-TS-T4T-1.1 section 4.4" for more details.
+     *
+     * @return Returns CC file content if success or null if failed to read.
+     * @hide
+     */
+    @SystemApi
+    @WorkerThread
+    @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
+    @Nullable
+    public T4tNdefNfceeCcFileInfo readCcfile() {
+        return NfcAdapter.callServiceReturn(() ->
+            NfcAdapter.sNdefNfceeService.readCcfile(), null);
+    }
+}
diff --git a/nfc/java/android/nfc/T4tNdefNfceeCcFileInfo.aidl b/nfc/java/android/nfc/T4tNdefNfceeCcFileInfo.aidl
new file mode 100644
index 0000000..f72f74e
--- /dev/null
+++ b/nfc/java/android/nfc/T4tNdefNfceeCcFileInfo.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.nfc;
+
+parcelable T4tNdefNfceeCcFileInfo;
+
diff --git a/nfc/java/android/nfc/T4tNdefNfceeCcFileInfo.java b/nfc/java/android/nfc/T4tNdefNfceeCcFileInfo.java
new file mode 100644
index 0000000..5fca052
--- /dev/null
+++ b/nfc/java/android/nfc/T4tNdefNfceeCcFileInfo.java
@@ -0,0 +1,293 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.nfc;
+
+import android.annotation.FlaggedApi;
+import android.annotation.IntDef;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * This class is used to represence T4T (Type-4 Tag) NDEF (NFC Data Exchange Format)
+ * NFCEE (NFC Execution Environment) CC (Capability Container) File data.
+ * The CC file stores metadata about the T4T tag being emulated.
+ *
+ * Refer to the NFC forum specification "NFCForum-TS-T4T-1.1 section 4.4" for more details.
+ * @hide
+ */
+@FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
+@SystemApi
+public final class T4tNdefNfceeCcFileInfo implements Parcelable {
+    /**
+     * Indicates the size of this capability container (called “CC File”)<p>
+     */
+    private int mCcLength;
+    /**
+     * Indicates the mapping specification version<p>
+     */
+    private int mVersion;
+    /**
+     * Indicates the max data size by a single ReadBinary<p>
+     */
+    private int mMaxReadLength;
+    /**
+     * Indicates the max data size by a single UpdateBinary<p>
+     */
+    private int mMaxWriteLength;
+    /**
+     * Indicates the NDEF File Identifier<p>
+     */
+    private int mFileId;
+    /**
+     * Indicates the maximum Max NDEF file size<p>
+     */
+    private int mMaxSize;
+    /**
+     * Indicates the read access condition<p>
+     */
+    private int mReadAccess;
+    /**
+     * Indicates the write access condition<p>
+     */
+    private int mWriteAccess;
+
+    /**
+     * Constructor to be used by NFC service and internal classes.
+     * @hide
+     */
+    public T4tNdefNfceeCcFileInfo(int cclen, int version, int maxLe, int maxLc,
+                      int ndefFileId, int ndefMaxSize,
+                      int ndefReadAccess, int ndefWriteAccess) {
+        mCcLength = cclen;
+        mVersion = version;
+        mMaxWriteLength = maxLc;
+        mMaxReadLength = maxLe;
+        mFileId = ndefFileId;
+        mMaxSize = ndefMaxSize;
+        mReadAccess = ndefReadAccess;
+        mWriteAccess = ndefWriteAccess;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+
+        dest.writeInt(mCcLength);
+        dest.writeInt(mVersion);
+        dest.writeInt(mMaxWriteLength);
+        dest.writeInt(mMaxReadLength);
+        dest.writeInt(mFileId);
+        dest.writeInt(mMaxSize);
+        dest.writeInt(mReadAccess);
+        dest.writeInt(mWriteAccess);
+    }
+
+    /**
+     * Indicates the size of this capability container (called “CC File”).
+     *
+     * @return length of the CC file.
+     */
+    @IntRange(from = 0xf, to = 0x7fff)
+    public int getCcFileLength() {
+        return mCcLength;
+    }
+
+    /**
+     * T4T tag mapping version 2.0.
+     * Refer to the NFC forum specification "NFCForum-TS-T4T-1.1 section 4.4" for more details.
+     */
+    public static final int VERSION_2_0 = 0x20;
+    /**
+     * T4T tag mapping version 2.0.
+     * Refer to the NFC forum specification "NFCForum-TS-T4T-1.1 section 4.4" for more details.
+     */
+    public static final int VERSION_3_0 = 0x30;
+
+    /**
+     * Possible return values for {@link #getVersion()}.
+     * @hide
+     */
+    @IntDef(prefix = { "VERSION_" }, value = {
+            VERSION_2_0,
+            VERSION_3_0,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Version{}
+
+    /**
+     * Indicates the mapping version of the T4T tag supported.
+     *
+     * Refer to the NFC forum specification "NFCForum-TS-T4T-1.1 section 4.5" for more details.
+     *
+     * @return version of the specification
+     */
+    @Version
+    public int getVersion() {
+        return mVersion;
+    }
+
+    /**
+     * Indicates the max data size that can be read by a single invocation of
+     * {@link T4tNdefNfcee#readData(int)}.
+     *
+     * Refer to the NFC forum specification "NFCForum-TS-T4T-1.1 section 4.4" MLe.
+     * @return max size of read (in bytes).
+     */
+    @IntRange(from = 0xf, to = 0xffff)
+    public int getMaxReadLength() {
+        return mMaxReadLength;
+    }
+
+    /**
+     * Indicates the max data size that can be written by a single invocation of
+     * {@link T4tNdefNfcee#writeData(int, byte[])}
+     *
+     * Refer to the NFC forum specification "NFCForum-TS-T4T-1.1 section 4.4" MLc.
+     * @return max size of write (in bytes).
+     */
+    @IntRange(from = 0xd, to = 0xffff)
+    public int getMaxWriteLength() {
+        return mMaxWriteLength;
+    }
+
+    /**
+     * Indicates the NDEF File Identifier. This is the identifier used in the last invocation of
+     * {@link T4tNdefNfcee#writeData(int, byte[])}
+     *
+     * @return FileId of the data stored or -1 if no data is present.
+     */
+    @IntRange(from = -1, to = 65535)
+    public int getFileId() {
+        return mFileId;
+    }
+
+    /**
+     * Indicates the maximum size of T4T NDEF data that can be written to the NFCEE.
+     *
+     * @return max size of the contents.
+     */
+    @IntRange(from = 0x5, to = 0x7fff)
+    public int getMaxSize() {
+        return mMaxSize;
+    }
+
+    /**
+     * T4T tag read access granted without any security.
+     * Refer to the NFC forum specification "NFCForum-TS-T4T-1.1 section 4.2" for more details.
+     */
+    public static final int READ_ACCESS_GRANTED_UNRESTRICTED = 0x0;
+    /**
+     * T4T tag read access granted with limited proprietary access only.
+     * Refer to the NFC forum specification "NFCForum-TS-T4T-1.1 section 4.2" for more details.
+     */
+    public static final int READ_ACCESS_GRANTED_RESTRICTED = 0x80;
+
+    /**
+     * Possible return values for {@link #getVersion()}.
+     * @hide
+     */
+    @IntDef(prefix = { "READ_ACCESS_GRANTED_" }, value = {
+            READ_ACCESS_GRANTED_RESTRICTED,
+            READ_ACCESS_GRANTED_UNRESTRICTED,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ReadAccess {}
+
+    /**
+     * Indicates the read access condition.
+     * Refer to the NFC forum specification "NFCForum-TS-T4T-1.1 section 4.2" for more details.
+     * @return read access restriction
+     */
+    @ReadAccess
+    public int getReadAccess() {
+        return mReadAccess;
+    }
+
+    /**
+     * T4T tag write access granted without any security.
+     * Refer to the NFC forum specification "NFCForum-TS-T4T-1.1 section 4.2" for more details.
+     */
+    public static final int WRITE_ACCESS_GRANTED_UNRESTRICTED = 0x0;
+    /**
+     * T4T tag write access granted with limited proprietary access only.
+     * Refer to the NFC forum specification "NFCForum-TS-T4T-1.1 section 4.2" for more details.
+     */
+    public static final int WRITE_ACCESS_GRANTED_RESTRICTED = 0x80;
+    /**
+     * T4T tag write access not granted.
+     * Refer to the NFC forum specification "NFCForum-TS-T4T-1.1 section 4.2" for more details.
+     */
+    public static final int WRITE_ACCESS_NOT_GRANTED = 0xFF;
+
+    /**
+     * Possible return values for {@link #getVersion()}.
+     * @hide
+     */
+    @IntDef(prefix = { "READ_ACCESS_GRANTED_" }, value = {
+            WRITE_ACCESS_GRANTED_RESTRICTED,
+            WRITE_ACCESS_GRANTED_UNRESTRICTED,
+            WRITE_ACCESS_NOT_GRANTED,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface WriteAccess {}
+
+    /**
+     * Indicates the write access condition.
+     * Refer to the NFC forum specification "NFCForum-TS-T4T-1.1 section 4.2" for more details.
+     * @return write access restriction
+     */
+    @WriteAccess
+    public int getWriteAccess() {
+        return mWriteAccess;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    public static final @NonNull Parcelable.Creator<T4tNdefNfceeCcFileInfo> CREATOR =
+            new Parcelable.Creator<>() {
+                @Override
+                public T4tNdefNfceeCcFileInfo createFromParcel(Parcel in) {
+
+                    // NdefNfceeCcFileInfo fields
+                    int cclen = in.readInt();
+                    int version = in.readInt();
+                    int maxLe = in.readInt();
+                    int maxLc = in.readInt();
+                    int ndefFileId = in.readInt();
+                    int ndefMaxSize = in.readInt();
+                    int ndefReadAccess = in.readInt();
+                    int ndefWriteAccess = in.readInt();
+
+                    return new T4tNdefNfceeCcFileInfo(cclen, version, maxLe, maxLc,
+                            ndefFileId, ndefMaxSize,
+                            ndefReadAccess, ndefWriteAccess);
+                }
+
+                @Override
+                public T4tNdefNfceeCcFileInfo[] newArray(int size) {
+                    return new T4tNdefNfceeCcFileInfo[size];
+                }
+            };
+}
diff --git a/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java b/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java
index 9ff83fe..308b5d1 100644
--- a/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java
+++ b/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java
@@ -171,6 +171,12 @@
     private boolean mShouldDefaultToObserveMode;
 
     /**
+     * Whether or not this service wants to share the same routing priority as the
+     * Wallet role owner.
+     */
+    private boolean mShareRolePriority;
+
+    /**
      * @hide
      */
     @UnsupportedAppUsage
@@ -307,6 +313,12 @@
                 mShouldDefaultToObserveMode = sa.getBoolean(
                         R.styleable.HostApduService_shouldDefaultToObserveMode,
                         false);
+                if (Flags.nfcAssociatedRoleServices()) {
+                    mShareRolePriority = sa.getBoolean(
+                            R.styleable.HostApduService_shareRolePriority,
+                            false
+                    );
+                }
                 sa.recycle();
             } else {
                 TypedArray sa = res.obtainAttributes(attrs,
@@ -337,6 +349,12 @@
                     }
                 }
                 mStaticOffHostName = mOffHostName;
+                if (Flags.nfcAssociatedRoleServices()) {
+                    mShareRolePriority = sa.getBoolean(
+                            R.styleable.OffHostApduService_shareRolePriority,
+                            false
+                    );
+                }
                 sa.recycle();
             }
 
@@ -728,6 +746,17 @@
     }
 
     /**
+     * Returns whether or not this service wants to share the Wallet role holder priority
+     * with other packages/services with the same signature.
+     *
+     * @return whether or not this service wants to share priority
+     */
+    @FlaggedApi(Flags.FLAG_NFC_ASSOCIATED_ROLE_SERVICES)
+    public boolean shareRolePriority() {
+        return mShareRolePriority;
+    }
+
+    /**
      * Returns description of service.
      * @return user readable description of service
      */
diff --git a/nfc/java/android/nfc/cardemulation/CardEmulation.java b/nfc/java/android/nfc/cardemulation/CardEmulation.java
index cb364fb..8037702 100644
--- a/nfc/java/android/nfc/cardemulation/CardEmulation.java
+++ b/nfc/java/android/nfc/cardemulation/CardEmulation.java
@@ -246,6 +246,25 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface SetServiceEnabledStatusCode {}
 
+    /**
+     * Property name used to indicate that an application wants to allow associated services
+     * to share the same AID routing priority when this application is the role holder.
+     * <p>
+     * Example:
+     * <pre>
+     *     {@code
+     *     <application>
+     *       ...
+     *       <property android:name="android.nfc.cardemulation.PROPERTY_ALLOW_SHARED_ROLE_PRIORITY"
+     *         android:value="true"/>
+     *     </application>
+     *     }
+     * </pre>
+     */
+    @FlaggedApi(Flags.FLAG_NFC_ASSOCIATED_ROLE_SERVICES)
+    public static final String PROPERTY_ALLOW_SHARED_ROLE_PRIORITY =
+            "android.nfc.cardemulation.PROPERTY_ALLOW_SHARED_ROLE_PRIORITY";
+
     static boolean sIsInitialized = false;
     static HashMap<Context, CardEmulation> sCardEmus = new HashMap<Context, CardEmulation>();
     static INfcCardEmulation sService;
diff --git a/packages/CrashRecovery/services/module/java/com/android/server/PackageWatchdog.java b/packages/CrashRecovery/services/module/java/com/android/server/PackageWatchdog.java
index 8e7b8dd5..2ba93f1 100644
--- a/packages/CrashRecovery/services/module/java/com/android/server/PackageWatchdog.java
+++ b/packages/CrashRecovery/services/module/java/com/android/server/PackageWatchdog.java
@@ -731,6 +731,25 @@
     }
 
     /**
+     * The minimum value that can be returned by any observer.
+     * It represents that no mitigations were available.
+     */
+    public static final int LEAST_PACKAGE_HEALTH_OBSERVER_IMPACT =
+            PackageHealthObserverImpact.USER_IMPACT_LEVEL_0;
+
+    /**
+     * The mitigation impact beyond which the user will start noticing the mitigations.
+     */
+    public static final int MEDIUM_USER_IMPACT_THRESHOLD =
+            PackageHealthObserverImpact.USER_IMPACT_LEVEL_20;
+
+    /**
+     * The mitigation impact beyond which the user impact is severely high.
+     */
+    public static final int HIGH_USER_IMPACT_THRESHOLD =
+            PackageHealthObserverImpact.USER_IMPACT_LEVEL_71;
+
+    /**
      * Possible severity values of the user impact of a
      * {@link PackageHealthObserver#onExecuteHealthCheckMitigation}.
      * @hide
@@ -773,6 +792,11 @@
         /**
          * Called when health check fails for the {@code versionedPackage}.
          *
+         * Note: if the returned user impact is higher than
+         * {@link #DEFAULT_HIGH_USER_IMPACT_THRESHOLD}, then
+         * {@link #onExecuteHealthCheckMitigation} would be called only in severe device conditions
+         * like boot-loop or network failure.
+         *
          * @param versionedPackage the package that is failing. This may be null if a native
          *                          service is crashing.
          * @param failureReason   the type of failure that is occurring.
@@ -780,8 +804,8 @@
          *                        (including this time).
          *
          *
-         * @return any one of {@link PackageHealthObserverImpact} to express the impact
-         * to the user on {@link #onExecuteHealthCheckMitigation}
+         * @return any value greater than {@link #LEAST_PACKAGE_HEALTH_OBSERVER_IMPACT} to express
+         * the impact of mitigation on the user in {@link #onExecuteHealthCheckMitigation}
          */
         @PackageHealthObserverImpact int onHealthCheckFailed(
                 @Nullable VersionedPackage versionedPackage,
@@ -790,9 +814,8 @@
 
         /**
          * This would be called after {@link #onHealthCheckFailed}.
-         * This is called only if current observer returned least
-         * {@link PackageHealthObserverImpact} mitigation for failed health
-         * check.
+         * This is called only if current observer returned least impact mitigation for failed
+         * health check.
          *
          * @param versionedPackage the package that is failing. This may be null if a native
          *                          service is crashing.
@@ -811,6 +834,9 @@
          *
          * @param mitigationCount the number of times mitigation has been attempted for this
          *                        boot loop (including this time).
+         *
+         * @return any value greater than {@link #LEAST_PACKAGE_HEALTH_OBSERVER_IMPACT} to express
+         * the impact of mitigation on the user in {@link #onExecuteBootLoopMitigation}
          */
         default @PackageHealthObserverImpact int onBootLoop(int mitigationCount) {
             return PackageHealthObserverImpact.USER_IMPACT_LEVEL_0;
@@ -818,11 +844,13 @@
 
         /**
          * This would be called after {@link #onBootLoop}.
-         * This is called only if current observer returned least
-         * {@link PackageHealthObserverImpact} mitigation for fixing boot loop
+         * This is called only if current observer returned least impact mitigation for fixing
+         * boot loop.
          *
          * @param mitigationCount the number of times mitigation has been attempted for this
          *                        boot loop (including this time).
+         *
+         * @return {@code true} if action was executed successfully, {@code false} otherwise
          */
         default boolean onExecuteBootLoopMitigation(int mitigationCount) {
             return false;
diff --git a/packages/SettingsLib/IntroPreference/src/com/android/settingslib/widget/IntroPreference.kt b/packages/SettingsLib/IntroPreference/src/com/android/settingslib/widget/IntroPreference.kt
index 0cdfc66..8133761 100644
--- a/packages/SettingsLib/IntroPreference/src/com/android/settingslib/widget/IntroPreference.kt
+++ b/packages/SettingsLib/IntroPreference/src/com/android/settingslib/widget/IntroPreference.kt
@@ -31,7 +31,7 @@
     attrs: AttributeSet? = null,
     defStyleAttr: Int = 0,
     defStyleRes: Int = 0
-) : Preference(context, attrs, defStyleAttr, defStyleRes) {
+) : Preference(context, attrs, defStyleAttr, defStyleRes), GroupSectionDividerMixin {
 
     private var isCollapsable: Boolean = false
     private var minLines: Int = 2
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java
index b3e48b2..fa28cf6 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java
@@ -94,6 +94,14 @@
     boolean setSubDeviceIfNeeded(CachedBluetoothDevice newDevice) {
         final long hiSyncId = newDevice.getHiSyncId();
         if (isValidHiSyncId(hiSyncId)) {
+            // The remote device supports CSIP, the other ear should be processed as a member
+            // device. Ignore hiSyncId grouping from ASHA here.
+            if (newDevice.getProfiles().stream().anyMatch(
+                    profile -> profile instanceof CsipSetCoordinatorProfile)) {
+                Log.w(TAG, "Skip ASHA grouping since this device supports CSIP");
+                return false;
+            }
+
             final CachedBluetoothDevice hearingAidDevice = getCachedDevice(hiSyncId);
             // Just add one of the hearing aids from a pair in the list that is shown in the UI.
             // Once there is another device with the same hiSyncId, to add new device as sub
@@ -161,6 +169,7 @@
             // device. Ignore hiSyncId grouping from ASHA here.
             if (cachedDevice.getProfiles().stream().anyMatch(
                     profile -> profile instanceof CsipSetCoordinatorProfile)) {
+                Log.w(TAG, "Skip ASHA grouping since this device supports CSIP");
                 continue;
             }
 
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index 927a1c59..1f291cd 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -107,6 +107,8 @@
         Settings.Secure.DISPLAY_WHITE_BALANCE_ENABLED,
         Settings.Secure.SYNC_PARENT_SOUNDS,
         Settings.Secure.CAMERA_DOUBLE_TWIST_TO_FLIP_ENABLED,
+        Settings.Secure.DOUBLE_TAP_POWER_BUTTON_GESTURE_ENABLED,
+        Settings.Secure.DOUBLE_TAP_POWER_BUTTON_GESTURE,
         Settings.Secure.CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED,
         Settings.Secure.SYSTEM_NAVIGATION_KEYS_ENABLED,
         // ACCESSIBILITY_QS_TARGETS needs to be restored after ENABLED_ACCESSIBILITY_SERVICES
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index 6d73ee2..abd5b9a 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -160,6 +160,9 @@
         VALIDATORS.put(Secure.DISPLAY_WHITE_BALANCE_ENABLED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.SYNC_PARENT_SOUNDS, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.CAMERA_DOUBLE_TWIST_TO_FLIP_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.DOUBLE_TAP_POWER_BUTTON_GESTURE_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.DOUBLE_TAP_POWER_BUTTON_GESTURE,
+                new InclusiveIntegerRangeValidator(0, 1));
         VALIDATORS.put(Secure.CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.SYSTEM_NAVIGATION_KEYS_ENABLED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.QS_TILES, TILE_LIST_VALIDATOR);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 600c36e..5ae11ba 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -2124,6 +2124,15 @@
                 SecureSettingsProto.Display.SCREEN_RESOLUTION_MODE);
         p.end(displayToken);
 
+        final long doubleTapPowerButtonToken = p.start(SecureSettingsProto.DOUBLE_TAP_POWER_BUTTON);
+        dumpSetting(s, p,
+                Settings.Secure.DOUBLE_TAP_POWER_BUTTON_GESTURE_ENABLED,
+                SecureSettingsProto.DoubleTapPowerButton.GESTURE_ENABLED);
+        dumpSetting(s, p,
+                Settings.Secure.DOUBLE_TAP_POWER_BUTTON_GESTURE,
+                SecureSettingsProto.DoubleTapPowerButton.GESTURE);
+        p.end(doubleTapPowerButtonToken);
+
         final long dozeToken = p.start(SecureSettingsProto.DOZE);
         dumpSetting(s, p,
                 Settings.Secure.DOZE_ENABLED,
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt
index eee0caf..f1cbba7 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.animation
 
 import android.app.ActivityManager
+import android.app.ActivityOptions
 import android.app.ActivityTaskManager
 import android.app.PendingIntent
 import android.app.TaskInfo
@@ -434,8 +435,7 @@
                     private fun cleanUp() {
                         cleanUpRunnable?.run()
                     }
-                },
-                initializeLazily = longLivedReturnAnimationsEnabled(),
+                }
             )
 
         // mTypeSet and mModes match back signals only, and not home. This is on purpose, because
@@ -478,8 +478,8 @@
     /** Create a new animation [Runner] controlled by [controller]. */
     @VisibleForTesting
     @JvmOverloads
-    fun createRunner(controller: Controller, initializeLazily: Boolean = false): Runner {
-        if (initializeLazily) assertLongLivedReturnAnimations()
+    fun createRunner(controller: Controller, longLived: Boolean = false): Runner {
+        if (longLived) assertLongLivedReturnAnimations()
 
         // Make sure we use the modified timings when animating a dialog into an app.
         val transitionAnimator =
@@ -489,13 +489,7 @@
                 transitionAnimator
             }
 
-        return Runner(
-            controller,
-            callback!!,
-            transitionAnimator,
-            lifecycleListener,
-            initializeLazily,
-        )
+        return Runner(controller, callback!!, transitionAnimator, lifecycleListener, longLived)
     }
 
     interface PendingIntentStarter {
@@ -699,7 +693,7 @@
             }
         val launchRemoteTransition =
             RemoteTransition(
-                OriginTransition(createRunner(controller, initializeLazily = true)),
+                OriginTransition(createRunner(controller, longLived = true)),
                 "${cookie}_launchTransition",
             )
         transitionRegister.register(launchFilter, launchRemoteTransition, includeTakeover = true)
@@ -721,7 +715,7 @@
             }
         val returnRemoteTransition =
             RemoteTransition(
-                OriginTransition(createRunner(returnController, initializeLazily = true)),
+                OriginTransition(createRunner(returnController, longLived = true)),
                 "${cookie}_returnTransition",
             )
         transitionRegister.register(returnFilter, returnRemoteTransition, includeTakeover = true)
@@ -910,14 +904,22 @@
 
     @VisibleForTesting
     inner class Runner(
-        private val controller: Controller,
+        /**
+         * This can hold a reference to a view, so it needs to be cleaned up and can't be held on to
+         * forever when ![longLived].
+         */
+        private var controller: Controller?,
         private val callback: Callback,
         /** The animator to use to animate the window transition. */
         private val transitionAnimator: TransitionAnimator,
         /** Listener for animation lifecycle events. */
         private val listener: Listener? = null,
-        /** Whether the internal [delegate] should be initialized lazily. */
-        private val initializeLazily: Boolean = false,
+        /**
+         * Whether the internal should be kept around after execution for later usage. IMPORTANT:
+         * should always be false if this [Runner] is to be used directly with [ActivityOptions]
+         * (i.e. for ephemeral launches), or the controller will leak its view.
+         */
+        private val longLived: Boolean = false,
     ) : IRemoteAnimationRunner.Stub() {
         // This is being passed across IPC boundaries and cycles (through PendingIntentRecords,
         // etc.) are possible. So we need to make sure we drop any references that might
@@ -926,7 +928,7 @@
 
         init {
             delegate = null
-            if (!initializeLazily) {
+            if (!longLived) {
                 // Ephemeral launches bundle the runner with the launch request (instead of being
                 // registered ahead of time for later use). This means that there could be a timeout
                 // between creation and invocation, so the delegate needs to exist from the
@@ -1004,16 +1006,17 @@
 
         @AnyThread
         private fun maybeSetUp() {
-            if (!initializeLazily || delegate != null) return
+            if (!longLived || delegate != null) return
             createDelegate()
         }
 
         @AnyThread
         private fun createDelegate() {
+            if (controller == null) return
             delegate =
                 AnimationDelegate(
                     mainExecutor,
-                    controller,
+                    controller!!,
                     callback,
                     DelegatingAnimationCompletionListener(listener, this::dispose),
                     transitionAnimator,
@@ -1025,7 +1028,12 @@
         fun dispose() {
             // Drop references to animation controller once we're done with the animation
             // to avoid leaking.
-            mainExecutor.execute { delegate = null }
+            mainExecutor.execute {
+                delegate = null
+                // When long lived, the same Runner can be used more than once. In this case we need
+                // to keep the controller around so we can rebuild the delegate on demand.
+                if (!longLived) controller = null
+            }
         }
     }
 
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt
index 2a2c2fc..105e8da 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt
@@ -21,7 +21,6 @@
 import androidx.compose.foundation.layout.fillMaxHeight
 import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.height
 import androidx.compose.foundation.layout.padding
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.getValue
@@ -70,10 +69,7 @@
     override val id: String = "default"
 
     @Composable
-    override fun SceneScope.Content(
-        viewModel: LockscreenContentViewModel,
-        modifier: Modifier,
-    ) {
+    override fun SceneScope.Content(viewModel: LockscreenContentViewModel, modifier: Modifier) {
         val isUdfpsVisible = viewModel.isUdfpsVisible
         val isShadeLayoutWide by viewModel.isShadeLayoutWide.collectAsStateWithLifecycle()
         val unfoldTranslations by viewModel.unfoldTranslations.collectAsStateWithLifecycle()
@@ -85,22 +81,18 @@
             with(notificationSection) { HeadsUpNotifications() }
         }
 
-        LockscreenLongPress(
-            viewModel = viewModel.touchHandling,
-            modifier = modifier,
-        ) { onSettingsMenuPlaced ->
+        LockscreenLongPress(viewModel = viewModel.touchHandling, modifier = modifier) {
+            onSettingsMenuPlaced ->
             Layout(
                 content = {
                     // Constrained to above the lock icon.
-                    Column(
-                        modifier = Modifier.fillMaxSize(),
-                    ) {
+                    Column(modifier = Modifier.fillMaxSize()) {
                         with(statusBarSection) {
                             StatusBar(
                                 modifier =
                                     Modifier.fillMaxWidth()
                                         .padding(
-                                            horizontal = { unfoldTranslations.start.roundToInt() },
+                                            horizontal = { unfoldTranslations.start.roundToInt() }
                                         )
                             )
                         }
@@ -109,13 +101,14 @@
                             with(topAreaSection) {
                                 DefaultClockLayout(
                                     smartSpacePaddingTop = viewModel::getSmartSpacePaddingTop,
+                                    isShadeLayoutWide = isShadeLayoutWide,
                                     modifier =
                                         Modifier.thenIf(isShadeLayoutWide) {
                                                 Modifier.fillMaxWidth(0.5f)
                                             }
                                             .graphicsLayer {
                                                 translationX = unfoldTranslations.start
-                                            }
+                                            },
                                 )
                             }
                             if (isShadeLayoutWide && !isBypassEnabled) {
@@ -127,7 +120,7 @@
                                         modifier =
                                             Modifier.fillMaxWidth(0.5f)
                                                 .fillMaxHeight()
-                                                .align(alignment = Alignment.TopEnd)
+                                                .align(alignment = Alignment.TopEnd),
                                     )
                                 }
                             }
@@ -142,7 +135,7 @@
                                     AodNotificationIcons(
                                         modifier =
                                             Modifier.align(alignment = Alignment.TopStart)
-                                                .padding(start = aodIconPadding),
+                                                .padding(start = aodIconPadding)
                                     )
                                     Notifications(
                                         areNotificationsVisible = areNotificationsVisible,
@@ -152,7 +145,7 @@
                                 }
                             } else {
                                 AodNotificationIcons(
-                                    modifier = Modifier.padding(start = aodIconPadding),
+                                    modifier = Modifier.padding(start = aodIconPadding)
                                 )
                             }
                         }
@@ -205,11 +198,7 @@
                 val endShortcutMeasurable = measurables[4]
                 val settingsMenuMeasurable = measurables[5]
 
-                val noMinConstraints =
-                    constraints.copy(
-                        minWidth = 0,
-                        minHeight = 0,
-                    )
+                val noMinConstraints = constraints.copy(minWidth = 0, minHeight = 0)
                 val lockIconPlaceable = lockIconMeasurable.measure(noMinConstraints)
                 val lockIconBounds =
                     IntRect(
@@ -235,14 +224,8 @@
                 val settingsMenuPlaceable = settingsMenuMeasurable.measure(noMinConstraints)
 
                 layout(constraints.maxWidth, constraints.maxHeight) {
-                    aboveLockIconPlaceable.place(
-                        x = 0,
-                        y = 0,
-                    )
-                    lockIconPlaceable.place(
-                        x = lockIconBounds.left,
-                        y = lockIconBounds.top,
-                    )
+                    aboveLockIconPlaceable.place(x = 0, y = 0)
+                    lockIconPlaceable.place(x = lockIconBounds.left, y = lockIconBounds.top)
                     belowLockIconPlaceable.place(
                         x = 0,
                         y = constraints.maxHeight - belowLockIconPlaceable.height,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/MediaCarouselSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/MediaCarouselSection.kt
index 3ca2b9c..4a9f44b 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/MediaCarouselSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/MediaCarouselSection.kt
@@ -17,9 +17,11 @@
 package com.android.systemui.keyguard.ui.composable.section
 
 import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.getValue
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.dimensionResource
 import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import com.android.compose.animation.scene.SceneScope
 import com.android.systemui.keyguard.ui.viewmodel.KeyguardMediaViewModel
@@ -27,6 +29,7 @@
 import com.android.systemui.media.controls.ui.controller.MediaCarouselController
 import com.android.systemui.media.controls.ui.view.MediaHost
 import com.android.systemui.media.dagger.MediaModule
+import com.android.systemui.res.R
 import javax.inject.Inject
 import javax.inject.Named
 
@@ -39,13 +42,22 @@
 ) {
 
     @Composable
-    fun SceneScope.KeyguardMediaCarousel() {
+    fun SceneScope.KeyguardMediaCarousel(
+        isShadeLayoutWide: Boolean,
+        modifier: Modifier = Modifier,
+    ) {
         val isMediaVisible by keyguardMediaViewModel.isMediaVisible.collectAsStateWithLifecycle()
-
+        val horizontalPadding =
+            if (isShadeLayoutWide) {
+                dimensionResource(id = R.dimen.notification_side_paddings)
+            } else {
+                dimensionResource(id = R.dimen.notification_side_paddings) +
+                    dimensionResource(id = R.dimen.notification_panel_margin_horizontal)
+            }
         MediaCarousel(
             isVisible = isMediaVisible,
             mediaHost = mediaHost,
-            modifier = Modifier.fillMaxWidth(),
+            modifier = modifier.fillMaxWidth().padding(horizontal = horizontalPadding),
             carouselController = mediaCarouselController,
         )
     }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt
index afa92f2..db33e7c 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt
@@ -63,6 +63,7 @@
     @Composable
     fun SceneScope.DefaultClockLayout(
         smartSpacePaddingTop: (Resources) -> Int,
+        isShadeLayoutWide: Boolean,
         modifier: Modifier = Modifier,
     ) {
         val currentClockLayout by clockViewModel.currentClockLayout.collectAsStateWithLifecycle()
@@ -128,7 +129,7 @@
                     )
                 }
             }
-            with(mediaCarouselSection) { KeyguardMediaCarousel() }
+            with(mediaCarouselSection) { KeyguardMediaCarousel(isShadeLayoutWide) }
         }
     }
 
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt
index e725ce5..58336c2 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt
@@ -79,8 +79,8 @@
         val MediaLandscapeTopOffset = ValueKey("MediaLandscapeTopOffset")
 
         object MediaOffset {
-            // Brightness + padding
-            val InQS = 92.dp
+            // Brightness
+            val InQS = 60.dp
             val Default = 0.dp
 
             @Composable
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
index 0e7165c..52adaf2 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
@@ -74,6 +74,7 @@
 import com.android.compose.animation.scene.animateSceneDpAsState
 import com.android.compose.animation.scene.animateSceneFloatAsState
 import com.android.compose.animation.scene.content.state.TransitionState
+import com.android.compose.modifiers.padding
 import com.android.compose.modifiers.thenIf
 import com.android.compose.windowsizeclass.LocalWindowSizeClass
 import com.android.systemui.battery.BatteryMeterViewController
@@ -379,7 +380,11 @@
                             mediaHost = mediaHost,
                             modifier =
                                 Modifier.fillMaxWidth()
-                                    .layoutId(QSMediaMeasurePolicy.LayoutId.Media),
+                                    .layoutId(QSMediaMeasurePolicy.LayoutId.Media)
+                                    .padding(
+                                        horizontal =
+                                            dimensionResource(id = R.dimen.qs_horizontal_margin)
+                                    ),
                             carouselController = mediaCarouselController,
                         )
                     }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt
index ae5dd8a..5fb9416 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt
@@ -19,12 +19,17 @@
 import androidx.compose.foundation.layout.Spacer
 import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.derivedStateOf
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.remember
 import androidx.compose.ui.Modifier
 import com.android.compose.animation.scene.SceneScope
 import com.android.compose.animation.scene.UserAction
 import com.android.compose.animation.scene.UserActionResult
 import com.android.compose.animation.scene.animateContentDpAsState
 import com.android.compose.animation.scene.animateContentFloatAsState
+import com.android.compose.animation.scene.content.state.TransitionState
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.lifecycle.ExclusiveActivatable
 import com.android.systemui.lifecycle.rememberViewModel
@@ -63,9 +68,25 @@
     }
 
     @Composable
-    override fun SceneScope.Content(
-        modifier: Modifier,
-    ) {
+    override fun SceneScope.Content(modifier: Modifier) {
+
+        val isIdle by remember {
+            derivedStateOf { layoutState.transitionState is TransitionState.Idle }
+        }
+
+        LaunchedEffect(isIdle) {
+            // Wait for being Idle on this Scene, otherwise LaunchedEffect would fire too soon,
+            // and another transition could override the NSSL stack bounds.
+            if (isIdle) {
+                // Reset the stack bounds to avoid caching these values from the previous Scenes,
+                // and not to confuse the StackScrollAlgorithm when it displays a HUN over GONE.
+                notificationStackScrolLView.get().apply {
+                    setStackTop(0f)
+                    setStackCutoff(0f)
+                }
+            }
+        }
+
         animateContentFloatAsState(
             value = QuickSettings.SharedValues.SquishinessValues.GoneSceneStarting,
             key = QuickSettings.SharedValues.TilesSquishiness,
@@ -75,9 +96,7 @@
         SnoozeableHeadsUpNotificationSpace(
             stackScrollView = notificationStackScrolLView.get(),
             viewModel =
-                rememberViewModel("GoneScene") {
-                    notificationsPlaceholderViewModelFactory.create()
-                },
+                rememberViewModel("GoneScene") { notificationsPlaceholderViewModelFactory.create() },
         )
     }
 }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
index bba3d69..fd1632e 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
@@ -353,13 +353,24 @@
                     )
                 }
 
+                val qqsLayoutPaddingBottom =
+                    dimensionResource(id = R.dimen.qqs_layout_padding_bottom)
                 ShadeMediaCarousel(
                     isVisible = isMediaVisible,
                     isInRow = mediaInRow,
                     mediaHost = mediaHost,
                     mediaOffsetProvider = mediaOffsetProvider,
                     carouselController = mediaCarouselController,
-                    modifier = Modifier.layoutId(SingleShadeMeasurePolicy.LayoutId.Media),
+                    modifier =
+                        Modifier.layoutId(SingleShadeMeasurePolicy.LayoutId.Media)
+                            .padding(
+                                horizontal =
+                                    shadeHorizontalPadding +
+                                        dimensionResource(id = R.dimen.qs_horizontal_margin)
+                            )
+                            .thenIf(!mediaInRow) {
+                                Modifier.padding(bottom = qqsLayoutPaddingBottom)
+                            },
                     usingCollapsedLandscapeMedia = usingCollapsedLandscapeMedia,
                     isInSplitShade = false,
                 )
@@ -562,10 +573,14 @@
                                 mediaOffsetProvider = mediaOffsetProvider,
                                 modifier =
                                     Modifier.thenIf(
-                                        MediaContentPicker.shouldElevateMedia(layoutState)
-                                    ) {
-                                        Modifier.zIndex(1f)
-                                    },
+                                            MediaContentPicker.shouldElevateMedia(layoutState)
+                                        ) {
+                                            Modifier.zIndex(1f)
+                                        }
+                                        .padding(
+                                            horizontal =
+                                                dimensionResource(id = R.dimen.qs_horizontal_margin)
+                                        ),
                                 carouselController = mediaCarouselController,
                                 isInSplitShade = true,
                             )
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/PerDisplayStoreImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/PerDisplayStoreImplTest.kt
index 6a0781b..085c1e4 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/PerDisplayStoreImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/PerDisplayStoreImplTest.kt
@@ -43,11 +43,6 @@
     private val store = kosmos.fakePerDisplayStore
 
     @Before
-    fun start() {
-        store.start()
-    }
-
-    @Before
     fun addDisplays() = runBlocking {
         fakeDisplayRepository.addDisplay(createDisplay(DEFAULT_DISPLAY_ID))
         fakeDisplayRepository.addDisplay(createDisplay(NON_DEFAULT_DISPLAY_ID))
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/QsBatteryModeControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/QsBatteryModeControllerTest.kt
index ab5fa8e..5566c10 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/QsBatteryModeControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/QsBatteryModeControllerTest.kt
@@ -38,7 +38,7 @@
 
     private val kosmos = testKosmos()
     private val insetsProviderStore = kosmos.fakeStatusBarContentInsetsProviderStore
-    private val insetsProvider = insetsProviderStore.defaultDisplay
+    private val insetsProvider = insetsProviderStore.forDisplay(context.displayId)
 
     @JvmField @Rule val mockitoRule = MockitoJUnit.rule()!!
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/LightBarControllerStoreImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/LightBarControllerStoreImplTest.kt
index 18eef33..9f550cf 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/LightBarControllerStoreImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/LightBarControllerStoreImplTest.kt
@@ -41,11 +41,6 @@
 
     private val underTest = kosmos.lightBarControllerStoreImpl
 
-    @Before
-    fun start() {
-        underTest.start()
-    }
-
     @Before fun addDisplays() = runBlocking { fakeDisplayRepository.addDisplay(DEFAULT_DISPLAY) }
 
     @Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/MultiDisplayDarkIconDispatcherStoreTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/MultiDisplayDarkIconDispatcherStoreTest.kt
index a2c3c66..49abc7d 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/MultiDisplayDarkIconDispatcherStoreTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/MultiDisplayDarkIconDispatcherStoreTest.kt
@@ -46,11 +46,6 @@
     // Lazy so that @EnableFlags has time to run before underTest is instantiated.
     private val underTest by lazy { kosmos.multiDisplayDarkIconDispatcherStore }
 
-    @Before
-    fun start() {
-        underTest.start()
-    }
-
     @Before fun addDisplays() = runBlocking { fakeDisplayRepository.addDisplay(DEFAULT_DISPLAY) }
 
     @Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/MultiDisplayStatusBarContentInsetsProviderStoreTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/MultiDisplayStatusBarContentInsetsProviderStoreTest.kt
index 4a26fdf..670cea3 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/MultiDisplayStatusBarContentInsetsProviderStoreTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/MultiDisplayStatusBarContentInsetsProviderStoreTest.kt
@@ -41,11 +41,6 @@
     private val fakeDisplayRepository = kosmos.displayRepository
     private val underTest = kosmos.multiDisplayStatusBarContentInsetsProviderStore
 
-    @Before
-    fun start() {
-        underTest.start()
-    }
-
     @Before fun addDisplays() = runBlocking { fakeDisplayRepository.addDisplay(DEFAULT_DISPLAY) }
 
     @Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/MultiDisplayStatusBarModeRepositoryStoreTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/MultiDisplayStatusBarModeRepositoryStoreTest.kt
index a9920ec5..27a0d55 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/MultiDisplayStatusBarModeRepositoryStoreTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/MultiDisplayStatusBarModeRepositoryStoreTest.kt
@@ -43,11 +43,6 @@
     private val fakeDisplayRepository = kosmos.displayRepository
     private val underTest by lazy { kosmos.multiDisplayStatusBarModeRepositoryStore }
 
-    @Before
-    fun start() {
-        underTest.start()
-    }
-
     @Before fun addDisplays() = runBlocking { fakeDisplayRepository.addDisplay(DEFAULT_DISPLAY) }
 
     @Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/SystemEventChipAnimationControllerStoreImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/SystemEventChipAnimationControllerStoreImplTest.kt
index e65c04c..6264e82 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/SystemEventChipAnimationControllerStoreImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/SystemEventChipAnimationControllerStoreImplTest.kt
@@ -46,11 +46,6 @@
     // Lazy so that @EnableFlags has time to run before underTest is instantiated.
     private val underTest by lazy { kosmos.systemEventChipAnimationControllerStoreImpl }
 
-    @Before
-    fun start() {
-        underTest.start()
-    }
-
     @Before fun addDisplays() = runBlocking { fakeDisplayRepository.addDisplay(DEFAULT_DISPLAY) }
 
     @Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.kt
index b815c6c..e8c5fe0 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.kt
@@ -160,7 +160,7 @@
 
         Mockito.`when`(iconManagerFactory.create(ArgumentMatchers.any(), ArgumentMatchers.any()))
             .thenReturn(iconManager)
-        Mockito.`when`(statusBarContentInsetsProviderStore.defaultDisplay)
+        Mockito.`when`(statusBarContentInsetsProviderStore.forDisplay(context.displayId))
             .thenReturn(kosmos.statusBarContentInsetsProvider)
         allowTestableLooperAsMainThread()
         looper.runWithLooper {
@@ -178,6 +178,7 @@
     private fun createController(): KeyguardStatusBarViewController {
         return KeyguardStatusBarViewController(
             kosmos.testDispatcher,
+            context,
             keyguardStatusBarView,
             carrierTextController,
             configurationController,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/window/MultiDisplayStatusBarWindowControllerStoreTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/window/MultiDisplayStatusBarWindowControllerStoreTest.kt
index 7a9d017..46abd91 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/window/MultiDisplayStatusBarWindowControllerStoreTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/window/MultiDisplayStatusBarWindowControllerStoreTest.kt
@@ -23,6 +23,7 @@
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.display.data.repository.displayRepository
 import com.android.systemui.kosmos.testScope
+import com.android.systemui.kosmos.useUnconfinedTestDispatcher
 import com.android.systemui.statusbar.core.StatusBarConnectedDisplays
 import com.android.systemui.testKosmos
 import kotlinx.coroutines.runBlocking
@@ -37,17 +38,12 @@
 @RunWith(AndroidJUnit4::class)
 @EnableFlags(StatusBarConnectedDisplays.FLAG_NAME)
 class MultiDisplayStatusBarWindowControllerStoreTest : SysuiTestCase() {
-    private val kosmos = testKosmos()
+    private val kosmos = testKosmos().useUnconfinedTestDispatcher()
     private val fakeDisplayRepository = kosmos.displayRepository
     private val testScope = kosmos.testScope
 
     private val underTest by lazy { kosmos.multiDisplayStatusBarWindowControllerStore }
 
-    @Before
-    fun start() {
-        underTest.start()
-    }
-
     @Before fun addDisplays() = runBlocking { fakeDisplayRepository.addDisplay(DEFAULT_DISPLAY) }
 
     @Test
diff --git a/packages/SystemUI/res/drawable/volume_background_top_legacy.xml b/packages/SystemUI/res/drawable/volume_background_top_legacy.xml
index 3cd87fc..58ae150 100644
--- a/packages/SystemUI/res/drawable/volume_background_top_legacy.xml
+++ b/packages/SystemUI/res/drawable/volume_background_top_legacy.xml
@@ -16,7 +16,7 @@
   -->
 <layer-list xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
-    <item>
+    <item android:gravity="bottom|end">
         <shape>
             <size android:width="@dimen/volume_dialog_panel_width" />
             <solid android:color="?androidprv:attr/colorSurface" />
diff --git a/packages/SystemUI/res/layout/volume_dialog_legacy.xml b/packages/SystemUI/res/layout/volume_dialog_legacy.xml
index 9010ab7..d44b6a8 100644
--- a/packages/SystemUI/res/layout/volume_dialog_legacy.xml
+++ b/packages/SystemUI/res/layout/volume_dialog_legacy.xml
@@ -93,9 +93,7 @@
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
                     android:background="@drawable/volume_background_bottom"
-                    android:paddingLeft="@dimen/volume_dialog_ringer_rows_padding"
-                    android:paddingBottom="@dimen/volume_dialog_ringer_rows_padding"
-                    android:paddingRight="@dimen/volume_dialog_ringer_rows_padding">
+                    android:paddingBottom="@dimen/volume_dialog_ringer_rows_padding">
                     <com.android.keyguard.AlphaOptimizedImageButton
                         android:id="@+id/settings"
                         android:src="@drawable/horizontal_ellipsis"
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 713aa47..3dd49bfe 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -3760,20 +3760,11 @@
          is a component that shows the user which keyboard shortcuts they can use.
          [CHAR LIMIT=NONE] -->
     <string name="shortcut_helper_customize_mode_title">Customize keyboard shortcuts</string>
-    <!-- Title at the top of the keyboard shortcut helper remove shortcut dialog.
-         The helper is a component that shows the user which keyboard shortcuts they can use. Also
-         allows the user to add/remove custom shortcuts.[CHAR LIMIT=NONE] -->
-    <string name="shortcut_customize_mode_remove_shortcut_dialog_title">Remove shortcut?</string>
     <!-- Sub title at the top of the keyboard shortcut helper customization dialog. Explains to the
          user what action they need to take in the customization dialog to assign a new custom shortcut.
-         The shortcut customize dialog allows users to add/remove custom shortcuts
+         The helper is a component that shows the user which keyboard shortcuts they can use.
          [CHAR LIMIT=NONE] -->
-    <string name="shortcut_customize_mode_add_shortcut_description">Press key to assign shortcut</string>
-    <!-- Sub title at the top of the remove custom shortcut dialog. Explains to the user what action
-         they're about to take when they click remove shortcut. The shortcut customize dialog allows
-         users to add/remove custom shortcuts
-         [CHAR LIMIT=NONE] -->
-    <string name="shortcut_customize_mode_remove_shortcut_description">This will delete your custom shortcut permanently.</string>
+    <string name="shortcut_helper_customize_mode_sub_title">Press key to assign shortcut</string>
     <!-- Placeholder text shown in the search box of the keyboard shortcut helper, when the user
          hasn't typed in anything in the search box yet. The helper is a  component that shows the
          user which keyboard shortcuts they can use. [CHAR LIMIT=NONE] -->
@@ -3829,10 +3820,6 @@
          confirm and assign key combination to selected shortcut. The helper is a  component that
          shows the user which keyboard shortcuts they can use. [CHAR LIMIT=NONE] -->
     <string name="shortcut_helper_customize_dialog_set_shortcut_button_label">Set shortcut</string>
-    <!-- Label on the remove shortcut button in keyboard shortcut helper customize dialog, that allows user to
-         confirm and remove previously added custom shortcut. The helper is a  component that
-         shows the user which keyboard shortcuts they can use. [CHAR LIMIT=NONE] -->
-    <string name="shortcut_helper_customize_dialog_remove_button_label">Remove</string>
     <!-- Label on the cancel button in keyboard shortcut helper customize dialog, that allows user to
          cancel and exit shortcut customization dialog, returning to the main shortcut helper page.
          The helper is a  component that shows the user which keyboard shortcuts they can use.
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index e14008a..0381811 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -831,6 +831,11 @@
         <item name="android:textColor">?attr/onSurfaceVariant</item>
     </style>
 
+    <style name="TextAppearance.QSEditTitle" >
+        <item name="android:fontFamily">"gsf-title-medium-emphasized"</item>
+        <item name="android:textColor">?attr/onSurfaceVariant</item>
+    </style>
+
     <style name="QSCustomizeToolbar" parent="@*android:style/Widget.DeviceDefault.Toolbar">
         <item name="android:textColor">?attr/onSurface</item>
         <item name="android:elevation">10dp</item>
diff --git a/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java b/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java
index 8ed675c..6ef7de4 100644
--- a/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java
+++ b/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java
@@ -16,7 +16,10 @@
 
 package com.android.keyguard;
 
+import static com.android.systemui.Flags.gsfBouncer;
+
 import android.content.Context;
+import android.graphics.Typeface;
 import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.view.MotionEvent;
@@ -122,6 +125,9 @@
                 textId = com.android.internal.R.string.lockscreen_emergency_call;
             }
             setText(textId);
+            if (gsfBouncer()) {
+                setTypeface(Typeface.create("gsf-title-medium", Typeface.NORMAL));
+            }
         } else {
             setVisibility(View.GONE);
         }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index 6bcacd0..fcaccd2 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -32,6 +32,7 @@
 import static androidx.constraintlayout.widget.ConstraintSet.TOP;
 import static androidx.constraintlayout.widget.ConstraintSet.WRAP_CONTENT;
 
+import static com.android.systemui.Flags.gsfBouncer;
 import static com.android.systemui.plugins.FalsingManager.LOW_PENALTY;
 
 import static java.lang.Integer.max;
@@ -51,6 +52,7 @@
 import android.graphics.BlendMode;
 import android.graphics.Canvas;
 import android.graphics.Rect;
+import android.graphics.Typeface;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.Icon;
@@ -1335,6 +1337,9 @@
                     true);
             mUserSwitcherViewGroup = mView.findViewById(R.id.keyguard_bouncer_user_switcher);
             mUserSwitcher = mView.findViewById(R.id.user_switcher_header);
+            if (gsfBouncer()) {
+                mUserSwitcher.setTypeface(Typeface.create("gsf-label-medium", Typeface.NORMAL));
+            }
         }
 
         interface UserSwitcherCallback {
diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
index 7fe4ec8..ebde8a3 100644
--- a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
@@ -15,11 +15,13 @@
  */
 package com.android.keyguard;
 
+import static com.android.systemui.Flags.gsfBouncer;
 import static com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants.ColorId.NUM_PAD_KEY;
 
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.TypedArray;
+import android.graphics.Typeface;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.GradientDrawable;
 import android.os.PowerManager;
@@ -158,6 +160,9 @@
         int klondikeColor = Utils.getColorAttr(getContext(), android.R.attr.textColorSecondary)
                 .getDefaultColor();
         mDigitText.setTextColor(textColor);
+        if (gsfBouncer()) {
+            mDigitText.setTypeface(Typeface.create("gsf-label-large-emphasized", Typeface.NORMAL));
+        }
         mKlondikeText.setTextColor(klondikeColor);
 
         if (mAnimator != null) mAnimator.reloadColors(getContext());
diff --git a/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java
index e634726..1176cb0 100644
--- a/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java
@@ -19,6 +19,7 @@
 
 import static com.android.settingslib.flags.Flags.newStatusBarIcons;
 import static com.android.systemui.DejankUtils.whitelistIpcs;
+import static com.android.systemui.Flags.gsfQuickSettings;
 
 import static java.lang.annotation.RetentionPolicy.SOURCE;
 
@@ -33,6 +34,7 @@
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.Rect;
+import android.graphics.Typeface;
 import android.graphics.drawable.Drawable;
 import android.os.UserHandle;
 import android.provider.Settings;
@@ -384,6 +386,9 @@
         }
         float fontHeight = mBatteryPercentView.getPaint().getFontMetricsInt(null);
         mBatteryPercentView.setLineHeight(TypedValue.COMPLEX_UNIT_PX, fontHeight);
+        if (gsfQuickSettings()) {
+            mBatteryPercentView.setTypeface(Typeface.create("gsf-label-large", Typeface.NORMAL));
+        }
         if (mTextColor != 0) mBatteryPercentView.setTextColor(mTextColor);
         addView(mBatteryPercentView, new LayoutParams(
                 LayoutParams.WRAP_CONTENT,
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/BouncerMessageView.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/BouncerMessageView.kt
index 79a11ee..ad49fd0 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/BouncerMessageView.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/BouncerMessageView.kt
@@ -17,11 +17,13 @@
 package com.android.systemui.bouncer.ui
 
 import android.content.Context
+import android.graphics.Typeface
 import android.util.AttributeSet
 import android.widget.LinearLayout
 import com.android.keyguard.BouncerKeyguardMessageArea
 import com.android.keyguard.KeyguardMessageArea
 import com.android.keyguard.KeyguardMessageAreaController
+import com.android.systemui.Flags
 import com.android.systemui.res.R
 
 class BouncerMessageView : LinearLayout {
@@ -37,10 +39,20 @@
     var secondaryMessageView: BouncerKeyguardMessageArea? = null
     var primaryMessage: KeyguardMessageAreaController<KeyguardMessageArea>? = null
     var secondaryMessage: KeyguardMessageAreaController<KeyguardMessageArea>? = null
+
     override fun onFinishInflate() {
         super.onFinishInflate()
         primaryMessageView = findViewById(R.id.bouncer_primary_message_area)
         secondaryMessageView = findViewById(R.id.bouncer_secondary_message_area)
+
+        if (Flags.gsfBouncer()) {
+            primaryMessageView?.apply {
+                typeface = Typeface.create("gsf-title-large-emphasized", Typeface.NORMAL)
+            }
+            secondaryMessageView?.apply {
+                typeface = Typeface.create("gsf-title-medium-emphasized", Typeface.NORMAL)
+            }
+        }
     }
 
     fun init(factory: KeyguardMessageAreaController.Factory) {
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
index 7b91eae..38cfb9b 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
@@ -25,6 +25,8 @@
 import com.android.systemui.biometrics.BiometricNotificationService
 import com.android.systemui.bouncer.domain.startable.BouncerStartable
 import com.android.systemui.clipboardoverlay.ClipboardListener
+import com.android.systemui.complication.ComplicationTypesUpdater
+import com.android.systemui.complication.DreamClockTimeComplication
 import com.android.systemui.controls.dagger.StartControlsStartableModule
 import com.android.systemui.dagger.qualifiers.PerUser
 import com.android.systemui.dreams.AssistantAttentionMonitor
@@ -337,4 +339,18 @@
     abstract fun bindDreamOverlayRegistrant(
         dreamOverlayRegistrant: DreamOverlayRegistrant
     ): CoreStartable
+
+    /** Inject into DreamClockTimeComplication.Registrant */
+    @Binds
+    @IntoMap
+    @ClassKey(DreamClockTimeComplication.Registrant::class)
+    abstract fun bindDreamClockTimeComplicationRegistrant(
+        registrant: DreamClockTimeComplication.Registrant
+    ): CoreStartable
+
+    /** Inject into ComplicationTypesUpdater. */
+    @Binds
+    @IntoMap
+    @ClassKey(ComplicationTypesUpdater::class)
+    abstract fun bindComplicationTypesUpdater(updater: ComplicationTypesUpdater): CoreStartable
 }
diff --git a/packages/SystemUI/src/com/android/systemui/display/data/repository/PerDisplayStore.kt b/packages/SystemUI/src/com/android/systemui/display/data/repository/PerDisplayStore.kt
index 711534f..dbfbccf 100644
--- a/packages/SystemUI/src/com/android/systemui/display/data/repository/PerDisplayStore.kt
+++ b/packages/SystemUI/src/com/android/systemui/display/data/repository/PerDisplayStore.kt
@@ -18,11 +18,11 @@
 
 import android.view.Display
 import com.android.app.tracing.coroutines.launchTraced as launch
-import com.android.systemui.CoreStartable
+import com.android.systemui.coroutines.newTracingContext
 import com.android.systemui.dagger.qualifiers.Background
-import java.io.PrintWriter
 import java.util.concurrent.ConcurrentHashMap
 import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.first
 
 /** Provides per display instances of [T]. */
 interface PerDisplayStore<T> {
@@ -47,10 +47,17 @@
 abstract class PerDisplayStoreImpl<T>(
     @Background private val backgroundApplicationScope: CoroutineScope,
     private val displayRepository: DisplayRepository,
-) : PerDisplayStore<T>, CoreStartable {
+) : PerDisplayStore<T> {
 
     private val perDisplayInstances = ConcurrentHashMap<Int, T>()
 
+    private val coroutineScope by lazy {
+        CoroutineScope(
+            backgroundApplicationScope.coroutineContext +
+                newTracingContext("PerDisplayStore<${instanceClass.simpleName}>")
+        )
+    }
+
     /**
      * The instance for the default/main display of the device. For example, on a phone or a tablet,
      * the default display is the internal/built-in display of the device.
@@ -71,19 +78,18 @@
             throw IllegalArgumentException("Display with id $displayId doesn't exist.")
         }
         return perDisplayInstances.computeIfAbsent(displayId) {
+            listenForDisplayRemoval(displayId)
             createInstanceForDisplay(displayId)
         }
     }
 
     protected abstract fun createInstanceForDisplay(displayId: Int): T
 
-    override fun start() {
-        val instanceType = instanceClass.simpleName
-        backgroundApplicationScope.launch("PerDisplayStore#<$instanceType>start") {
-            displayRepository.displayRemovalEvent.collect { removedDisplayId ->
-                val removedInstance = perDisplayInstances.remove(removedDisplayId)
-                removedInstance?.let { onDisplayRemovalAction(it) }
-            }
+    private fun listenForDisplayRemoval(displayId: Int) {
+        coroutineScope.launch("listenForDisplayRemoval($displayId)") {
+            displayRepository.displayRemovalEvent.first { it == displayId }
+            val removedInstance = perDisplayInstances.remove(displayId)
+            removedInstance?.let { onDisplayRemovalAction(it) }
         }
     }
 
@@ -94,10 +100,6 @@
      * any clean up if needed.
      */
     open suspend fun onDisplayRemovalAction(instance: T) {}
-
-    override fun dump(pw: PrintWriter, args: Array<out String>) {
-        pw.println(perDisplayInstances)
-    }
 }
 
 class SingleDisplayStore<T>(defaultInstance: T) : PerDisplayStore<T> {
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutCustomizationRequestInfo.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutCustomizationRequestInfo.kt
index 2d3e7f6..203228b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutCustomizationRequestInfo.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutCustomizationRequestInfo.kt
@@ -18,14 +18,8 @@
 
 sealed interface ShortcutCustomizationRequestInfo {
     data class Add(
-        val label: String = "",
-        val categoryType: ShortcutCategoryType = ShortcutCategoryType.System,
-        val subCategoryLabel: String = "",
-    ) : ShortcutCustomizationRequestInfo
-
-    data class Delete(
-        val label: String = "",
-        val categoryType: ShortcutCategoryType = ShortcutCategoryType.System,
-        val subCategoryLabel: String = "",
+        val label: String,
+        val categoryType: ShortcutCategoryType,
+        val subCategoryLabel: String,
     ) : ShortcutCustomizationRequestInfo
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/ShortcutCustomizationDialogStarter.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/ShortcutCustomizationDialogStarter.kt
index 67caadb..310078a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/ShortcutCustomizationDialogStarter.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/ShortcutCustomizationDialogStarter.kt
@@ -27,10 +27,8 @@
 import androidx.compose.ui.unit.dp
 import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCustomizationRequestInfo
-import com.android.systemui.keyboard.shortcut.ui.composable.ShortcutCustomizationDialog
+import com.android.systemui.keyboard.shortcut.ui.composable.AssignNewShortcutDialog
 import com.android.systemui.keyboard.shortcut.ui.model.ShortcutCustomizationUiState
-import com.android.systemui.keyboard.shortcut.ui.model.ShortcutCustomizationUiState.AddShortcutDialog
-import com.android.systemui.keyboard.shortcut.ui.model.ShortcutCustomizationUiState.DeleteShortcutDialog
 import com.android.systemui.keyboard.shortcut.ui.viewmodel.ShortcutCustomizationViewModel
 import com.android.systemui.lifecycle.ExclusiveActivatable
 import com.android.systemui.statusbar.phone.SystemUIDialogFactory
@@ -52,11 +50,12 @@
 
     override suspend fun onActivated(): Nothing {
         viewModel.shortcutCustomizationUiState.collect { uiState ->
-            val shouldShowAddDialog = uiState is AddShortcutDialog && !uiState.isDialogShowing
-            val shouldShowDeleteDialog = uiState is DeleteShortcutDialog && !uiState.isDialogShowing
-            if (shouldShowDeleteDialog || shouldShowAddDialog) {
-                dialog = createDialog().also { it.show() }
-                viewModel.onDialogShown()
+            if (
+                uiState is ShortcutCustomizationUiState.AddShortcutDialog &&
+                !uiState.isDialogShowing
+            ) {
+                dialog = createAddShortcutDialog().also { it.show() }
+                viewModel.onAddShortcutDialogShown()
             } else if (uiState is ShortcutCustomizationUiState.Inactive) {
                 dialog?.dismiss()
                 dialog = null
@@ -69,7 +68,7 @@
         viewModel.onShortcutCustomizationRequested(requestInfo)
     }
 
-    private fun createDialog(): Dialog {
+    private fun createAddShortcutDialog(): Dialog {
         return dialogFactory.create(dialogDelegate = ShortcutCustomizationDialogDelegate()) { dialog
             ->
             val uiState by
@@ -77,7 +76,7 @@
                 initialValue = ShortcutCustomizationUiState.Inactive
             )
             val coroutineScope = rememberCoroutineScope()
-            ShortcutCustomizationDialog(
+            AssignNewShortcutDialog(
                 uiState = uiState,
                 modifier = Modifier
                     .width(364.dp)
@@ -88,7 +87,6 @@
                 onConfirmSetShortcut = {
                     coroutineScope.launch { viewModel.onSetShortcut() }
                 },
-                onConfirmDeleteShortcut = { viewModel.onDeleteShortcut() },
             )
             dialog.setOnDismissListener { viewModel.onDialogDismissed() }
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutCustomizer.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutCustomizer.kt
index 20040c6..c9b778e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutCustomizer.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutCustomizer.kt
@@ -61,74 +61,40 @@
 import com.android.systemui.res.R
 
 @Composable
-fun ShortcutCustomizationDialog(
+fun AssignNewShortcutDialog(
     uiState: ShortcutCustomizationUiState,
     modifier: Modifier = Modifier,
     onKeyPress: (KeyEvent) -> Boolean,
     onCancel: () -> Unit,
     onConfirmSetShortcut: () -> Unit,
-    onConfirmDeleteShortcut: () -> Unit,
 ) {
-    when (uiState) {
-        is ShortcutCustomizationUiState.AddShortcutDialog -> {
-            Column(modifier = modifier) {
-                Title(uiState.shortcutLabel)
-                Description(
-                    text =
-                        stringResource(
-                            id = R.string.shortcut_customize_mode_add_shortcut_description
-                        )
-                )
-                PromptShortcutModifier(
-                    modifier =
-                        Modifier.padding(top = 24.dp, start = 116.5.dp, end = 116.5.dp)
-                            .width(131.dp)
-                            .height(48.dp),
-                    defaultModifierKey = uiState.defaultCustomShortcutModifierKey,
-                )
-                SelectedKeyCombinationContainer(
-                    shouldShowError = uiState.errorMessage.isNotEmpty(),
-                    onKeyPress = onKeyPress,
-                    pressedKeys = uiState.pressedKeys,
-                )
-                ErrorMessageContainer(uiState.errorMessage)
-                DialogButtons(
-                    onCancel,
-                    isConfirmButtonEnabled = uiState.pressedKeys.isNotEmpty(),
-                    onConfirm = onConfirmSetShortcut,
-                    confirmButtonText =
-                        stringResource(
-                            R.string.shortcut_helper_customize_dialog_set_shortcut_button_label
-                        ),
-                )
-            }
-        }
-        is ShortcutCustomizationUiState.DeleteShortcutDialog -> {
-            Column(modifier) {
-                Title(
-                    title =
-                        stringResource(
-                            id = R.string.shortcut_customize_mode_remove_shortcut_dialog_title
-                        )
-                )
-                Description(
-                    text =
-                        stringResource(
-                            id = R.string.shortcut_customize_mode_remove_shortcut_description
-                        )
-                )
-                DialogButtons(
-                    onCancel = onCancel,
-                    onConfirm = onConfirmDeleteShortcut,
-                    confirmButtonText =
-                        stringResource(
-                            R.string.shortcut_helper_customize_dialog_remove_button_label
-                        ),
-                )
-            }
-        }
-        else -> {
-            /* No-Op */
+    if (uiState is ShortcutCustomizationUiState.AddShortcutDialog) {
+        Column(modifier = modifier) {
+            Title(
+                uiState.shortcutLabel,
+                modifier = Modifier.padding(horizontal = 24.dp).width(316.dp),
+            )
+            Description(
+                modifier = Modifier.padding(top = 24.dp, start = 24.dp, end = 24.dp).width(316.dp)
+            )
+            PromptShortcutModifier(
+                modifier =
+                    Modifier.padding(top = 24.dp, start = 116.5.dp, end = 116.5.dp)
+                        .width(131.dp)
+                        .height(48.dp),
+                defaultModifierKey = uiState.defaultCustomShortcutModifierKey,
+            )
+            SelectedKeyCombinationContainer(
+                shouldShowError = uiState.errorMessage.isNotEmpty(),
+                onKeyPress = onKeyPress,
+                pressedKeys = uiState.pressedKeys,
+            )
+            ErrorMessageContainer(uiState.errorMessage)
+            DialogButtons(
+                onCancel,
+                isSetShortcutButtonEnabled = uiState.pressedKeys.isNotEmpty(),
+                onConfirm = onConfirmSetShortcut,
+            )
         }
     }
 }
@@ -136,9 +102,8 @@
 @Composable
 fun DialogButtons(
     onCancel: () -> Unit,
-    isConfirmButtonEnabled: Boolean = true,
+    isSetShortcutButtonEnabled: Boolean,
     onConfirm: () -> Unit,
-    confirmButtonText: String,
 ) {
     Row(
         modifier =
@@ -161,8 +126,9 @@
             color = MaterialTheme.colorScheme.primary,
             width = 116.dp,
             contentColor = MaterialTheme.colorScheme.onPrimary,
-            text = confirmButtonText,
-            enabled = isConfirmButtonEnabled,
+            text =
+                stringResource(R.string.shortcut_helper_customize_dialog_set_shortcut_button_label),
+            enabled = isSetShortcutButtonEnabled,
         )
     }
 }
@@ -296,28 +262,23 @@
 }
 
 @Composable
-private fun Title(title: String) {
+private fun Title(title: String, modifier: Modifier = Modifier) {
     Text(
         text = title,
         style = MaterialTheme.typography.headlineSmall,
         fontSize = 24.sp,
-        modifier =
-            Modifier.padding(horizontal = 24.dp).width(316.dp).wrapContentSize(Alignment.Center),
+        modifier = modifier.wrapContentSize(Alignment.Center),
         color = MaterialTheme.colorScheme.onSurface,
         lineHeight = 32.sp,
-        fontWeight = FontWeight.W400,
     )
 }
 
 @Composable
-private fun Description(text: String) {
+private fun Description(modifier: Modifier = Modifier) {
     Text(
-        text = text,
+        text = stringResource(id = R.string.shortcut_helper_customize_mode_sub_title),
         style = MaterialTheme.typography.bodyMedium,
-        modifier =
-            Modifier.padding(top = 24.dp, start = 24.dp, end = 24.dp)
-                .width(316.dp)
-                .wrapContentSize(Alignment.Center),
+        modifier = modifier.wrapContentSize(Alignment.Center),
         color = MaterialTheme.colorScheme.onSurfaceVariant,
     )
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt
index cd13e87..b6b5d17 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt
@@ -111,6 +111,7 @@
 import androidx.compose.ui.util.fastForEachIndexed
 import com.android.compose.modifiers.thenIf
 import com.android.compose.ui.graphics.painter.rememberDrawablePainter
+import com.android.systemui.keyboard.shortcut.shared.model.Shortcut as ShortcutModel
 import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType
 import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCommand
 import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCustomizationRequestInfo
@@ -121,7 +122,6 @@
 import com.android.systemui.keyboard.shortcut.ui.model.ShortcutCategoryUi
 import com.android.systemui.keyboard.shortcut.ui.model.ShortcutsUiState
 import com.android.systemui.res.R
-import com.android.systemui.keyboard.shortcut.shared.model.Shortcut as ShortcutModel
 import kotlinx.coroutines.delay
 
 @Composable
@@ -462,18 +462,14 @@
                 searchQuery = searchQuery,
                 subCategory = subcategory,
                 isCustomizing = isCustomizing,
-                onCustomizationRequested = { requestInfo ->
-                    when (requestInfo) {
-                        is ShortcutCustomizationRequestInfo.Add ->
-                            onCustomizationRequested(
-                                requestInfo.copy(categoryType = category.type)
-                            )
-
-                        is ShortcutCustomizationRequestInfo.Delete ->
-                            onCustomizationRequested(
-                                requestInfo.copy(categoryType = category.type)
-                            )
-                    }
+                onCustomizationRequested = { label, subCategoryLabel ->
+                    onCustomizationRequested(
+                        ShortcutCustomizationRequestInfo.Add(
+                            label = label,
+                            subCategoryLabel = subCategoryLabel,
+                            categoryType = category.type,
+                        )
+                    )
                 },
             )
             Spacer(modifier = Modifier.height(8.dp))
@@ -504,7 +500,7 @@
     searchQuery: String,
     subCategory: ShortcutSubCategory,
     isCustomizing: Boolean,
-    onCustomizationRequested: (ShortcutCustomizationRequestInfo) -> Unit,
+    onCustomizationRequested: (String, String) -> Unit = { _: String, _: String -> },
 ) {
     Surface(
         modifier = Modifier.fillMaxWidth(),
@@ -526,19 +522,7 @@
                     searchQuery = searchQuery,
                     shortcut = shortcut,
                     isCustomizing = isCustomizing,
-                    onCustomizationRequested = { requestInfo ->
-                        when (requestInfo) {
-                            is ShortcutCustomizationRequestInfo.Add ->
-                                onCustomizationRequested(
-                                    requestInfo.copy(subCategoryLabel = subCategory.label)
-                                )
-
-                            is ShortcutCustomizationRequestInfo.Delete ->
-                                onCustomizationRequested(
-                                    requestInfo.copy(subCategoryLabel = subCategory.label)
-                                )
-                        }
-                    },
+                    onCustomizationRequested = { onCustomizationRequested(it, subCategory.label) },
                 )
             }
         }
@@ -560,7 +544,7 @@
     searchQuery: String,
     shortcut: ShortcutModel,
     isCustomizing: Boolean = false,
-    onCustomizationRequested: (ShortcutCustomizationRequestInfo) -> Unit = {},
+    onCustomizationRequested: (String) -> Unit = {},
 ) {
     val interactionSource = remember { MutableInteractionSource() }
     val isFocused by interactionSource.collectIsFocusedAsState()
@@ -588,16 +572,7 @@
             modifier = Modifier.weight(.666f),
             shortcut = shortcut,
             isCustomizing = isCustomizing,
-            onAddShortcutRequested = {
-                onCustomizationRequested(
-                    ShortcutCustomizationRequestInfo.Add(label = shortcut.label)
-                )
-            },
-            onDeleteShortcutRequested = {
-                onCustomizationRequested(
-                    ShortcutCustomizationRequestInfo.Delete(label = shortcut.label)
-                )
-            },
+            onAddShortcutRequested = { onCustomizationRequested(shortcut.label) },
         )
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/model/ShortcutCustomizationUiState.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/model/ShortcutCustomizationUiState.kt
index 990257d..adadeeb 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/model/ShortcutCustomizationUiState.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/model/ShortcutCustomizationUiState.kt
@@ -27,7 +27,5 @@
         val pressedKeys: List<ShortcutKey> = emptyList(),
     ) : ShortcutCustomizationUiState
 
-    data class DeleteShortcutDialog(val isDialogShowing: Boolean) : ShortcutCustomizationUiState
-
     data object Inactive : ShortcutCustomizationUiState
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModel.kt
index 8696827..8178c6a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModel.kt
@@ -29,8 +29,6 @@
 import com.android.systemui.keyboard.shortcut.shared.model.KeyCombination
 import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCustomizationRequestInfo
 import com.android.systemui.keyboard.shortcut.ui.model.ShortcutCustomizationUiState
-import com.android.systemui.keyboard.shortcut.ui.model.ShortcutCustomizationUiState.AddShortcutDialog
-import com.android.systemui.keyboard.shortcut.ui.model.ShortcutCustomizationUiState.DeleteShortcutDialog
 import com.android.systemui.res.R
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
@@ -57,7 +55,7 @@
                 }
             }
             .combine(_shortcutCustomizationUiState) { keys, uiState ->
-                if (uiState is AddShortcutDialog) {
+                if (uiState is ShortcutCustomizationUiState.AddShortcutDialog) {
                     uiState.copy(pressedKeys = keys)
                 } else {
                     uiState
@@ -68,7 +66,7 @@
         when (requestInfo) {
             is ShortcutCustomizationRequestInfo.Add -> {
                 _shortcutCustomizationUiState.value =
-                    AddShortcutDialog(
+                    ShortcutCustomizationUiState.AddShortcutDialog(
                         shortcutLabel = requestInfo.label,
                         defaultCustomShortcutModifierKey =
                             shortcutCustomizationInteractor.getDefaultCustomShortcutModifierKey(),
@@ -77,20 +75,14 @@
                     )
                 shortcutCustomizationInteractor.onCustomizationRequested(requestInfo)
             }
-
-            is ShortcutCustomizationRequestInfo.Delete -> {
-                _shortcutCustomizationUiState.value =
-                    DeleteShortcutDialog(isDialogShowing = false)
-                shortcutCustomizationInteractor.onCustomizationRequested(requestInfo)
-            }
         }
     }
 
-    fun onDialogShown() {
+    fun onAddShortcutDialogShown() {
         _shortcutCustomizationUiState.update { uiState ->
-            (uiState as? AddShortcutDialog)?.copy(isDialogShowing = true)
-                ?: (uiState as? DeleteShortcutDialog)?.copy(isDialogShowing = true)
-                ?: uiState
+            (uiState as? ShortcutCustomizationUiState.AddShortcutDialog)?.copy(
+                isDialogShowing = true
+            ) ?: uiState
         }
     }
 
@@ -123,7 +115,6 @@
                             ),
                     )
                 }
-
                 ShortcutCustomizationRequestResult.ERROR_OTHER ->
                     getUiStateWithErrorMessage(
                         uiState = uiState,
@@ -134,15 +125,11 @@
         }
     }
 
-    fun onDeleteShortcut() {
-        // TODO(b/373631984) not yet implemented
-    }
-
     private fun getUiStateWithErrorMessage(
         uiState: ShortcutCustomizationUiState,
         errorMessage: String,
     ): ShortcutCustomizationUiState {
-        return (uiState as? AddShortcutDialog)?.copy(
+        return (uiState as? ShortcutCustomizationUiState.AddShortcutDialog)?.copy(
             errorMessage = errorMessage
         ) ?: uiState
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java
index d715f42..dc188c2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java
@@ -16,8 +16,11 @@
 
 package com.android.systemui.qs;
 
+import static com.android.systemui.Flags.gsfQuickSettings;
+
 import android.content.ClipData;
 import android.content.ClipboardManager;
+import android.graphics.Typeface;
 import android.text.TextUtils;
 import android.view.View;
 import android.widget.TextView;
@@ -64,6 +67,9 @@
         mRetailModeInteractor = retailModeInteractor;
 
         mBuildText = mView.findViewById(R.id.build);
+        if (gsfQuickSettings()) {
+            mBuildText.setTypeface(Typeface.create("gsf-body-medium", Typeface.NORMAL));
+        }
         mPageIndicator = mView.findViewById(R.id.footer_page_indicator);
         mEditButton = mView.findViewById(android.R.id.edit);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
index f8d4080..0e64820 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
@@ -15,6 +15,8 @@
  */
 package com.android.systemui.qs.customize;
 
+import static com.android.systemui.Flags.gsfQuickSettings;
+
 import android.animation.Animator;
 import android.animation.Animator.AnimatorListener;
 import android.animation.AnimatorListenerAdapter;
@@ -81,6 +83,10 @@
         mToolbar.getMenu().add(Menu.NONE, MENU_RESET, 0, com.android.internal.R.string.reset)
                 .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
         mToolbar.setTitle(R.string.qs_edit);
+        if (gsfQuickSettings()) {
+            mToolbar.setTitleTextAppearance(context, R.style.TextAppearance_QSEditTitle);
+        }
+
         mRecyclerView = findViewById(android.R.id.list);
         mTransparentView = findViewById(R.id.customizer_transparent_view);
         DefaultItemAnimator animator = new DefaultItemAnimator();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
index 829c419..db778a2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
@@ -14,12 +14,15 @@
 
 package com.android.systemui.qs.customize;
 
+import static com.android.systemui.Flags.gsfQuickSettings;
+
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
 import android.graphics.Rect;
+import android.graphics.Typeface;
 import android.graphics.drawable.Drawable;
 import android.os.Handler;
 import android.view.LayoutInflater;
@@ -309,6 +312,10 @@
         if (viewType == TYPE_HEADER) {
             View v = inflater.inflate(R.layout.qs_customize_header, parent, false);
             v.setMinimumHeight(calculateHeaderMinHeight(context));
+            if (gsfQuickSettings()) {
+                ((TextView) v.findViewById(android.R.id.title)).setTypeface(
+                        Typeface.create("gsf-label-large", Typeface.NORMAL));
+            }
             return new Holder(v);
         }
         if (viewType == TYPE_DIVIDER) {
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 1fb76f1..b7ebce2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
@@ -27,6 +27,7 @@
 import android.graphics.Color
 import android.graphics.PorterDuff
 import android.graphics.Rect
+import android.graphics.Typeface
 import android.graphics.drawable.Drawable
 import android.graphics.drawable.GradientDrawable
 import android.graphics.drawable.LayerDrawable
@@ -308,6 +309,14 @@
         }
         setLabelColor(getLabelColorForState(QSTile.State.DEFAULT_STATE))
         setSecondaryLabelColor(getSecondaryLabelColorForState(QSTile.State.DEFAULT_STATE))
+
+        if (Flags.gsfQuickSettings()) {
+            label.apply {
+                typeface = Typeface.create("gsf-title-small-emphasized", Typeface.NORMAL)
+            }
+            secondaryLabel.apply { typeface = Typeface.create("gsf-label-medium", Typeface.NORMAL) }
+        }
+
         addView(labelContainer)
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/shade/QsBatteryModeController.kt b/packages/SystemUI/src/com/android/systemui/shade/QsBatteryModeController.kt
index 7a70966..3fd3329 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/QsBatteryModeController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/QsBatteryModeController.kt
@@ -15,10 +15,11 @@
 @Inject
 constructor(
     @ShadeDisplayAware private val context: Context,
-    insetsProviderStore: StatusBarContentInsetsProviderStore,
+    private val insetsProviderStore: StatusBarContentInsetsProviderStore,
 ) {
 
-    private val insetsProvider = insetsProviderStore.defaultDisplay
+    private val insetsProvider
+        get() = insetsProviderStore.forDisplay(context.displayId)
 
     private companion object {
         // MotionLayout frames are in [0, 100]. Where 0 and 100 are reserved for start and end
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt
index e8a792c..7bf2b7e 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt
@@ -21,6 +21,7 @@
 import android.annotation.IdRes
 import android.app.PendingIntent
 import android.app.StatusBarManager
+import android.content.Context
 import android.content.Intent
 import android.content.res.Configuration
 import android.graphics.Insets
@@ -92,6 +93,7 @@
     private val privacyIconsController: HeaderPrivacyIconsController,
     private val insetsProviderStore: StatusBarContentInsetsProviderStore,
     @ShadeDisplayAware private val configurationController: ConfigurationController,
+    @ShadeDisplayAware private val shadeDisplayAwareContext: Context,
     private val variableDateViewControllerFactory: VariableDateViewController.Factory,
     @Named(SHADE_HEADER) private val batteryMeterViewController: BatteryMeterViewController,
     private val dumpManager: DumpManager,
@@ -104,7 +106,8 @@
     private val statusOverlayHoverListenerFactory: StatusOverlayHoverListenerFactory,
 ) : ViewController<View>(header), Dumpable {
 
-    private val insetsProvider = insetsProviderStore.defaultDisplay
+    private val insetsProvider
+        get() = insetsProviderStore.forDisplay(shadeDisplayAwareContext.displayId)
 
     companion object {
         /** IDs for transitions and constraints for the [MotionLayout]. */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt
index 4341200..d3d2c58 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt
@@ -102,20 +102,6 @@
 
         @Provides
         @SysUISingleton
-        @IntoMap
-        @ClassKey(MultiDisplayStatusBarWindowControllerStore::class)
-        fun multiDisplayControllerStoreAsCoreStartable(
-            storeLazy: Lazy<MultiDisplayStatusBarWindowControllerStore>
-        ): CoreStartable {
-            return if (StatusBarConnectedDisplays.isEnabled) {
-                storeLazy.get()
-            } else {
-                CoreStartable.NOP
-            }
-        }
-
-        @Provides
-        @SysUISingleton
         @OngoingCallLog
         fun provideOngoingCallLogBuffer(factory: LogBufferFactory): LogBuffer {
             return factory.create("OngoingCall", 75)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/DarkIconDispatcherStore.kt b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/DarkIconDispatcherStore.kt
index 8183a48..f0d5b64 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/DarkIconDispatcherStore.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/DarkIconDispatcherStore.kt
@@ -18,7 +18,6 @@
 
 import android.content.Context
 import android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR
-import com.android.systemui.CoreStartable
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.display.data.repository.DisplayRepository
@@ -34,8 +33,6 @@
 import dagger.Lazy
 import dagger.Module
 import dagger.Provides
-import dagger.multibindings.ClassKey
-import dagger.multibindings.IntoMap
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
 
@@ -124,19 +121,5 @@
                 singleDisplayLazy.get()
             }
         }
-
-        @Provides
-        @SysUISingleton
-        @IntoMap
-        @ClassKey(DarkIconDispatcherStore::class)
-        fun storeAsCoreStartable(
-            multiDisplayLazy: Lazy<MultiDisplayDarkIconDispatcherStore>
-        ): CoreStartable {
-            return if (StatusBarConnectedDisplays.isEnabled) {
-                multiDisplayLazy.get()
-            } else {
-                CoreStartable.NOP
-            }
-        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/LightBarControllerStore.kt b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/LightBarControllerStore.kt
index e498755..17f9838 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/LightBarControllerStore.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/LightBarControllerStore.kt
@@ -16,7 +16,6 @@
 
 package com.android.systemui.statusbar.data.repository
 
-import com.android.systemui.CoreStartable
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.display.data.repository.DisplayRepository
@@ -27,8 +26,6 @@
 import com.android.systemui.statusbar.phone.LightBarControllerImpl
 import dagger.Binds
 import dagger.Module
-import dagger.multibindings.ClassKey
-import dagger.multibindings.IntoMap
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
 
@@ -71,9 +68,4 @@
 interface LightBarControllerStoreModule {
 
     @Binds fun store(impl: LightBarControllerStoreImpl): LightBarControllerStore
-
-    @Binds
-    @IntoMap
-    @ClassKey(LightBarControllerStore::class)
-    fun storeAsCoreStartable(impl: LightBarControllerStoreImpl): CoreStartable
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/PrivacyDotViewControllerStore.kt b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/PrivacyDotViewControllerStore.kt
index bd61c44..f1b3862 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/PrivacyDotViewControllerStore.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/PrivacyDotViewControllerStore.kt
@@ -16,7 +16,6 @@
 
 package com.android.systemui.statusbar.data.repository
 
-import com.android.systemui.CoreStartable
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.display.data.repository.DisplayRepository
@@ -30,8 +29,6 @@
 import dagger.Lazy
 import dagger.Module
 import dagger.Provides
-import dagger.multibindings.ClassKey
-import dagger.multibindings.IntoMap
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
 
@@ -91,18 +88,4 @@
             singleDisplayLazy.get()
         }
     }
-
-    @Provides
-    @SysUISingleton
-    @IntoMap
-    @ClassKey(PrivacyDotViewControllerStore::class)
-    fun storeAsCoreStartable(
-        multiDisplayLazy: Lazy<MultiDisplayPrivacyDotViewControllerStore>
-    ): CoreStartable {
-        return if (StatusBarConnectedDisplays.isEnabled) {
-            multiDisplayLazy.get()
-        } else {
-            CoreStartable.NOP
-        }
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/PrivacyDotWindowControllerStore.kt b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/PrivacyDotWindowControllerStore.kt
index a1f5655..da7edee 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/PrivacyDotWindowControllerStore.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/PrivacyDotWindowControllerStore.kt
@@ -19,7 +19,6 @@
 import android.view.Display
 import android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL
 import com.android.app.viewcapture.ViewCaptureAwareWindowManager
-import com.android.systemui.CoreStartable
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.display.data.repository.DisplayRepository
@@ -29,11 +28,7 @@
 import com.android.systemui.statusbar.core.StatusBarConnectedDisplays
 import com.android.systemui.statusbar.events.PrivacyDotWindowController
 import dagger.Binds
-import dagger.Lazy
 import dagger.Module
-import dagger.Provides
-import dagger.multibindings.ClassKey
-import dagger.multibindings.IntoMap
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
 
@@ -80,20 +75,4 @@
 interface PrivacyDotWindowControllerStoreModule {
 
     @Binds fun store(impl: PrivacyDotWindowControllerStoreImpl): PrivacyDotWindowControllerStore
-
-    companion object {
-        @Provides
-        @SysUISingleton
-        @IntoMap
-        @ClassKey(PrivacyDotWindowControllerStore::class)
-        fun storeAsCoreStartable(
-            storeLazy: Lazy<PrivacyDotWindowControllerStoreImpl>
-        ): CoreStartable {
-            return if (StatusBarConnectedDisplays.isEnabled) {
-                storeLazy.get()
-            } else {
-                CoreStartable.NOP
-            }
-        }
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarConfigurationControllerStore.kt b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarConfigurationControllerStore.kt
index 280d66b..bf9491b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarConfigurationControllerStore.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarConfigurationControllerStore.kt
@@ -17,7 +17,6 @@
 package com.android.systemui.statusbar.data.repository
 
 import android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR
-import com.android.systemui.CoreStartable
 import com.android.systemui.common.ui.GlobalConfig
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Background
@@ -32,8 +31,6 @@
 import dagger.Lazy
 import dagger.Module
 import dagger.Provides
-import dagger.multibindings.ClassKey
-import dagger.multibindings.IntoMap
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
 
@@ -100,18 +97,4 @@
             singleDisplayLazy.get()
         }
     }
-
-    @Provides
-    @SysUISingleton
-    @IntoMap
-    @ClassKey(StatusBarConfigurationControllerStore::class)
-    fun storeAsCoreStartable(
-        multiDisplayLazy: Lazy<MultiDisplayStatusBarConfigurationControllerStore>
-    ): CoreStartable {
-        return if (StatusBarConnectedDisplays.isEnabled) {
-            multiDisplayLazy.get()
-        } else {
-            CoreStartable.NOP
-        }
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarContentInsetsProviderStore.kt b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarContentInsetsProviderStore.kt
index e471b12..b0518ca 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarContentInsetsProviderStore.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarContentInsetsProviderStore.kt
@@ -18,7 +18,6 @@
 
 import android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR
 import com.android.systemui.CameraProtectionLoaderImpl
-import com.android.systemui.CoreStartable
 import com.android.systemui.SysUICutoutProviderImpl
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Background
@@ -33,8 +32,6 @@
 import dagger.Lazy
 import dagger.Module
 import dagger.Provides
-import dagger.multibindings.ClassKey
-import dagger.multibindings.IntoMap
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
 
@@ -92,20 +89,6 @@
 
     @Provides
     @SysUISingleton
-    @IntoMap
-    @ClassKey(StatusBarContentInsetsProviderStore::class)
-    fun storeAsCoreStartable(
-        multiDisplayLazy: Lazy<MultiDisplayStatusBarContentInsetsProviderStore>
-    ): CoreStartable {
-        return if (StatusBarConnectedDisplays.isEnabled) {
-            return multiDisplayLazy.get()
-        } else {
-            CoreStartable.NOP
-        }
-    }
-
-    @Provides
-    @SysUISingleton
     fun store(
         singleDisplayLazy: Lazy<SingleDisplayStatusBarContentInsetsProviderStore>,
         multiDisplayLazy: Lazy<MultiDisplayStatusBarContentInsetsProviderStore>,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarModeRepositoryStore.kt b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarModeRepositoryStore.kt
index 143e998..ebd38b3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarModeRepositoryStore.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarModeRepositoryStore.kt
@@ -30,8 +30,6 @@
 import dagger.Lazy
 import dagger.Module
 import dagger.Provides
-import dagger.multibindings.ClassKey
-import dagger.multibindings.IntoMap
 import dagger.multibindings.IntoSet
 import java.io.PrintWriter
 import javax.inject.Inject
@@ -104,20 +102,6 @@
     ): StatusBarInitializer.OnStatusBarViewInitializedListener
 
     companion object {
-        @Provides
-        @SysUISingleton
-        @IntoMap
-        @ClassKey(StatusBarModeRepositoryStore::class)
-        fun storeAsCoreStartable(
-            singleDisplayLazy: Lazy<StatusBarModeRepositoryImpl>,
-            multiDisplayLazy: Lazy<MultiDisplayStatusBarModeRepositoryStore>,
-        ): CoreStartable {
-            return if (StatusBarConnectedDisplays.isEnabled) {
-                multiDisplayLazy.get()
-            } else {
-                singleDisplayLazy.get()
-            }
-        }
 
         @Provides
         @SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/SystemEventChipAnimationControllerStore.kt b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/SystemEventChipAnimationControllerStore.kt
index 7760f58..21c52e3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/SystemEventChipAnimationControllerStore.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/SystemEventChipAnimationControllerStore.kt
@@ -17,7 +17,6 @@
 package com.android.systemui.statusbar.data.repository
 
 import android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR
-import com.android.systemui.CoreStartable
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.display.data.repository.DisplayRepository
@@ -29,11 +28,7 @@
 import com.android.systemui.statusbar.events.SystemEventChipAnimationControllerImpl
 import com.android.systemui.statusbar.window.StatusBarWindowControllerStore
 import dagger.Binds
-import dagger.Lazy
 import dagger.Module
-import dagger.Provides
-import dagger.multibindings.ClassKey
-import dagger.multibindings.IntoMap
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
 
@@ -85,20 +80,4 @@
     fun store(
         impl: SystemEventChipAnimationControllerStoreImpl
     ): SystemEventChipAnimationControllerStore
-
-    companion object {
-        @Provides
-        @SysUISingleton
-        @IntoMap
-        @ClassKey(SystemEventChipAnimationControllerStore::class)
-        fun storeAsCoreStartable(
-            implLazy: Lazy<SystemEventChipAnimationControllerStoreImpl>
-        ): CoreStartable {
-            return if (StatusBarConnectedDisplays.isEnabled) {
-                implLazy.get()
-            } else {
-                CoreStartable.NOP
-            }
-        }
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
index 2433b78..e78656ea 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
@@ -23,6 +23,7 @@
 import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
 import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow;
 
+import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.database.ContentObserver;
@@ -56,6 +57,7 @@
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.res.R;
 import com.android.systemui.scene.shared.flag.SceneContainerFlag;
+import com.android.systemui.shade.ShadeDisplayAware;
 import com.android.systemui.shade.ShadeViewStateProvider;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.StatusBarState;
@@ -113,6 +115,7 @@
             R.id.keyguard_hun_animator_start_tag);
 
     private final CoroutineDispatcher mCoroutineDispatcher;
+    private final Context mContext;
     private final CarrierTextController mCarrierTextController;
     private final ConfigurationController mConfigurationController;
     private final SystemStatusAnimationScheduler mAnimationScheduler;
@@ -128,7 +131,7 @@
     private final KeyguardStatusBarViewModel mKeyguardStatusBarViewModel;
     private final BiometricUnlockController mBiometricUnlockController;
     private final SysuiStatusBarStateController mStatusBarStateController;
-    private final StatusBarContentInsetsProvider mInsetsProvider;
+    private final StatusBarContentInsetsProviderStore mInsetsProviderStore;
     private final UserManager mUserManager;
     private final StatusBarUserChipViewModel mStatusBarUserChipViewModel;
     private final SecureSettings mSecureSettings;
@@ -313,6 +316,7 @@
     @Inject
     public KeyguardStatusBarViewController(
             @Main CoroutineDispatcher dispatcher,
+            @ShadeDisplayAware Context context,
             KeyguardStatusBarView view,
             CarrierTextController carrierTextController,
             ConfigurationController configurationController,
@@ -346,6 +350,7 @@
     ) {
         super(view);
         mCoroutineDispatcher = dispatcher;
+        mContext = context;
         mCarrierTextController = carrierTextController;
         mConfigurationController = configurationController;
         mAnimationScheduler = animationScheduler;
@@ -361,7 +366,7 @@
         mKeyguardStatusBarViewModel = keyguardStatusBarViewModel;
         mBiometricUnlockController = biometricUnlockController;
         mStatusBarStateController = statusBarStateController;
-        mInsetsProvider = statusBarContentInsetsProviderStore.getDefaultDisplay();
+        mInsetsProviderStore = statusBarContentInsetsProviderStore;
         mUserManager = userManager;
         mStatusBarUserChipViewModel = userChipViewModel;
         mSecureSettings = secureSettings;
@@ -403,6 +408,10 @@
         mStatusOverlayHoverListenerFactory = statusOverlayHoverListenerFactory;
     }
 
+    private StatusBarContentInsetsProvider insetsProvider() {
+        return mInsetsProviderStore.forDisplay(mContext.getDisplayId());
+    }
+
     @Override
     protected void onInit() {
         super.onInit();
@@ -445,7 +454,7 @@
                 .createDarkAwareListener(mSystemIconsContainer, mView.darkChangeFlow());
         mSystemIconsContainer.setOnHoverListener(hoverListener);
         mView.setOnApplyWindowInsetsListener(
-                (view, windowInsets) -> mView.updateWindowInsets(windowInsets, mInsetsProvider));
+                (view, windowInsets) -> mView.updateWindowInsets(windowInsets, insetsProvider()));
         mSecureSettings.registerContentObserverForUserSync(
                 Settings.Secure.STATUS_BAR_SHOW_VIBRATE_ICON,
                 false,
@@ -643,7 +652,7 @@
      * {@code OnApplyWindowInsetsListener}s.
      */
     public void setDisplayCutout(@Nullable DisplayCutout displayCutout) {
-        mView.setDisplayCutout(displayCutout, mInsetsProvider);
+        mView.setDisplayCutout(displayCutout, insetsProvider());
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
index 16e023c..a0c13c6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
@@ -41,7 +41,6 @@
 import com.android.systemui.shade.StatusBarLongPressGestureDetector
 import com.android.systemui.shade.domain.interactor.PanelExpansionInteractor
 import com.android.systemui.shared.animation.UnfoldMoveFromCenterAnimator
-import com.android.systemui.statusbar.data.repository.StatusBarContentInsetsProviderStore
 import com.android.systemui.statusbar.policy.Clock
 import com.android.systemui.statusbar.policy.ConfigurationController
 import com.android.systemui.statusbar.window.StatusBarWindowStateController
@@ -343,7 +342,7 @@
         private val configurationController: ConfigurationController,
         private val statusOverlayHoverListenerFactory: StatusOverlayHoverListenerFactory,
         @DisplaySpecific private val darkIconDispatcher: DarkIconDispatcher,
-        private val statusBarContentInsetsProviderStore: StatusBarContentInsetsProviderStore,
+        @DisplaySpecific private val statusBarContentInsetsProvider: StatusBarContentInsetsProvider,
     ) {
         fun create(view: PhoneStatusBarView): PhoneStatusBarViewController {
             val statusBarMoveFromCenterAnimationController =
@@ -370,7 +369,7 @@
                 configurationController,
                 statusOverlayHoverListenerFactory,
                 darkIconDispatcher,
-                statusBarContentInsetsProviderStore.defaultDisplay,
+                statusBarContentInsetsProvider,
             )
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.kt
index 58386b0..e1cdc58 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.kt
@@ -162,20 +162,6 @@
 
         @Provides
         @SysUISingleton
-        @IntoMap
-        @ClassKey(StatusBarInitializerStore::class)
-        fun initializerStoreAsCoreStartable(
-            multiDisplayStoreLazy: Lazy<MultiDisplayStatusBarInitializerStore>
-        ): CoreStartable {
-            return if (StatusBarConnectedDisplays.isEnabled) {
-                multiDisplayStoreLazy.get()
-            } else {
-                CoreStartable.NOP
-            }
-        }
-
-        @Provides
-        @SysUISingleton
         fun initializerStore(
             singleDisplayStoreLazy: Lazy<SingleDisplayStatusBarInitializerStore>,
             multiDisplayStoreLazy: Lazy<MultiDisplayStatusBarInitializerStore>,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/HomeStatusBarModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/HomeStatusBarModule.java
index 182f8d7..f70c92e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/HomeStatusBarModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/HomeStatusBarModule.java
@@ -28,9 +28,11 @@
 import com.android.systemui.statusbar.data.repository.DarkIconDispatcherStore;
 import com.android.systemui.statusbar.data.repository.StatusBarConfigurationController;
 import com.android.systemui.statusbar.data.repository.StatusBarConfigurationControllerStore;
+import com.android.systemui.statusbar.data.repository.StatusBarContentInsetsProviderStore;
 import com.android.systemui.statusbar.phone.PhoneStatusBarTransitions;
 import com.android.systemui.statusbar.phone.PhoneStatusBarView;
 import com.android.systemui.statusbar.phone.PhoneStatusBarViewController;
+import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider;
 import com.android.systemui.statusbar.phone.StatusBarLocation;
 import com.android.systemui.statusbar.policy.Clock;
 import com.android.systemui.statusbar.window.StatusBarWindowController;
@@ -174,4 +176,13 @@
             @DisplaySpecific int displayId, DarkIconDispatcherStore store) {
         return store.forDisplay(displayId);
     }
+
+    /** */
+    @Provides
+    @HomeStatusBarScope
+    @DisplaySpecific
+    static StatusBarContentInsetsProvider contentInsetsProvider(
+            @DisplaySpecific int displayId, StatusBarContentInsetsProviderStore store) {
+        return store.forDisplay(displayId);
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityTransitionAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityTransitionAnimatorTest.kt
index 425aad2..4aaa82e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityTransitionAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityTransitionAnimatorTest.kt
@@ -404,7 +404,7 @@
     @Test
     fun creatingRunnerWithLazyInitializationThrows_whenTheFlagsAreDisabled() {
         assertThrows(IllegalStateException::class.java) {
-            activityTransitionAnimator.createRunner(controller, initializeLazily = true)
+            activityTransitionAnimator.createRunner(controller, longLived = true)
         }
     }
 
@@ -414,7 +414,7 @@
     )
     @Test
     fun runnerCreatesDelegateLazily_whenPostingTimeouts() {
-        val runner = activityTransitionAnimator.createRunner(controller, initializeLazily = true)
+        val runner = activityTransitionAnimator.createRunner(controller, longLived = true)
         assertNull(runner.delegate)
         runner.postTimeouts()
         assertNotNull(runner.delegate)
@@ -426,7 +426,7 @@
     )
     @Test
     fun runnerCreatesDelegateLazily_onAnimationStart() {
-        val runner = activityTransitionAnimator.createRunner(controller, initializeLazily = true)
+        val runner = activityTransitionAnimator.createRunner(controller, longLived = true)
         assertNull(runner.delegate)
 
         // The delegate is cleaned up after execution (which happens in another thread), so what we
@@ -458,7 +458,7 @@
     )
     @Test
     fun runnerCreatesDelegateLazily_onAnimationTakeover() {
-        val runner = activityTransitionAnimator.createRunner(controller, initializeLazily = true)
+        val runner = activityTransitionAnimator.createRunner(controller, longLived = true)
         assertNull(runner.delegate)
 
         // The delegate is cleaned up after execution (which happens in another thread), so what we
@@ -489,7 +489,7 @@
     )
     @Test
     fun animationTakeoverThrows_whenTheFlagsAreDisabled() {
-        val runner = activityTransitionAnimator.createRunner(controller, initializeLazily = false)
+        val runner = activityTransitionAnimator.createRunner(controller, longLived = false)
         assertThrows(IllegalStateException::class.java) {
             runner.takeOverAnimation(
                 arrayOf(fakeWindow()),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModelTest.kt
index f706cf6..85ab746 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModelTest.kt
@@ -95,21 +95,11 @@
     }
 
     @Test
-    fun uiState_correctlyUpdatedWhenDeleteShortcutCustomizationIsRequested() {
-        testScope.runTest {
-            viewModel.onShortcutCustomizationRequested(standardDeleteShortcutRequest)
-            val uiState by collectLastValue(viewModel.shortcutCustomizationUiState)
-
-            assertThat(uiState).isEqualTo(expectedStandardDeleteShortcutUiState)
-        }
-    }
-
-    @Test
     fun uiState_consumedOnAddDialogShown() {
         testScope.runTest {
             val uiState by collectLastValue(viewModel.shortcutCustomizationUiState)
             viewModel.onShortcutCustomizationRequested(standardAddShortcutRequest)
-            viewModel.onDialogShown()
+            viewModel.onAddShortcutDialogShown()
 
             assertThat((uiState as ShortcutCustomizationUiState.AddShortcutDialog).isDialogShowing)
                 .isTrue()
@@ -117,25 +107,11 @@
     }
 
     @Test
-    fun uiState_consumedOnDeleteDialogShown() {
-        testScope.runTest {
-            val uiState by collectLastValue(viewModel.shortcutCustomizationUiState)
-            viewModel.onShortcutCustomizationRequested(standardDeleteShortcutRequest)
-            viewModel.onDialogShown()
-
-            assertThat(
-                    (uiState as ShortcutCustomizationUiState.DeleteShortcutDialog).isDialogShowing
-                )
-                .isTrue()
-        }
-    }
-
-    @Test
     fun uiState_inactiveAfterDialogIsDismissed() {
         testScope.runTest {
             val uiState by collectLastValue(viewModel.shortcutCustomizationUiState)
             viewModel.onShortcutCustomizationRequested(standardAddShortcutRequest)
-            viewModel.onDialogShown()
+            viewModel.onAddShortcutDialogShown()
             viewModel.onDialogDismissed()
             assertThat(uiState).isEqualTo(ShortcutCustomizationUiState.Inactive)
         }
@@ -169,7 +145,7 @@
         testScope.runTest {
             val uiState by collectLastValue(viewModel.shortcutCustomizationUiState)
             viewModel.onShortcutCustomizationRequested(allAppsShortcutCustomizationRequest)
-            viewModel.onDialogShown()
+            viewModel.onAddShortcutDialogShown()
 
             assertThat((uiState as ShortcutCustomizationUiState.AddShortcutDialog).errorMessage)
                 .isEmpty()
@@ -282,7 +258,7 @@
 
     private suspend fun openAddShortcutDialogAndSetShortcut() {
         viewModel.onShortcutCustomizationRequested(allAppsShortcutCustomizationRequest)
-        viewModel.onDialogShown()
+        viewModel.onAddShortcutDialogShown()
 
         viewModel.onKeyPressed(keyDownEventWithActionKeyPressed)
         viewModel.onKeyPressed(keyUpEventWithActionKeyPressed)
@@ -333,13 +309,6 @@
             subCategoryLabel = "Standard subcategory",
         )
 
-    private val standardDeleteShortcutRequest =
-        ShortcutCustomizationRequestInfo.Delete(
-            label = "Standard shortcut",
-            categoryType = ShortcutCategoryType.System,
-            subCategoryLabel = "Standard subcategory",
-        )
-
     private val allAppsShortcutCustomizationRequest =
         ShortcutCustomizationRequestInfo.Add(
             label = "Open apps list",
@@ -354,7 +323,4 @@
                 ShortcutKey.Icon.ResIdIcon(R.drawable.ic_ksh_key_meta),
             isDialogShowing = false,
         )
-
-    private val expectedStandardDeleteShortcutUiState =
-        ShortcutCustomizationUiState.DeleteShortcutDialog(isDialogShowing = false)
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeHeaderControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeHeaderControllerTest.kt
index eae8285..a904dab 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeHeaderControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeHeaderControllerTest.kt
@@ -96,7 +96,7 @@
 
     private val kosmos = testKosmos()
     private val insetsProviderStore = kosmos.fakeStatusBarContentInsetsProviderStore
-    private val insetsProvider = insetsProviderStore.defaultDisplay
+    private val insetsProvider = insetsProviderStore.forDisplay(context.displayId)
 
     @Mock(answer = Answers.RETURNS_MOCKS) private lateinit var view: MotionLayout
     @Mock private lateinit var statusIcons: StatusIconContainer
@@ -196,6 +196,7 @@
                 privacyIconsController,
                 insetsProviderStore,
                 configurationController,
+                context,
                 variableDateViewControllerFactory,
                 batteryMeterViewController,
                 dumpManager,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
index 69efa87..1fe4285 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
@@ -401,7 +401,7 @@
                 configurationController,
                 mStatusOverlayHoverListenerFactory,
                 fakeDarkIconDispatcher,
-                statusBarContentInsetsProviderStore,
+                statusBarContentInsetsProvider,
             )
             .create(view)
             .also { it.init() }
diff --git a/services/accessibility/accessibility.aconfig b/services/accessibility/accessibility.aconfig
index 2808056..a0b989b 100644
--- a/services/accessibility/accessibility.aconfig
+++ b/services/accessibility/accessibility.aconfig
@@ -55,16 +55,6 @@
 }
 
 flag {
-    name: "compute_window_changes_on_a11y_v2"
-    namespace: "accessibility"
-    description: "Computes accessibility window changes in accessibility instead of wm package."
-    bug: "322444245"
-    metadata {
-        purpose: PURPOSE_BUGFIX
-    }
-}
-
-flag {
     name: "deprecate_package_list_observer"
     namespace: "accessibility"
     description: "Stops using the deprecated PackageListObserver."
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
index 9a81aa6..5cbe0c4 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
@@ -433,22 +433,10 @@
             return Collections.emptyList();
         }
 
-        /**
-         * Callbacks from window manager when there's an accessibility change in windows.
-         *
-         * @param forceSend Send the windows for accessibility even if they haven't changed.
-         * @param topFocusedDisplayId The display Id which has the top focused window.
-         * @param topFocusedWindowToken The window token of top focused window.
-         * @param windows The windows for accessibility.
-         */
-        @Override
-        public void onWindowsForAccessibilityChanged(boolean forceSend, int topFocusedDisplayId,
+        private void onWindowsForAccessibilityChanged(boolean forceSend, int topFocusedDisplayId,
                 IBinder topFocusedWindowToken, @NonNull List<WindowInfo> windows) {
+            // TODO(b/322444245): no longer need to get a lock.
             synchronized (mLock) {
-                if (!Flags.computeWindowChangesOnA11yV2()) {
-                    // If the flag is enabled, it's already done in #createWindowInfoListLocked.
-                    updateWindowsByWindowAttributesLocked(windows);
-                }
                 if (DEBUG) {
                     Slogf.i(LOG_TAG, "mDisplayId=%d, topFocusedDisplayId=%d, currentUserId=%d, "
                                     + "visibleBgUsers=%s", mDisplayId, topFocusedDisplayId,
@@ -490,9 +478,7 @@
         }
 
         /**
-         * Called when the windows for accessibility changed. This is called if
-         * {@link com.android.server.accessibility.Flags.FLAG_COMPUTE_WINDOW_CHANGES_ON_A11Y_V2} is
-         * true.
+         * Called when the windows for accessibility changed.
          *
          * @param forceSend             Send the windows for accessibility even if they haven't
          *                              changed.
@@ -655,16 +641,6 @@
             return true;
         }
 
-        private void updateWindowsByWindowAttributesLocked(List<WindowInfo> windows) {
-            for (int i = windows.size() - 1; i >= 0; i--) {
-                final WindowInfo windowInfo = windows.get(i);
-                final IBinder token = windowInfo.token;
-                final int windowId = findWindowIdLocked(
-                        mAccessibilityUserManager.getCurrentUserIdLocked(), token);
-                updateWindowWithWindowAttributes(windowInfo, mWindowAttributes.get(windowId));
-            }
-        }
-
         private void updateWindowWithWindowAttributes(@NonNull WindowInfo windowInfo,
                 @Nullable AccessibilityWindowAttributes attributes) {
             if (attributes == null) {
@@ -990,19 +966,6 @@
         private AccessibilityWindowInfo populateReportedWindowLocked(int userId,
                 WindowInfo window, SparseArray<AccessibilityWindowInfo> oldWindowsById) {
             final int windowId = findWindowIdLocked(userId, window.token);
-
-            // With the flag enabled, createWindowInfoListLocked() already removes invalid windows.
-            if (!Flags.computeWindowChangesOnA11yV2()) {
-                if (windowId < 0) {
-                    return null;
-                }
-
-                // Don't need to add the embedded hierarchy windows into the a11y windows list.
-                if (isEmbeddedHierarchyWindowsLocked(windowId)) {
-                    return null;
-                }
-            }
-
             final AccessibilityWindowInfo reportedWindow = AccessibilityWindowInfo.obtain();
 
             reportedWindow.setId(windowId);
diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
index 8b5b93e..d4beb019 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
@@ -44,7 +44,6 @@
 import android.app.admin.DevicePolicyManager;
 import android.app.compat.CompatChanges;
 import android.companion.AssociationInfo;
-import android.companion.AssociationRequest;
 import android.companion.virtual.ActivityPolicyExemption;
 import android.companion.virtual.IVirtualDevice;
 import android.companion.virtual.IVirtualDeviceActivityListener;
@@ -156,9 +155,6 @@
 
     private static final String PERSISTENT_ID_PREFIX_CDM_ASSOCIATION = "companion:";
 
-    private static final List<String> DEVICE_PROFILES_ALLOWING_MIRROR_DISPLAYS = List.of(
-            AssociationRequest.DEVICE_PROFILE_APP_STREAMING);
-
     /**
      * Timeout until {@link #launchPendingIntent} stops waiting for an activity to be launched.
      */
@@ -1352,11 +1348,6 @@
         return hasCustomAudioInputSupportInternal();
     }
 
-    @Override
-    public boolean canCreateMirrorDisplays() {
-        return DEVICE_PROFILES_ALLOWING_MIRROR_DISPLAYS.contains(getDeviceProfile());
-    }
-
     private boolean hasCustomAudioInputSupportInternal() {
         if (!Flags.vdmPublicApis()) {
             return false;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 5c5361b..1a5d1f5 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -131,6 +131,9 @@
 import static android.provider.Settings.Global.DEBUG_APP;
 import static android.provider.Settings.Global.WAIT_FOR_DEBUGGER;
 import static android.security.Flags.preventIntentRedirect;
+import static android.security.Flags.preventIntentRedirectCollectNestedKeysOnServerIfNotCollected;
+import static android.security.Flags.preventIntentRedirectShowToast;
+import static android.security.Flags.preventIntentRedirectThrowExceptionIfNestedKeysNotCollected;
 import static android.util.FeatureFlagUtils.SETTINGS_ENABLE_MONITOR_PHANTOM_PROCS;
 import static android.view.Display.INVALID_DISPLAY;
 
@@ -387,6 +390,7 @@
 import android.view.View;
 import android.view.WindowManager;
 import android.view.autofill.AutofillManagerInternal;
+import android.widget.Toast;
 
 import com.android.internal.annotations.CompositeRWLock;
 import com.android.internal.annotations.GuardedBy;
@@ -437,6 +441,7 @@
 import com.android.server.SystemService;
 import com.android.server.SystemServiceManager;
 import com.android.server.ThreadPriorityBooster;
+import com.android.server.UiThread;
 import com.android.server.Watchdog;
 import com.android.server.am.LowMemDetector.MemFactor;
 import com.android.server.appop.AppOpsService;
@@ -478,6 +483,7 @@
 
 import dalvik.annotation.optimization.NeverCompile;
 import dalvik.system.VMRuntime;
+
 import libcore.util.EmptyArray;
 
 import java.io.File;
@@ -19304,9 +19310,32 @@
      */
     public void addCreatorToken(@Nullable Intent intent, String creatorPackage) {
         if (!preventIntentRedirect()) return;
-
         if (intent == null) return;
 
+        if ((intent.getExtendedFlags() & Intent.EXTENDED_FLAG_NESTED_INTENT_KEYS_COLLECTED) == 0) {
+            Slog.wtf(TAG,
+                    "[IntentRedirect] The intent does not have its nested keys collected as a "
+                            + "preparation for creating intent creator tokens. Intent: "
+                            + intent + "; creatorPackage: " + creatorPackage);
+            if (preventIntentRedirectShowToast()) {
+                UiThread.getHandler().post(
+                        () -> Toast.makeText(mContext,
+                                "Nested keys not collected. go/report-bug-intentRedir to report a"
+                                        + " bug", Toast.LENGTH_LONG).show());
+            }
+            if (preventIntentRedirectThrowExceptionIfNestedKeysNotCollected()) {
+                // this flag will be internal only, not ramped to public.
+                throw new SecurityException(
+                        "The intent does not have its nested keys collected as a preparation for "
+                                + "creating intent creator tokens. Intent: "
+                                + intent + "; creatorPackage: " + creatorPackage);
+            }
+            if (preventIntentRedirectCollectNestedKeysOnServerIfNotCollected()) {
+                // this flag will be ramped to public.
+                intent.collectExtraIntentKeys();
+            }
+        }
+
         String targetPackage = intent.getComponent() != null
                 ? intent.getComponent().getPackageName()
                 : intent.getPackage();
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index b84bf6b9..f42641e 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -1376,9 +1376,11 @@
             ProcessRecord app = lruList.get(i);
             final ProcessStateRecord state = app.mState;
             if (!app.isKilledByAm() && app.getThread() != null) {
-                // We don't need to apply the update for the process which didn't get computed
-                if (state.getCompletedAdjSeq() == mAdjSeq) {
-                    applyOomAdjLSP(app, doingAll, now, nowElapsed, oomAdjReason, true);
+                if (!Flags.fixApplyOomadjOrder()) {
+                    // We don't need to apply the update for the process which didn't get computed
+                    if (state.getCompletedAdjSeq() == mAdjSeq) {
+                        applyOomAdjLSP(app, doingAll, now, nowElapsed, oomAdjReason, true);
+                    }
                 }
 
                 if (app.isPendingFinishAttach()) {
@@ -1480,6 +1482,19 @@
             }
         }
 
+        if (Flags.fixApplyOomadjOrder()) {
+            // We need to apply the update starting from the least recently used.
+            // Otherwise, they won't be in the correct LRU order in LMKD.
+            for (int i = 0; i < numLru; i++) {
+                ProcessRecord app = lruList.get(i);
+                // We don't need to apply the update for the process which didn't get computed
+                if (!app.isKilledByAm() && app.getThread() != null
+                        && app.mState.getCompletedAdjSeq() == mAdjSeq) {
+                    applyOomAdjLSP(app, doingAll, now, nowElapsed, oomAdjReason, true);
+                }
+            }
+        }
+
         if (!mProcsToOomAdj.isEmpty()) {
             mInjector.batchSetOomAdj(mProcsToOomAdj);
             mProcsToOomAdj.clear();
diff --git a/services/core/java/com/android/server/am/flags.aconfig b/services/core/java/com/android/server/am/flags.aconfig
index 6d247d2..89e4a8d 100644
--- a/services/core/java/com/android/server/am/flags.aconfig
+++ b/services/core/java/com/android/server/am/flags.aconfig
@@ -245,6 +245,14 @@
 }
 
 flag {
+    name: "fix_apply_oomadj_order"
+    namespace: "backstage_power"
+    is_fixed_read_only: true
+    description: "Fix the iteration direction of process LRU list when applying oom adj"
+    bug: "378580264"
+}
+
+flag {
     name: "phantom_processes_fix"
     namespace: "backstage_power"
     description: "Make sure setProcessGroupForPhantomProcessOfApp deals with phantom processes properly"
diff --git a/services/core/java/com/android/server/app/GameManagerService.java b/services/core/java/com/android/server/app/GameManagerService.java
index 8c5152f..6f8dc10 100644
--- a/services/core/java/com/android/server/app/GameManagerService.java
+++ b/services/core/java/com/android/server/app/GameManagerService.java
@@ -100,6 +100,7 @@
 import com.android.server.ServiceThread;
 import com.android.server.SystemService;
 import com.android.server.SystemService.TargetUser;
+import com.android.server.utils.LazyJniRegistrar;
 import com.android.server.wm.ActivityTaskManagerInternal;
 import com.android.server.wm.CompatScaleProvider;
 
@@ -158,6 +159,10 @@
     private static final String GAME_MODE_INTERVENTION_LIST_FILE_NAME =
             "game_mode_intervention.list";
 
+    static {
+        LazyJniRegistrar.registerGameManagerService();
+    }
+
     private final Context mContext;
     private final Object mLock = new Object();
     private final Object mDeviceConfigLock = new Object();
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index 97a8854..b365ef7 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -434,21 +434,12 @@
 
         public boolean getMandatoryBiometricsEnabledAndRequirementsSatisfiedForUser(int userId) {
             if (!mMandatoryBiometricsEnabled.containsKey(userId)) {
-                Slog.d(TAG, "update mb toggle for user " + userId);
                 updateMandatoryBiometricsForAllProfiles(userId);
             }
             if (!mMandatoryBiometricsRequirementsSatisfied.containsKey(userId)) {
-                Slog.d(TAG, "update mb reqs for user " + userId);
                 updateMandatoryBiometricsRequirementsForAllProfiles(userId);
             }
 
-            Slog.d(TAG, mMandatoryBiometricsEnabled.getOrDefault(userId,
-                    DEFAULT_MANDATORY_BIOMETRICS_STATUS)
-                    + " " + mMandatoryBiometricsRequirementsSatisfied.getOrDefault(userId,
-                    DEFAULT_MANDATORY_BIOMETRICS_REQUIREMENTS_SATISFIED_STATUS)
-                    + " " + getEnabledForApps(userId)
-                    + " " + (mFingerprintEnrolledForUser.getOrDefault(userId, false /* default */)
-                    || mFaceEnrolledForUser.getOrDefault(userId, false /* default */)));
             return mMandatoryBiometricsEnabled.getOrDefault(userId,
                     DEFAULT_MANDATORY_BIOMETRICS_STATUS)
                     && mMandatoryBiometricsRequirementsSatisfied.getOrDefault(userId,
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index ae74dbe..3871f2a 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -17,6 +17,7 @@
 package com.android.server.display;
 
 import static android.Manifest.permission.ADD_ALWAYS_UNLOCKED_DISPLAY;
+import static android.Manifest.permission.ADD_MIRROR_DISPLAY;
 import static android.Manifest.permission.ADD_TRUSTED_DISPLAY;
 import static android.Manifest.permission.CAPTURE_SECURE_VIDEO_OUTPUT;
 import static android.Manifest.permission.CAPTURE_VIDEO_OUTPUT;
@@ -1677,15 +1678,10 @@
     }
 
     private boolean canCreateMirrorDisplays(IVirtualDevice virtualDevice) {
-        if (virtualDevice == null) {
-            return false;
+        if (android.companion.virtualdevice.flags.Flags.enableLimitedVdmRole()) {
+            return checkCallingPermission(ADD_MIRROR_DISPLAY, "canCreateMirrorDisplays");
         }
-        try {
-            return virtualDevice.canCreateMirrorDisplays();
-        } catch (RemoteException e) {
-            Slog.e(TAG, "Unable to query virtual device for permissions", e);
-            return false;
-        }
+        return virtualDevice != null;
     }
 
     private boolean canProjectVideo(IMediaProjection projection) {
@@ -1818,7 +1814,7 @@
             // display.
             if (!canProjectVideo(projection) && !canCreateMirrorDisplays(virtualDevice)
                     && !hasVideoOutputPermission("createVirtualDisplayInternal")) {
-                throw new SecurityException("Requires CAPTURE_VIDEO_OUTPUT or "
+                throw new SecurityException("Requires ADD_MIRROR_DISPLAY, CAPTURE_VIDEO_OUTPUT or "
                         + "CAPTURE_SECURE_VIDEO_OUTPUT permission, or an appropriate "
                         + "MediaProjection token in order to create a screen sharing virtual "
                         + "display. In order to create a virtual display that does not perform "
diff --git a/services/core/java/com/android/server/pm/InstallDependencyHelper.java b/services/core/java/com/android/server/pm/InstallDependencyHelper.java
index 527d680..65140bf 100644
--- a/services/core/java/com/android/server/pm/InstallDependencyHelper.java
+++ b/services/core/java/com/android/server/pm/InstallDependencyHelper.java
@@ -23,6 +23,7 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.PackageInstaller.SessionInfo;
 import android.content.pm.ResolveInfo;
 import android.content.pm.SharedLibraryInfo;
 import android.content.pm.dependencyinstaller.DependencyInstallerCallback;
@@ -33,12 +34,14 @@
 import android.os.OutcomeReceiver;
 import android.os.Process;
 import android.os.RemoteException;
+import android.util.ArraySet;
 import android.util.Slog;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.infra.AndroidFuture;
 import com.android.internal.infra.ServiceConnector;
 
+import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.TimeUnit;
 
@@ -54,16 +57,21 @@
     private static final long UNBIND_TIMEOUT_MILLIS = TimeUnit.HOURS.toMillis(6);
     private static final long REQUEST_TIMEOUT_MILLIS = TimeUnit.MINUTES.toMillis(1);
 
-    private final SharedLibrariesImpl mSharedLibraries;
     private final Context mContext;
+    private final SharedLibrariesImpl mSharedLibraries;
+    private final PackageInstallerService mPackageInstallerService;
     private final Object mRemoteServiceLock = new Object();
+    @GuardedBy("mTrackers")
+    private final List<DependencyInstallTracker> mTrackers = new ArrayList<>();
 
     @GuardedBy("mRemoteServiceLock")
     private ServiceConnector<IDependencyInstallerService> mRemoteService = null;
 
-    InstallDependencyHelper(Context context, SharedLibrariesImpl sharedLibraries) {
+    InstallDependencyHelper(Context context, SharedLibrariesImpl sharedLibraries,
+            PackageInstallerService packageInstallerService) {
         mContext = context;
         mSharedLibraries = sharedLibraries;
+        mPackageInstallerService = packageInstallerService;
     }
 
     void resolveLibraryDependenciesIfNeeded(PackageLite pkg, Computer snapshot, int userId,
@@ -98,19 +106,8 @@
             return;
         }
 
-        IDependencyInstallerCallback serviceCallback = new IDependencyInstallerCallback.Stub() {
-            @Override
-            public void onAllDependenciesResolved(int[] sessionIds) throws RemoteException {
-                // TODO(b/372862145): Implement waiting for sessions to finish installation
-                callback.onResult(null);
-            }
-
-            @Override
-            public void onFailureToResolveAllDependencies() throws RemoteException {
-                onError(callback, "Failed to resolve all dependencies automatically");
-            }
-        };
-
+        IDependencyInstallerCallback serviceCallback =
+                new DependencyInstallerCallbackCallOnce(handler, callback);
         boolean scheduleSuccess;
         synchronized (mRemoteServiceLock) {
             scheduleSuccess = mRemoteService.run(service -> {
@@ -123,10 +120,28 @@
         }
     }
 
-    private void onError(CallOnceProxy callback, String msg) {
+    void notifySessionComplete(int sessionId, boolean success) {
+        if (DEBUG) {
+            Slog.i(TAG, "Session complete for " + sessionId + " result: " + success);
+        }
+        synchronized (mTrackers) {
+            List<DependencyInstallTracker> completedTrackers = new ArrayList<>();
+            for (DependencyInstallTracker tracker: mTrackers) {
+                if (!tracker.onSessionComplete(sessionId, success)) {
+                    completedTrackers.add(tracker);
+                }
+            }
+            mTrackers.removeAll(completedTrackers);
+        }
+    }
+
+    private static void onError(CallOnceProxy callback, String msg) {
         PackageManagerException pe = new PackageManagerException(
                 INSTALL_FAILED_MISSING_SHARED_LIBRARY, msg);
         callback.onError(pe);
+        if (DEBUG) {
+            Slog.i(TAG, "Orig session error: " + msg);
+        }
     }
 
     private boolean bindToDependencyInstallerIfNeeded(int userId, Handler handler,
@@ -253,4 +268,135 @@
             }
         }
     }
+
+    /**
+     * Ensure we call one of the outcomes only once, on the right handler.
+     *
+     * Repeated calls will be no-op.
+     */
+    private class DependencyInstallerCallbackCallOnce extends IDependencyInstallerCallback.Stub {
+
+        private final Handler mHandler;
+        private final CallOnceProxy mCallback;
+
+        @GuardedBy("this")
+        private boolean mCalled = false;
+
+        DependencyInstallerCallbackCallOnce(Handler handler, CallOnceProxy callback) {
+            mHandler = handler;
+            mCallback = callback;
+        }
+
+        // TODO(b/372862145): Consider turning the binder call to two-way so that we can
+        //  throw IllegalArgumentException
+        @Override
+        public void onAllDependenciesResolved(int[] sessionIds) throws RemoteException {
+            synchronized (this) {
+                if (mCalled) {
+                    return;
+                }
+                mCalled = true;
+            }
+
+            ArraySet<Integer> set = new ArraySet<>();
+            for (int i = 0; i < sessionIds.length; i++) {
+                if (DEBUG) {
+                    Slog.i(TAG, "onAllDependenciesResolved called with " + sessionIds[i]);
+                }
+                set.add(sessionIds[i]);
+            }
+
+            DependencyInstallTracker tracker = new DependencyInstallTracker(mCallback, set);
+            synchronized (mTrackers) {
+                mTrackers.add(tracker);
+            }
+
+            // In case any of the session ids have already been installed, check if they
+            // are valid.
+            mHandler.post(() -> {
+                if (DEBUG) {
+                    Slog.i(TAG, "onAllDependenciesResolved cleaning up invalid sessions");
+                }
+
+                for (int i = 0; i < sessionIds.length; i++) {
+                    int sessionId = sessionIds[i];
+                    SessionInfo sessionInfo = mPackageInstallerService.getSessionInfo(sessionId);
+
+                    // Continue waiting if session exists and hasn't passed or failed yet.
+                    if (sessionInfo != null && !sessionInfo.isSessionApplied
+                            && !sessionInfo.isSessionFailed) {
+                        continue;
+                    }
+
+                    if (DEBUG) {
+                        Slog.i(TAG, "onAllDependenciesResolved cleaning up finished"
+                                + " session: " + sessionId);
+                    }
+
+                    // If session info is null, we assume it to be success.
+                    // TODO(b/372862145): Check historical sessions to be more precise.
+                    boolean success = sessionInfo == null || sessionInfo.isSessionApplied;
+
+                    notifySessionComplete(sessionId, /*success=*/success);
+                }
+            });
+        }
+
+        @Override
+        public void onFailureToResolveAllDependencies() throws RemoteException {
+            synchronized (this) {
+                if (mCalled) {
+                    return;
+                }
+                onError(mCallback, "Failed to resolve all dependencies automatically");
+                mCalled = true;
+            }
+        }
+    }
+
+    /**
+     * Tracks a list of session ids against a particular callback.
+     *
+     * If all the sessions completes successfully, it invokes the positive flow. If any of the
+     * sessions fails, it invokes the failure flow immediately.
+     */
+    // TODO(b/372862145): Determine and add support for rebooting while dependency is being resolved
+    private static class DependencyInstallTracker {
+        private final CallOnceProxy mCallback;
+        private final ArraySet<Integer> mPendingSessionIds;
+
+        DependencyInstallTracker(CallOnceProxy callback, ArraySet<Integer> pendingSessionIds) {
+            mCallback = callback;
+            mPendingSessionIds = pendingSessionIds;
+        }
+
+        /**
+         * Process a session complete event.
+         *
+         * Returns true if we still need to continue tracking.
+         */
+        public boolean onSessionComplete(int sessionId, boolean success) {
+            synchronized (this) {
+                if (!mPendingSessionIds.contains(sessionId)) {
+                    // This had no impact on tracker, so continue tracking
+                    return true;
+                }
+
+                if (!success) {
+                    // If one of the dependency fails, the orig session would fail too.
+                    onError(mCallback, "Failed to install all dependencies");
+                    // TODO(b/372862145): Abandon the rest of the pending sessions.
+                    return false; // No point in tracking anymore
+                }
+
+                mPendingSessionIds.remove(sessionId);
+                if (mPendingSessionIds.isEmpty()) {
+                    mCallback.onResult(null);
+                    return false; // Nothing to track anymore
+                }
+                return true; // Keep on tracking
+            }
+        }
+
+    }
 }
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index 8168c54..e5e2744 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -229,6 +229,7 @@
     private final SharedLibrariesImpl mSharedLibraries;
     private final PackageManagerServiceInjector mInjector;
     private final UpdateOwnershipHelper mUpdateOwnershipHelper;
+    private final InstallDependencyHelper mInstallDependencyHelper;
 
     private final Object mInternalLock = new Object();
     @GuardedBy("mInternalLock")
@@ -239,7 +240,8 @@
                          AppDataHelper appDataHelper,
                          RemovePackageHelper removePackageHelper,
                          DeletePackageHelper deletePackageHelper,
-                         BroadcastHelper broadcastHelper) {
+                         BroadcastHelper broadcastHelper,
+                         InstallDependencyHelper installDependencyHelper) {
         mPm = pm;
         mInjector = pm.mInjector;
         mAppDataHelper = appDataHelper;
@@ -253,6 +255,7 @@
         mPackageAbiHelper = pm.mInjector.getAbiHelper();
         mSharedLibraries = pm.mInjector.getSharedLibrariesImpl();
         mUpdateOwnershipHelper = pm.mInjector.getUpdateOwnershipHelper();
+        mInstallDependencyHelper = installDependencyHelper;
     }
 
     /**
@@ -1364,6 +1367,10 @@
                 }
             }
         }
+
+        for (InstallRequest request : requests) {
+            mInstallDependencyHelper.notifySessionComplete(request.getSessionId(), success);
+        }
     }
 
     @GuardedBy("mPm.mInstallLock")
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index a4152a7..47b7850 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -327,7 +327,7 @@
                 context, mInstallThread.getLooper(), new AppStateHelper(context));
         mPackageArchiver = new PackageArchiver(mContext, mPm);
         mInstallDependencyHelper = new InstallDependencyHelper(mContext,
-                mPm.mInjector.getSharedLibrariesImpl());
+                mPm.mInjector.getSharedLibrariesImpl(), this);
 
         LocalServices.getService(SystemServiceManager.class).startService(
                 new Lifecycle(context, this));
@@ -337,6 +337,10 @@
         return mStagingManager;
     }
 
+    InstallDependencyHelper getInstallDependencyHelper() {
+        return mInstallDependencyHelper;
+    }
+
     boolean okToSendBroadcasts()  {
         return mOkToSendBroadcasts;
     }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 807445e..7156334 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -2118,7 +2118,8 @@
         mDeletePackageHelper = new DeletePackageHelper(this, mRemovePackageHelper,
                 mBroadcastHelper);
         mInstallPackageHelper = new InstallPackageHelper(this, mAppDataHelper, mRemovePackageHelper,
-                mDeletePackageHelper, mBroadcastHelper);
+                mDeletePackageHelper, mBroadcastHelper,
+                injector.getPackageInstallerService().getInstallDependencyHelper());
 
         mInstantAppRegistry = new InstantAppRegistry(mContext, mPermissionManager,
                 mInjector.getUserManagerInternal(), mDeletePackageHelper);
diff --git a/services/core/java/com/android/server/security/intrusiondetection/IntrusionDetectionEventTransportConnection.java b/services/core/java/com/android/server/security/intrusiondetection/IntrusionDetectionEventTransportConnection.java
index 82f39b3..b25656e 100644
--- a/services/core/java/com/android/server/security/intrusiondetection/IntrusionDetectionEventTransportConnection.java
+++ b/services/core/java/com/android/server/security/intrusiondetection/IntrusionDetectionEventTransportConnection.java
@@ -60,7 +60,7 @@
         if (!bindService()) {
             return false;
         }
-        AndroidFuture<Integer> resultFuture = new AndroidFuture<>();
+        AndroidFuture<Boolean> resultFuture = new AndroidFuture<>();
         try {
             mService.initialize(resultFuture);
         } catch (RemoteException e) {
@@ -68,8 +68,8 @@
             unbindService();
             return false;
         }
-        Integer result = getFutureResult(resultFuture);
-        if (result != null && result == 0) {
+        Boolean result = getFutureResult(resultFuture);
+        if (result != null && result == true) {
             return true;
         } else {
             unbindService();
@@ -83,22 +83,22 @@
      * @return Whether the data is added to the binder service.
      */
     public boolean addData(List<IntrusionDetectionEvent> data) {
-        AndroidFuture<Integer> resultFuture = new AndroidFuture<>();
+        AndroidFuture<Boolean> resultFuture = new AndroidFuture<>();
         try {
             mService.addData(data, resultFuture);
         } catch (RemoteException e) {
             Slog.e(TAG, "Remote Exception", e);
             return false;
         }
-        Integer result = getFutureResult(resultFuture);
-        return result != null && result == 0;
+        Boolean result = getFutureResult(resultFuture);
+        return result != null && result == true;
     }
 
     /**
      * Release the BackupTransport binder service.
      */
     public void release() {
-        AndroidFuture<Integer> resultFuture = new AndroidFuture<>();
+        AndroidFuture<Boolean> resultFuture = new AndroidFuture<>();
         try {
             mService.release(resultFuture);
         } catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/utils/LazyJniRegistrar.java b/services/core/java/com/android/server/utils/LazyJniRegistrar.java
index ac4a92e..6d29e9e 100644
--- a/services/core/java/com/android/server/utils/LazyJniRegistrar.java
+++ b/services/core/java/com/android/server/utils/LazyJniRegistrar.java
@@ -42,6 +42,9 @@
     /** Registers native methods for ConsumerIrService. */
     public static native void registerConsumerIrService();
 
+    /** Registers native methods for GameManagerService. */
+    public static native void registerGameManagerService();
+
     /** Registers native methods for VrManagerService. */
     public static native void registerVrManagerService();
 }
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index d019516..0337f5f 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -1513,11 +1513,15 @@
             }
             if (wallpaper.getComponent() != null
                     && isPackageModified(wallpaper.getComponent().getPackageName())) {
+                ServiceInfo serviceInfo = null;
                 try {
-                    mContext.getPackageManager().getServiceInfo(wallpaper.getComponent(),
-                            PackageManager.MATCH_DIRECT_BOOT_AWARE
-                                    | PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
-                } catch (NameNotFoundException e) {
+                    serviceInfo = mIPackageManager.getServiceInfo(
+                            wallpaper.getComponent(), PackageManager.MATCH_DIRECT_BOOT_AWARE
+                                    | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, wallpaper.userId);
+                } catch (RemoteException e) {
+                    Slog.w(TAG, "Failed to call IPackageManager.getServiceInfo", e);
+                }
+                if (serviceInfo == null) {
                     Slog.e(TAG, "Wallpaper component gone, removing: "
                             + wallpaper.getComponent());
                     clearWallpaperLocked(wallpaper.mWhich, wallpaper.userId, false, null);
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 7cbacd6..4b7e74a 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -22,7 +22,6 @@
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_EXCLUDE_FROM_SCREEN_MAGNIFICATION;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
 import static android.view.WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY;
 import static android.view.WindowManager.TRANSIT_FLAG_IS_RECENTS;
 
@@ -1784,22 +1783,13 @@
                 mA11yWindowsPopulator.populateVisibleWindowsOnScreenLocked(
                         mDisplayId, visibleWindows);
 
-                if (!com.android.server.accessibility.Flags.computeWindowChangesOnA11yV2()) {
-                    windows = buildWindowInfoListLocked(visibleWindows, screenSize);
-                }
-
                 // Gets the top focused display Id and window token for supporting multi-display.
                 topFocusedDisplayId = mService.mRoot.getTopFocusedDisplayContent().getDisplayId();
                 topFocusedWindowToken = topFocusedWindowState.mClient.asBinder();
             }
 
-            if (com.android.server.accessibility.Flags.computeWindowChangesOnA11yV2()) {
-                mCallback.onAccessibilityWindowsChanged(forceSend, topFocusedDisplayId,
-                        topFocusedWindowToken, screenSize, visibleWindows);
-            } else {
-                mCallback.onWindowsForAccessibilityChanged(forceSend, topFocusedDisplayId,
-                        topFocusedWindowToken, windows);
-            }
+            mCallback.onAccessibilityWindowsChanged(forceSend, topFocusedDisplayId,
+                    topFocusedWindowToken, screenSize, visibleWindows);
 
             // Recycle the windows as we do not need them.
             for (final AccessibilityWindowsPopulator.AccessibilityWindow window : visibleWindows) {
@@ -1808,166 +1798,6 @@
             mInitialized = true;
         }
 
-        // Here are old code paths, called when computeWindowChangesOnA11yV2 flag is disabled.
-        // LINT.IfChange
-
-        /**
-         * From a list of windows, decides windows to be exposed to accessibility based on touchable
-         * region in the screen.
-         */
-        private List<WindowInfo> buildWindowInfoListLocked(List<AccessibilityWindow> visibleWindows,
-                Point screenSize) {
-            final List<WindowInfo> windows = new ArrayList<>();
-            final Set<IBinder> addedWindows = mTempBinderSet;
-            addedWindows.clear();
-
-            boolean focusedWindowAdded = false;
-
-            final int visibleWindowCount = visibleWindows.size();
-
-            Region unaccountedSpace = mTempRegion;
-            unaccountedSpace.set(0, 0, screenSize.x, screenSize.y);
-
-            // Iterate until we figure out what is touchable for the entire screen.
-            for (int i = 0; i < visibleWindowCount; i++) {
-                final AccessibilityWindow a11yWindow = visibleWindows.get(i);
-                final Region regionInWindow = new Region();
-                a11yWindow.getTouchableRegionInWindow(regionInWindow);
-                if (windowMattersToAccessibility(a11yWindow, regionInWindow, unaccountedSpace)) {
-                    addPopulatedWindowInfo(a11yWindow, regionInWindow, windows, addedWindows);
-                    if (windowMattersToUnaccountedSpaceComputation(a11yWindow)) {
-                        updateUnaccountedSpace(a11yWindow, unaccountedSpace);
-                    }
-                    focusedWindowAdded |= a11yWindow.isFocused();
-                } else if (a11yWindow.isUntouchableNavigationBar()) {
-                    // If this widow is navigation bar without touchable region, accounting the
-                    // region of navigation bar inset because all touch events from this region
-                    // would be received by launcher, i.e. this region is a un-touchable one
-                    // for the application.
-                    unaccountedSpace.op(
-                            getSystemBarInsetsFrame(
-                                    mService.mWindowMap.get(a11yWindow.getWindowInfo().token)),
-                            unaccountedSpace,
-                            Region.Op.REVERSE_DIFFERENCE);
-                }
-
-                if (unaccountedSpace.isEmpty() && focusedWindowAdded) {
-                    break;
-                }
-            }
-
-            // Remove child/parent references to windows that were not added.
-            final int windowCount = windows.size();
-            for (int i = 0; i < windowCount; i++) {
-                WindowInfo window = windows.get(i);
-                if (!addedWindows.contains(window.parentToken)) {
-                    window.parentToken = null;
-                }
-                if (window.childTokens != null) {
-                    final int childTokenCount = window.childTokens.size();
-                    for (int j = childTokenCount - 1; j >= 0; j--) {
-                        if (!addedWindows.contains(window.childTokens.get(j))) {
-                            window.childTokens.remove(j);
-                        }
-                    }
-                    // Leave the child token list if empty.
-                }
-            }
-
-            addedWindows.clear();
-
-            return windows;
-        }
-
-        // Some windows should be excluded from unaccounted space computation, though they still
-        // should be reported
-        private boolean windowMattersToUnaccountedSpaceComputation(AccessibilityWindow a11yWindow) {
-            // Do not account space of trusted non-touchable windows, except the split-screen
-            // divider.
-            // If it's not trusted, touch events are not sent to the windows behind it.
-            if (!a11yWindow.isTouchable()
-                    && (a11yWindow.getType() != TYPE_DOCK_DIVIDER)
-                    && a11yWindow.isTrustedOverlay()) {
-                return false;
-            }
-
-            if (a11yWindow.getType() == WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY) {
-                return false;
-            }
-            return true;
-        }
-
-        private boolean windowMattersToAccessibility(AccessibilityWindow a11yWindow,
-                Region regionInScreen, Region unaccountedSpace) {
-            if (a11yWindow.isFocused()) {
-                return true;
-            }
-
-            // Ignore non-touchable windows, except the split-screen divider, which is
-            // occasionally non-touchable but still useful for identifying split-screen
-            // mode and the PIP menu.
-            if (!a11yWindow.isTouchable()
-                    && (a11yWindow.getType() != TYPE_DOCK_DIVIDER
-                    && !a11yWindow.isPIPMenu())) {
-                return false;
-            }
-
-            // If the window is completely covered by other windows - ignore.
-            if (unaccountedSpace.quickReject(regionInScreen)) {
-                return false;
-            }
-
-            // Add windows of certain types not covered by modal windows.
-            if (isReportedWindowType(a11yWindow.getType())) {
-                return true;
-            }
-
-            return false;
-        }
-
-        private void updateUnaccountedSpace(AccessibilityWindow a11yWindow,
-                Region unaccountedSpace) {
-            if (a11yWindow.getType()
-                    != WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY) {
-                // Account for the space this window takes if the window
-                // is not an accessibility overlay which does not change
-                // the reported windows.
-                final Region touchableRegion = mTempRegion2;
-                a11yWindow.getTouchableRegionInScreen(touchableRegion);
-                unaccountedSpace.op(touchableRegion, unaccountedSpace,
-                        Region.Op.REVERSE_DIFFERENCE);
-            }
-        }
-
-        private static void addPopulatedWindowInfo(AccessibilityWindow a11yWindow,
-                Region regionInScreen, List<WindowInfo> out, Set<IBinder> tokenOut) {
-            final WindowInfo window = a11yWindow.getWindowInfo();
-            if (window.token == null) {
-                // The window was used in calculating visible windows but does not have an
-                // associated IWindow token, so exclude it from the list returned to accessibility.
-                return;
-            }
-            window.regionInScreen.set(regionInScreen);
-            window.layer = tokenOut.size();
-            out.add(window);
-            tokenOut.add(window.token);
-        }
-
-        private static boolean isReportedWindowType(int windowType) {
-            return (windowType != WindowManager.LayoutParams.TYPE_WALLPAPER
-                    && windowType != WindowManager.LayoutParams.TYPE_BOOT_PROGRESS
-                    && windowType != WindowManager.LayoutParams.TYPE_DISPLAY_OVERLAY
-                    && windowType != WindowManager.LayoutParams.TYPE_DRAG
-                    && windowType != WindowManager.LayoutParams.TYPE_INPUT_CONSUMER
-                    && windowType != WindowManager.LayoutParams.TYPE_POINTER
-                    && windowType != TYPE_MAGNIFICATION_OVERLAY
-                    && windowType != WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY
-                    && windowType != WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY
-                    && windowType != WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION);
-        }
-
-        // LINT.ThenChange(/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java)
-
         private WindowState getTopFocusWindow() {
             return mService.mRoot.getTopFocusedDisplayContent().mCurrentFocus;
         }
diff --git a/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java b/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java
index fd2a909..7fc11e6 100644
--- a/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java
+++ b/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java
@@ -724,8 +724,7 @@
             }
 
             // Compute system bar insets frame if needed.
-            if (com.android.server.accessibility.Flags.computeWindowChangesOnA11yV2()
-                    && windowState != null && instance.isUntouchableNavigationBar()) {
+            if (windowState != null && instance.isUntouchableNavigationBar()) {
                 final InsetsSourceProvider provider =
                         windowState.getControllableInsetProvider();
                 if (provider != null) {
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index f70dec1..ae55a1a 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -4575,10 +4575,22 @@
                 // at #postWindowRemoveCleanupLocked
                 return false;
             }
+
+            // Link the fixed rotation transform to this activity since we are transferring the
+            // starting window.
+            if (fromActivity.hasFixedRotationTransform()) {
+                mDisplayContent.handleTopActivityLaunchingInDifferentOrientation(this,
+                        false /* checkOpening */);
+            }
             // Do not transfer if the orientation doesn't match, redraw starting window while it is
             // on top will cause flicker.
-            if (fromActivity.getRequestedConfigurationOrientation()
-                    != getRequestedConfigurationOrientation()) {
+            final int fromOrientation = fromActivity.getConfiguration().orientation;
+            final int requestedOrientation = getRequestedConfigurationOrientation();
+            if (requestedOrientation == ORIENTATION_UNDEFINED) {
+                if (fromOrientation != getConfiguration().orientation) {
+                    return false;
+                }
+            } else if (fromOrientation != requestedOrientation) {
                 return false;
             }
             // In this case, the starting icon has already been displayed, so start
@@ -4592,13 +4604,6 @@
 
             final long origId = Binder.clearCallingIdentity();
             try {
-                // Link the fixed rotation transform to this activity since we are transferring the
-                // starting window.
-                if (fromActivity.hasFixedRotationTransform()) {
-                    mDisplayContent.handleTopActivityLaunchingInDifferentOrientation(this,
-                            false /* checkOpening */);
-                }
-
                 // Transfer the starting window over to the new token.
                 mStartingData = fromActivity.mStartingData;
                 mStartingSurface = fromActivity.mStartingSurface;
diff --git a/services/core/java/com/android/server/wm/AppCompatController.java b/services/core/java/com/android/server/wm/AppCompatController.java
index 145a376..203932d 100644
--- a/services/core/java/com/android/server/wm/AppCompatController.java
+++ b/services/core/java/com/android/server/wm/AppCompatController.java
@@ -76,6 +76,16 @@
         mAppCompatSizeCompatModePolicy = new AppCompatSizeCompatModePolicy(mActivityRecord,
                 mAppCompatOverrides);
         mAllowRestrictedResizability = AppCompatUtils.asLazy(() -> {
+            // Application level.
+            try {
+                if (packageManager.getProperty(PROPERTY_COMPAT_ALLOW_RESTRICTED_RESIZABILITY,
+                        mActivityRecord.packageName).getBoolean()) {
+                    return true;
+                }
+            } catch (PackageManager.NameNotFoundException e) {
+                // Fall through.
+            }
+            // Activity level.
             try {
                 return packageManager.getPropertyAsUser(
                         PROPERTY_COMPAT_ALLOW_RESTRICTED_RESIZABILITY,
diff --git a/services/core/java/com/android/server/wm/DesktopAppCompatAspectRatioPolicy.java b/services/core/java/com/android/server/wm/DesktopAppCompatAspectRatioPolicy.java
index c8cb621..43855aa 100644
--- a/services/core/java/com/android/server/wm/DesktopAppCompatAspectRatioPolicy.java
+++ b/services/core/java/com/android/server/wm/DesktopAppCompatAspectRatioPolicy.java
@@ -196,10 +196,11 @@
 
         if (!aspectRatioOverrides.shouldOverrideMinAspectRatio()
                 && !AppCompatCameraPolicy.shouldOverrideMinAspectRatioForCamera(mActivityRecord)) {
-            if (mActivityRecord.isUniversalResizeable()) {
+            final float minAspectRatio = info.getMinAspectRatio();
+            if (minAspectRatio == 0 || mActivityRecord.isUniversalResizeable()) {
                 return 0;
             }
-            return info.getMinAspectRatio();
+            return minAspectRatio;
         }
 
         if (info.isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY)
@@ -242,10 +243,11 @@
         if (mTransparentPolicy.isRunning()) {
             return mTransparentPolicy.getInheritedMaxAspectRatio();
         }
-        if (mActivityRecord.isUniversalResizeable()) {
+        final float maxAspectRatio = mActivityRecord.info.getMaxAspectRatio();
+        if (maxAspectRatio == 0 || mActivityRecord.isUniversalResizeable()) {
             return 0;
         }
-        return mActivityRecord.info.getMaxAspectRatio();
+        return maxAspectRatio;
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index e9e550e..9a33df1 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -5502,14 +5502,18 @@
             // Attach the SystemUiContext to this DisplayContent the get latest configuration.
             // Note that the SystemUiContext will be removed automatically if this DisplayContent
             // is detached.
-            final WindowProcessController wpc = mAtmService.getProcessController(
-                    getDisplayUiContext().getIApplicationThread());
-            mWmService.mWindowContextListenerController.registerWindowContainerListener(
-                    wpc, getDisplayUiContext().getWindowContextToken(), this,
-                    INVALID_WINDOW_TYPE, null /* options */);
+            registerSystemUiContext();
         }
     }
 
+    private void registerSystemUiContext() {
+        final WindowProcessController wpc = mAtmService.getProcessController(
+                getDisplayUiContext().getIApplicationThread());
+        mWmService.mWindowContextListenerController.registerWindowContainerListener(
+                wpc, getDisplayUiContext().getWindowContextToken(), this,
+                INVALID_WINDOW_TYPE, null /* options */);
+    }
+
     @Override
     void assignChildLayers(SurfaceControl.Transaction t) {
         assignRelativeLayerForIme(t, false /* forceUpdate */);
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index 4cf1fb4..df209ff 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -485,6 +485,9 @@
             if (isDefaultDisplay) {
                 updateOrientationListenerLw();
             }
+        } else if (mCompatPolicyForImmersiveApps != null
+                && mCompatPolicyForImmersiveApps.deferOrientationUpdate()) {
+            return false;
         }
         return updateRotationUnchecked(forceUpdate);
     }
diff --git a/services/core/java/com/android/server/wm/DisplayRotationImmersiveAppCompatPolicy.java b/services/core/java/com/android/server/wm/DisplayRotationImmersiveAppCompatPolicy.java
index 094434d..046ed61 100644
--- a/services/core/java/com/android/server/wm/DisplayRotationImmersiveAppCompatPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayRotationImmersiveAppCompatPolicy.java
@@ -17,10 +17,13 @@
 package com.android.server.wm;
 
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
 import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
 import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
 
+import static com.android.server.policy.WindowManagerPolicy.USER_ROTATION_FREE;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.res.Configuration.Orientation;
@@ -66,6 +69,37 @@
     }
 
     /**
+     * Returns {@code true} if the orientation update should be skipped and it will update when
+     * transition is done. This is to keep the orientation which was preserved by
+     * {@link #isRotationLockEnforced} from being changed by a transient launch (i.e. recents).
+     */
+    boolean deferOrientationUpdate() {
+        if (mDisplayRotation.getUserRotation() != USER_ROTATION_FREE
+                || mDisplayRotation.getLastOrientation() != SCREEN_ORIENTATION_UNSPECIFIED) {
+            return false;
+        }
+        final WindowOrientationListener orientationListener =
+                mDisplayRotation.getOrientationListener();
+        if (orientationListener == null
+                || orientationListener.getProposedRotation() == mDisplayRotation.getRotation()) {
+            return false;
+        }
+        // The above conditions mean that isRotationLockEnforced might have taken effect:
+        // Auto-rotation is enabled and the proposed rotation is not applied.
+        // Then the update should defer until the transition idle to avoid disturbing animation.
+        if (!mDisplayContent.mTransitionController.hasTransientLaunch(mDisplayContent)) {
+            return false;
+        }
+        mDisplayContent.mTransitionController.mStateValidators.add(() -> {
+            if (!isRotationLockEnforcedLocked(orientationListener.getProposedRotation())) {
+                mDisplayContent.mWmService.updateRotation(false /* alwaysSendConfiguration */,
+                        false /* forceRelayout */);
+            }
+        });
+        return true;
+    }
+
+    /**
      * Decides whether it is necessary to lock screen rotation, preventing auto rotation, based on
      * the top activity configuration and proposed screen rotation.
      *
diff --git a/services/core/java/com/android/server/wm/SafeActivityOptions.java b/services/core/java/com/android/server/wm/SafeActivityOptions.java
index 70b214c..88e5343 100644
--- a/services/core/java/com/android/server/wm/SafeActivityOptions.java
+++ b/services/core/java/com/android/server/wm/SafeActivityOptions.java
@@ -361,10 +361,13 @@
         }
 
         // If launched from bubble is specified, then ensure that the caller is system or sysui.
-        if (options.getLaunchedFromBubble() && !isSystemOrSystemUI(callingPid, callingUid)) {
+        if ((options.getLaunchedFromBubble() || options.getTaskAlwaysOnTop())
+                && !isSystemOrSystemUI(callingPid, callingUid)) {
             final String msg = "Permission Denial: starting " + getIntentString(intent)
                     + " from " + callerApp + " (pid=" + callingPid
-                    + ", uid=" + callingUid + ") with launchedFromBubble=true";
+                    + ", uid=" + callingUid + ") with"
+                    + (options.getLaunchedFromBubble() ? " launchedFromBubble=true" : "")
+                    + (options.getTaskAlwaysOnTop() ? " taskAlwaysOnTop=true" : "");
             Slog.w(TAG, msg);
             throw new SecurityException(msg);
         }
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index ce032b4..c77b1d9 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -46,7 +46,6 @@
 import android.view.Surface;
 import android.view.SurfaceControl;
 import android.view.SurfaceControlViewHost;
-import android.view.WindowInfo;
 import android.view.WindowManager.DisplayImePolicy;
 import android.view.inputmethod.ImeTracker;
 import android.window.ScreenCapture;
@@ -158,26 +157,8 @@
      * accessibility changed.
      */
     public interface WindowsForAccessibilityCallback {
-
         /**
-         * Called when the windows for accessibility changed. This is called if
-         * {@link com.android.server.accessibility.Flags.FLAG_COMPUTE_WINDOW_CHANGES_ON_A11Y_V2} is
-         * false.
-         *
-         * @param forceSend Send the windows for accessibility even if they haven't changed.
-         * @param topFocusedDisplayId The display Id which has the top focused window.
-         * @param topFocusedWindowToken The window token of top focused window.
-         * @param windows The windows for accessibility.
-         */
-        void onWindowsForAccessibilityChanged(boolean forceSend, int topFocusedDisplayId,
-                IBinder topFocusedWindowToken, @NonNull List<WindowInfo> windows);
-
-        /**
-         * Called when the windows for accessibility changed. This is called if
-         * {@link com.android.server.accessibility.Flags.FLAG_COMPUTE_WINDOW_CHANGES_ON_A11Y_V2} is
-         * true.
-         * TODO(b/322444245): Remove screenSize parameter by getting it from
-         *  DisplayManager#getDisplay(int).getRealSize() on the a11y side.
+         * Called when the windows for accessibility changed.
          *
          * @param forceSend Send the windows for accessibility even if they haven't changed.
          * @param topFocusedDisplayId The display Id which has the top focused window.
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 8268cae..63f29f6 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -3030,8 +3030,8 @@
 
                 mWindowContextListenerController.unregisterWindowContainerListener(clientToken);
 
-                final WindowToken token = wc.asWindowToken();
-                if (token != null && token.isFromClient()) {
+                final WindowToken token = wc != null ? wc.asWindowToken() : null;
+                if (token != null && token.isFromClient() && token.getDisplayContent() != null) {
                     removeWindowToken(token.token, token.getDisplayContent().getDisplayId());
                 }
             }
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index eaa3a37..4c0cee4 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -38,7 +38,6 @@
         "com_android_server_adb_AdbDebuggingManager.cpp",
         "com_android_server_am_BatteryStatsService.cpp",
         "com_android_server_biometrics_SurfaceToNativeHandleConverter.cpp",
-        "com_android_server_ConsumerIrService.cpp",
         "com_android_server_companion_virtual_InputController.cpp",
         "com_android_server_companion_virtual_VirtualDeviceImpl.cpp",
         "com_android_server_devicepolicy_CryptoTestHelper.cpp",
@@ -63,7 +62,6 @@
         "com_android_server_SystemServer.cpp",
         "com_android_server_tv_TvUinputBridge.cpp",
         "com_android_server_tv_TvInputHal.cpp",
-        "com_android_server_vr_VrManagerService.cpp",
         "com_android_server_UsbAlsaJackDetector.cpp",
         "com_android_server_UsbAlsaMidiDevice.cpp",
         "com_android_server_UsbDeviceManager.cpp",
@@ -75,14 +73,13 @@
         "com_android_server_am_LowMemDetector.cpp",
         "com_android_server_pm_PackageManagerShellCommandDataLoader.cpp",
         "com_android_server_sensor_SensorService.cpp",
-        "com_android_server_utils_LazyJniRegistrar.cpp",
         "com_android_server_wm_TaskFpsCallbackController.cpp",
         "onload.cpp",
         ":lib_cachedAppOptimizer_native",
         ":lib_freezer_native",
-        ":lib_gameManagerService_native",
         ":lib_oomConnection_native",
         ":lib_anrTimer_native",
+        ":lib_lazilyRegisteredServices_native",
     ],
 
     include_dirs: [
@@ -248,13 +245,6 @@
 }
 
 filegroup {
-    name: "lib_gameManagerService_native",
-    srcs: [
-        "com_android_server_app_GameManagerService.cpp",
-    ],
-}
-
-filegroup {
     name: "lib_oomConnection_native",
     srcs: ["com_android_server_am_OomConnection.cpp"],
 }
@@ -265,3 +255,13 @@
         "com_android_server_utils_AnrTimer.cpp",
     ],
 }
+
+filegroup {
+    name: "lib_lazilyRegisteredServices_native",
+    srcs: [
+        "com_android_server_ConsumerIrService.cpp",
+        "com_android_server_app_GameManagerService.cpp",
+        "com_android_server_utils_LazyJniRegistrar.cpp",
+        "com_android_server_vr_VrManagerService.cpp",
+    ],
+}
diff --git a/services/core/jni/com_android_server_utils_LazyJniRegistrar.cpp b/services/core/jni/com_android_server_utils_LazyJniRegistrar.cpp
index ad7781e..0c0f8b0 100644
--- a/services/core/jni/com_android_server_utils_LazyJniRegistrar.cpp
+++ b/services/core/jni/com_android_server_utils_LazyJniRegistrar.cpp
@@ -22,6 +22,7 @@
 
 // Forward declared per-class registration methods.
 int register_android_server_ConsumerIrService(JNIEnv* env);
+int register_android_server_app_GameManagerService(JNIEnv* env);
 int register_android_server_vr_VrManagerService(JNIEnv* env);
 
 namespace {
@@ -33,12 +34,17 @@
     register_android_server_ConsumerIrService(env);
 }
 
+void registerGameManagerService(JNIEnv* env, jclass) {
+    register_android_server_app_GameManagerService(env);
+}
+
 void registerVrManagerService(JNIEnv* env, jclass) {
     register_android_server_vr_VrManagerService(env);
 }
 
 static const JNINativeMethod sJniRegistrarMethods[] = {
         {"registerConsumerIrService", "()V", (void*)registerConsumerIrService},
+        {"registerGameManagerService", "()V", (void*)registerGameManagerService},
         {"registerVrManagerService", "()V", (void*)registerVrManagerService},
 };
 
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index c170ae9..df37ec3 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -65,7 +65,6 @@
 int register_android_server_sensor_SensorService(JavaVM* vm, JNIEnv* env);
 int register_android_server_companion_virtual_InputController(JNIEnv* env);
 int register_android_server_companion_virtual_VirtualDeviceImpl(JNIEnv* env);
-int register_android_server_app_GameManagerService(JNIEnv* env);
 int register_com_android_server_wm_TaskFpsCallbackController(JNIEnv* env);
 int register_com_android_server_display_DisplayControl(JNIEnv* env);
 int register_com_android_server_SystemClockTime(JNIEnv* env);
@@ -131,7 +130,6 @@
     register_android_server_sensor_SensorService(vm, env);
     register_android_server_companion_virtual_InputController(env);
     register_android_server_companion_virtual_VirtualDeviceImpl(env);
-    register_android_server_app_GameManagerService(env);
     register_com_android_server_wm_TaskFpsCallbackController(env);
     register_com_android_server_display_DisplayControl(env);
     register_com_android_server_SystemClockTime(env);
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
index 759976f..47e96d3 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
@@ -17,6 +17,7 @@
 package com.android.server.display;
 
 import static android.Manifest.permission.ADD_ALWAYS_UNLOCKED_DISPLAY;
+import static android.Manifest.permission.ADD_MIRROR_DISPLAY;
 import static android.Manifest.permission.ADD_TRUSTED_DISPLAY;
 import static android.Manifest.permission.CAPTURE_VIDEO_OUTPUT;
 import static android.Manifest.permission.CONTROL_DISPLAY_BRIGHTNESS;
@@ -122,6 +123,7 @@
 import android.os.SystemProperties;
 import android.os.UserManager;
 import android.os.test.FakePermissionEnforcer;
+import android.platform.test.annotations.EnableFlags;
 import android.platform.test.flag.junit.SetFlagsRule;
 import android.provider.Settings;
 import android.provider.Settings.SettingNotFoundException;
@@ -1388,6 +1390,7 @@
      * Tests that it's not allowed to create an auto-mirror virtual display without
      * CAPTURE_VIDEO_OUTPUT permission or a virtual device that can mirror displays
      */
+    @EnableFlags(android.companion.virtualdevice.flags.Flags.FLAG_ENABLE_LIMITED_VDM_ROLE)
     @Test
     public void createAutoMirrorDisplay_withoutPermissionOrAllowedVirtualDevice_throwsException()
             throws Exception {
@@ -1397,7 +1400,8 @@
         when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
         IVirtualDevice virtualDevice = mock(IVirtualDevice.class);
         when(virtualDevice.getDeviceId()).thenReturn(1);
-        when(virtualDevice.canCreateMirrorDisplays()).thenReturn(false);
+        when(mContext.checkCallingPermission(ADD_MIRROR_DISPLAY))
+                .thenReturn(PackageManager.PERMISSION_DENIED);
         when(mIVirtualDeviceManager.isValidVirtualDeviceId(1)).thenReturn(true);
         when(mContext.checkCallingPermission(CAPTURE_VIDEO_OUTPUT)).thenReturn(
                 PackageManager.PERMISSION_DENIED);
@@ -1428,7 +1432,8 @@
         when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
         IVirtualDevice virtualDevice = mock(IVirtualDevice.class);
         when(virtualDevice.getDeviceId()).thenReturn(1);
-        when(virtualDevice.canCreateMirrorDisplays()).thenReturn(true);
+        when(mContext.checkCallingPermission(ADD_MIRROR_DISPLAY))
+                .thenReturn(PackageManager.PERMISSION_GRANTED);
         when(mIVirtualDeviceManager.isValidVirtualDeviceId(1)).thenReturn(true);
 
         // Create an auto-mirror virtual display using a virtual device.
@@ -1461,7 +1466,8 @@
         when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
         IVirtualDevice virtualDevice = mock(IVirtualDevice.class);
         when(virtualDevice.getDeviceId()).thenReturn(1);
-        when(virtualDevice.canCreateMirrorDisplays()).thenReturn(true);
+        when(mContext.checkCallingPermission(ADD_MIRROR_DISPLAY))
+                .thenReturn(PackageManager.PERMISSION_GRANTED);
         when(mIVirtualDeviceManager.isValidVirtualDeviceId(1)).thenReturn(true);
 
         // Create an auto-mirror virtual display using a virtual device.
@@ -1528,7 +1534,8 @@
         when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
         IVirtualDevice virtualDevice = mock(IVirtualDevice.class);
         when(virtualDevice.getDeviceId()).thenReturn(1);
-        when(virtualDevice.canCreateMirrorDisplays()).thenReturn(true);
+        when(mContext.checkCallingPermission(ADD_MIRROR_DISPLAY))
+                .thenReturn(PackageManager.PERMISSION_GRANTED);
         when(mIVirtualDeviceManager.isValidVirtualDeviceId(1)).thenReturn(true);
         when(mContext.checkCallingPermission(ADD_ALWAYS_UNLOCKED_DISPLAY))
                 .thenReturn(PackageManager.PERMISSION_GRANTED);
@@ -1564,7 +1571,8 @@
         when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
         IVirtualDevice virtualDevice = mock(IVirtualDevice.class);
         when(virtualDevice.getDeviceId()).thenReturn(1);
-        when(virtualDevice.canCreateMirrorDisplays()).thenReturn(true);
+        when(mContext.checkCallingPermission(ADD_MIRROR_DISPLAY))
+                .thenReturn(PackageManager.PERMISSION_GRANTED);
         when(mIVirtualDeviceManager.isValidVirtualDeviceId(1)).thenReturn(true);
 
         // Create an auto-mirror virtual display using a virtual device.
diff --git a/services/tests/mockingservicestests/jni/Android.bp b/services/tests/mockingservicestests/jni/Android.bp
index 00543a8..94d4b95 100644
--- a/services/tests/mockingservicestests/jni/Android.bp
+++ b/services/tests/mockingservicestests/jni/Android.bp
@@ -22,8 +22,8 @@
     srcs: [
         ":lib_cachedAppOptimizer_native",
         ":lib_freezer_native",
-        ":lib_gameManagerService_native",
         ":lib_oomConnection_native",
+        ":lib_lazilyRegisteredServices_native",
         "onload.cpp",
     ],
 
@@ -54,6 +54,8 @@
         "android.hardware.graphics.bufferqueue@2.0",
         "android.hardware.graphics.common@1.2",
         "android.hardware.graphics.mapper@4.0",
+        "android.hardware.ir@1.0",
+        "android.hardware.vr@1.0",
         "android.hidl.token@1.0-utils",
     ],
 }
diff --git a/services/tests/mockingservicestests/jni/onload.cpp b/services/tests/mockingservicestests/jni/onload.cpp
index cb246d1..9b4c817 100644
--- a/services/tests/mockingservicestests/jni/onload.cpp
+++ b/services/tests/mockingservicestests/jni/onload.cpp
@@ -26,8 +26,8 @@
 namespace android {
 int register_android_server_am_CachedAppOptimizer(JNIEnv* env);
 int register_android_server_am_Freezer(JNIEnv* env);
-int register_android_server_app_GameManagerService(JNIEnv* env);
 int register_android_server_am_OomConnection(JNIEnv* env);
+int register_android_server_utils_LazyJniRegistrar(JNIEnv* env);
 };
 
 using namespace android;
@@ -44,7 +44,7 @@
     ALOG_ASSERT(env, "Could not retrieve the env!");
     register_android_server_am_CachedAppOptimizer(env);
     register_android_server_am_Freezer(env);
-    register_android_server_app_GameManagerService(env);
     register_android_server_am_OomConnection(env);
+    register_android_server_utils_LazyJniRegistrar(env);
     return JNI_VERSION_1_4;
 }
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 a9569b4..1efe470 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
@@ -105,6 +105,7 @@
 import android.os.Process;
 import android.os.SystemClock;
 import android.os.UserHandle;
+import android.platform.test.annotations.EnableFlags;
 import android.platform.test.annotations.Presubmit;
 import android.platform.test.flag.junit.SetFlagsRule;
 import android.util.ArrayMap;
@@ -3260,6 +3261,24 @@
                 "cch-empty");
     }
 
+    @SuppressWarnings("GuardedBy")
+    @Test
+    @EnableFlags(Flags.FLAG_FIX_APPLY_OOMADJ_ORDER)
+    public void testUpdateOomAdj_ApplyOomAdjInCorrectOrder() {
+        final int numberOfApps = 5;
+        final ProcessRecord[] apps = new ProcessRecord[numberOfApps];
+        for (int i = 0; i < numberOfApps; i++) {
+            apps[i] = spy(makeDefaultProcessRecord(MOCKAPP_PID + i, MOCKAPP_UID + i,
+                    MOCKAPP_PROCESSNAME + i, MOCKAPP_PACKAGENAME + i, true));
+        }
+        updateOomAdj(apps);
+        for (int i = 1; i < numberOfApps; i++) {
+            final int pre = mInjector.mSetOomAdjAppliedAt.get(apps[i - 1].mPid);
+            final int cur = mInjector.mSetOomAdjAppliedAt.get(apps[i].mPid);
+            assertTrue("setOomAdj is called in wrong order", pre < cur);
+        }
+    }
+
     private ProcessRecord makeDefaultProcessRecord(int pid, int uid, String processName,
             String packageName, boolean hasShownUi) {
         return new ProcessRecordBuilder(pid, uid, processName, packageName).setHasShownUi(
@@ -3589,9 +3608,16 @@
         long mTimeOffsetMillis = 0;
         private SparseIntArray mLastSetOomAdj = new SparseIntArray();
 
+        // A sequence number that increases every time setOomAdj is called
+        int mLastAppliedAt = 0;
+        // Holds the last sequence number setOomAdj is called for a pid
+        private SparseIntArray mSetOomAdjAppliedAt = new SparseIntArray();
+
         void reset() {
             mTimeOffsetMillis = 0;
             mLastSetOomAdj.clear();
+            mLastAppliedAt = 0;
+            mSetOomAdjAppliedAt.clear();
         }
 
         void jumpUptimeAheadTo(long uptimeMillis) {
@@ -3616,6 +3642,7 @@
                 final int pid = proc.getPid();
                 if (pid <= 0) continue;
                 mLastSetOomAdj.put(pid, proc.mState.getCurAdj());
+                mSetOomAdjAppliedAt.put(pid, mLastAppliedAt++);
             }
         }
 
@@ -3623,6 +3650,7 @@
         void setOomAdj(int pid, int uid, int adj) {
             if (pid <= 0) return;
             mLastSetOomAdj.put(pid, adj);
+            mSetOomAdjAppliedAt.put(pid, mLastAppliedAt++);
         }
 
         @Override
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/ApexManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/ApexManagerTest.java
index 769f071..405024c 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/ApexManagerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/ApexManagerTest.java
@@ -134,7 +134,7 @@
         mMockSystem.system().validateFinalState();
         mInstallPackageHelper = new InstallPackageHelper(mPmService, mock(AppDataHelper.class),
                 mock(RemovePackageHelper.class), mock(DeletePackageHelper.class),
-                mock(BroadcastHelper.class));
+                mock(BroadcastHelper.class), mock(InstallDependencyHelper.class));
     }
 
     @NonNull
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/InstallDependencyHelperTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/InstallDependencyHelperTest.java
index 20ac078..0304a74 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/InstallDependencyHelperTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/InstallDependencyHelperTest.java
@@ -79,12 +79,14 @@
     @Mock private SharedLibrariesImpl mSharedLibraries;
     @Mock private Context mContext;
     @Mock private Computer mComputer;
+    @Mock private PackageInstallerService mPackageInstallerService;
     private InstallDependencyHelper mInstallDependencyHelper;
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
-        mInstallDependencyHelper = new InstallDependencyHelper(mContext, mSharedLibraries);
+        mInstallDependencyHelper = new InstallDependencyHelper(mContext, mSharedLibraries,
+                mPackageInstallerService);
     }
 
     @Test
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
index 0a6edf1..b53dbc8 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
@@ -218,6 +218,8 @@
         val handler = TestHandler(null)
         val defaultAppProvider: DefaultAppProvider = mock()
         val backgroundHandler = TestHandler(null)
+        val packageInstallerService: PackageInstallerService = mock()
+        val installDependencyHelper: InstallDependencyHelper = mock()
         val updateOwnershipHelper: UpdateOwnershipHelper = mock()
     }
 
@@ -306,6 +308,7 @@
         whenever(mocks.injector.handler) { mocks.handler }
         whenever(mocks.injector.defaultAppProvider) { mocks.defaultAppProvider }
         whenever(mocks.injector.backgroundHandler) { mocks.backgroundHandler }
+        whenever(mocks.injector.packageInstallerService) { mocks.packageInstallerService }
         whenever(mocks.injector.updateOwnershipHelper) { mocks.updateOwnershipHelper }
         whenever(mocks.injector.getSystemService(AppOpsManager::class.java)) { mocks.appOpsManager }
         wheneverStatic { SystemConfig.getInstance() }.thenReturn(mocks.systemConfig)
@@ -332,6 +335,8 @@
             DEVICE_PROVISIONING_PACKAGE_NAME
         }
         whenever(mocks.apexManager.activeApexInfos).thenReturn(DEFAULT_ACTIVE_APEX_INFO_LIST)
+        whenever(mocks.packageInstallerService.installDependencyHelper).thenReturn(
+            mocks.installDependencyHelper)
         whenever(mocks.settings.packagesLocked).thenReturn(mSettingsMap)
         whenever(mocks.settings.internalVersion).thenReturn(DEFAULT_VERSION_INFO)
         whenever(mocks.settings.keySetManagerService).thenReturn(mocks.keySetManagerService)
diff --git a/services/tests/servicestests/jni/Android.bp b/services/tests/servicestests/jni/Android.bp
index 0a31037..e738c19 100644
--- a/services/tests/servicestests/jni/Android.bp
+++ b/services/tests/servicestests/jni/Android.bp
@@ -22,9 +22,9 @@
     srcs: [
         ":lib_cachedAppOptimizer_native",
         ":lib_freezer_native",
-        ":lib_gameManagerService_native",
         ":lib_oomConnection_native",
         ":lib_anrTimer_native",
+        ":lib_lazilyRegisteredServices_native",
         "onload.cpp",
     ],
 
@@ -55,6 +55,8 @@
         "android.hardware.graphics.bufferqueue@2.0",
         "android.hardware.graphics.common@1.2",
         "android.hardware.graphics.mapper@4.0",
+        "android.hardware.ir@1.0",
+        "android.hardware.vr@1.0",
         "android.hidl.token@1.0-utils",
     ],
 }
diff --git a/services/tests/servicestests/jni/onload.cpp b/services/tests/servicestests/jni/onload.cpp
index 25487c5..ad979c6 100644
--- a/services/tests/servicestests/jni/onload.cpp
+++ b/services/tests/servicestests/jni/onload.cpp
@@ -25,9 +25,9 @@
 
 namespace android {
 int register_android_server_am_CachedAppOptimizer(JNIEnv* env);
-int register_android_server_app_GameManagerService(JNIEnv* env);
 int register_android_server_am_OomConnection(JNIEnv* env);
 int register_android_server_utils_AnrTimer(JNIEnv *env);
+int register_android_server_utils_LazyJniRegistrar(JNIEnv* env);
 };
 
 using namespace android;
@@ -43,8 +43,8 @@
     }
     ALOG_ASSERT(env, "Could not retrieve the env!");
     register_android_server_am_CachedAppOptimizer(env);
-    register_android_server_app_GameManagerService(env);
     register_android_server_am_OomConnection(env);
     register_android_server_utils_AnrTimer(env);
+    register_android_server_utils_LazyJniRegistrar(env);
     return JNI_VERSION_1_4;
 }
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java
index 403930d..2ae31ad 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java
@@ -18,20 +18,24 @@
 
 import static com.android.server.accessibility.AbstractAccessibilityServiceConnection.DISPLAY_TYPE_DEFAULT;
 import static com.android.server.accessibility.AccessibilityWindowManagerTest.DisplayIdMatcher.displayId;
+import static com.android.server.accessibility.AccessibilityWindowManagerTest.EventWindowIdMatcher.eventWindowId;
 import static com.android.server.accessibility.AccessibilityWindowManagerTest.WindowChangesMatcher.a11yWindowChanges;
-import static com.android.server.accessibility.AccessibilityWindowManagerTest.WindowIdMatcher.a11yWindowId;
+import static com.android.server.accessibility.AccessibilityWindowManagerTest.WindowIdMatcher.windowId;
 
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertNotNull;
 import static junit.framework.Assert.assertNull;
 import static junit.framework.Assert.assertTrue;
 
+import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.allOf;
+import static org.hamcrest.Matchers.hasItem;
+import static org.hamcrest.Matchers.hasSize;
 import static org.hamcrest.Matchers.is;
 import static org.hamcrest.Matchers.not;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertThat;
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
@@ -42,14 +46,13 @@
 import static org.mockito.Mockito.when;
 
 import android.annotation.Nullable;
+import android.graphics.Point;
+import android.graphics.Rect;
 import android.graphics.Region;
 import android.os.IBinder;
 import android.os.LocaleList;
 import android.os.RemoteException;
 import android.os.UserHandle;
-import android.platform.test.annotations.RequiresFlagsDisabled;
-import android.platform.test.flag.junit.CheckFlagsRule;
-import android.platform.test.flag.junit.DeviceFlagsValueProvider;
 import android.util.SparseArray;
 import android.view.Display;
 import android.view.IWindow;
@@ -63,6 +66,7 @@
 
 import com.android.server.accessibility.AccessibilityWindowManager.RemoteAccessibilityConnection;
 import com.android.server.accessibility.test.MessageCapturingHandler;
+import com.android.server.wm.AccessibilityWindowsPopulator.AccessibilityWindow;
 import com.android.server.wm.WindowManagerInternal;
 import com.android.server.wm.WindowManagerInternal.WindowsForAccessibilityCallback;
 
@@ -70,7 +74,6 @@
 import org.hamcrest.TypeSafeMatcher;
 import org.junit.After;
 import org.junit.Before;
-import org.junit.Rule;
 import org.junit.Test;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
@@ -81,17 +84,9 @@
 import java.util.Arrays;
 import java.util.List;
 
-// This test verifies deprecated codepath. Probably changing this file means
-// AccessibilityWindowManagerWithAccessibilityWindowTest also needs to be updated.
-// LINT.IfChange
-
 /**
- * Tests for the AccessibilityWindowManager with Flags.FLAG_COMPUTE_WINDOW_CHANGES_ON_A11Y_V2
- * enabled.
- * TODO(b/322444245): Merge with AccessibilityWindowManagerWithAccessibilityWindowTest
- *  after completing the flag migration.
+ * Tests for the AccessibilityWindowManager.
  */
-@RequiresFlagsDisabled(Flags.FLAG_COMPUTE_WINDOW_CHANGES_ON_A11Y_V2)
 public class AccessibilityWindowManagerTest {
     private static final String PACKAGE_NAME = "com.android.server.accessibility";
     private static final boolean FORCE_SEND = true;
@@ -122,9 +117,8 @@
 
     // List of window token, mapping from windowId -> window token.
     private final SparseArray<IWindow> mA11yWindowTokens = new SparseArray<>();
-    // List of window info lists, mapping from displayId -> window info lists.
-    private final SparseArray<ArrayList<WindowInfo>> mWindowInfos =
-            new SparseArray<>();
+    // List of window info lists, mapping from displayId -> a11y window lists.
+    private final SparseArray<ArrayList<AccessibilityWindow>> mWindows = new SparseArray<>();
     // List of callback, mapping from displayId -> callback.
     private final SparseArray<WindowsForAccessibilityCallback> mCallbackOfWindows =
             new SparseArray<>();
@@ -134,6 +128,13 @@
 
     private final MessageCapturingHandler mHandler = new MessageCapturingHandler(null);
 
+    // This maps displayId -> next region offset.
+    // Touchable region must have un-occluded area so that it's exposed to a11y services.
+    // This offset can be used as left and top of new region so that top-left of each region are
+    // kept visible.
+    // It's expected to be incremented by some amount everytime the value is used.
+    private final SparseArray<Integer> mNextRegionOffsets = new SparseArray<>();
+
     @Mock private WindowManagerInternal mMockWindowManagerInternal;
     @Mock private AccessibilityWindowManager.AccessibilityEventSender mMockA11yEventSender;
     @Mock private AccessibilitySecurityPolicy mMockA11ySecurityPolicy;
@@ -144,9 +145,6 @@
     @Mock private IBinder mMockEmbeddedToken;
     @Mock private IBinder mMockInvalidToken;
 
-    @Rule
-    public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
-
     @Before
     public void setUp() throws RemoteException {
         MockitoAnnotations.initMocks(this);
@@ -159,7 +157,7 @@
                 anyString(), anyInt(), anyInt(), anyInt())).thenReturn(PACKAGE_NAME);
 
         doAnswer((invocation) -> {
-            onWindowsForAccessibilityChanged(invocation.getArgument(0), false);
+            onAccessibilityWindowsChanged(invocation.getArgument(0), false);
             return null;
         }).when(mMockWindowManagerInternal).computeWindowsForAccessibility(anyInt());
 
@@ -173,7 +171,7 @@
         // as top focused display before each testing starts.
         startTrackingPerDisplay(Display.DEFAULT_DISPLAY);
 
-        // AccessibilityEventSender is invoked during onWindowsForAccessibilityChanged.
+        // AccessibilityEventSender is invoked during onAccessibilityWindowsChanged.
         // Resets it for mockito verify of further test case.
         Mockito.reset(mMockA11yEventSender);
 
@@ -237,19 +235,18 @@
     @Test
     public void onWindowsChanged_duringTouchInteractAndFocusChange_shouldChangeActiveWindow() {
         final int activeWindowId = mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID);
-        WindowInfo focusedWindowInfo =
-                mWindowInfos.get(Display.DEFAULT_DISPLAY).get(DEFAULT_FOCUSED_INDEX);
+        final WindowInfo focusedWindowInfo =
+                mWindows.get(Display.DEFAULT_DISPLAY).get(DEFAULT_FOCUSED_INDEX).getWindowInfo();
         assertEquals(activeWindowId, mA11yWindowManager.findWindowIdLocked(
                 USER_SYSTEM_ID, focusedWindowInfo.token));
 
         focusedWindowInfo.focused = false;
-        focusedWindowInfo =
-                mWindowInfos.get(Display.DEFAULT_DISPLAY).get(DEFAULT_FOCUSED_INDEX + 1);
-        focusedWindowInfo.focused = true;
+        mWindows.get(Display.DEFAULT_DISPLAY).get(
+                DEFAULT_FOCUSED_INDEX + 1).getWindowInfo().focused = true;
 
         mA11yWindowManager.onTouchInteractionStart();
         setTopFocusedWindowAndDisplay(Display.DEFAULT_DISPLAY, DEFAULT_FOCUSED_INDEX + 1);
-        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
 
         assertNotEquals(activeWindowId, mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID));
     }
@@ -273,7 +270,7 @@
         changeFocusedWindowOnDisplayPerDisplayFocusConfig(SECONDARY_DISPLAY_ID,
                 DEFAULT_FOCUSED_INDEX + 1, Display.DEFAULT_DISPLAY, DEFAULT_FOCUSED_INDEX);
 
-        onWindowsForAccessibilityChanged(SECONDARY_DISPLAY_ID, SEND_ON_WINDOW_CHANGES);
+        onAccessibilityWindowsChanged(SECONDARY_DISPLAY_ID, SEND_ON_WINDOW_CHANGES);
         // The active window should not be changed.
         assertEquals(activeWindowId, mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID));
         // The top focused window should not be changed.
@@ -301,8 +298,8 @@
         changeFocusedWindowOnDisplayPerDisplayFocusConfig(SECONDARY_DISPLAY_ID,
                 DEFAULT_FOCUSED_INDEX, Display.DEFAULT_DISPLAY, DEFAULT_FOCUSED_INDEX);
 
-        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
-        onWindowsForAccessibilityChanged(SECONDARY_DISPLAY_ID, SEND_ON_WINDOW_CHANGES);
+        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+        onAccessibilityWindowsChanged(SECONDARY_DISPLAY_ID, SEND_ON_WINDOW_CHANGES);
         // The active window should be changed.
         assertNotEquals(activeWindowId, mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID));
         // The top focused window should be changed.
@@ -312,53 +309,181 @@
 
     @Test
     public void onWindowsChanged_shouldReportCorrectLayer() {
-        // AccessibilityWindowManager#onWindowsForAccessibilityChanged already invoked in setup.
+        // AccessibilityWindowManager#onAccessibilityWindowsChanged already invoked in setup.
         List<AccessibilityWindowInfo> a11yWindows =
                 mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
         for (int i = 0; i < a11yWindows.size(); i++) {
             final AccessibilityWindowInfo a11yWindow = a11yWindows.get(i);
-            final WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(i);
-            assertThat(mWindowInfos.get(Display.DEFAULT_DISPLAY).size() - windowInfo.layer - 1,
+            assertThat(mWindows.get(Display.DEFAULT_DISPLAY).size() - i - 1,
                     is(a11yWindow.getLayer()));
         }
     }
 
     @Test
     public void onWindowsChanged_shouldReportCorrectOrder() {
-        // AccessibilityWindowManager#onWindowsForAccessibilityChanged already invoked in setup.
+        // AccessibilityWindowManager#onAccessibilityWindowsChanged already invoked in setup.
         List<AccessibilityWindowInfo> a11yWindows =
                 mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
         for (int i = 0; i < a11yWindows.size(); i++) {
             final AccessibilityWindowInfo a11yWindow = a11yWindows.get(i);
             final IBinder windowToken = mA11yWindowManager
                     .getWindowTokenForUserAndWindowIdLocked(USER_SYSTEM_ID, a11yWindow.getId());
-            final WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(i);
+            final WindowInfo windowInfo = mWindows.get(Display.DEFAULT_DISPLAY)
+                    .get(i).getWindowInfo();
             assertThat(windowToken, is(windowInfo.token));
         }
     }
 
     @Test
-    public void onWindowsChangedAndForceSend_shouldUpdateWindows() {
-        final WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0);
-        final int correctLayer =
-                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY).get(0).getLayer();
-        windowInfo.layer += 1;
+    public void onWindowsChanged_shouldNotReportNonTouchableWindow() {
+        final AccessibilityWindow window = mWindows.get(Display.DEFAULT_DISPLAY).get(0);
+        when(window.isTouchable()).thenReturn(false);
+        final int windowId = mA11yWindowManager.findWindowIdLocked(
+                USER_SYSTEM_ID, window.getWindowInfo().token);
 
-        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, FORCE_SEND);
-        assertNotEquals(correctLayer,
-                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY).get(0).getLayer());
+        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+
+        final List<AccessibilityWindowInfo> a11yWindows =
+                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
+        assertThat(a11yWindows, not(hasItem(windowId(windowId))));
     }
 
     @Test
-    public void onWindowsChangedNoForceSend_layerChanged_shouldNotUpdateWindows() {
-        final WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0);
-        final int correctLayer =
-                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY).get(0).getLayer();
-        windowInfo.layer += 1;
+    public void onWindowsChanged_shouldReportFocusedNonTouchableWindow() {
+        final AccessibilityWindow window = mWindows.get(Display.DEFAULT_DISPLAY).get(
+                DEFAULT_FOCUSED_INDEX);
+        when(window.isTouchable()).thenReturn(false);
+        final int windowId = mA11yWindowManager.findWindowIdLocked(
+                USER_SYSTEM_ID, window.getWindowInfo().token);
 
-        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
-        assertEquals(correctLayer,
-                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY).get(0).getLayer());
+        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+
+        final List<AccessibilityWindowInfo> a11yWindows =
+                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
+        assertThat(a11yWindows, hasItem(windowId(windowId)));
+    }
+
+    @Test
+    public void onWindowsChanged_trustedFocusedNonTouchableWindow_shouldNotHideWindowsBelow() {
+        // Make the focused trusted un-touchable window fullscreen.
+        final AccessibilityWindow window = mWindows.get(Display.DEFAULT_DISPLAY).get(
+                DEFAULT_FOCUSED_INDEX);
+        setRegionForMockAccessibilityWindow(window, new Region(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT));
+        when(window.isTouchable()).thenReturn(false);
+        when(window.isTrustedOverlay()).thenReturn(true);
+
+        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+
+        final List<AccessibilityWindowInfo> a11yWindows =
+                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
+        assertThat(a11yWindows, hasSize(NUM_OF_WINDOWS));
+    }
+
+    @Test
+    public void onWindowsChanged_accessibilityOverlay_shouldNotHideWindowsBelow() {
+        // Make the a11y overlay window fullscreen.
+        final AccessibilityWindow window = mWindows.get(Display.DEFAULT_DISPLAY).get(0);
+        setRegionForMockAccessibilityWindow(window, new Region(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT));
+        when(window.getType()).thenReturn(WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY);
+
+        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+
+        final List<AccessibilityWindowInfo> a11yWindows =
+                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
+        assertThat(a11yWindows, hasSize(NUM_OF_WINDOWS));
+    }
+
+    @Test
+    public void onWindowsChanged_shouldReportFocusedWindowEvenIfOccluded() {
+        // Make the front window fullscreen.
+        final AccessibilityWindow frontWindow = mWindows.get(Display.DEFAULT_DISPLAY).get(0);
+        setRegionForMockAccessibilityWindow(frontWindow,
+                new Region(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT));
+        final int frontWindowId = mA11yWindowManager.findWindowIdLocked(
+                USER_SYSTEM_ID, frontWindow.getWindowInfo().token);
+
+        final AccessibilityWindow focusedWindow = mWindows.get(Display.DEFAULT_DISPLAY).get(
+                DEFAULT_FOCUSED_INDEX);
+        final int focusedWindowId = mA11yWindowManager.findWindowIdLocked(
+                USER_SYSTEM_ID, focusedWindow.getWindowInfo().token);
+
+        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+
+        final List<AccessibilityWindowInfo> a11yWindows =
+                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
+        assertThat(a11yWindows, hasSize(2));
+        assertThat(a11yWindows.get(0), windowId(frontWindowId));
+        assertThat(a11yWindows.get(1), windowId(focusedWindowId));
+    }
+
+    @Test
+    public void onWindowsChanged_embeddedWindows_shouldOnlyReportHost() throws RemoteException {
+        final Rect embeddingBounds = new Rect(0, 0, 200, 100);
+
+        // The embedded window comes front of the host window.
+        final IBinder embeddedWindowLeashToken = Mockito.mock(IBinder.class);
+        final int embeddedWindowId = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY,
+                false, embeddedWindowLeashToken, USER_SYSTEM_ID);
+        final AccessibilityWindow embeddedWindow = createMockAccessibilityWindow(
+                mA11yWindowTokens.get(embeddedWindowId), Display.DEFAULT_DISPLAY);
+        setRegionForMockAccessibilityWindow(embeddedWindow, new Region(embeddingBounds));
+        mWindows.get(Display.DEFAULT_DISPLAY).set(0, embeddedWindow);
+
+        final IBinder hostWindowLeashToken = Mockito.mock(IBinder.class);
+        final int hostWindowId = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY,
+                false, hostWindowLeashToken, USER_SYSTEM_ID);
+        final AccessibilityWindow hostWindow = createMockAccessibilityWindow(
+                mA11yWindowTokens.get(hostWindowId), Display.DEFAULT_DISPLAY);
+        setRegionForMockAccessibilityWindow(hostWindow, new Region(embeddingBounds));
+        mWindows.get(Display.DEFAULT_DISPLAY).set(1, hostWindow);
+
+        mA11yWindowManager.associateEmbeddedHierarchyLocked(
+                hostWindowLeashToken, embeddedWindowLeashToken);
+
+        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+
+        final List<AccessibilityWindowInfo> a11yWindows =
+                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
+        assertThat(a11yWindows, not(hasItem(windowId(embeddedWindowId))));
+        assertThat(a11yWindows.get(0), windowId(hostWindowId));
+        final Rect bounds = new Rect();
+        a11yWindows.get(0).getBoundsInScreen(bounds);
+        assertEquals(bounds, embeddingBounds);
+    }
+
+    @Test
+    public void onWindowsChanged_shouldNotReportfullyOccludedWindow() {
+        final AccessibilityWindow frontWindow = mWindows.get(Display.DEFAULT_DISPLAY).get(0);
+        setRegionForMockAccessibilityWindow(frontWindow, new Region(100, 100, 300, 300));
+        final int frontWindowId = mA11yWindowManager.findWindowIdLocked(
+                USER_SYSTEM_ID, frontWindow.getWindowInfo().token);
+
+        // index 1 is focused. Let's use the next one for this test.
+        final AccessibilityWindow occludedWindow = mWindows.get(Display.DEFAULT_DISPLAY).get(2);
+        setRegionForMockAccessibilityWindow(occludedWindow, new Region(150, 150, 250, 250));
+        final int occludedWindowId = mA11yWindowManager.findWindowIdLocked(
+                USER_SYSTEM_ID, occludedWindow.getWindowInfo().token);
+
+        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+
+        final List<AccessibilityWindowInfo> a11yWindows =
+                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
+        assertThat(a11yWindows, hasItem(windowId(frontWindowId)));
+        assertThat(a11yWindows, not(hasItem(windowId(occludedWindowId))));
+    }
+
+    @Test
+    public void onWindowsChangedAndForceSend_shouldUpdateWindows() {
+        assertNotEquals("new title",
+                toString(mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY)
+                        .get(0).getTitle()));
+
+        mWindows.get(Display.DEFAULT_DISPLAY).get(0).getWindowInfo().title = "new title";
+
+        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, FORCE_SEND);
+        assertEquals("new title",
+                toString(mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY)
+                        .get(0).getTitle()));
     }
 
     @Test
@@ -368,14 +493,10 @@
                 mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY).get(0);
         final IWindow token = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY,
                 true, USER_SYSTEM_ID);
-        final WindowInfo windowInfo = WindowInfo.obtain();
-        windowInfo.type = AccessibilityWindowInfo.TYPE_APPLICATION;
-        windowInfo.token = token.asBinder();
-        windowInfo.layer = 0;
-        windowInfo.regionInScreen.set(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
-        mWindowInfos.get(Display.DEFAULT_DISPLAY).set(0, windowInfo);
+        mWindows.get(Display.DEFAULT_DISPLAY).set(0,
+                createMockAccessibilityWindow(token, Display.DEFAULT_DISPLAY));
 
-        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
         assertNotEquals(oldWindow,
                 mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY).get(0));
     }
@@ -383,12 +504,12 @@
     @Test
     public void onWindowsChangedNoForceSend_focusChanged_shouldUpdateWindows() {
         final WindowInfo focusedWindowInfo =
-                mWindowInfos.get(Display.DEFAULT_DISPLAY).get(DEFAULT_FOCUSED_INDEX);
-        final WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0);
+                mWindows.get(Display.DEFAULT_DISPLAY).get(DEFAULT_FOCUSED_INDEX).getWindowInfo();
+        final WindowInfo windowInfo = mWindows.get(Display.DEFAULT_DISPLAY).get(0).getWindowInfo();
         focusedWindowInfo.focused = false;
         windowInfo.focused = true;
 
-        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
         assertTrue(mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY).get(0)
                 .isFocused());
     }
@@ -497,15 +618,18 @@
     @Test
     public void computePartialInteractiveRegionForWindow_wholeVisible_returnWholeRegion() {
         // Updates top 2 z-order WindowInfo are whole visible.
-        WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0);
-        windowInfo.regionInScreen.set(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT / 2);
-        windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(1);
-        windowInfo.regionInScreen.set(0, SCREEN_HEIGHT / 2,
-                SCREEN_WIDTH, SCREEN_HEIGHT);
-        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+        final AccessibilityWindow firstWindow = mWindows.get(Display.DEFAULT_DISPLAY).get(0);
+        setRegionForMockAccessibilityWindow(firstWindow,
+                new Region(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT / 2));
+        final AccessibilityWindow secondWindow = mWindows.get(Display.DEFAULT_DISPLAY).get(1);
+        setRegionForMockAccessibilityWindow(secondWindow,
+                new Region(0, SCREEN_HEIGHT / 2, SCREEN_WIDTH, SCREEN_HEIGHT));
+
+        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
 
         final List<AccessibilityWindowInfo> a11yWindows =
                 mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
+        assertThat(a11yWindows, hasSize(2));
         final Region outBounds = new Region();
         int windowId = a11yWindows.get(0).getId();
 
@@ -523,12 +647,17 @@
     @Test
     public void computePartialInteractiveRegionForWindow_halfVisible_returnHalfRegion() {
         // Updates z-order #1 WindowInfo is half visible.
-        WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0);
-        windowInfo.regionInScreen.set(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT / 2);
+        final AccessibilityWindow firstWindow = mWindows.get(Display.DEFAULT_DISPLAY).get(0);
+        setRegionForMockAccessibilityWindow(firstWindow,
+                new Region(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT / 2));
+        final AccessibilityWindow secondWindow = mWindows.get(Display.DEFAULT_DISPLAY).get(1);
+        setRegionForMockAccessibilityWindow(secondWindow,
+                new Region(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT));
 
-        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
         final List<AccessibilityWindowInfo> a11yWindows =
                 mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
+        assertThat(a11yWindows, hasSize(2));
         final Region outBounds = new Region();
         int windowId = a11yWindows.get(1).getId();
 
@@ -539,9 +668,17 @@
 
     @Test
     public void computePartialInteractiveRegionForWindow_notVisible_returnEmptyRegion() {
-        // Since z-order #0 WindowInfo is full screen, z-order #1 WindowInfo should be invisible.
+        // z-order #0 WindowInfo is full screen, z-order #1 WindowInfo should be invisible.
+        final AccessibilityWindow firstWindow = mWindows.get(Display.DEFAULT_DISPLAY).get(0);
+        setRegionForMockAccessibilityWindow(firstWindow,
+                new Region(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT));
+
+        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+
         final List<AccessibilityWindowInfo> a11yWindows =
                 mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
+        // Note that the second window is also exposed even if region is empty because it's focused.
+        assertThat(a11yWindows, hasSize(2));
         final Region outBounds = new Region();
         int windowId = a11yWindows.get(1).getId();
 
@@ -552,16 +689,21 @@
     @Test
     public void computePartialInteractiveRegionForWindow_partialVisible_returnVisibleRegion() {
         // Updates z-order #0 WindowInfo to have two interact-able areas.
-        Region region = new Region(0, 0, SCREEN_WIDTH, 200);
+        final Region region = new Region(0, 0, SCREEN_WIDTH, 200);
         region.op(0, SCREEN_HEIGHT - 200, SCREEN_WIDTH, SCREEN_HEIGHT, Region.Op.UNION);
-        WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0);
-        windowInfo.regionInScreen.set(region);
-        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+        final AccessibilityWindow firstWindow = mWindows.get(Display.DEFAULT_DISPLAY).get(0);
+        setRegionForMockAccessibilityWindow(firstWindow, region);
+        final AccessibilityWindow secondWindow = mWindows.get(Display.DEFAULT_DISPLAY).get(1);
+        setRegionForMockAccessibilityWindow(secondWindow,
+                new Region(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT));
+
+        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
 
         final List<AccessibilityWindowInfo> a11yWindows =
                 mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
+        assertThat(a11yWindows, hasSize(2));
         final Region outBounds = new Region();
-        int windowId = a11yWindows.get(1).getId();
+        final int windowId = a11yWindows.get(1).getId();
 
         mA11yWindowManager.computePartialInteractiveRegionForWindowLocked(windowId, outBounds);
         assertFalse(outBounds.getBounds().isEmpty());
@@ -572,7 +714,8 @@
     @Test
     public void updateActiveAndA11yFocusedWindow_windowStateChangedEvent_noTracking_shouldUpdate() {
         final IBinder eventWindowToken =
-                mWindowInfos.get(Display.DEFAULT_DISPLAY).get(DEFAULT_FOCUSED_INDEX + 1).token;
+                mWindows.get(Display.DEFAULT_DISPLAY)
+                        .get(DEFAULT_FOCUSED_INDEX + 1).getWindowInfo().token;
         final int eventWindowId = mA11yWindowManager.findWindowIdLocked(
                 USER_SYSTEM_ID, eventWindowToken);
         when(mMockWindowManagerInternal.getFocusedWindowTokenFromWindowStates())
@@ -611,11 +754,11 @@
                 .sendAccessibilityEventForCurrentUserLocked(captor.capture());
         assertThat(captor.getAllValues().get(0),
                 allOf(displayId(Display.DEFAULT_DISPLAY),
-                        a11yWindowId(currentActiveWindowId),
+                        eventWindowId(currentActiveWindowId),
                         a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_ACTIVE)));
         assertThat(captor.getAllValues().get(1),
                 allOf(displayId(Display.DEFAULT_DISPLAY),
-                        a11yWindowId(eventWindowId),
+                        eventWindowId(eventWindowId),
                         a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_ACTIVE)));
     }
 
@@ -641,7 +784,7 @@
                 .sendAccessibilityEventForCurrentUserLocked(captor.capture());
         assertThat(captor.getAllValues().get(0),
                 allOf(displayId(Display.DEFAULT_DISPLAY),
-                        a11yWindowId(eventWindowId),
+                        eventWindowId(eventWindowId),
                         a11yWindowChanges(
                                 AccessibilityEvent.WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED)));
     }
@@ -690,12 +833,12 @@
                 .sendAccessibilityEventForCurrentUserLocked(captor.capture());
         assertThat(captor.getAllValues().get(0),
                 allOf(displayId(initialDisplayId),
-                        a11yWindowId(initialWindowId),
+                        eventWindowId(initialWindowId),
                         a11yWindowChanges(
                                 AccessibilityEvent.WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED)));
         assertThat(captor.getAllValues().get(1),
                 allOf(displayId(eventDisplayId),
-                        a11yWindowId(eventWindowId),
+                        eventWindowId(eventWindowId),
                         a11yWindowChanges(
                                 AccessibilityEvent.WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED)));
     }
@@ -722,7 +865,7 @@
                 AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED,
                 noUse);
         assertThat(mA11yWindowManager.getFocusedWindowId(
-                AccessibilityNodeInfo.FOCUS_ACCESSIBILITY),
+                        AccessibilityNodeInfo.FOCUS_ACCESSIBILITY),
                 is(AccessibilityWindowInfo.UNDEFINED_WINDOW_ID));
     }
 
@@ -751,11 +894,11 @@
                 .sendAccessibilityEventForCurrentUserLocked(captor.capture());
         assertThat(captor.getAllValues().get(0),
                 allOf(displayId(Display.DEFAULT_DISPLAY),
-                        a11yWindowId(eventWindowId),
+                        eventWindowId(eventWindowId),
                         a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_ACTIVE)));
         assertThat(captor.getAllValues().get(1),
                 allOf(displayId(Display.DEFAULT_DISPLAY),
-                        a11yWindowId(currentActiveWindowId),
+                        eventWindowId(currentActiveWindowId),
                         a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_ACTIVE)));
     }
 
@@ -763,7 +906,8 @@
     public void onTouchInteractionEnd_noServiceInteractiveWindow_shouldClearA11yFocus()
             throws RemoteException {
         final IBinder defaultFocusWinToken =
-                mWindowInfos.get(Display.DEFAULT_DISPLAY).get(DEFAULT_FOCUSED_INDEX).token;
+                mWindows.get(Display.DEFAULT_DISPLAY).get(
+                        DEFAULT_FOCUSED_INDEX).getWindowInfo().token;
         final int defaultFocusWindowId = mA11yWindowManager.findWindowIdLocked(
                 USER_SYSTEM_ID, defaultFocusWinToken);
         when(mMockWindowManagerInternal.getFocusedWindowTokenFromWindowStates())
@@ -808,8 +952,8 @@
     @Test
     public void getPictureInPictureWindow_shouldNotNull() {
         assertNull(mA11yWindowManager.getPictureInPictureWindowLocked());
-        mWindowInfos.get(Display.DEFAULT_DISPLAY).get(1).inPictureInPicture = true;
-        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+        mWindows.get(Display.DEFAULT_DISPLAY).get(1).getWindowInfo().inPictureInPicture = true;
+        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
 
         assertNotNull(mA11yWindowManager.getPictureInPictureWindowLocked());
     }
@@ -823,8 +967,9 @@
         final IAccessibilityInteractionConnection mockRemoteConnection =
                 mA11yWindowManager.getConnectionLocked(
                         USER_SYSTEM_ID, outsideWindowId).getRemote();
-        mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0).hasFlagWatchOutsideTouch = true;
-        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+        mWindows.get(Display.DEFAULT_DISPLAY).get(0).getWindowInfo().hasFlagWatchOutsideTouch =
+                true;
+        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
 
         mA11yWindowManager.notifyOutsideTouch(USER_SYSTEM_ID, targetWindowId);
         verify(mockRemoteConnection).notifyOutsideTouch();
@@ -942,18 +1087,14 @@
 
     @Test
     public void sendAccessibilityEventOnWindowRemoval() {
-        final ArrayList<WindowInfo> infos = mWindowInfos.get(Display.DEFAULT_DISPLAY);
+        final ArrayList<AccessibilityWindow> windows = mWindows.get(Display.DEFAULT_DISPLAY);
 
         // Removing index 0 because it's not focused, and avoids unnecessary layer change.
         final int windowId =
                 getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, 0);
-        infos.remove(0);
-        for (WindowInfo info : infos) {
-            // Adjust layer number because it should start from 0.
-            info.layer--;
-        }
+        windows.remove(0);
 
-        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, FORCE_SEND);
+        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, FORCE_SEND);
 
         final ArgumentCaptor<AccessibilityEvent> captor =
                 ArgumentCaptor.forClass(AccessibilityEvent.class);
@@ -961,27 +1102,21 @@
                 .sendAccessibilityEventForCurrentUserLocked(captor.capture());
         assertThat(captor.getAllValues().get(0),
                 allOf(displayId(Display.DEFAULT_DISPLAY),
-                        a11yWindowId(windowId),
+                        eventWindowId(windowId),
                         a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_REMOVED)));
     }
 
     @Test
     public void sendAccessibilityEventOnWindowAddition() throws RemoteException {
-        final ArrayList<WindowInfo> infos = mWindowInfos.get(Display.DEFAULT_DISPLAY);
-
-        for (WindowInfo info : infos) {
-            // Adjust layer number because new window will have 0 so that layer number in
-            // A11yWindowInfo in window won't be changed.
-            info.layer++;
-        }
+        final ArrayList<AccessibilityWindow> windows = mWindows.get(Display.DEFAULT_DISPLAY);
 
         final IWindow token = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY,
                 false, USER_SYSTEM_ID);
-        addWindowInfo(infos, token, 0);
-        final int windowId =
-                getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, infos.size() - 1);
+        // Adding window to the front so that other windows' layer won't change.
+        windows.add(0, createMockAccessibilityWindow(token, Display.DEFAULT_DISPLAY));
+        final int windowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, 0);
 
-        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, FORCE_SEND);
+        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, FORCE_SEND);
 
         final ArgumentCaptor<AccessibilityEvent> captor =
                 ArgumentCaptor.forClass(AccessibilityEvent.class);
@@ -989,17 +1124,17 @@
                 .sendAccessibilityEventForCurrentUserLocked(captor.capture());
         assertThat(captor.getAllValues().get(0),
                 allOf(displayId(Display.DEFAULT_DISPLAY),
-                        a11yWindowId(windowId),
+                        eventWindowId(windowId),
                         a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_ADDED)));
     }
 
     @Test
     public void sendAccessibilityEventOnWindowChange() {
-        final ArrayList<WindowInfo> infos = mWindowInfos.get(Display.DEFAULT_DISPLAY);
-        infos.get(0).title = "new title";
+        final ArrayList<AccessibilityWindow> windows = mWindows.get(Display.DEFAULT_DISPLAY);
+        windows.get(0).getWindowInfo().title = "new title";
         final int windowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, 0);
 
-        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, FORCE_SEND);
+        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, FORCE_SEND);
 
         final ArgumentCaptor<AccessibilityEvent> captor =
                 ArgumentCaptor.forClass(AccessibilityEvent.class);
@@ -1007,7 +1142,7 @@
                 .sendAccessibilityEventForCurrentUserLocked(captor.capture());
         assertThat(captor.getAllValues().get(0),
                 allOf(displayId(Display.DEFAULT_DISPLAY),
-                        a11yWindowId(windowId),
+                        eventWindowId(windowId),
                         a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_TITLE)));
     }
 
@@ -1017,48 +1152,47 @@
     }
 
     private void startTrackingPerDisplay(int displayId) throws RemoteException {
-        ArrayList<WindowInfo> windowInfosForDisplay = new ArrayList<>();
+        ArrayList<AccessibilityWindow> windowsForDisplay = new ArrayList<>();
         // Adds RemoteAccessibilityConnection into AccessibilityWindowManager, and copy
         // mock window token into mA11yWindowTokens. Also, preparing WindowInfo mWindowInfos
         // for the test.
-        int layer = 0;
         for (int i = 0; i < NUM_GLOBAL_WINDOWS; i++) {
             final IWindow token = addAccessibilityInteractionConnection(displayId,
                     true, USER_SYSTEM_ID);
-            addWindowInfo(windowInfosForDisplay, token, layer++);
+            windowsForDisplay.add(createMockAccessibilityWindow(token, displayId));
 
         }
         for (int i = 0; i < NUM_APP_WINDOWS; i++) {
             final IWindow token = addAccessibilityInteractionConnection(displayId,
                     false, USER_SYSTEM_ID);
-            addWindowInfo(windowInfosForDisplay, token, layer++);
+            windowsForDisplay.add(createMockAccessibilityWindow(token, displayId));
         }
         // Sets up current focused window of display.
         // Each display has its own current focused window if config_perDisplayFocusEnabled is true.
         // Otherwise only default display needs to current focused window.
         if (mSupportPerDisplayFocus || displayId == Display.DEFAULT_DISPLAY) {
-            windowInfosForDisplay.get(DEFAULT_FOCUSED_INDEX).focused = true;
+            windowsForDisplay.get(DEFAULT_FOCUSED_INDEX).getWindowInfo().focused = true;
         }
         // Turns on windows tracking, and update window info.
         mA11yWindowManager.startTrackingWindows(displayId, false);
         // Puts window lists into array.
-        mWindowInfos.put(displayId, windowInfosForDisplay);
+        mWindows.put(displayId, windowsForDisplay);
         // Sets the default display is the top focused display and
         // its current focused window is the top focused window.
         if (displayId == Display.DEFAULT_DISPLAY) {
             setTopFocusedWindowAndDisplay(displayId, DEFAULT_FOCUSED_INDEX);
         }
         // Invokes callback for sending window lists to A11y framework.
-        onWindowsForAccessibilityChanged(displayId, FORCE_SEND);
+        onAccessibilityWindowsChanged(displayId, FORCE_SEND);
 
         assertEquals(mA11yWindowManager.getWindowListLocked(displayId).size(),
-                windowInfosForDisplay.size());
+                windowsForDisplay.size());
     }
 
     private WindowsForAccessibilityCallback getWindowsForAccessibilityCallbacks(int displayId) {
         ArgumentCaptor<WindowsForAccessibilityCallback> windowsForAccessibilityCallbacksCaptor =
                 ArgumentCaptor.forClass(
-                        WindowManagerInternal.WindowsForAccessibilityCallback.class);
+                        WindowsForAccessibilityCallback.class);
         verify(mMockWindowManagerInternal)
                 .setWindowsForAccessibilityCallback(eq(displayId),
                         windowsForAccessibilityCallbacksCaptor.capture());
@@ -1106,36 +1240,28 @@
         return windowId;
     }
 
-    private void addWindowInfo(ArrayList<WindowInfo> windowInfos, IWindow windowToken, int layer) {
-        final WindowInfo windowInfo = WindowInfo.obtain();
-        windowInfo.type = AccessibilityWindowInfo.TYPE_APPLICATION;
-        windowInfo.token = windowToken.asBinder();
-        windowInfo.layer = layer;
-        windowInfo.regionInScreen.set(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
-        windowInfos.add(windowInfo);
-    }
-
     private int getWindowIdFromWindowInfosForDisplay(int displayId, int index) {
-        final IBinder windowToken = mWindowInfos.get(displayId).get(index).token;
+        final IBinder windowToken = mWindows.get(displayId).get(index).getWindowInfo().token;
         return mA11yWindowManager.findWindowIdLocked(
                 USER_SYSTEM_ID, windowToken);
     }
 
     private void setTopFocusedWindowAndDisplay(int displayId, int index) {
         // Sets the top focus window.
-        mTopFocusedWindowToken = mWindowInfos.get(displayId).get(index).token;
+        mTopFocusedWindowToken = mWindows.get(displayId).get(index).getWindowInfo().token;
         // Sets the top focused display.
         mTopFocusedDisplayId = displayId;
     }
 
-    private void onWindowsForAccessibilityChanged(int displayId, boolean forceSend) {
+    private void onAccessibilityWindowsChanged(int displayId, boolean forceSend) {
         WindowsForAccessibilityCallback callbacks = mCallbackOfWindows.get(displayId);
         if (callbacks == null) {
             callbacks = getWindowsForAccessibilityCallbacks(displayId);
             mCallbackOfWindows.put(displayId, callbacks);
         }
-        callbacks.onWindowsForAccessibilityChanged(forceSend, mTopFocusedDisplayId,
-                mTopFocusedWindowToken, mWindowInfos.get(displayId));
+        callbacks.onAccessibilityWindowsChanged(forceSend, mTopFocusedDisplayId,
+                mTopFocusedWindowToken, new Point(SCREEN_WIDTH, SCREEN_HEIGHT),
+                mWindows.get(displayId));
     }
 
     private void changeFocusedWindowOnDisplayPerDisplayFocusConfig(
@@ -1144,23 +1270,23 @@
         if (mSupportPerDisplayFocus) {
             // Gets the old focused window of display which wants to change focused window.
             WindowInfo focusedWindowInfo =
-                    mWindowInfos.get(changeFocusedDisplayId).get(oldFocusedWindowIndex);
+                    mWindows.get(changeFocusedDisplayId).get(oldFocusedWindowIndex).getWindowInfo();
             // Resets the focus of old focused window.
             focusedWindowInfo.focused = false;
             // Gets the new window of display which wants to change focused window.
             focusedWindowInfo =
-                    mWindowInfos.get(changeFocusedDisplayId).get(newFocusedWindowIndex);
+                    mWindows.get(changeFocusedDisplayId).get(newFocusedWindowIndex).getWindowInfo();
             // Sets the focus of new focused window.
             focusedWindowInfo.focused = true;
         } else {
             // Gets the window of display which wants to change focused window.
             WindowInfo focusedWindowInfo =
-                    mWindowInfos.get(changeFocusedDisplayId).get(newFocusedWindowIndex);
+                    mWindows.get(changeFocusedDisplayId).get(newFocusedWindowIndex).getWindowInfo();
             // Sets the focus of new focused window.
             focusedWindowInfo.focused = true;
             // Gets the old focused window of old top focused display.
             focusedWindowInfo =
-                    mWindowInfos.get(oldTopFocusedDisplayId).get(oldFocusedWindowIndex);
+                    mWindows.get(oldTopFocusedDisplayId).get(oldFocusedWindowIndex).getWindowInfo();
             // Resets the focus of old focused window.
             focusedWindowInfo.focused = false;
             // Changes the top focused display and window.
@@ -1168,6 +1294,39 @@
         }
     }
 
+    private AccessibilityWindow createMockAccessibilityWindow(IWindow windowToken, int displayId) {
+        final WindowInfo windowInfo = WindowInfo.obtain();
+        windowInfo.type = WindowManager.LayoutParams.TYPE_APPLICATION;
+        windowInfo.token = windowToken.asBinder();
+
+        final AccessibilityWindow window = Mockito.mock(AccessibilityWindow.class);
+        when(window.getWindowInfo()).thenReturn(windowInfo);
+        when(window.isFocused()).thenAnswer(invocation -> windowInfo.focused);
+        when(window.isTouchable()).thenReturn(true);
+        when(window.getType()).thenReturn(windowInfo.type);
+
+        setRegionForMockAccessibilityWindow(window, nextToucableRegion(displayId));
+        return window;
+    }
+
+    private void setRegionForMockAccessibilityWindow(AccessibilityWindow window, Region region) {
+        doAnswer(invocation -> {
+            ((Region) invocation.getArgument(0)).set(region);
+            return null;
+        }).when(window).getTouchableRegionInScreen(any(Region.class));
+        doAnswer(invocation -> {
+            ((Region) invocation.getArgument(0)).set(region);
+            return null;
+        }).when(window).getTouchableRegionInWindow(any(Region.class));
+    }
+
+    private Region nextToucableRegion(int displayId) {
+        final int topLeft = mNextRegionOffsets.get(displayId, 0);
+        final int bottomRight = topLeft + 100;
+        mNextRegionOffsets.put(displayId, topLeft + 10);
+        return new Region(topLeft, topLeft, bottomRight, bottomRight);
+    }
+
     @Nullable
     private static String toString(@Nullable CharSequence cs) {
         return cs == null ? null : cs.toString();
@@ -1196,16 +1355,16 @@
         }
     }
 
-    static class WindowIdMatcher extends TypeSafeMatcher<AccessibilityEvent> {
+    static class EventWindowIdMatcher extends TypeSafeMatcher<AccessibilityEvent> {
         private int mWindowId;
 
-        WindowIdMatcher(int windowId) {
+        EventWindowIdMatcher(int windowId) {
             super();
             mWindowId = windowId;
         }
 
-        static WindowIdMatcher a11yWindowId(int windowId) {
-            return new WindowIdMatcher(windowId);
+        static EventWindowIdMatcher eventWindowId(int windowId) {
+            return new EventWindowIdMatcher(windowId);
         }
 
         @Override
@@ -1241,5 +1400,27 @@
             description.appendText("Matching to window changes " + mWindowChanges);
         }
     }
+
+    static class WindowIdMatcher extends TypeSafeMatcher<AccessibilityWindowInfo> {
+        private final int mWindowId;
+
+        WindowIdMatcher(int windowId) {
+            super();
+            mWindowId = windowId;
+        }
+
+        static WindowIdMatcher windowId(int windowId) {
+            return new WindowIdMatcher(windowId);
+        }
+
+        @Override
+        protected boolean matchesSafely(AccessibilityWindowInfo window) {
+            return window.getId() == mWindowId;
+        }
+
+        @Override
+        public void describeTo(Description description) {
+            description.appendText("Matching to windowId " + mWindowId);
+        }
+    }
 }
-// LINT.ThenChange(/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerWithAccessibilityWindowTest.java)
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerWithAccessibilityWindowTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerWithAccessibilityWindowTest.java
deleted file mode 100644
index 1904145..0000000
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerWithAccessibilityWindowTest.java
+++ /dev/null
@@ -1,1444 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.accessibility;
-
-import static com.android.server.accessibility.AbstractAccessibilityServiceConnection.DISPLAY_TYPE_DEFAULT;
-import static com.android.server.accessibility.AccessibilityWindowManagerWithAccessibilityWindowTest.DisplayIdMatcher.displayId;
-import static com.android.server.accessibility.AccessibilityWindowManagerWithAccessibilityWindowTest.WindowIdMatcher.windowId;
-import static com.android.server.accessibility.AccessibilityWindowManagerWithAccessibilityWindowTest.WindowChangesMatcher.a11yWindowChanges;
-import static com.android.server.accessibility.AccessibilityWindowManagerWithAccessibilityWindowTest.EventWindowIdMatcher.eventWindowId;
-
-import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertNotNull;
-import static junit.framework.Assert.assertNull;
-import static junit.framework.Assert.assertTrue;
-
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.allOf;
-import static org.hamcrest.Matchers.hasItem;
-import static org.hamcrest.Matchers.hasSize;
-import static org.hamcrest.Matchers.is;
-import static org.hamcrest.Matchers.not;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.ArgumentMatchers.isNull;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.annotation.Nullable;
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.graphics.Region;
-import android.os.IBinder;
-import android.os.LocaleList;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.platform.test.annotations.RequiresFlagsEnabled;
-import android.platform.test.flag.junit.CheckFlagsRule;
-import android.platform.test.flag.junit.DeviceFlagsValueProvider;
-import android.util.SparseArray;
-import android.view.Display;
-import android.view.IWindow;
-import android.view.WindowInfo;
-import android.view.WindowManager;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityNodeInfo;
-import android.view.accessibility.AccessibilityWindowAttributes;
-import android.view.accessibility.AccessibilityWindowInfo;
-import android.view.accessibility.IAccessibilityInteractionConnection;
-
-import com.android.server.accessibility.AccessibilityWindowManager.RemoteAccessibilityConnection;
-import com.android.server.accessibility.test.MessageCapturingHandler;
-import com.android.server.wm.AccessibilityWindowsPopulator.AccessibilityWindow;
-import com.android.server.wm.WindowManagerInternal;
-import com.android.server.wm.WindowManagerInternal.WindowsForAccessibilityCallback;
-
-import org.hamcrest.Description;
-import org.hamcrest.TypeSafeMatcher;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-/**
- * Tests for the AccessibilityWindowManager with Flags.FLAG_COMPUTE_WINDOW_CHANGES_ON_A11Y_V2
- * TODO(b/322444245): Merge with AccessibilityWindowManagerTest
- *  after completing the flag migration.
- */
-@RequiresFlagsEnabled(Flags.FLAG_COMPUTE_WINDOW_CHANGES_ON_A11Y_V2)
-public class AccessibilityWindowManagerWithAccessibilityWindowTest {
-    private static final String PACKAGE_NAME = "com.android.server.accessibility";
-    private static final boolean FORCE_SEND = true;
-    private static final boolean SEND_ON_WINDOW_CHANGES = false;
-    private static final int USER_SYSTEM_ID = UserHandle.USER_SYSTEM;
-    private static final int USER_PROFILE = 11;
-    private static final int USER_PROFILE_PARENT = 1;
-    private static final int SECONDARY_DISPLAY_ID = Display.DEFAULT_DISPLAY + 1;
-    private static final int NUM_GLOBAL_WINDOWS = 4;
-    private static final int NUM_APP_WINDOWS = 4;
-    private static final int NUM_OF_WINDOWS = (NUM_GLOBAL_WINDOWS + NUM_APP_WINDOWS);
-    private static final int DEFAULT_FOCUSED_INDEX = 1;
-    private static final int SCREEN_WIDTH = 1080;
-    private static final int SCREEN_HEIGHT = 1920;
-    private static final int INVALID_ID = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
-    private static final int HOST_WINDOW_ID = 10;
-    private static final int EMBEDDED_WINDOW_ID = 11;
-    private static final int OTHER_WINDOW_ID = 12;
-
-    private AccessibilityWindowManager mA11yWindowManager;
-    // Window manager will support multiple focused window if config_perDisplayFocusEnabled is true,
-    // i.e., each display would have its current focused window, and one of all focused windows
-    // would be top focused window. Otherwise, window manager only supports one focused window
-    // at all displays, and that focused window would be top focused window.
-    private boolean mSupportPerDisplayFocus = false;
-    private int mTopFocusedDisplayId = Display.INVALID_DISPLAY;
-    private IBinder mTopFocusedWindowToken = null;
-
-    // List of window token, mapping from windowId -> window token.
-    private final SparseArray<IWindow> mA11yWindowTokens = new SparseArray<>();
-    // List of window info lists, mapping from displayId -> a11y window lists.
-    private final SparseArray<ArrayList<AccessibilityWindow>> mWindows = new SparseArray<>();
-    // List of callback, mapping from displayId -> callback.
-    private final SparseArray<WindowsForAccessibilityCallback> mCallbackOfWindows =
-            new SparseArray<>();
-    // List of display ID.
-    private final ArrayList<Integer> mExpectedDisplayList = new ArrayList<>(Arrays.asList(
-            Display.DEFAULT_DISPLAY, SECONDARY_DISPLAY_ID));
-
-    private final MessageCapturingHandler mHandler = new MessageCapturingHandler(null);
-
-    // This maps displayId -> next region offset.
-    // Touchable region must have un-occluded area so that it's exposed to a11y services.
-    // This offset can be used as left and top of new region so that top-left of each region are
-    // kept visible.
-    // It's expected to be incremented by some amount everytime the value is used.
-    private final SparseArray<Integer> mNextRegionOffsets = new SparseArray<>();
-
-    @Mock
-    private WindowManagerInternal mMockWindowManagerInternal;
-    @Mock
-    private AccessibilityWindowManager.AccessibilityEventSender mMockA11yEventSender;
-    @Mock
-    private AccessibilitySecurityPolicy mMockA11ySecurityPolicy;
-    @Mock
-    private AccessibilitySecurityPolicy.AccessibilityUserManager mMockA11yUserManager;
-    @Mock
-    private AccessibilityTraceManager mMockA11yTraceManager;
-
-    @Mock
-    private IBinder mMockHostToken;
-    @Mock
-    private IBinder mMockEmbeddedToken;
-    @Mock
-    private IBinder mMockInvalidToken;
-
-    @Rule
-    public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
-
-    @Before
-    public void setUp() throws RemoteException {
-        MockitoAnnotations.initMocks(this);
-        when(mMockA11yUserManager.getCurrentUserIdLocked()).thenReturn(USER_SYSTEM_ID);
-        when(mMockA11ySecurityPolicy.resolveCallingUserIdEnforcingPermissionsLocked(
-                USER_PROFILE)).thenReturn(USER_PROFILE_PARENT);
-        when(mMockA11ySecurityPolicy.resolveCallingUserIdEnforcingPermissionsLocked(
-                USER_SYSTEM_ID)).thenReturn(USER_SYSTEM_ID);
-        when(mMockA11ySecurityPolicy.resolveValidReportedPackageLocked(
-                anyString(), anyInt(), anyInt(), anyInt())).thenReturn(PACKAGE_NAME);
-
-        doAnswer((invocation) -> {
-            onAccessibilityWindowsChanged(invocation.getArgument(0), false);
-            return null;
-        }).when(mMockWindowManagerInternal).computeWindowsForAccessibility(anyInt());
-
-        mA11yWindowManager = new AccessibilityWindowManager(new Object(), mHandler,
-                mMockWindowManagerInternal,
-                mMockA11yEventSender,
-                mMockA11ySecurityPolicy,
-                mMockA11yUserManager,
-                mMockA11yTraceManager);
-        // Starts tracking window of default display and sets the default display
-        // as top focused display before each testing starts.
-        startTrackingPerDisplay(Display.DEFAULT_DISPLAY);
-
-        // AccessibilityEventSender is invoked during onAccessibilityWindowsChanged.
-        // Resets it for mockito verify of further test case.
-        Mockito.reset(mMockA11yEventSender);
-
-        registerLeashedTokenAndWindowId();
-    }
-
-    @After
-    public void tearDown() {
-        mHandler.removeAllMessages();
-    }
-
-    @Test
-    public void startTrackingWindows_shouldEnableWindowManagerCallback() {
-        // AccessibilityWindowManager#startTrackingWindows already invoked in setup.
-        assertTrue(mA11yWindowManager.isTrackingWindowsLocked(Display.DEFAULT_DISPLAY));
-        final WindowsForAccessibilityCallback callbacks =
-                mCallbackOfWindows.get(Display.DEFAULT_DISPLAY);
-        verify(mMockWindowManagerInternal).setWindowsForAccessibilityCallback(
-                eq(Display.DEFAULT_DISPLAY), eq(callbacks));
-    }
-
-    @Test
-    public void stopTrackingWindows_shouldDisableWindowManagerCallback() {
-        assertTrue(mA11yWindowManager.isTrackingWindowsLocked(Display.DEFAULT_DISPLAY));
-        Mockito.reset(mMockWindowManagerInternal);
-
-        mA11yWindowManager.stopTrackingWindows(Display.DEFAULT_DISPLAY);
-        assertFalse(mA11yWindowManager.isTrackingWindowsLocked(Display.DEFAULT_DISPLAY));
-        verify(mMockWindowManagerInternal).setWindowsForAccessibilityCallback(
-                eq(Display.DEFAULT_DISPLAY), isNull());
-
-    }
-
-    @Test
-    public void stopTrackingWindows_shouldClearWindows() {
-        assertTrue(mA11yWindowManager.isTrackingWindowsLocked(Display.DEFAULT_DISPLAY));
-        final int activeWindowId = mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID);
-
-        mA11yWindowManager.stopTrackingWindows(Display.DEFAULT_DISPLAY);
-        assertNull(mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY));
-        assertEquals(mA11yWindowManager.getFocusedWindowId(AccessibilityNodeInfo.FOCUS_INPUT),
-                AccessibilityWindowInfo.UNDEFINED_WINDOW_ID);
-        assertEquals(mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID),
-                activeWindowId);
-    }
-
-    @Test
-    public void stopTrackingWindows_onNonTopFocusedDisplay_shouldNotResetTopFocusWindow()
-            throws RemoteException {
-        // At setup, the default display sets be the top focused display and
-        // its current focused window sets be the top focused window.
-        // Starts tracking window of second display.
-        startTrackingPerDisplay(SECONDARY_DISPLAY_ID);
-        assertTrue(mA11yWindowManager.isTrackingWindowsLocked(SECONDARY_DISPLAY_ID));
-        // Stops tracking windows of second display.
-        mA11yWindowManager.stopTrackingWindows(SECONDARY_DISPLAY_ID);
-        assertNotEquals(mA11yWindowManager.getFocusedWindowId(AccessibilityNodeInfo.FOCUS_INPUT),
-                AccessibilityWindowInfo.UNDEFINED_WINDOW_ID);
-    }
-
-    @Test
-    public void onWindowsChanged_duringTouchInteractAndFocusChange_shouldChangeActiveWindow() {
-        final int activeWindowId = mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID);
-        final WindowInfo focusedWindowInfo =
-                mWindows.get(Display.DEFAULT_DISPLAY).get(DEFAULT_FOCUSED_INDEX).getWindowInfo();
-        assertEquals(activeWindowId, mA11yWindowManager.findWindowIdLocked(
-                USER_SYSTEM_ID, focusedWindowInfo.token));
-
-        focusedWindowInfo.focused = false;
-        mWindows.get(Display.DEFAULT_DISPLAY).get(
-                DEFAULT_FOCUSED_INDEX + 1).getWindowInfo().focused = true;
-
-        mA11yWindowManager.onTouchInteractionStart();
-        setTopFocusedWindowAndDisplay(Display.DEFAULT_DISPLAY, DEFAULT_FOCUSED_INDEX + 1);
-        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
-
-        assertNotEquals(activeWindowId, mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID));
-    }
-
-    @Test
-    public void
-            onWindowsChanged_focusChangeOnNonTopFocusedDisplay_perDisplayFocusOn_notChangeWindow()
-            throws RemoteException {
-        // At setup, the default display sets be the top focused display and
-        // its current focused window sets be the top focused window.
-        // Sets supporting multiple focused window, i.e., config_perDisplayFocusEnabled is true.
-        mSupportPerDisplayFocus = true;
-        // Starts tracking window of second display.
-        startTrackingPerDisplay(SECONDARY_DISPLAY_ID);
-        // Gets the active window.
-        final int activeWindowId = mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID);
-        // Gets the top focused window.
-        final int topFocusedWindowId =
-                mA11yWindowManager.getFocusedWindowId(AccessibilityNodeInfo.FOCUS_INPUT);
-        // Changes the current focused window at second display.
-        changeFocusedWindowOnDisplayPerDisplayFocusConfig(SECONDARY_DISPLAY_ID,
-                DEFAULT_FOCUSED_INDEX + 1, Display.DEFAULT_DISPLAY, DEFAULT_FOCUSED_INDEX);
-
-        onAccessibilityWindowsChanged(SECONDARY_DISPLAY_ID, SEND_ON_WINDOW_CHANGES);
-        // The active window should not be changed.
-        assertEquals(activeWindowId, mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID));
-        // The top focused window should not be changed.
-        assertEquals(topFocusedWindowId,
-                mA11yWindowManager.getFocusedWindowId(AccessibilityNodeInfo.FOCUS_INPUT));
-    }
-
-    @Test
-    public void
-            onWindowChange_focusChangeToNonTopFocusedDisplay_perDisplayFocusOff_shouldChangeWindow()
-            throws RemoteException {
-        // At setup, the default display sets be the top focused display and
-        // its current focused window sets be the top focused window.
-        // Sets not supporting multiple focused window, i.e., config_perDisplayFocusEnabled is
-        // false.
-        mSupportPerDisplayFocus = false;
-        // Starts tracking window of second display.
-        startTrackingPerDisplay(SECONDARY_DISPLAY_ID);
-        // Gets the active window.
-        final int activeWindowId = mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID);
-        // Gets the top focused window.
-        final int topFocusedWindowId =
-                mA11yWindowManager.getFocusedWindowId(AccessibilityNodeInfo.FOCUS_INPUT);
-        // Changes the current focused window from default display to second display.
-        changeFocusedWindowOnDisplayPerDisplayFocusConfig(SECONDARY_DISPLAY_ID,
-                DEFAULT_FOCUSED_INDEX, Display.DEFAULT_DISPLAY, DEFAULT_FOCUSED_INDEX);
-
-        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
-        onAccessibilityWindowsChanged(SECONDARY_DISPLAY_ID, SEND_ON_WINDOW_CHANGES);
-        // The active window should be changed.
-        assertNotEquals(activeWindowId, mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID));
-        // The top focused window should be changed.
-        assertNotEquals(topFocusedWindowId,
-                mA11yWindowManager.getFocusedWindowId(AccessibilityNodeInfo.FOCUS_INPUT));
-    }
-
-    @Test
-    public void onWindowsChanged_shouldReportCorrectLayer() {
-        // AccessibilityWindowManager#onAccessibilityWindowsChanged already invoked in setup.
-        List<AccessibilityWindowInfo> a11yWindows =
-                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
-        for (int i = 0; i < a11yWindows.size(); i++) {
-            final AccessibilityWindowInfo a11yWindow = a11yWindows.get(i);
-            assertThat(mWindows.get(Display.DEFAULT_DISPLAY).size() - i - 1,
-                    is(a11yWindow.getLayer()));
-        }
-    }
-
-    @Test
-    public void onWindowsChanged_shouldReportCorrectOrder() {
-        // AccessibilityWindowManager#onAccessibilityWindowsChanged already invoked in setup.
-        List<AccessibilityWindowInfo> a11yWindows =
-                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
-        for (int i = 0; i < a11yWindows.size(); i++) {
-            final AccessibilityWindowInfo a11yWindow = a11yWindows.get(i);
-            final IBinder windowToken = mA11yWindowManager
-                    .getWindowTokenForUserAndWindowIdLocked(USER_SYSTEM_ID, a11yWindow.getId());
-            final WindowInfo windowInfo = mWindows.get(Display.DEFAULT_DISPLAY)
-                    .get(i).getWindowInfo();
-            assertThat(windowToken, is(windowInfo.token));
-        }
-    }
-
-    @Test
-    public void onWindowsChanged_shouldNotReportNonTouchableWindow() {
-        final AccessibilityWindow window = mWindows.get(Display.DEFAULT_DISPLAY).get(0);
-        when(window.isTouchable()).thenReturn(false);
-        final int windowId = mA11yWindowManager.findWindowIdLocked(
-                USER_SYSTEM_ID, window.getWindowInfo().token);
-
-        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
-
-        final List<AccessibilityWindowInfo> a11yWindows =
-                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
-        assertThat(a11yWindows, not(hasItem(windowId(windowId))));
-    }
-
-    @Test
-    public void onWindowsChanged_shouldReportFocusedNonTouchableWindow() {
-        final AccessibilityWindow window = mWindows.get(Display.DEFAULT_DISPLAY).get(
-                DEFAULT_FOCUSED_INDEX);
-        when(window.isTouchable()).thenReturn(false);
-        final int windowId = mA11yWindowManager.findWindowIdLocked(
-                USER_SYSTEM_ID, window.getWindowInfo().token);
-
-        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
-
-        final List<AccessibilityWindowInfo> a11yWindows =
-                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
-        assertThat(a11yWindows, hasItem(windowId(windowId)));
-    }
-
-    @Test
-    public void onWindowsChanged_trustedFocusedNonTouchableWindow_shouldNotHideWindowsBelow() {
-        // Make the focused trusted un-touchable window fullscreen.
-        final AccessibilityWindow window = mWindows.get(Display.DEFAULT_DISPLAY).get(
-                DEFAULT_FOCUSED_INDEX);
-        setRegionForMockAccessibilityWindow(window, new Region(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT));
-        when(window.isTouchable()).thenReturn(false);
-        when(window.isTrustedOverlay()).thenReturn(true);
-
-        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
-
-        final List<AccessibilityWindowInfo> a11yWindows =
-                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
-        assertThat(a11yWindows, hasSize(NUM_OF_WINDOWS));
-    }
-
-    @Test
-    public void onWindowsChanged_accessibilityOverlay_shouldNotHideWindowsBelow() {
-        // Make the a11y overlay window fullscreen.
-        final AccessibilityWindow window = mWindows.get(Display.DEFAULT_DISPLAY).get(0);
-        setRegionForMockAccessibilityWindow(window, new Region(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT));
-        when(window.getType()).thenReturn(WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY);
-
-        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
-
-        final List<AccessibilityWindowInfo> a11yWindows =
-                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
-        assertThat(a11yWindows, hasSize(NUM_OF_WINDOWS));
-    }
-
-    @Test
-    public void onWindowsChanged_shouldReportFocusedWindowEvenIfOccluded() {
-        // Make the front window fullscreen.
-        final AccessibilityWindow frontWindow = mWindows.get(Display.DEFAULT_DISPLAY).get(0);
-        setRegionForMockAccessibilityWindow(frontWindow,
-                new Region(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT));
-        final int frontWindowId = mA11yWindowManager.findWindowIdLocked(
-                USER_SYSTEM_ID, frontWindow.getWindowInfo().token);
-
-        final AccessibilityWindow focusedWindow = mWindows.get(Display.DEFAULT_DISPLAY).get(
-                DEFAULT_FOCUSED_INDEX);
-        final int focusedWindowId = mA11yWindowManager.findWindowIdLocked(
-                USER_SYSTEM_ID, focusedWindow.getWindowInfo().token);
-
-        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
-
-        final List<AccessibilityWindowInfo> a11yWindows =
-                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
-        assertThat(a11yWindows, hasSize(2));
-        assertThat(a11yWindows.get(0), windowId(frontWindowId));
-        assertThat(a11yWindows.get(1), windowId(focusedWindowId));
-    }
-
-    @Test
-    public void onWindowsChanged_embeddedWindows_shouldOnlyReportHost() throws RemoteException {
-        final Rect embeddingBounds = new Rect(0, 0, 200, 100);
-
-        // The embedded window comes front of the host window.
-        final IBinder embeddedWindowLeashToken = Mockito.mock(IBinder.class);
-        final int embeddedWindowId = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY,
-                false, embeddedWindowLeashToken, USER_SYSTEM_ID);
-        final AccessibilityWindow embeddedWindow = createMockAccessibilityWindow(
-                mA11yWindowTokens.get(embeddedWindowId), Display.DEFAULT_DISPLAY);
-        setRegionForMockAccessibilityWindow(embeddedWindow, new Region(embeddingBounds));
-        mWindows.get(Display.DEFAULT_DISPLAY).set(0, embeddedWindow);
-
-        final IBinder hostWindowLeashToken = Mockito.mock(IBinder.class);
-        final int hostWindowId = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY,
-                false, hostWindowLeashToken, USER_SYSTEM_ID);
-        final AccessibilityWindow hostWindow = createMockAccessibilityWindow(
-                mA11yWindowTokens.get(hostWindowId), Display.DEFAULT_DISPLAY);
-        setRegionForMockAccessibilityWindow(hostWindow, new Region(embeddingBounds));
-        mWindows.get(Display.DEFAULT_DISPLAY).set(1, hostWindow);
-
-        mA11yWindowManager.associateEmbeddedHierarchyLocked(
-                hostWindowLeashToken, embeddedWindowLeashToken);
-
-        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
-
-        final List<AccessibilityWindowInfo> a11yWindows =
-                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
-        assertThat(a11yWindows, not(hasItem(windowId(embeddedWindowId))));
-        assertThat(a11yWindows.get(0), windowId(hostWindowId));
-        final Rect bounds = new Rect();
-        a11yWindows.get(0).getBoundsInScreen(bounds);
-        assertEquals(bounds, embeddingBounds);
-    }
-
-    @Test
-    public void onWindowsChanged_shouldNotReportfullyOccludedWindow() {
-        final AccessibilityWindow frontWindow = mWindows.get(Display.DEFAULT_DISPLAY).get(0);
-        setRegionForMockAccessibilityWindow(frontWindow, new Region(100, 100, 300, 300));
-        final int frontWindowId = mA11yWindowManager.findWindowIdLocked(
-                USER_SYSTEM_ID, frontWindow.getWindowInfo().token);
-
-        // index 1 is focused. Let's use the next one for this test.
-        final AccessibilityWindow occludedWindow = mWindows.get(Display.DEFAULT_DISPLAY).get(2);
-        setRegionForMockAccessibilityWindow(occludedWindow, new Region(150, 150, 250, 250));
-        final int occludedWindowId = mA11yWindowManager.findWindowIdLocked(
-                USER_SYSTEM_ID, occludedWindow.getWindowInfo().token);
-
-        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
-
-        final List<AccessibilityWindowInfo> a11yWindows =
-                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
-        assertThat(a11yWindows, hasItem(windowId(frontWindowId)));
-        assertThat(a11yWindows, not(hasItem(windowId(occludedWindowId))));
-    }
-
-    @Test
-    public void onWindowsChangedAndForceSend_shouldUpdateWindows() {
-        assertNotEquals("new title",
-                toString(mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY)
-                        .get(0).getTitle()));
-
-        mWindows.get(Display.DEFAULT_DISPLAY).get(0).getWindowInfo().title = "new title";
-
-        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, FORCE_SEND);
-        assertEquals("new title",
-                toString(mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY)
-                        .get(0).getTitle()));
-    }
-
-    @Test
-    public void onWindowsChangedNoForceSend_windowChanged_shouldUpdateWindows()
-            throws RemoteException {
-        final AccessibilityWindowInfo oldWindow =
-                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY).get(0);
-        final IWindow token = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY,
-                true, USER_SYSTEM_ID);
-        mWindows.get(Display.DEFAULT_DISPLAY).set(0,
-                createMockAccessibilityWindow(token, Display.DEFAULT_DISPLAY));
-
-        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
-        assertNotEquals(oldWindow,
-                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY).get(0));
-    }
-
-    @Test
-    public void onWindowsChangedNoForceSend_focusChanged_shouldUpdateWindows() {
-        final WindowInfo focusedWindowInfo =
-                mWindows.get(Display.DEFAULT_DISPLAY).get(DEFAULT_FOCUSED_INDEX).getWindowInfo();
-        final WindowInfo windowInfo = mWindows.get(Display.DEFAULT_DISPLAY).get(0).getWindowInfo();
-        focusedWindowInfo.focused = false;
-        windowInfo.focused = true;
-
-        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
-        assertTrue(mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY).get(0)
-                .isFocused());
-    }
-
-    @Test
-    public void removeAccessibilityInteractionConnection_byWindowToken_shouldRemoved() {
-        for (int i = 0; i < NUM_OF_WINDOWS; i++) {
-            final int windowId = mA11yWindowTokens.keyAt(i);
-            final IWindow windowToken = mA11yWindowTokens.valueAt(i);
-            assertNotNull(mA11yWindowManager.getConnectionLocked(USER_SYSTEM_ID, windowId));
-
-            mA11yWindowManager.removeAccessibilityInteractionConnection(windowToken);
-            assertNull(mA11yWindowManager.getConnectionLocked(USER_SYSTEM_ID, windowId));
-        }
-    }
-
-    @Test
-    public void remoteAccessibilityConnection_binderDied_shouldRemoveConnection() {
-        for (int i = 0; i < NUM_OF_WINDOWS; i++) {
-            final int windowId = mA11yWindowTokens.keyAt(i);
-            final RemoteAccessibilityConnection remoteA11yConnection =
-                    mA11yWindowManager.getConnectionLocked(USER_SYSTEM_ID, windowId);
-            assertNotNull(remoteA11yConnection);
-
-            remoteA11yConnection.binderDied();
-            assertNull(mA11yWindowManager.getConnectionLocked(USER_SYSTEM_ID, windowId));
-        }
-    }
-
-    @Test
-    public void getWindowTokenForUserAndWindowId_shouldNotNull() {
-        final List<AccessibilityWindowInfo> windows =
-                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
-        for (int i = 0; i < windows.size(); i++) {
-            final int windowId = windows.get(i).getId();
-
-            assertNotNull(mA11yWindowManager.getWindowTokenForUserAndWindowIdLocked(
-                    USER_SYSTEM_ID, windowId));
-        }
-    }
-
-    @Test
-    public void findWindowId() {
-        final List<AccessibilityWindowInfo> windows =
-                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
-        for (int i = 0; i < windows.size(); i++) {
-            final int windowId = windows.get(i).getId();
-            final IBinder windowToken = mA11yWindowManager.getWindowTokenForUserAndWindowIdLocked(
-                    USER_SYSTEM_ID, windowId);
-
-            assertEquals(mA11yWindowManager.findWindowIdLocked(
-                    USER_SYSTEM_ID, windowToken), windowId);
-        }
-    }
-
-    @Test
-    public void resolveParentWindowId_windowIsNotEmbedded_shouldReturnGivenId()
-            throws RemoteException {
-        final int windowId = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY, false,
-                Mockito.mock(IBinder.class), USER_SYSTEM_ID);
-        assertEquals(windowId, mA11yWindowManager.resolveParentWindowIdLocked(windowId));
-    }
-
-    @Test
-    public void resolveParentWindowId_windowIsNotRegistered_shouldReturnGivenId() {
-        final int windowId = -1;
-        assertEquals(windowId, mA11yWindowManager.resolveParentWindowIdLocked(windowId));
-    }
-
-    @Test
-    public void resolveParentWindowId_windowIsAssociated_shouldReturnParentWindowId()
-            throws RemoteException {
-        final IBinder mockHostToken = Mockito.mock(IBinder.class);
-        final IBinder mockEmbeddedToken = Mockito.mock(IBinder.class);
-        final int hostWindowId = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY,
-                false, mockHostToken, USER_SYSTEM_ID);
-        final int embeddedWindowId = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY,
-                false, mockEmbeddedToken, USER_SYSTEM_ID);
-
-        mA11yWindowManager.associateEmbeddedHierarchyLocked(mockHostToken, mockEmbeddedToken);
-
-        final int resolvedWindowId = mA11yWindowManager.resolveParentWindowIdLocked(
-                embeddedWindowId);
-        assertEquals(hostWindowId, resolvedWindowId);
-    }
-
-    @Test
-    public void resolveParentWindowId_windowIsDisassociated_shouldReturnGivenId()
-            throws RemoteException {
-        final IBinder mockHostToken = Mockito.mock(IBinder.class);
-        final IBinder mockEmbeddedToken = Mockito.mock(IBinder.class);
-        final int hostWindowId = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY,
-                false, mockHostToken, USER_SYSTEM_ID);
-        final int embeddedWindowId = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY,
-                false, mockEmbeddedToken, USER_SYSTEM_ID);
-
-        mA11yWindowManager.associateEmbeddedHierarchyLocked(mockHostToken, mockEmbeddedToken);
-        mA11yWindowManager.disassociateEmbeddedHierarchyLocked(mockEmbeddedToken);
-
-        final int resolvedWindowId = mA11yWindowManager.resolveParentWindowIdLocked(
-                embeddedWindowId);
-        assertNotEquals(hostWindowId, resolvedWindowId);
-        assertEquals(embeddedWindowId, resolvedWindowId);
-    }
-
-    @Test
-    public void computePartialInteractiveRegionForWindow_wholeVisible_returnWholeRegion() {
-        // Updates top 2 z-order WindowInfo are whole visible.
-        final AccessibilityWindow firstWindow = mWindows.get(Display.DEFAULT_DISPLAY).get(0);
-        setRegionForMockAccessibilityWindow(firstWindow,
-                new Region(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT / 2));
-        final AccessibilityWindow secondWindow = mWindows.get(Display.DEFAULT_DISPLAY).get(1);
-        setRegionForMockAccessibilityWindow(secondWindow,
-                new Region(0, SCREEN_HEIGHT / 2, SCREEN_WIDTH, SCREEN_HEIGHT));
-
-        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
-
-        final List<AccessibilityWindowInfo> a11yWindows =
-                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
-        assertThat(a11yWindows, hasSize(2));
-        final Region outBounds = new Region();
-        int windowId = a11yWindows.get(0).getId();
-
-        mA11yWindowManager.computePartialInteractiveRegionForWindowLocked(windowId, outBounds);
-        assertThat(outBounds.getBounds().width(), is(SCREEN_WIDTH));
-        assertThat(outBounds.getBounds().height(), is(SCREEN_HEIGHT / 2));
-
-        windowId = a11yWindows.get(1).getId();
-
-        mA11yWindowManager.computePartialInteractiveRegionForWindowLocked(windowId, outBounds);
-        assertThat(outBounds.getBounds().width(), is(SCREEN_WIDTH));
-        assertThat(outBounds.getBounds().height(), is(SCREEN_HEIGHT / 2));
-    }
-
-    @Test
-    public void computePartialInteractiveRegionForWindow_halfVisible_returnHalfRegion() {
-        // Updates z-order #1 WindowInfo is half visible.
-        final AccessibilityWindow firstWindow = mWindows.get(Display.DEFAULT_DISPLAY).get(0);
-        setRegionForMockAccessibilityWindow(firstWindow,
-                new Region(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT / 2));
-        final AccessibilityWindow secondWindow = mWindows.get(Display.DEFAULT_DISPLAY).get(1);
-        setRegionForMockAccessibilityWindow(secondWindow,
-                new Region(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT));
-
-        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
-        final List<AccessibilityWindowInfo> a11yWindows =
-                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
-        assertThat(a11yWindows, hasSize(2));
-        final Region outBounds = new Region();
-        int windowId = a11yWindows.get(1).getId();
-
-        mA11yWindowManager.computePartialInteractiveRegionForWindowLocked(windowId, outBounds);
-        assertThat(outBounds.getBounds().width(), is(SCREEN_WIDTH));
-        assertThat(outBounds.getBounds().height(), is(SCREEN_HEIGHT / 2));
-    }
-
-    @Test
-    public void computePartialInteractiveRegionForWindow_notVisible_returnEmptyRegion() {
-        // z-order #0 WindowInfo is full screen, z-order #1 WindowInfo should be invisible.
-        final AccessibilityWindow firstWindow = mWindows.get(Display.DEFAULT_DISPLAY).get(0);
-        setRegionForMockAccessibilityWindow(firstWindow,
-                new Region(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT));
-
-        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
-
-        final List<AccessibilityWindowInfo> a11yWindows =
-                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
-        // Note that the second window is also exposed even if region is empty because it's focused.
-        assertThat(a11yWindows, hasSize(2));
-        final Region outBounds = new Region();
-        int windowId = a11yWindows.get(1).getId();
-
-        mA11yWindowManager.computePartialInteractiveRegionForWindowLocked(windowId, outBounds);
-        assertTrue(outBounds.getBounds().isEmpty());
-    }
-
-    @Test
-    public void computePartialInteractiveRegionForWindow_partialVisible_returnVisibleRegion() {
-        // Updates z-order #0 WindowInfo to have two interact-able areas.
-        final Region region = new Region(0, 0, SCREEN_WIDTH, 200);
-        region.op(0, SCREEN_HEIGHT - 200, SCREEN_WIDTH, SCREEN_HEIGHT, Region.Op.UNION);
-        final AccessibilityWindow firstWindow = mWindows.get(Display.DEFAULT_DISPLAY).get(0);
-        setRegionForMockAccessibilityWindow(firstWindow, region);
-        final AccessibilityWindow secondWindow = mWindows.get(Display.DEFAULT_DISPLAY).get(1);
-        setRegionForMockAccessibilityWindow(secondWindow,
-                new Region(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT));
-
-        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
-
-        final List<AccessibilityWindowInfo> a11yWindows =
-                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
-        assertThat(a11yWindows, hasSize(2));
-        final Region outBounds = new Region();
-        final int windowId = a11yWindows.get(1).getId();
-
-        mA11yWindowManager.computePartialInteractiveRegionForWindowLocked(windowId, outBounds);
-        assertFalse(outBounds.getBounds().isEmpty());
-        assertThat(outBounds.getBounds().width(), is(SCREEN_WIDTH));
-        assertThat(outBounds.getBounds().height(), is(SCREEN_HEIGHT - 400));
-    }
-
-    @Test
-    public void updateActiveAndA11yFocusedWindow_windowStateChangedEvent_noTracking_shouldUpdate() {
-        final IBinder eventWindowToken =
-                mWindows.get(Display.DEFAULT_DISPLAY)
-                        .get(DEFAULT_FOCUSED_INDEX + 1).getWindowInfo().token;
-        final int eventWindowId = mA11yWindowManager.findWindowIdLocked(
-                USER_SYSTEM_ID, eventWindowToken);
-        when(mMockWindowManagerInternal.getFocusedWindowTokenFromWindowStates())
-                .thenReturn(eventWindowToken);
-
-        final int noUse = 0;
-        mA11yWindowManager.stopTrackingWindows(Display.DEFAULT_DISPLAY);
-        mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID,
-                eventWindowId,
-                noUse,
-                AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED,
-                noUse);
-        assertThat(mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID), is(eventWindowId));
-        assertThat(mA11yWindowManager.getFocusedWindowId(AccessibilityNodeInfo.FOCUS_INPUT),
-                is(eventWindowId));
-    }
-
-    @Test
-    public void updateActiveAndA11yFocusedWindow_hoverEvent_touchInteract_shouldSetActiveWindow() {
-        final int eventWindowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY,
-                DEFAULT_FOCUSED_INDEX + 1);
-        final int currentActiveWindowId = mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID);
-        assertThat(currentActiveWindowId, is(not(eventWindowId)));
-
-        final int noUse = 0;
-        mA11yWindowManager.onTouchInteractionStart();
-        mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID,
-                eventWindowId,
-                noUse,
-                AccessibilityEvent.TYPE_VIEW_HOVER_ENTER,
-                noUse);
-        assertThat(mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID), is(eventWindowId));
-        final ArgumentCaptor<AccessibilityEvent> captor =
-                ArgumentCaptor.forClass(AccessibilityEvent.class);
-        verify(mMockA11yEventSender, times(2))
-                .sendAccessibilityEventForCurrentUserLocked(captor.capture());
-        assertThat(captor.getAllValues().get(0),
-                allOf(displayId(Display.DEFAULT_DISPLAY),
-                        eventWindowId(currentActiveWindowId),
-                        a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_ACTIVE)));
-        assertThat(captor.getAllValues().get(1),
-                allOf(displayId(Display.DEFAULT_DISPLAY),
-                        eventWindowId(eventWindowId),
-                        a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_ACTIVE)));
-    }
-
-    @Test
-    public void updateActiveAndA11yFocusedWindow_a11yFocusEvent_shouldUpdateA11yFocus() {
-        final int eventWindowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY,
-                DEFAULT_FOCUSED_INDEX);
-        final int currentA11yFocusedWindowId = mA11yWindowManager.getFocusedWindowId(
-                AccessibilityNodeInfo.FOCUS_ACCESSIBILITY);
-        assertThat(currentA11yFocusedWindowId, is(AccessibilityWindowInfo.UNDEFINED_WINDOW_ID));
-
-        final int noUse = 0;
-        mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID,
-                eventWindowId,
-                AccessibilityNodeInfo.ROOT_NODE_ID,
-                AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED,
-                noUse);
-        assertThat(mA11yWindowManager.getFocusedWindowId(
-                AccessibilityNodeInfo.FOCUS_ACCESSIBILITY), is(eventWindowId));
-        final ArgumentCaptor<AccessibilityEvent> captor =
-                ArgumentCaptor.forClass(AccessibilityEvent.class);
-        verify(mMockA11yEventSender, times(1))
-                .sendAccessibilityEventForCurrentUserLocked(captor.capture());
-        assertThat(captor.getAllValues().get(0),
-                allOf(displayId(Display.DEFAULT_DISPLAY),
-                        eventWindowId(eventWindowId),
-                        a11yWindowChanges(
-                                AccessibilityEvent.WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED)));
-    }
-
-    @Test
-    public void updateActiveAndA11yFocusedWindow_a11yFocusEvent_multiDisplay_defaultToSecondary()
-            throws RemoteException {
-        runUpdateActiveAndA11yFocusedWindow_MultiDisplayTest(
-                Display.DEFAULT_DISPLAY, SECONDARY_DISPLAY_ID);
-    }
-
-    @Test
-    public void updateActiveAndA11yFocusedWindow_a11yFocusEvent_multiDisplay_SecondaryToDefault()
-            throws RemoteException {
-        runUpdateActiveAndA11yFocusedWindow_MultiDisplayTest(
-                SECONDARY_DISPLAY_ID, Display.DEFAULT_DISPLAY);
-    }
-
-    private void runUpdateActiveAndA11yFocusedWindow_MultiDisplayTest(
-            int initialDisplayId, int eventDisplayId) throws RemoteException {
-        startTrackingPerDisplay(SECONDARY_DISPLAY_ID);
-        final int initialWindowId = getWindowIdFromWindowInfosForDisplay(
-                initialDisplayId, DEFAULT_FOCUSED_INDEX);
-        final int noUse = 0;
-        mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID,
-                initialWindowId,
-                AccessibilityNodeInfo.ROOT_NODE_ID,
-                AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED,
-                noUse);
-        assertThat(mA11yWindowManager.getFocusedWindowId(
-                AccessibilityNodeInfo.FOCUS_ACCESSIBILITY), is(initialWindowId));
-        Mockito.reset(mMockA11yEventSender);
-
-        final int eventWindowId = getWindowIdFromWindowInfosForDisplay(
-                eventDisplayId, DEFAULT_FOCUSED_INDEX);
-        mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID,
-                eventWindowId,
-                AccessibilityNodeInfo.ROOT_NODE_ID,
-                AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED,
-                noUse);
-        assertThat(mA11yWindowManager.getFocusedWindowId(
-                AccessibilityNodeInfo.FOCUS_ACCESSIBILITY), is(eventWindowId));
-        final ArgumentCaptor<AccessibilityEvent> captor =
-                ArgumentCaptor.forClass(AccessibilityEvent.class);
-        verify(mMockA11yEventSender, times(2))
-                .sendAccessibilityEventForCurrentUserLocked(captor.capture());
-        assertThat(captor.getAllValues().get(0),
-                allOf(displayId(initialDisplayId),
-                        eventWindowId(initialWindowId),
-                        a11yWindowChanges(
-                                AccessibilityEvent.WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED)));
-        assertThat(captor.getAllValues().get(1),
-                allOf(displayId(eventDisplayId),
-                        eventWindowId(eventWindowId),
-                        a11yWindowChanges(
-                                AccessibilityEvent.WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED)));
-    }
-
-    @Test
-    public void updateActiveAndA11yFocusedWindow_clearA11yFocusEvent_shouldClearA11yFocus() {
-        final int eventWindowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY,
-                DEFAULT_FOCUSED_INDEX);
-        final int currentA11yFocusedWindowId = mA11yWindowManager.getFocusedWindowId(
-                AccessibilityNodeInfo.FOCUS_ACCESSIBILITY);
-        assertThat(currentA11yFocusedWindowId, is(not(eventWindowId)));
-
-        final int noUse = 0;
-        mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID,
-                eventWindowId,
-                AccessibilityNodeInfo.ROOT_NODE_ID,
-                AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED,
-                noUse);
-        assertThat(mA11yWindowManager.getFocusedWindowId(
-                AccessibilityNodeInfo.FOCUS_ACCESSIBILITY), is(eventWindowId));
-        mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID,
-                eventWindowId,
-                AccessibilityNodeInfo.ROOT_NODE_ID,
-                AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED,
-                noUse);
-        assertThat(mA11yWindowManager.getFocusedWindowId(
-                        AccessibilityNodeInfo.FOCUS_ACCESSIBILITY),
-                is(AccessibilityWindowInfo.UNDEFINED_WINDOW_ID));
-    }
-
-    @Test
-    public void onTouchInteractionEnd_shouldRollbackActiveWindow() {
-        final int eventWindowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY,
-                DEFAULT_FOCUSED_INDEX + 1);
-        final int currentActiveWindowId = mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID);
-        assertThat(currentActiveWindowId, is(not(eventWindowId)));
-
-        final int noUse = 0;
-        mA11yWindowManager.onTouchInteractionStart();
-        mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID,
-                eventWindowId,
-                noUse,
-                AccessibilityEvent.TYPE_VIEW_HOVER_ENTER,
-                noUse);
-        assertThat(mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID), is(eventWindowId));
-        // AccessibilityEventSender is invoked after active window changed. Reset it.
-        Mockito.reset(mMockA11yEventSender);
-
-        mA11yWindowManager.onTouchInteractionEnd();
-        final ArgumentCaptor<AccessibilityEvent> captor =
-                ArgumentCaptor.forClass(AccessibilityEvent.class);
-        verify(mMockA11yEventSender, times(2))
-                .sendAccessibilityEventForCurrentUserLocked(captor.capture());
-        assertThat(captor.getAllValues().get(0),
-                allOf(displayId(Display.DEFAULT_DISPLAY),
-                        eventWindowId(eventWindowId),
-                        a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_ACTIVE)));
-        assertThat(captor.getAllValues().get(1),
-                allOf(displayId(Display.DEFAULT_DISPLAY),
-                        eventWindowId(currentActiveWindowId),
-                        a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_ACTIVE)));
-    }
-
-    @Test
-    public void onTouchInteractionEnd_noServiceInteractiveWindow_shouldClearA11yFocus()
-            throws RemoteException {
-        final IBinder defaultFocusWinToken =
-                mWindows.get(Display.DEFAULT_DISPLAY).get(
-                        DEFAULT_FOCUSED_INDEX).getWindowInfo().token;
-        final int defaultFocusWindowId = mA11yWindowManager.findWindowIdLocked(
-                USER_SYSTEM_ID, defaultFocusWinToken);
-        when(mMockWindowManagerInternal.getFocusedWindowTokenFromWindowStates())
-                .thenReturn(defaultFocusWinToken);
-        final int newFocusWindowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY,
-                DEFAULT_FOCUSED_INDEX + 1);
-        final IAccessibilityInteractionConnection mockNewFocusConnection =
-                mA11yWindowManager.getConnectionLocked(
-                        USER_SYSTEM_ID, newFocusWindowId).getRemote();
-
-        mA11yWindowManager.stopTrackingWindows(Display.DEFAULT_DISPLAY);
-        final int noUse = 0;
-        mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID,
-                defaultFocusWindowId,
-                noUse,
-                AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED,
-                noUse);
-        assertThat(mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID), is(defaultFocusWindowId));
-        assertThat(mA11yWindowManager.getFocusedWindowId(AccessibilityNodeInfo.FOCUS_INPUT),
-                is(defaultFocusWindowId));
-
-        mA11yWindowManager.onTouchInteractionStart();
-        mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID,
-                newFocusWindowId,
-                noUse,
-                AccessibilityEvent.TYPE_VIEW_HOVER_ENTER,
-                noUse);
-        mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID,
-                newFocusWindowId,
-                AccessibilityNodeInfo.ROOT_NODE_ID,
-                AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED,
-                noUse);
-        assertThat(mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID), is(newFocusWindowId));
-        assertThat(mA11yWindowManager.getFocusedWindowId(
-                AccessibilityNodeInfo.FOCUS_ACCESSIBILITY), is(newFocusWindowId));
-
-        mA11yWindowManager.onTouchInteractionEnd();
-        mHandler.sendLastMessage();
-        verify(mockNewFocusConnection).clearAccessibilityFocus();
-    }
-
-    @Test
-    public void getPictureInPictureWindow_shouldNotNull() {
-        assertNull(mA11yWindowManager.getPictureInPictureWindowLocked());
-        mWindows.get(Display.DEFAULT_DISPLAY).get(1).getWindowInfo().inPictureInPicture = true;
-        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
-
-        assertNotNull(mA11yWindowManager.getPictureInPictureWindowLocked());
-    }
-
-    @Test
-    public void notifyOutsideTouch() throws RemoteException {
-        final int targetWindowId =
-                getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, 1);
-        final int outsideWindowId =
-                getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, 0);
-        final IAccessibilityInteractionConnection mockRemoteConnection =
-                mA11yWindowManager.getConnectionLocked(
-                        USER_SYSTEM_ID, outsideWindowId).getRemote();
-        mWindows.get(Display.DEFAULT_DISPLAY).get(0).getWindowInfo().hasFlagWatchOutsideTouch =
-                true;
-        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
-
-        mA11yWindowManager.notifyOutsideTouch(USER_SYSTEM_ID, targetWindowId);
-        verify(mockRemoteConnection).notifyOutsideTouch();
-    }
-
-    @Test
-    public void addAccessibilityInteractionConnection_profileUser_findInParentUser()
-            throws RemoteException {
-        final IWindow token = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY,
-                false, USER_PROFILE);
-        final int windowId = mA11yWindowManager.findWindowIdLocked(
-                USER_PROFILE_PARENT, token.asBinder());
-        assertTrue(windowId >= 0);
-    }
-
-    @Test
-    public void getDisplayList() throws RemoteException {
-        // Starts tracking window of second display.
-        startTrackingPerDisplay(SECONDARY_DISPLAY_ID);
-
-        final ArrayList<Integer> displayList = mA11yWindowManager.getDisplayListLocked(
-                DISPLAY_TYPE_DEFAULT);
-        assertTrue(displayList.equals(mExpectedDisplayList));
-    }
-
-    @Test
-    public void setAccessibilityWindowIdToSurfaceMetadata()
-            throws RemoteException {
-        final IWindow token = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY,
-                true, USER_SYSTEM_ID);
-        int windowId = -1;
-        for (int i = 0; i < mA11yWindowTokens.size(); i++) {
-            if (mA11yWindowTokens.valueAt(i).equals(token)) {
-                windowId = mA11yWindowTokens.keyAt(i);
-            }
-        }
-        assertNotEquals("Returned token is not found in mA11yWindowTokens", -1, windowId);
-        verify(mMockWindowManagerInternal, times(1)).setAccessibilityIdToSurfaceMetadata(
-                token.asBinder(), windowId);
-
-        mA11yWindowManager.removeAccessibilityInteractionConnection(token);
-        verify(mMockWindowManagerInternal, times(1)).setAccessibilityIdToSurfaceMetadata(
-                token.asBinder(), -1);
-    }
-
-    @Test
-    public void getHostTokenLocked_hierarchiesAreAssociated_shouldReturnHostToken() {
-        mA11yWindowManager.associateLocked(mMockEmbeddedToken, mMockHostToken);
-        final IBinder hostToken = mA11yWindowManager.getHostTokenLocked(mMockEmbeddedToken);
-        assertEquals(hostToken, mMockHostToken);
-    }
-
-    @Test
-    public void getHostTokenLocked_hierarchiesAreNotAssociated_shouldReturnNull() {
-        final IBinder hostToken = mA11yWindowManager.getHostTokenLocked(mMockEmbeddedToken);
-        assertNull(hostToken);
-    }
-
-    @Test
-    public void getHostTokenLocked_embeddedHierarchiesAreDisassociated_shouldReturnNull() {
-        mA11yWindowManager.associateLocked(mMockEmbeddedToken, mMockHostToken);
-        mA11yWindowManager.disassociateLocked(mMockEmbeddedToken);
-        final IBinder hostToken = mA11yWindowManager.getHostTokenLocked(mMockEmbeddedToken);
-        assertNull(hostToken);
-    }
-
-    @Test
-    public void getHostTokenLocked_hostHierarchiesAreDisassociated_shouldReturnNull() {
-        mA11yWindowManager.associateLocked(mMockEmbeddedToken, mMockHostToken);
-        mA11yWindowManager.disassociateLocked(mMockHostToken);
-        final IBinder hostToken = mA11yWindowManager.getHostTokenLocked(mMockHostToken);
-        assertNull(hostToken);
-    }
-
-    @Test
-    public void getWindowIdLocked_windowIsRegistered_shouldReturnWindowId() {
-        final int windowId = mA11yWindowManager.getWindowIdLocked(mMockHostToken);
-        assertEquals(windowId, HOST_WINDOW_ID);
-    }
-
-    @Test
-    public void getWindowIdLocked_windowIsNotRegistered_shouldReturnInvalidWindowId() {
-        final int windowId = mA11yWindowManager.getWindowIdLocked(mMockInvalidToken);
-        assertEquals(windowId, INVALID_ID);
-    }
-
-    @Test
-    public void getTokenLocked_windowIsRegistered_shouldReturnToken() {
-        final IBinder token = mA11yWindowManager.getLeashTokenLocked(HOST_WINDOW_ID);
-        assertEquals(token, mMockHostToken);
-    }
-
-    @Test
-    public void getTokenLocked_windowIsNotRegistered_shouldReturnNull() {
-        final IBinder token = mA11yWindowManager.getLeashTokenLocked(OTHER_WINDOW_ID);
-        assertNull(token);
-    }
-
-    @Test
-    public void setAccessibilityWindowAttributes_windowIsNotRegistered_titleIsChanged() {
-        final int windowId =
-                getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, 0);
-        final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
-        layoutParams.accessibilityTitle = "accessibility window title";
-        final AccessibilityWindowAttributes attributes = new AccessibilityWindowAttributes(
-                layoutParams, new LocaleList());
-
-        mA11yWindowManager.setAccessibilityWindowAttributes(Display.DEFAULT_DISPLAY, windowId,
-                USER_SYSTEM_ID, attributes);
-
-        final AccessibilityWindowInfo a11yWindow = mA11yWindowManager.findA11yWindowInfoByIdLocked(
-                windowId);
-        assertEquals(toString(layoutParams.accessibilityTitle), toString(a11yWindow.getTitle()));
-    }
-
-    @Test
-    public void sendAccessibilityEventOnWindowRemoval() {
-        final ArrayList<AccessibilityWindow> windows = mWindows.get(Display.DEFAULT_DISPLAY);
-
-        // Removing index 0 because it's not focused, and avoids unnecessary layer change.
-        final int windowId =
-                getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, 0);
-        windows.remove(0);
-
-        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, FORCE_SEND);
-
-        final ArgumentCaptor<AccessibilityEvent> captor =
-                ArgumentCaptor.forClass(AccessibilityEvent.class);
-        verify(mMockA11yEventSender, times(1))
-                .sendAccessibilityEventForCurrentUserLocked(captor.capture());
-        assertThat(captor.getAllValues().get(0),
-                allOf(displayId(Display.DEFAULT_DISPLAY),
-                        eventWindowId(windowId),
-                        a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_REMOVED)));
-    }
-
-    @Test
-    public void sendAccessibilityEventOnWindowAddition() throws RemoteException {
-        final ArrayList<AccessibilityWindow> windows = mWindows.get(Display.DEFAULT_DISPLAY);
-
-        final IWindow token = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY,
-                false, USER_SYSTEM_ID);
-        // Adding window to the front so that other windows' layer won't change.
-        windows.add(0, createMockAccessibilityWindow(token, Display.DEFAULT_DISPLAY));
-        final int windowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, 0);
-
-        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, FORCE_SEND);
-
-        final ArgumentCaptor<AccessibilityEvent> captor =
-                ArgumentCaptor.forClass(AccessibilityEvent.class);
-        verify(mMockA11yEventSender, times(1))
-                .sendAccessibilityEventForCurrentUserLocked(captor.capture());
-        assertThat(captor.getAllValues().get(0),
-                allOf(displayId(Display.DEFAULT_DISPLAY),
-                        eventWindowId(windowId),
-                        a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_ADDED)));
-    }
-
-    @Test
-    public void sendAccessibilityEventOnWindowChange() {
-        final ArrayList<AccessibilityWindow> windows = mWindows.get(Display.DEFAULT_DISPLAY);
-        windows.get(0).getWindowInfo().title = "new title";
-        final int windowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, 0);
-
-        onAccessibilityWindowsChanged(Display.DEFAULT_DISPLAY, FORCE_SEND);
-
-        final ArgumentCaptor<AccessibilityEvent> captor =
-                ArgumentCaptor.forClass(AccessibilityEvent.class);
-        verify(mMockA11yEventSender, times(1))
-                .sendAccessibilityEventForCurrentUserLocked(captor.capture());
-        assertThat(captor.getAllValues().get(0),
-                allOf(displayId(Display.DEFAULT_DISPLAY),
-                        eventWindowId(windowId),
-                        a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_TITLE)));
-    }
-
-    private void registerLeashedTokenAndWindowId() {
-        mA11yWindowManager.registerIdLocked(mMockHostToken, HOST_WINDOW_ID);
-        mA11yWindowManager.registerIdLocked(mMockEmbeddedToken, EMBEDDED_WINDOW_ID);
-    }
-
-    private void startTrackingPerDisplay(int displayId) throws RemoteException {
-        ArrayList<AccessibilityWindow> windowsForDisplay = new ArrayList<>();
-        // Adds RemoteAccessibilityConnection into AccessibilityWindowManager, and copy
-        // mock window token into mA11yWindowTokens. Also, preparing WindowInfo mWindowInfos
-        // for the test.
-        for (int i = 0; i < NUM_GLOBAL_WINDOWS; i++) {
-            final IWindow token = addAccessibilityInteractionConnection(displayId,
-                    true, USER_SYSTEM_ID);
-            windowsForDisplay.add(createMockAccessibilityWindow(token, displayId));
-
-        }
-        for (int i = 0; i < NUM_APP_WINDOWS; i++) {
-            final IWindow token = addAccessibilityInteractionConnection(displayId,
-                    false, USER_SYSTEM_ID);
-            windowsForDisplay.add(createMockAccessibilityWindow(token, displayId));
-        }
-        // Sets up current focused window of display.
-        // Each display has its own current focused window if config_perDisplayFocusEnabled is true.
-        // Otherwise only default display needs to current focused window.
-        if (mSupportPerDisplayFocus || displayId == Display.DEFAULT_DISPLAY) {
-            windowsForDisplay.get(DEFAULT_FOCUSED_INDEX).getWindowInfo().focused = true;
-        }
-        // Turns on windows tracking, and update window info.
-        mA11yWindowManager.startTrackingWindows(displayId, false);
-        // Puts window lists into array.
-        mWindows.put(displayId, windowsForDisplay);
-        // Sets the default display is the top focused display and
-        // its current focused window is the top focused window.
-        if (displayId == Display.DEFAULT_DISPLAY) {
-            setTopFocusedWindowAndDisplay(displayId, DEFAULT_FOCUSED_INDEX);
-        }
-        // Invokes callback for sending window lists to A11y framework.
-        onAccessibilityWindowsChanged(displayId, FORCE_SEND);
-
-        assertEquals(mA11yWindowManager.getWindowListLocked(displayId).size(),
-                windowsForDisplay.size());
-    }
-
-    private WindowsForAccessibilityCallback getWindowsForAccessibilityCallbacks(int displayId) {
-        ArgumentCaptor<WindowsForAccessibilityCallback> windowsForAccessibilityCallbacksCaptor =
-                ArgumentCaptor.forClass(
-                        WindowsForAccessibilityCallback.class);
-        verify(mMockWindowManagerInternal)
-                .setWindowsForAccessibilityCallback(eq(displayId),
-                        windowsForAccessibilityCallbacksCaptor.capture());
-        return windowsForAccessibilityCallbacksCaptor.getValue();
-    }
-
-    private IWindow addAccessibilityInteractionConnection(int displayId, boolean bGlobal,
-            int userId) throws RemoteException {
-        final IWindow mockWindowToken = Mockito.mock(IWindow.class);
-        final IAccessibilityInteractionConnection mockA11yConnection = Mockito.mock(
-                IAccessibilityInteractionConnection.class);
-        final IBinder mockConnectionBinder = Mockito.mock(IBinder.class);
-        final IBinder mockWindowBinder = Mockito.mock(IBinder.class);
-        final IBinder mockLeashToken = Mockito.mock(IBinder.class);
-        when(mockA11yConnection.asBinder()).thenReturn(mockConnectionBinder);
-        when(mockWindowToken.asBinder()).thenReturn(mockWindowBinder);
-        when(mMockA11ySecurityPolicy.isCallerInteractingAcrossUsers(userId))
-                .thenReturn(bGlobal);
-        when(mMockWindowManagerInternal.getDisplayIdForWindow(mockWindowBinder))
-                .thenReturn(displayId);
-
-        int windowId = mA11yWindowManager.addAccessibilityInteractionConnection(
-                mockWindowToken, mockLeashToken, mockA11yConnection, PACKAGE_NAME, userId);
-        mA11yWindowTokens.put(windowId, mockWindowToken);
-        return mockWindowToken;
-    }
-
-    private int addAccessibilityInteractionConnection(int displayId, boolean bGlobal,
-            IBinder leashToken, int userId) throws RemoteException {
-        final IWindow mockWindowToken = Mockito.mock(IWindow.class);
-        final IAccessibilityInteractionConnection mockA11yConnection = Mockito.mock(
-                IAccessibilityInteractionConnection.class);
-        final IBinder mockConnectionBinder = Mockito.mock(IBinder.class);
-        final IBinder mockWindowBinder = Mockito.mock(IBinder.class);
-        when(mockA11yConnection.asBinder()).thenReturn(mockConnectionBinder);
-        when(mockWindowToken.asBinder()).thenReturn(mockWindowBinder);
-        when(mMockA11ySecurityPolicy.isCallerInteractingAcrossUsers(userId))
-                .thenReturn(bGlobal);
-        when(mMockWindowManagerInternal.getDisplayIdForWindow(mockWindowBinder))
-                .thenReturn(displayId);
-
-        int windowId = mA11yWindowManager.addAccessibilityInteractionConnection(
-                mockWindowToken, leashToken, mockA11yConnection, PACKAGE_NAME, userId);
-        mA11yWindowTokens.put(windowId, mockWindowToken);
-        return windowId;
-    }
-
-    private int getWindowIdFromWindowInfosForDisplay(int displayId, int index) {
-        final IBinder windowToken = mWindows.get(displayId).get(index).getWindowInfo().token;
-        return mA11yWindowManager.findWindowIdLocked(
-                USER_SYSTEM_ID, windowToken);
-    }
-
-    private void setTopFocusedWindowAndDisplay(int displayId, int index) {
-        // Sets the top focus window.
-        mTopFocusedWindowToken = mWindows.get(displayId).get(index).getWindowInfo().token;
-        // Sets the top focused display.
-        mTopFocusedDisplayId = displayId;
-    }
-
-    private void onAccessibilityWindowsChanged(int displayId, boolean forceSend) {
-        WindowsForAccessibilityCallback callbacks = mCallbackOfWindows.get(displayId);
-        if (callbacks == null) {
-            callbacks = getWindowsForAccessibilityCallbacks(displayId);
-            mCallbackOfWindows.put(displayId, callbacks);
-        }
-        callbacks.onAccessibilityWindowsChanged(forceSend, mTopFocusedDisplayId,
-                mTopFocusedWindowToken, new Point(SCREEN_WIDTH, SCREEN_HEIGHT),
-                mWindows.get(displayId));
-    }
-
-    private void changeFocusedWindowOnDisplayPerDisplayFocusConfig(
-            int changeFocusedDisplayId, int newFocusedWindowIndex, int oldTopFocusedDisplayId,
-            int oldFocusedWindowIndex) {
-        if (mSupportPerDisplayFocus) {
-            // Gets the old focused window of display which wants to change focused window.
-            WindowInfo focusedWindowInfo =
-                    mWindows.get(changeFocusedDisplayId).get(oldFocusedWindowIndex).getWindowInfo();
-            // Resets the focus of old focused window.
-            focusedWindowInfo.focused = false;
-            // Gets the new window of display which wants to change focused window.
-            focusedWindowInfo =
-                    mWindows.get(changeFocusedDisplayId).get(newFocusedWindowIndex).getWindowInfo();
-            // Sets the focus of new focused window.
-            focusedWindowInfo.focused = true;
-        } else {
-            // Gets the window of display which wants to change focused window.
-            WindowInfo focusedWindowInfo =
-                    mWindows.get(changeFocusedDisplayId).get(newFocusedWindowIndex).getWindowInfo();
-            // Sets the focus of new focused window.
-            focusedWindowInfo.focused = true;
-            // Gets the old focused window of old top focused display.
-            focusedWindowInfo =
-                    mWindows.get(oldTopFocusedDisplayId).get(oldFocusedWindowIndex).getWindowInfo();
-            // Resets the focus of old focused window.
-            focusedWindowInfo.focused = false;
-            // Changes the top focused display and window.
-            setTopFocusedWindowAndDisplay(changeFocusedDisplayId, newFocusedWindowIndex);
-        }
-    }
-
-    private AccessibilityWindow createMockAccessibilityWindow(IWindow windowToken, int displayId) {
-        final WindowInfo windowInfo = WindowInfo.obtain();
-        windowInfo.type = WindowManager.LayoutParams.TYPE_APPLICATION;
-        windowInfo.token = windowToken.asBinder();
-
-        final AccessibilityWindow window = Mockito.mock(AccessibilityWindow.class);
-        when(window.getWindowInfo()).thenReturn(windowInfo);
-        when(window.isFocused()).thenAnswer(invocation -> windowInfo.focused);
-        when(window.isTouchable()).thenReturn(true);
-        when(window.getType()).thenReturn(windowInfo.type);
-
-        setRegionForMockAccessibilityWindow(window, nextToucableRegion(displayId));
-        return window;
-    }
-
-    private void setRegionForMockAccessibilityWindow(AccessibilityWindow window, Region region) {
-        doAnswer(invocation -> {
-            ((Region) invocation.getArgument(0)).set(region);
-            return null;
-        }).when(window).getTouchableRegionInScreen(any(Region.class));
-        doAnswer(invocation -> {
-            ((Region) invocation.getArgument(0)).set(region);
-            return null;
-        }).when(window).getTouchableRegionInWindow(any(Region.class));
-    }
-
-    private Region nextToucableRegion(int displayId) {
-        final int topLeft = mNextRegionOffsets.get(displayId, 0);
-        final int bottomRight = topLeft + 100;
-        mNextRegionOffsets.put(displayId, topLeft + 10);
-        return new Region(topLeft, topLeft, bottomRight, bottomRight);
-    }
-
-    @Nullable
-    private static String toString(@Nullable CharSequence cs) {
-        return cs == null ? null : cs.toString();
-    }
-
-    static class DisplayIdMatcher extends TypeSafeMatcher<AccessibilityEvent> {
-        private final int mDisplayId;
-
-        DisplayIdMatcher(int displayId) {
-            super();
-            mDisplayId = displayId;
-        }
-
-        static DisplayIdMatcher displayId(int displayId) {
-            return new DisplayIdMatcher(displayId);
-        }
-
-        @Override
-        protected boolean matchesSafely(AccessibilityEvent event) {
-            return event.getDisplayId() == mDisplayId;
-        }
-
-        @Override
-        public void describeTo(Description description) {
-            description.appendText("Matching to displayId " + mDisplayId);
-        }
-    }
-
-    static class EventWindowIdMatcher extends TypeSafeMatcher<AccessibilityEvent> {
-        private int mWindowId;
-
-        EventWindowIdMatcher(int windowId) {
-            super();
-            mWindowId = windowId;
-        }
-
-        static EventWindowIdMatcher eventWindowId(int windowId) {
-            return new EventWindowIdMatcher(windowId);
-        }
-
-        @Override
-        protected boolean matchesSafely(AccessibilityEvent event) {
-            return event.getWindowId() == mWindowId;
-        }
-
-        @Override
-        public void describeTo(Description description) {
-            description.appendText("Matching to windowId " + mWindowId);
-        }
-    }
-
-    static class WindowChangesMatcher extends TypeSafeMatcher<AccessibilityEvent> {
-        private int mWindowChanges;
-
-        WindowChangesMatcher(int windowChanges) {
-            super();
-            mWindowChanges = windowChanges;
-        }
-
-        static WindowChangesMatcher a11yWindowChanges(int windowChanges) {
-            return new WindowChangesMatcher(windowChanges);
-        }
-
-        @Override
-        protected boolean matchesSafely(AccessibilityEvent event) {
-            return event.getWindowChanges() == mWindowChanges;
-        }
-
-        @Override
-        public void describeTo(Description description) {
-            description.appendText("Matching to window changes " + mWindowChanges);
-        }
-    }
-
-    static class WindowIdMatcher extends TypeSafeMatcher<AccessibilityWindowInfo> {
-        private final int mWindowId;
-
-        WindowIdMatcher(int windowId) {
-            super();
-            mWindowId = windowId;
-        }
-
-        static WindowIdMatcher windowId(int windowId) {
-            return new WindowIdMatcher(windowId);
-        }
-
-        @Override
-        protected boolean matchesSafely(AccessibilityWindowInfo window) {
-            return window.getId() == mWindowId;
-        }
-
-        @Override
-        public void describeTo(Description description) {
-            description.appendText("Matching to windowId " + mWindowId);
-        }
-    }
-}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index cf5dc4b..a7bf3e1 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -4404,6 +4404,7 @@
     }
 
     @Test
+    @Ignore("b/277916462")
     public void testSetAutoTimeEnabledModifiesSetting() throws Exception {
         mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
         setupDeviceOwner();
@@ -4415,6 +4416,7 @@
     }
 
     @Test
+    @Ignore("b/277916462")
     public void testSetAutoTimeEnabledWithPOOnUser0() throws Exception {
         mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
         setupProfileOwnerOnUser0();
@@ -4434,7 +4436,7 @@
     }
 
     @Test
-    @Ignore("b/359188869")
+    @Ignore("b/277916462")
     public void testSetAutoTimeEnabledWithPOOfOrganizationOwnedDevice() throws Exception {
         setupProfileOwner();
         configureProfileOwnerOfOrgOwnedDevice(admin1, CALLER_USER_HANDLE);
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationImmersiveAppCompatPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationImmersiveAppCompatPolicyTests.java
index c8fc482..6397334 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationImmersiveAppCompatPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationImmersiveAppCompatPolicyTests.java
@@ -20,16 +20,19 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
 import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
 import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
 
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.verify;
 
 import android.platform.test.annotations.Presubmit;
 import android.view.Surface;
@@ -54,6 +57,7 @@
 
     private DisplayRotationImmersiveAppCompatPolicy mPolicy;
 
+    private DisplayRotation mMockDisplayRotation;
     private AppCompatConfiguration mMockAppCompatConfiguration;
     private ActivityRecord mMockActivityRecord;
     private Task mMockTask;
@@ -98,6 +102,7 @@
         when(mockDisplayRotation.isLandscapeOrSeascape(Surface.ROTATION_90)).thenReturn(true);
         when(mockDisplayRotation.isLandscapeOrSeascape(Surface.ROTATION_180)).thenReturn(false);
         when(mockDisplayRotation.isLandscapeOrSeascape(Surface.ROTATION_270)).thenReturn(true);
+        mMockDisplayRotation = mockDisplayRotation;
 
         return mockDisplayRotation;
     }
@@ -196,6 +201,24 @@
     }
 
     @Test
+    public void testDeferOrientationUpdate() {
+        assertFalse(mPolicy.deferOrientationUpdate());
+
+        doReturn(SCREEN_ORIENTATION_UNSPECIFIED).when(mMockDisplayRotation).getLastOrientation();
+        final WindowOrientationListener orientationListener = mock(WindowOrientationListener.class);
+        doReturn(Surface.ROTATION_90).when(orientationListener).getProposedRotation();
+        doReturn(orientationListener).when(mMockDisplayRotation).getOrientationListener();
+        spyOn(mDisplayContent.mTransitionController);
+        doReturn(true).when(mDisplayContent.mTransitionController)
+                .hasTransientLaunch(mDisplayContent);
+
+        assertTrue(mPolicy.deferOrientationUpdate());
+        mDisplayContent.mTransitionController.mStateValidators.getFirst().run();
+
+        verify(mWm).updateRotation(false, false);
+    }
+
+    @Test
     public void testRotationChoiceEnforcedOnly_nullTopRunningActivity_lockNotEnforced() {
         when(mDisplayContent.topRunningActivity()).thenReturn(null);
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/SafeActivityOptionsTest.java b/services/tests/wmtests/src/com/android/server/wm/SafeActivityOptionsTest.java
index 791b5b5..a92fe3a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SafeActivityOptionsTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SafeActivityOptionsTest.java
@@ -162,6 +162,10 @@
             verifySecureExceptionThrown(activityOptions, taskSupervisor);
 
             activityOptions = ActivityOptions.makeBasic();
+            activityOptions.setTaskAlwaysOnTop(true);
+            verifySecureExceptionThrown(activityOptions, taskSupervisor);
+
+            activityOptions = ActivityOptions.makeBasic();
             activityOptions.setLaunchDisplayId(DEFAULT_DISPLAY);
             verifySecureExceptionThrown(activityOptions, taskSupervisor);
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index ad66118..4fbe492 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -4928,6 +4928,7 @@
         spyOn(pm);
         final PackageManager.Property property = new PackageManager.Property("propertyName",
                 true /* value */, name.getPackageName(), name.getClassName());
+        // Activity level.
         try {
             doReturn(property).when(pm).getPropertyAsUser(
                     WindowManager.PROPERTY_COMPAT_ALLOW_RESTRICTED_RESIZABILITY,
@@ -4938,6 +4939,19 @@
         final ActivityRecord optOutActivity = new ActivityBuilder(mAtm)
                 .setComponent(name).setTask(mTask).build();
         assertFalse(optOutActivity.isUniversalResizeable());
+
+        // Application level.
+        try {
+            doReturn(property).when(pm).getProperty(
+                    WindowManager.PROPERTY_COMPAT_ALLOW_RESTRICTED_RESIZABILITY,
+                    name.getPackageName());
+        } catch (PackageManager.NameNotFoundException e) {
+            throw new RuntimeException(e);
+        }
+        final ActivityRecord optOutAppActivity = new ActivityBuilder(mAtm)
+                .setComponent(getUniqueComponentName(mContext.getPackageName()))
+                .setTask(mTask).build();
+        assertFalse(optOutAppActivity.isUniversalResizeable());
     }
 
 
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index e22d75e..ad5d42a 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -19599,4 +19599,37 @@
             throw ex.rethrowAsRuntimeException();
         }
     }
+
+    /**
+     * Returns carrier id maps to the passing CarrierIdentifier.
+     * To recognize a carrier (including MVNO) as a first-class identity,
+     * Android assigns each carrier with a canonical integer a.k.a. carrier id.
+     * The carrier ID is an Android platform-wide identifier for a carrier.
+     * AOSP maintains carrier ID assignments in
+     * <a href="https://android.googlesource.com/platform/packages/providers/TelephonyProvider/+/master/assets/latest_carrier_id/carrier_list.textpb">here</a>
+     *
+     * @param carrierIdentifier {@link CarrierIdentifier}
+     *
+     * @return Carrier id. Return {@link #UNKNOWN_CARRIER_ID} if the carrier cannot be identified.
+     * @throws UnsupportedOperationException If the device does not have
+     *          {@link PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}.
+     *
+     * @hide
+     */
+    @FlaggedApi(Flags.FLAG_CARRIER_ID_FROM_CARRIER_IDENTIFIER)
+    @SystemApi
+    @WorkerThread
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
+    @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    public int getCarrierIdFromCarrierIdentifier(@NonNull CarrierIdentifier carrierIdentifier) {
+        try {
+            ITelephony service = getITelephony();
+            if (service != null) {
+                return service.getCarrierIdFromIdentifier(carrierIdentifier);
+            }
+        } catch (RemoteException ex) {
+            // This could happen if binder process crashes.
+        }
+        return UNKNOWN_CARRIER_ID;
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index d22e9fa..294c93c 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -3519,4 +3519,15 @@
     * @hide
     */
     void setNtnSmsSupported(boolean ntnSmsSupported);
+
+    /**
+     * Returns carrier id maps to the passing {@link CarrierIdentifier}.
+     *
+     * @param {@link CarrierIdentifier}.
+     *
+     * @return carrier id from passing {@link CarrierIdentifier} or {@link #UNKNOWN_CARRIER_ID}
+     * if the carrier cannot be identified
+     * @hide
+     */
+    int getCarrierIdFromIdentifier(in CarrierIdentifier carrierIdentifier);
 }
diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/DesktopModeAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/DesktopModeAppHelper.kt
index 6432827..e0900a6 100644
--- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/DesktopModeAppHelper.kt
+++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/DesktopModeAppHelper.kt
@@ -23,6 +23,7 @@
 import android.graphics.Region
 import android.os.SystemClock
 import android.platform.uiautomatorhelpers.DeviceHelpers
+import android.tools.PlatformConsts
 import android.tools.device.apphelpers.IStandardAppHelper
 import android.tools.helpers.SYSTEMUI_PACKAGE
 import android.tools.traces.parsers.WindowManagerStateHelper
@@ -163,7 +164,10 @@
             .StateSyncBuilder()
             .withAppTransitionIdle()
             .apply {
-                if (isPip) withPipShown() else withWindowSurfaceDisappeared(innerHelper)
+                if (isPip) withPipShown()
+                else
+                    withWindowSurfaceDisappeared(innerHelper)
+                        .withActivityState(innerHelper, PlatformConsts.STATE_STOPPED)
             }
             .waitForAndVerify()
     }
diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt
index 931e4f8..db4838e 100644
--- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt
+++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt
@@ -250,18 +250,13 @@
             wmHelper,
             launchedAppComponentMatcherOverride,
             action,
-            stringExtras,
-            waitConditionsBuilder =
-                wmHelper
-                    .StateSyncBuilder()
-                    .add(ConditionsFactory.isWMStateComplete())
-                    .withAppTransitionIdle()
-                    .add(ConditionsFactory.hasPipWindow())
+            stringExtras
         )
 
         wmHelper
             .StateSyncBuilder()
             .withWindowSurfaceAppeared(this)
+            .add(ConditionsFactory.isWMStateComplete())
             .withPipShown()
             .waitForAndVerify()
     }