Merge "Updated AggregatedMobileDataStatsPuller" into main
diff --git a/boot/Android.bp b/boot/Android.bp
index cdfa7c80..f60bb9e 100644
--- a/boot/Android.bp
+++ b/boot/Android.bp
@@ -31,6 +31,7 @@
         "car_bootclasspath_fragment",
         "nfc_apex_bootclasspath_fragment",
         "release_crashrecovery_module",
+        "release_package_profiling_module",
     ],
     properties: [
         "fragments",
@@ -122,10 +123,6 @@
             module: "com.android.permission-bootclasspath-fragment",
         },
         {
-            apex: "com.android.profiling",
-            module: "com.android.profiling-bootclasspath-fragment",
-        },
-        {
             apex: "com.android.scheduling",
             module: "com.android.scheduling-bootclasspath-fragment",
         },
@@ -179,6 +176,15 @@
                 },
             ],
         },
+        release_package_profiling_module: {
+            fragments: [
+                // only used if profiling is enabled.
+                {
+                    apex: "com.android.profiling",
+                    module: "com.android.profiling-bootclasspath-fragment",
+                },
+            ],
+        },
     },
 
     // Additional information needed by hidden api processing.
diff --git a/core/api/current.txt b/core/api/current.txt
index d9c82b1..bc89f12 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -203,7 +203,7 @@
     field public static final String MANAGE_DEVICE_POLICY_SYSTEM_APPS = "android.permission.MANAGE_DEVICE_POLICY_SYSTEM_APPS";
     field public static final String MANAGE_DEVICE_POLICY_SYSTEM_DIALOGS = "android.permission.MANAGE_DEVICE_POLICY_SYSTEM_DIALOGS";
     field public static final String MANAGE_DEVICE_POLICY_SYSTEM_UPDATES = "android.permission.MANAGE_DEVICE_POLICY_SYSTEM_UPDATES";
-    field @FlaggedApi("com.android.net.thread.flags.thread_user_restriction_enabled") public static final String MANAGE_DEVICE_POLICY_THREAD_NETWORK = "android.permission.MANAGE_DEVICE_POLICY_THREAD_NETWORK";
+    field @FlaggedApi("com.android.net.thread.platform.flags.thread_user_restriction_enabled") public static final String MANAGE_DEVICE_POLICY_THREAD_NETWORK = "android.permission.MANAGE_DEVICE_POLICY_THREAD_NETWORK";
     field public static final String MANAGE_DEVICE_POLICY_TIME = "android.permission.MANAGE_DEVICE_POLICY_TIME";
     field public static final String MANAGE_DEVICE_POLICY_USB_DATA_SIGNALLING = "android.permission.MANAGE_DEVICE_POLICY_USB_DATA_SIGNALLING";
     field public static final String MANAGE_DEVICE_POLICY_USB_FILE_TRANSFER = "android.permission.MANAGE_DEVICE_POLICY_USB_FILE_TRANSFER";
@@ -13218,7 +13218,7 @@
     field public static final String FEATURE_TELEPHONY_RADIO_ACCESS = "android.hardware.telephony.radio.access";
     field public static final String FEATURE_TELEPHONY_SUBSCRIPTION = "android.hardware.telephony.subscription";
     field @Deprecated public static final String FEATURE_TELEVISION = "android.hardware.type.television";
-    field @FlaggedApi("com.android.net.thread.flags.thread_enabled_platform") public static final String FEATURE_THREAD_NETWORK = "android.hardware.thread_network";
+    field @FlaggedApi("com.android.net.thread.platform.flags.thread_enabled_platform") public static final String FEATURE_THREAD_NETWORK = "android.hardware.thread_network";
     field public static final String FEATURE_TOUCHSCREEN = "android.hardware.touchscreen";
     field public static final String FEATURE_TOUCHSCREEN_MULTITOUCH = "android.hardware.touchscreen.multitouch";
     field public static final String FEATURE_TOUCHSCREEN_MULTITOUCH_DISTINCT = "android.hardware.touchscreen.multitouch.distinct";
@@ -34086,7 +34086,7 @@
     field @FlaggedApi("android.app.admin.flags.esim_management_enabled") public static final String DISALLOW_SIM_GLOBALLY = "no_sim_globally";
     field public static final String DISALLOW_SMS = "no_sms";
     field public static final String DISALLOW_SYSTEM_ERROR_DIALOGS = "no_system_error_dialogs";
-    field @FlaggedApi("com.android.net.thread.flags.thread_user_restriction_enabled") public static final String DISALLOW_THREAD_NETWORK = "no_thread_network";
+    field @FlaggedApi("com.android.net.thread.platform.flags.thread_user_restriction_enabled") public static final String DISALLOW_THREAD_NETWORK = "no_thread_network";
     field public static final String DISALLOW_ULTRA_WIDEBAND_RADIO = "no_ultra_wideband_radio";
     field public static final String DISALLOW_UNIFIED_PASSWORD = "no_unified_password";
     field public static final String DISALLOW_UNINSTALL_APPS = "no_uninstall_apps";
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index b2db7c1..2fec0ad 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -388,7 +388,7 @@
     field public static final String SYSTEM_APPLICATION_OVERLAY = "android.permission.SYSTEM_APPLICATION_OVERLAY";
     field public static final String SYSTEM_CAMERA = "android.permission.SYSTEM_CAMERA";
     field public static final String TETHER_PRIVILEGED = "android.permission.TETHER_PRIVILEGED";
-    field @FlaggedApi("com.android.net.thread.flags.thread_enabled_platform") public static final String THREAD_NETWORK_PRIVILEGED = "android.permission.THREAD_NETWORK_PRIVILEGED";
+    field @FlaggedApi("com.android.net.thread.platform.flags.thread_enabled_platform") public static final String THREAD_NETWORK_PRIVILEGED = "android.permission.THREAD_NETWORK_PRIVILEGED";
     field public static final String TIS_EXTENSION_INTERFACE = "android.permission.TIS_EXTENSION_INTERFACE";
     field public static final String TOGGLE_AUTOMOTIVE_PROJECTION = "android.permission.TOGGLE_AUTOMOTIVE_PROJECTION";
     field public static final String TRIGGER_LOST_MODE = "android.permission.TRIGGER_LOST_MODE";
@@ -3787,7 +3787,7 @@
     field public static final String SYSTEM_CONFIG_SERVICE = "system_config";
     field public static final String SYSTEM_UPDATE_SERVICE = "system_update";
     field public static final String TETHERING_SERVICE = "tethering";
-    field @FlaggedApi("com.android.net.thread.flags.thread_enabled_platform") public static final String THREAD_NETWORK_SERVICE = "thread_network";
+    field @FlaggedApi("com.android.net.thread.platform.flags.thread_enabled_platform") public static final String THREAD_NETWORK_SERVICE = "thread_network";
     field public static final String TIME_MANAGER_SERVICE = "time_manager";
     field public static final String TRANSLATION_MANAGER_SERVICE = "translation";
     field public static final String UI_TRANSLATION_SERVICE = "ui_translation";
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index cdf232c..b8c32a4 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -251,6 +251,7 @@
     method @RequiresPermission("android.permission.MANAGE_APPOPS") public void getHistoricalOpsFromDiskRaw(@NonNull android.app.AppOpsManager.HistoricalOpsRequest, @Nullable java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.AppOpsManager.HistoricalOps>);
     method public static int getNumOps();
     method public boolean isOperationActive(int, int, String);
+    method public int noteOpNoThrow(int, @NonNull android.content.AttributionSource, @Nullable String);
     method @RequiresPermission("android.permission.MANAGE_APPOPS") public void offsetHistory(long);
     method public static String opToPermission(int);
     method public static int permissionToOpCode(String);
@@ -3966,6 +3967,7 @@
   }
 
   public final class InputMethodInfo implements android.os.Parcelable {
+    ctor public InputMethodInfo(@NonNull String, @NonNull String, @NonNull CharSequence, @NonNull String, @NonNull String, boolean, @NonNull String);
     ctor @FlaggedApi("android.view.inputmethod.connectionless_handwriting") public InputMethodInfo(@NonNull String, @NonNull String, @NonNull CharSequence, @NonNull String, @NonNull String, boolean, boolean, @NonNull String);
     ctor public InputMethodInfo(@NonNull String, @NonNull String, @NonNull CharSequence, @NonNull String, int);
     field public static final int COMPONENT_NAME_MAX_LENGTH = 1000; // 0x3e8
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 39900a0..2afc78c 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -7800,7 +7800,7 @@
         }
         final List<AppOpsManager.PackageOps> result;
         try {
-            result =  mService.getPackagesForOpsForDevice(opCodes, persistentDeviceId);
+            result = mService.getPackagesForOpsForDevice(opCodes, persistentDeviceId);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -8272,14 +8272,24 @@
                 cb = new IAppOpsCallback.Stub() {
                     public void opChanged(int op, int uid, String packageName,
                             String persistentDeviceId) {
-                        if (callback instanceof OnOpChangedInternalListener) {
-                            ((OnOpChangedInternalListener)callback).onOpChanged(op, packageName,
-                                persistentDeviceId);
-                        }
-                        if (sAppOpInfos[op].name != null) {
-
-                            callback.onOpChanged(sAppOpInfos[op].name, packageName,
-                                    UserHandle.getUserId(uid), persistentDeviceId);
+                        if (Flags.deviceAwarePermissionApisEnabled()) {
+                            if (callback instanceof OnOpChangedInternalListener) {
+                                ((OnOpChangedInternalListener)callback).onOpChanged(op, packageName,
+                                        persistentDeviceId);
+                            }
+                            if (sAppOpInfos[op].name != null) {
+                                callback.onOpChanged(sAppOpInfos[op].name, packageName,
+                                        UserHandle.getUserId(uid), persistentDeviceId);
+                            }
+                        } else {
+                            if (callback instanceof OnOpChangedInternalListener) {
+                                ((OnOpChangedInternalListener) callback).onOpChanged(op,
+                                        packageName);
+                            }
+                            if (sAppOpInfos[op].name != null) {
+                                callback.onOpChanged(sAppOpInfos[op].name, packageName,
+                                        UserHandle.getUserId(uid));
+                            }
                         }
                     }
                 };
@@ -8940,6 +8950,8 @@
      *
      * @hide
      */
+    @TestApi
+    @SuppressLint("UnflaggedApi")
     public int noteOpNoThrow(int op, @NonNull AttributionSource attributionSource,
             @Nullable String message) {
         return noteOpNoThrow(op, attributionSource.getUid(), attributionSource.getPackageName(),
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index a426eda..70d2c7a 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -4816,9 +4816,7 @@
      * @see android.net.thread.ThreadNetworkManager
      * @hide
      */
-    // TODO (b/325886480): update the flag to
-    // "com.android.net.thread.platform.flags.Flags.FLAG_THREAD_ENABLED_PLATFORM"
-    @FlaggedApi("com.android.net.thread.flags.thread_enabled_platform")
+    @FlaggedApi(com.android.net.thread.platform.flags.Flags.FLAG_THREAD_ENABLED_PLATFORM)
     @SystemApi
     public static final String THREAD_NETWORK_SERVICE = "thread_network";
 
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 7a015cd..240cff3 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -3974,9 +3974,7 @@
      * The device is capable of communicating with other devices via
      * <a href="https://www.threadgroup.org">Thread</a> networking protocol.
      */
-    // TODO (b/325886480): update the flag to
-    // "com.android.net.thread.platform.flags.Flags.FLAG_THREAD_ENABLED_PLATFORM"
-    @FlaggedApi("com.android.net.thread.flags.thread_enabled_platform")
+    @FlaggedApi(com.android.net.thread.platform.flags.Flags.FLAG_THREAD_ENABLED_PLATFORM)
     @SdkConstant(SdkConstantType.FEATURE)
     public static final String FEATURE_THREAD_NETWORK = "android.hardware.thread_network";
 
diff --git a/core/java/android/credentials/GetCandidateCredentialsResponse.java b/core/java/android/credentials/GetCandidateCredentialsResponse.java
index 6e53fd9..3d8ccaa 100644
--- a/core/java/android/credentials/GetCandidateCredentialsResponse.java
+++ b/core/java/android/credentials/GetCandidateCredentialsResponse.java
@@ -18,7 +18,7 @@
 
 import android.annotation.Hide;
 import android.annotation.NonNull;
-import android.app.PendingIntent;
+import android.content.Intent;
 import android.credentials.selection.GetCredentialProviderData;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -39,32 +39,22 @@
     @NonNull
     private final List<GetCredentialProviderData> mCandidateProviderDataList;
 
-    private final PendingIntent mPendingIntent;
+    @NonNull
+    private final Intent mIntent;
 
     /**
      * @hide
      */
     @Hide
     public GetCandidateCredentialsResponse(
-            GetCredentialResponse getCredentialResponse
-    ) {
-        mCandidateProviderDataList = null;
-        mPendingIntent = null;
-    }
-
-    /**
-     * @hide
-     */
-    @Hide
-    public GetCandidateCredentialsResponse(
-            List<GetCredentialProviderData> candidateProviderDataList,
-            PendingIntent pendingIntent
+            @NonNull List<GetCredentialProviderData> candidateProviderDataList,
+            @NonNull Intent intent
     ) {
         Preconditions.checkCollectionNotEmpty(
                 candidateProviderDataList,
                 /*valueName=*/ "candidateProviderDataList");
         mCandidateProviderDataList = new ArrayList<>(candidateProviderDataList);
-        mPendingIntent = pendingIntent;
+        mIntent = intent;
     }
 
     /**
@@ -81,8 +71,9 @@
      *
      * @hide
      */
-    public PendingIntent getPendingIntent() {
-        return mPendingIntent;
+    @NonNull
+    public Intent getIntent() {
+        return mIntent;
     }
 
     protected GetCandidateCredentialsResponse(Parcel in) {
@@ -91,14 +82,13 @@
         mCandidateProviderDataList = candidateProviderDataList;
 
         AnnotationValidations.validate(NonNull.class, null, mCandidateProviderDataList);
-
-        mPendingIntent = in.readTypedObject(PendingIntent.CREATOR);
+        mIntent = in.readTypedObject(Intent.CREATOR);
     }
 
     @Override
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeTypedList(mCandidateProviderDataList);
-        dest.writeTypedObject(mPendingIntent, flags);
+        dest.writeTypedObject(mIntent, flags);
     }
 
     @Override
diff --git a/core/java/android/inputmethodservice/navigationbar/NavigationBarView.java b/core/java/android/inputmethodservice/navigationbar/NavigationBarView.java
index 510b14e..e28f345 100644
--- a/core/java/android/inputmethodservice/navigationbar/NavigationBarView.java
+++ b/core/java/android/inputmethodservice/navigationbar/NavigationBarView.java
@@ -99,7 +99,11 @@
 
         mDeadZone = new android.inputmethodservice.navigationbar.DeadZone(this);
 
-        getImeSwitchButton().setOnClickListener(view -> view.getContext()
+        getBackButton().setLongClickable(false);
+
+        final ButtonDispatcher imeSwitchButton = getImeSwitchButton();
+        imeSwitchButton.setLongClickable(false);
+        imeSwitchButton.setOnClickListener(view -> view.getContext()
                 .getSystemService(InputMethodManager.class).showInputMethodPicker());
     }
 
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index be17d7c..ccb534e 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -1920,9 +1920,7 @@
      * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
      * @see #getUserRestrictions()
      */
-    // TODO (b/325886480): update the flag to
-    // "com.android.net.thread.platform.flags.Flags.FLAG_THREAD_USER_RESTRICTION_ENABLED"
-    @FlaggedApi("com.android.net.thread.flags.thread_user_restriction_enabled")
+    @FlaggedApi(com.android.net.thread.platform.flags.Flags.FLAG_THREAD_USER_RESTRICTION_ENABLED)
     public static final String DISALLOW_THREAD_NETWORK = "no_thread_network";
 
     /**
diff --git a/core/java/android/os/storage/OWNERS b/core/java/android/os/storage/OWNERS
index 2cb16d337b..c21895a 100644
--- a/core/java/android/os/storage/OWNERS
+++ b/core/java/android/os/storage/OWNERS
@@ -3,11 +3,15 @@
 # PLEASE ASSIGN NEW BUGS TO android-storage-triage@, NOT TO INDIVIDUAL PEOPLE
 
 # Android Storage Team
+aibra@google.com
+akgaurav@google.com
 alukin@google.com
 ankitavyas@google.com
 dipankarb@google.com
 gargshivam@google.com
+ishneet@google.com
 krishang@google.com
+oeissa@google.com
 riyaghai@google.com
 sahanas@google.com
 shikhamalhotra@google.com
diff --git a/core/java/android/permission/PermissionUsageHelper.java b/core/java/android/permission/PermissionUsageHelper.java
index 460b4dd..141ffc9 100644
--- a/core/java/android/permission/PermissionUsageHelper.java
+++ b/core/java/android/permission/PermissionUsageHelper.java
@@ -359,8 +359,7 @@
                         new PermissionGroupUsage(usage.packageName, usage.uid, usage.lastAccessTime,
                                 permGroup,
                                 usage.isRunning, isPhone, usage.attributionTag, attributionLabel,
-                                usagesWithLabels.valueAt(usageNum),
-                                VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT));
+                                usagesWithLabels.valueAt(usageNum), deviceId));
             }
         }
 
diff --git a/core/java/android/service/chooser/flags.aconfig b/core/java/android/service/chooser/flags.aconfig
index 00236df..d72441f 100644
--- a/core/java/android/service/chooser/flags.aconfig
+++ b/core/java/android/service/chooser/flags.aconfig
@@ -27,3 +27,14 @@
   description: "Provides additional callbacks with information about user actions in ChooserResult"
   bug: "263474465"
 }
+
+flag {
+  name: "legacy_chooser_pinning_removal"
+  namespace: "intentresolver"
+  description: "Removing pinning functionality from the legacy chooser (used by partial screenshare)"
+  bug: "301068735"
+  metadata {
+    purpose: PURPOSE_BUGFIX
+  }
+}
+
diff --git a/core/java/android/view/OWNERS b/core/java/android/view/OWNERS
index ad326e4..a2f767d 100644
--- a/core/java/android/view/OWNERS
+++ b/core/java/android/view/OWNERS
@@ -102,6 +102,7 @@
 per-file IWindow*.aidl = file:/services/core/java/com/android/server/wm/OWNERS
 per-file RemoteAnimation*.java = file:/services/core/java/com/android/server/wm/OWNERS
 per-file RemoteAnimation*.aidl = file:/services/core/java/com/android/server/wm/OWNERS
+per-file ScreenRecordingCallbacks.java = file:/services/core/java/com/android/server/wm/OWNERS
 per-file *SurfaceControl*.java = file:/services/core/java/com/android/server/wm/OWNERS
 per-file SurfaceControl*.aidl = file:/services/core/java/com/android/server/wm/OWNERS
 per-file SurfaceSession.java = file:/services/core/java/com/android/server/wm/OWNERS
diff --git a/core/java/android/view/RoundedCorners.java b/core/java/android/view/RoundedCorners.java
index f68cc69..1f841bf 100644
--- a/core/java/android/view/RoundedCorners.java
+++ b/core/java/android/view/RoundedCorners.java
@@ -198,6 +198,12 @@
             radius = res.getDimensionPixelSize(R.dimen.rounded_corner_radius);
         }
         array.recycle();
+        // For devices with round displays (e.g. watches) that don't otherwise provide the rounded
+        // corner radius via resource overlays, we can infer the corner radius directly from the
+        // display size.
+        if (radius == 0 && res.getConfiguration().isScreenRound()) {
+            radius = res.getDisplayMetrics().widthPixels / 2;
+        }
         return radius;
     }
 
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index cbb3be7..042af1f 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -15314,6 +15314,7 @@
      * {@link #isLongClickable()}, {@link #isContextClickable()},
      * {@link #isScreenReaderFocusable()}, or {@link #isFocusable()}
      * <li>Has an {@link AccessibilityDelegate}
+     * <li>Has an {@link AccessibilityNodeProvider}
      * <li>Has an interaction listener, e.g. {@link OnTouchListener},
      * {@link OnKeyListener}, etc.
      * <li>Is an accessibility live region, e.g.
@@ -15346,7 +15347,8 @@
         }
 
         return mode == IMPORTANT_FOR_ACCESSIBILITY_YES || isActionableForAccessibility()
-                || hasListenersForAccessibility() || mAccessibilityDelegate != null
+                || hasListenersForAccessibility() || getAccessibilityNodeProvider() != null
+                || getAccessibilityDelegate() != null
                 || getAccessibilityLiveRegion() != ACCESSIBILITY_LIVE_REGION_NONE
                 || isAccessibilityPane() || isAccessibilityHeading();
     }
diff --git a/core/java/android/view/inputmethod/InputMethodInfo.java b/core/java/android/view/inputmethod/InputMethodInfo.java
index 7c9678f..16fecc1 100644
--- a/core/java/android/view/inputmethod/InputMethodInfo.java
+++ b/core/java/android/view/inputmethod/InputMethodInfo.java
@@ -497,6 +497,25 @@
      * @hide
      */
     @TestApi
+    public InputMethodInfo(@NonNull String packageName, @NonNull String className,
+            @NonNull CharSequence label, @NonNull String settingsActivity,
+            @NonNull String languageSettingsActivity, boolean supportStylusHandwriting,
+            @NonNull String stylusHandwritingSettingsActivityAttr) {
+        this(buildFakeResolveInfo(packageName, className, label), false /* isAuxIme */,
+                settingsActivity, languageSettingsActivity, null /* subtypes */,
+                0 /* isDefaultResId */, false /* forceDefault */,
+                true /* supportsSwitchingToNextInputMethod */,
+                false /* inlineSuggestionsEnabled */, false /* isVrOnly */,
+                false /* isVirtualDeviceOnly */, 0 /* handledConfigChanges */,
+                supportStylusHandwriting, false /* supportConnectionlessStylusHandwriting */,
+                stylusHandwritingSettingsActivityAttr, false /* inlineSuggestionsEnabled */);
+    }
+
+    /**
+     * Test API for creating a built-in input method to verify stylus handwriting.
+     * @hide
+     */
+    @TestApi
     @FlaggedApi(Flags.FLAG_CONNECTIONLESS_HANDWRITING)
     public InputMethodInfo(@NonNull String packageName, @NonNull String className,
             @NonNull CharSequence label, @NonNull String settingsActivity,
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 3bce155..f349ae9 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -3490,8 +3490,7 @@
             return false;
         }
         mServedView = mNextServedView;
-        if (initiationWithoutInputConnection() && mServedView.onCheckIsTextEditor()
-                && mServedView.isHandwritingDelegate()) {
+        if (initiationWithoutInputConnection() && mServedView.isHandwritingDelegate()) {
             mServedView.getViewRootImpl().getHandwritingInitiator().onDelegateViewFocused(
                     mServedView);
         }
diff --git a/core/java/android/window/flags/OWNERS b/core/java/android/window/flags/OWNERS
index 3fa3760..fd73d35 100644
--- a/core/java/android/window/flags/OWNERS
+++ b/core/java/android/window/flags/OWNERS
@@ -1,2 +1,3 @@
 per-file responsible_apis.aconfig = file:/BAL_OWNERS
 per-file large_screen_experiences_app_compat.aconfig = file:/LSE_APP_COMPAT_OWNERS
+per-file accessibility.aconfig = file:/core/java/android/view/accessibility/OWNERS
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 86d3037..29669d3 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -96,6 +96,7 @@
 import android.provider.OpenableColumns;
 import android.provider.Settings;
 import android.service.chooser.ChooserTarget;
+import android.service.chooser.Flags;
 import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.util.HashedStringCache;
@@ -2543,6 +2544,9 @@
 
         @Override
         public boolean isComponentPinned(ComponentName name) {
+            if (Flags.legacyChooserPinningRemoval()) {
+                return false;
+            }
             return mPinnedSharedPrefs.getBoolean(name.flattenToString(), false);
         }
 
@@ -3147,6 +3151,10 @@
     }
 
     private boolean shouldShowTargetDetails(TargetInfo ti) {
+        if (Flags.legacyChooserPinningRemoval()) {
+            // Never show the long press menu if we've removed pinning.
+            return false;
+        }
         ComponentName nearbyShare = getNearbySharingComponent();
         //  Suppress target details for nearby share to hide pin/unpin action
         boolean isNearbyShare = nearbyShare != null && nearbyShare.equals(
diff --git a/core/java/com/android/internal/pm/parsing/pkg/PackageImpl.java b/core/java/com/android/internal/pm/parsing/pkg/PackageImpl.java
index 73df5e8..5e89d06 100644
--- a/core/java/com/android/internal/pm/parsing/pkg/PackageImpl.java
+++ b/core/java/com/android/internal/pm/parsing/pkg/PackageImpl.java
@@ -421,6 +421,8 @@
     @NonNull
     private String[] mUsesStaticLibrariesSorted;
 
+    private boolean mAppMetadataFileInApk = false;
+
     @NonNull
     public static PackageImpl forParsing(@NonNull String packageName, @NonNull String baseCodePath,
             @NonNull String codePath, @NonNull TypedArray manifestArray, boolean isCoreApp,
@@ -1063,6 +1065,11 @@
         return memtagMode;
     }
 
+    @Override
+    public boolean isAppMetadataFileInApk() {
+        return mAppMetadataFileInApk;
+    }
+
     @Nullable
     @Override
     public Bundle getMetaData() {
@@ -2151,6 +2158,12 @@
     }
 
     @Override
+    public PackageImpl setAppMetadataFileInApk(boolean fileInApk) {
+        mAppMetadataFileInApk = fileInApk;
+        return this;
+    }
+
+    @Override
     public PackageImpl setMetaData(@Nullable Bundle value) {
         metaData = value;
         return this;
@@ -3264,6 +3277,7 @@
         dest.writeLong(this.mBooleans);
         dest.writeLong(this.mBooleans2);
         dest.writeBoolean(this.mAllowCrossUidActivitySwitchFromBelow);
+        dest.writeBoolean(this.mAppMetadataFileInApk);
     }
 
     public PackageImpl(Parcel in) {
@@ -3426,6 +3440,7 @@
         this.mBooleans = in.readLong();
         this.mBooleans2 = in.readLong();
         this.mAllowCrossUidActivitySwitchFromBelow = in.readBoolean();
+        this.mAppMetadataFileInApk = in.readBoolean();
 
         assignDerivedFields();
         assignDerivedFields2();
diff --git a/core/java/com/android/internal/pm/parsing/pkg/ParsedPackage.java b/core/java/com/android/internal/pm/parsing/pkg/ParsedPackage.java
index 66cfb69..3c26a7c 100644
--- a/core/java/com/android/internal/pm/parsing/pkg/ParsedPackage.java
+++ b/core/java/com/android/internal/pm/parsing/pkg/ParsedPackage.java
@@ -127,4 +127,7 @@
     ParsedPackage setDirectBootAware(boolean directBootAware);
 
     ParsedPackage setPersistent(boolean persistent);
+
+    /** Retrieves whether the apk contains a app metadata file. */
+    boolean isAppMetadataFileInApk();
 }
diff --git a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackage.java b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackage.java
index 5d185af..5ab17a6 100644
--- a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackage.java
+++ b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackage.java
@@ -133,6 +133,9 @@
             @Nullable SparseArray<int[]> splitDependencies
     );
 
+    /** Sets whether the apk contains a app metadata file. */
+    ParsingPackage setAppMetadataFileInApk(boolean fileInApk);
+
     ParsingPackage setMetaData(Bundle metaData);
 
     ParsingPackage setForceQueryable(boolean forceQueryable);
diff --git a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java
index 2e6053d..00c4827 100644
--- a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java
+++ b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java
@@ -46,6 +46,7 @@
 import android.content.pm.ConfigurationInfo;
 import android.content.pm.FeatureGroupInfo;
 import android.content.pm.FeatureInfo;
+import android.content.pm.Flags;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.Property;
@@ -163,6 +164,8 @@
      */
     public static final String ANDROID_MANIFEST_FILENAME = "AndroidManifest.xml";
 
+    public static final String APP_METADATA_FILE_NAME = "app.metadata";
+
     /**
      * Path prefix for apps on expanded storage
      */
@@ -636,6 +639,11 @@
                 pkg.setSigningDetails(SigningDetails.UNKNOWN);
             }
 
+            if (Flags.aslInApkAppMetadataSource()
+                    && ArrayUtils.contains(assets.list(""), APP_METADATA_FILE_NAME)) {
+                pkg.setAppMetadataFileInApk(true);
+            }
+
             return input.success(pkg);
         } catch (Exception e) {
             return input.error(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
@@ -686,7 +694,8 @@
      */
     private ParseResult<ParsingPackage> parseBaseApk(ParseInput input, String apkPath,
             String codePath, Resources res, XmlResourceParser parser, int flags,
-            boolean shouldSkipComponents) throws XmlPullParserException, IOException {
+            boolean shouldSkipComponents)
+            throws XmlPullParserException, IOException {
         final String splitName;
         final String pkgName;
 
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 0938ce17..3ed9f49 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -1965,7 +1965,7 @@
 
     // If this zygote isn't root, it won't be able to create a process group,
     // since the directory is owned by root.
-    if (!is_system_server && getuid() == 0) {
+    if (getuid() == 0) {
         const int rc = createProcessGroup(uid, getpid());
         if (rc != 0) {
             fail_fn(rc == -EROFS ? CREATE_ERROR("createProcessGroup failed, kernel missing "
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 525bdc9..487b5be 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2281,7 +2281,7 @@
     <!-- @SystemApi @hide Allows changing Thread network state and access to Thread network
         credentials such as Network Key and PSKc.
         <p>Not for use by third-party applications.
-        @FlaggedApi("com.android.net.thread.flags.thread_enabled_platform") -->
+        @FlaggedApi("com.android.net.thread.platform.flags.thread_enabled_platform") -->
     <permission android:name="android.permission.THREAD_NETWORK_PRIVILEGED"
                 android:protectionLevel="signature|privileged" />
 
@@ -3629,7 +3629,7 @@
 
     <!-- Allows an application to set policy related to <a
     href="https://www.threadgroup.org">Thread</a> network.
-        @FlaggedApi("com.android.net.thread.flags.thread_user_restriction_enabled")
+        @FlaggedApi("com.android.net.thread.platform.flags.thread_user_restriction_enabled")
     -->
     <permission android:name="android.permission.MANAGE_DEVICE_POLICY_THREAD_NETWORK"
                 android:protectionLevel="internal|role" />
diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp
index 37e6780..e72beee 100644
--- a/core/tests/coretests/Android.bp
+++ b/core/tests/coretests/Android.bp
@@ -28,10 +28,19 @@
     visibility: ["//visibility:private"],
 }
 
+java_defaults {
+    name: "FrameworksCoreTests-resources",
+    aaptflags: [
+        "-0 .dat",
+        "-0 .gld",
+        "-c fa",
+    ],
+    resource_dirs: ["res"],
+}
+
 android_test {
     name: "FrameworksCoreTests",
-    // FrameworksCoreTestsRavenwood references the .aapt.srcjar
-    use_resource_processor: false,
+    defaults: ["FrameworksCoreTests-resources"],
 
     srcs: [
         "src/**/*.java",
@@ -117,7 +126,6 @@
 
     certificate: "platform",
 
-    resource_dirs: ["res"],
     resource_zips: [":FrameworksCoreTests_apks_as_resources"],
     java_resources: [":FrameworksCoreTests_unit_test_cert_der"],
 
@@ -128,6 +136,24 @@
     ],
 }
 
+// FrameworksCoreTestsRavenwood pulls in the R.java class from this one.
+// Note, "FrameworksCoreTests" and "FrameworksCoreTests-resonly" _might_ not have indentical
+// R.java (not sure if there's a guarantee), but that doesn't matter as long as
+// FrameworksCoreTestsRavenwood consistently uses the R definition in this module.
+android_app {
+    name: "FrameworksCoreTests-resonly",
+    defaults: ["FrameworksCoreTests-resources"],
+
+    // FrameworksCoreTestsRavenwood references the .aapt.srcjar
+    use_resource_processor: false,
+    libs: [
+        "framework-res",
+        "android.test.runner",
+        "org.apache.http.legacy",
+    ],
+    sdk_version: "core_platform",
+}
+
 // Rules to copy all the test apks to the intermediate raw resource directory
 java_genrule {
     name: "FrameworksCoreTests_apks_as_resources",
@@ -225,7 +251,11 @@
         "src/com/android/internal/util/**/*.java",
         "src/com/android/internal/power/EnergyConsumerStatsTest.java",
 
-        ":FrameworksCoreTests{.aapt.srcjar}",
+        // Pull in R.java from FrameworksCoreTests-resonly, not from FrameworksCoreTests,
+        // to avoid having a dependency to FrameworksCoreTests.
+        // This way, when updating source files and running this test, we don't need to
+        // rebuild the entire FrameworksCoreTests, which would be slow.
+        ":FrameworksCoreTests-resonly{.aapt.srcjar}",
         ":FrameworksCoreTests-aidl",
         ":FrameworksCoreTests-helpers",
         ":FrameworksCoreTestDoubles-sources",
diff --git a/core/tests/coretests/src/android/view/RoundedCornersTest.java b/core/tests/coretests/src/android/view/RoundedCornersTest.java
index 07ef33a..ec665ad 100644
--- a/core/tests/coretests/src/android/view/RoundedCornersTest.java
+++ b/core/tests/coretests/src/android/view/RoundedCornersTest.java
@@ -16,6 +16,8 @@
 
 package android.view;
 
+import static android.content.res.Configuration.SCREENLAYOUT_ROUND_NO;
+import static android.content.res.Configuration.SCREENLAYOUT_ROUND_YES;
 import static android.view.RoundedCorner.POSITION_BOTTOM_LEFT;
 import static android.view.RoundedCorner.POSITION_BOTTOM_RIGHT;
 import static android.view.RoundedCorner.POSITION_TOP_LEFT;
@@ -28,22 +30,47 @@
 import static org.hamcrest.Matchers.not;
 import static org.hamcrest.Matchers.nullValue;
 import static org.hamcrest.Matchers.sameInstance;
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertThat;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.when;
 
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
 import android.platform.test.annotations.Presubmit;
+import android.util.DisplayMetrics;
 import android.util.Pair;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.internal.R;
+
+import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
 
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 @Presubmit
 public class RoundedCornersTest {
 
+    @Mock
+    DisplayMetrics mMockDisplayMetrics;
+    @Mock
+    Resources mMockResources;
+    @Mock TypedArray mMockTypedArray;
+    Configuration mConfiguration;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mConfiguration = Configuration.EMPTY;
+    }
+
     final RoundedCorners mRoundedCorners = new RoundedCorners(
             new RoundedCorner(POSITION_TOP_LEFT, 10, 10, 10),
             new RoundedCorner(POSITION_TOP_RIGHT, 10, 190, 10),
@@ -199,4 +226,63 @@
         assertThat(RoundedCorners.fromRadii(radius, 200, 300),
                 not(sameInstance(cached)));
     }
+
+    @Test
+    public void testGetRoundedCornerRadius_withRoundDevice_usesDisplayRadiusAsDefault() {
+        final int displayWidth = 400;
+        mConfiguration.screenLayout = SCREENLAYOUT_ROUND_YES;
+        mMockDisplayMetrics.widthPixels = displayWidth;
+
+        when(mMockResources.getConfiguration()).thenReturn(mConfiguration);
+        when(mMockResources.getDisplayMetrics()).thenReturn(mMockDisplayMetrics);
+        when(mMockResources.getStringArray(R.array.config_displayUniqueIdArray))
+                .thenReturn(new String[]{"0"});
+        when(mMockTypedArray.length()).thenReturn(0);
+        when(mMockResources.obtainTypedArray(anyInt())).thenReturn(mMockTypedArray);
+        when(mMockResources.getDimensionPixelSize(R.dimen.rounded_corner_radius))
+                .thenReturn(0);
+
+
+        int radius = RoundedCorners.getRoundedCornerRadius(mMockResources, "0");
+        assertEquals((displayWidth / 2), radius);
+    }
+
+    @Test
+    public void testGetRoundedCornerRadius_withRoundDevice_usesOverlayIfProvided() {
+        final int displayWidth = 400;
+        final int overlayValue = 199;
+        mConfiguration.screenLayout = SCREENLAYOUT_ROUND_YES;
+        mMockDisplayMetrics.widthPixels = displayWidth;
+
+        when(mMockResources.getConfiguration()).thenReturn(mConfiguration);
+        when(mMockResources.getDisplayMetrics()).thenReturn(mMockDisplayMetrics);
+        when(mMockResources.getStringArray(R.array.config_displayUniqueIdArray))
+                .thenReturn(new String[]{"0"});
+        when(mMockTypedArray.length()).thenReturn(0);
+        when(mMockResources.obtainTypedArray(anyInt())).thenReturn(mMockTypedArray);
+        when(mMockResources.getDimensionPixelSize(R.dimen.rounded_corner_radius))
+                .thenReturn(overlayValue);
+
+        int radius = RoundedCorners.getRoundedCornerRadius(mMockResources, "0");
+        assertEquals(overlayValue, radius);
+    }
+
+    @Test
+    public void testGetRoundedCornerRadius_withNonRoundDevice_noDisplayDefault() {
+        final int displayWidth = 400;
+        mConfiguration.screenLayout = SCREENLAYOUT_ROUND_NO;
+        mMockDisplayMetrics.widthPixels = displayWidth;
+
+        when(mMockResources.getConfiguration()).thenReturn(mConfiguration);
+        when(mMockResources.getDisplayMetrics()).thenReturn(mMockDisplayMetrics);
+        when(mMockResources.getStringArray(R.array.config_displayUniqueIdArray))
+                .thenReturn(new String[]{"0"});
+        when(mMockTypedArray.length()).thenReturn(0);
+        when(mMockResources.obtainTypedArray(anyInt())).thenReturn(mMockTypedArray);
+        when(mMockResources.getDimensionPixelSize(R.dimen.rounded_corner_radius))
+                .thenReturn(0);
+
+        int radius = RoundedCorners.getRoundedCornerRadius(mMockResources, "0");
+        assertEquals(0, radius);
+    }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
index c70a821..9130edf 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
@@ -470,10 +470,12 @@
                 }
 
                 final float cornerRadius;
-                if (a.hasRoundedCorners() && isTask) {
-                    // hasRoundedCorners is currently only enabled for tasks
+                if (a.hasRoundedCorners()) {
+                    final int displayId = isTask ? change.getTaskInfo().displayId
+                            : info.getRoot(TransitionUtil.rootIndexFor(change, info))
+                                    .getDisplayId();
                     final Context displayContext =
-                            mDisplayController.getDisplayContext(change.getTaskInfo().displayId);
+                            mDisplayController.getDisplayContext(displayId);
                     cornerRadius = displayContext == null ? 0
                             : ScreenDecorationsUtils.getWindowCornerRadius(displayContext);
                 } else {
diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java
index ea136ed..c90c441 100644
--- a/media/java/android/media/AudioFormat.java
+++ b/media/java/android/media/AudioFormat.java
@@ -1079,7 +1079,7 @@
      * @return one of the values that can be set in {@link Builder#setEncoding(int)} or
      * {@link AudioFormat#ENCODING_INVALID} if not set.
      */
-    public @Encoding int getEncoding() {
+    public @EncodingCanBeInvalid int getEncoding() {
         return mEncoding;
     }
 
@@ -1486,6 +1486,44 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface Encoding {}
 
+    /** @hide same as @Encoding, but adding ENCODING_INVALID */
+    @IntDef(flag = false, prefix = "ENCODING", value = {
+            ENCODING_INVALID,
+            ENCODING_DEFAULT,
+            ENCODING_PCM_16BIT,
+            ENCODING_PCM_8BIT,
+            ENCODING_PCM_FLOAT,
+            ENCODING_AC3,
+            ENCODING_E_AC3,
+            ENCODING_DTS,
+            ENCODING_DTS_HD,
+            ENCODING_MP3,
+            ENCODING_AAC_LC,
+            ENCODING_AAC_HE_V1,
+            ENCODING_AAC_HE_V2,
+            ENCODING_IEC61937,
+            ENCODING_DOLBY_TRUEHD,
+            ENCODING_AAC_ELD,
+            ENCODING_AAC_XHE,
+            ENCODING_AC4,
+            ENCODING_E_AC3_JOC,
+            ENCODING_DOLBY_MAT,
+            ENCODING_OPUS,
+            ENCODING_PCM_24BIT_PACKED,
+            ENCODING_PCM_32BIT,
+            ENCODING_MPEGH_BL_L3,
+            ENCODING_MPEGH_BL_L4,
+            ENCODING_MPEGH_LC_L3,
+            ENCODING_MPEGH_LC_L4,
+            ENCODING_DTS_UHD_P1,
+            ENCODING_DRA,
+            ENCODING_DTS_HD_MA,
+            ENCODING_DTS_UHD_P2,
+            ENCODING_DSD }
+    )
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface EncodingCanBeInvalid {}
+
     /** @hide */
     public static final int[] SURROUND_SOUND_ENCODING = {
             ENCODING_AC3,
diff --git a/packages/CrashRecovery/framework/Android.bp b/packages/CrashRecovery/framework/Android.bp
index c0d93531..9480327 100644
--- a/packages/CrashRecovery/framework/Android.bp
+++ b/packages/CrashRecovery/framework/Android.bp
@@ -3,7 +3,7 @@
     module_type: "filegroup",
     config_namespace: "ANDROID",
     bool_variables: [
-        "move_crashrecovery_files",
+        "crashrecovery_files_in_platform",
     ],
     properties: [
         "srcs",
@@ -12,14 +12,13 @@
 
 platform_filegroup {
     name: "framework-crashrecovery-sources",
-    srcs: [
-        "java/**/*.java",
-        "java/**/*.aidl",
-    ],
     soong_config_variables: {
-        // if the flag is enabled, then files would be moved to module
-        move_crashrecovery_files: {
-            srcs: [],
+        // if this flag is enabled, then files are part of platform
+        crashrecovery_files_in_platform: {
+            srcs: [
+                "java/**/*.java",
+                "java/**/*.aidl",
+            ],
         },
     },
     path: "java",
@@ -31,7 +30,7 @@
     module_type: "filegroup",
     config_namespace: "ANDROID",
     bool_variables: [
-        "move_crashrecovery_files",
+        "crashrecovery_files_in_module",
     ],
     properties: [
         "srcs",
@@ -40,10 +39,9 @@
 
 module_filegroup {
     name: "framework-crashrecovery-module-sources",
-    srcs: [],
     soong_config_variables: {
-        // if the flag is enabled, then files would be moved to module
-        move_crashrecovery_files: {
+        // if this flag is enabled, then files are part of module
+        crashrecovery_files_in_module: {
             srcs: [
                 "java/**/*.java",
                 "java/**/*.aidl",
diff --git a/packages/CrashRecovery/services/Android.bp b/packages/CrashRecovery/services/Android.bp
index ab10b5a..961b41f 100644
--- a/packages/CrashRecovery/services/Android.bp
+++ b/packages/CrashRecovery/services/Android.bp
@@ -3,7 +3,7 @@
     module_type: "filegroup",
     config_namespace: "ANDROID",
     bool_variables: [
-        "move_crashrecovery_files",
+        "crashrecovery_files_in_platform",
     ],
     properties: [
         "srcs",
@@ -12,15 +12,14 @@
 
 platform_filegroup {
     name: "services-crashrecovery-sources",
-    srcs: [
-        "java/**/*.java",
-        "java/**/*.aidl",
-        ":statslog-crashrecovery-java-gen",
-    ],
     soong_config_variables: {
-        // if the flag is enabled, then files would be moved to module
-        move_crashrecovery_files: {
-            srcs: [],
+        // if this flag is enabled, then files are part of platform
+        crashrecovery_files_in_platform: {
+            srcs: [
+                "java/**/*.java",
+                "java/**/*.aidl",
+                ":statslog-crashrecovery-java-gen",
+            ],
         },
     },
     visibility: ["//frameworks/base:__subpackages__"],
@@ -31,7 +30,7 @@
     module_type: "filegroup",
     config_namespace: "ANDROID",
     bool_variables: [
-        "move_crashrecovery_files",
+        "crashrecovery_files_in_module",
     ],
     properties: [
         "srcs",
@@ -40,10 +39,9 @@
 
 module_filegroup {
     name: "services-crashrecovery-module-sources",
-    srcs: [],
     soong_config_variables: {
-        // if the flag is enabled, then files would be moved to module
-        move_crashrecovery_files: {
+        // if this flag is enabled, then files are part of module
+        crashrecovery_files_in_module: {
             srcs: [
                 "java/**/*.java",
                 "java/**/*.aidl",
diff --git a/packages/CrashRecovery/services/java/com/android/server/PackageWatchdog.java b/packages/CrashRecovery/services/java/com/android/server/PackageWatchdog.java
index ce8fb65..5d71b7d 100644
--- a/packages/CrashRecovery/services/java/com/android/server/PackageWatchdog.java
+++ b/packages/CrashRecovery/services/java/com/android/server/PackageWatchdog.java
@@ -38,13 +38,13 @@
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.AtomicFile;
+import android.util.BackgroundThread;
 import android.util.LongArrayQueue;
 import android.util.Slog;
 import android.util.Xml;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.os.BackgroundThread;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.XmlUtils;
 import com.android.modules.utils.TypedXmlPullParser;
diff --git a/packages/CrashRecovery/services/java/com/android/server/rollback/RollbackPackageHealthObserver.java b/packages/CrashRecovery/services/java/com/android/server/rollback/RollbackPackageHealthObserver.java
index 5fb47dd..0fb9327 100644
--- a/packages/CrashRecovery/services/java/com/android/server/rollback/RollbackPackageHealthObserver.java
+++ b/packages/CrashRecovery/services/java/com/android/server/rollback/RollbackPackageHealthObserver.java
@@ -75,6 +75,9 @@
     private static final int PERSISTENT_MASK = ApplicationInfo.FLAG_PERSISTENT
             | ApplicationInfo.FLAG_SYSTEM;
 
+    private static final String PROP_DISABLE_HIGH_IMPACT_ROLLBACK_FLAG =
+            "persist.device_config.configuration.disable_high_impact_rollback";
+
     private final Context mContext;
     private final Handler mHandler;
     private final ApexManager mApexManager;
@@ -605,6 +608,10 @@
             // Apply all available low impact rollbacks.
             mHandler.post(() -> rollbackAllLowImpact(availableRollbacks, rollbackReason));
         } else if (minRollbackImpactLevel == PackageManager.ROLLBACK_USER_IMPACT_HIGH) {
+            // Check disable_high_impact_rollback device config before performing rollback
+            if (SystemProperties.getBoolean(PROP_DISABLE_HIGH_IMPACT_ROLLBACK_FLAG, false)) {
+                return;
+            }
             // Rollback one package at a time. If that doesn't resolve the issue, rollback
             // next with same impact level.
             mHandler.post(() -> rollbackHighImpact(availableRollbacks, rollbackReason));
@@ -718,7 +725,9 @@
                 impact = PackageHealthObserverImpact.USER_IMPACT_LEVEL_70;
                 break;
             case PackageManager.ROLLBACK_USER_IMPACT_HIGH:
-                impact = PackageHealthObserverImpact.USER_IMPACT_LEVEL_90;
+                if (!SystemProperties.getBoolean(PROP_DISABLE_HIGH_IMPACT_ROLLBACK_FLAG, false)) {
+                    impact = PackageHealthObserverImpact.USER_IMPACT_LEVEL_90;
+                }
                 break;
             default:
                 impact = PackageHealthObserverImpact.USER_IMPACT_LEVEL_0;
diff --git a/packages/CrashRecovery/services/java/com/android/util/BackgroundThread.java b/packages/CrashRecovery/services/java/com/android/util/BackgroundThread.java
new file mode 100644
index 0000000..a6ae68f
--- /dev/null
+++ b/packages/CrashRecovery/services/java/com/android/util/BackgroundThread.java
@@ -0,0 +1,103 @@
+/*
+ *  * 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.util;
+
+import android.annotation.NonNull;
+import android.os.Handler;
+import android.os.HandlerThread;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.concurrent.Executor;
+
+/**
+ * Thread for asynchronous event processing. This thread is configured as
+ * {@link android.os.Process#THREAD_PRIORITY_BACKGROUND}, which means fewer CPU
+ * resources will be dedicated to it, and it will "have less chance of impacting
+ * the responsiveness of the user interface."
+ * <p>
+ * This thread is best suited for tasks that the user is not actively waiting
+ * for, or for tasks that the user expects to be executed eventually.
+ *
+ * @see com.android.internal.os.BackgroundThread
+ *
+ * TODO: b/326916057 depend on modules-utils-backgroundthread instead
+ * @hide
+ */
+public final class BackgroundThread extends HandlerThread {
+    private static final Object sLock = new Object();
+
+    @GuardedBy("sLock")
+    private static BackgroundThread sInstance;
+    @GuardedBy("sLock")
+    private static Handler sHandler;
+    @GuardedBy("sLock")
+    private static HandlerExecutor sHandlerExecutor;
+
+    private BackgroundThread() {
+        super(BackgroundThread.class.getName(), android.os.Process.THREAD_PRIORITY_BACKGROUND);
+    }
+
+    @GuardedBy("sLock")
+    private static void ensureThreadLocked() {
+        if (sInstance == null) {
+            sInstance = new BackgroundThread();
+            sInstance.start();
+            sHandler = new Handler(sInstance.getLooper());
+            sHandlerExecutor = new HandlerExecutor(sHandler);
+        }
+    }
+
+    /**
+     * Get the singleton instance of this class.
+     *
+     * @return the singleton instance of this class
+     */
+    @NonNull
+    public static BackgroundThread get() {
+        synchronized (sLock) {
+            ensureThreadLocked();
+            return sInstance;
+        }
+    }
+
+    /**
+     * Get the singleton {@link Handler} for this class.
+     *
+     * @return the singleton {@link Handler} for this class.
+     */
+    @NonNull
+    public static Handler getHandler() {
+        synchronized (sLock) {
+            ensureThreadLocked();
+            return sHandler;
+        }
+    }
+
+    /**
+     * Get the singleton {@link Executor} for this class.
+     *
+     * @return the singleton {@link Executor} for this class.
+     */
+    @NonNull
+    public static Executor getExecutor() {
+        synchronized (sLock) {
+            ensureThreadLocked();
+            return sHandlerExecutor;
+        }
+    }
+}
diff --git a/packages/CrashRecovery/services/java/com/android/util/HandlerExecutor.java b/packages/CrashRecovery/services/java/com/android/util/HandlerExecutor.java
new file mode 100644
index 0000000..948ebcca
--- /dev/null
+++ b/packages/CrashRecovery/services/java/com/android/util/HandlerExecutor.java
@@ -0,0 +1,46 @@
+/*
+ * 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.util;
+
+import android.annotation.NonNull;
+import android.os.Handler;
+
+import java.util.Objects;
+import java.util.concurrent.Executor;
+import java.util.concurrent.RejectedExecutionException;
+
+/**
+ * An adapter {@link Executor} that posts all executed tasks onto the given
+ * {@link Handler}.
+ *
+ * TODO: b/326916057 depend on modules-utils-backgroundthread instead
+ * @hide
+ */
+public class HandlerExecutor implements Executor {
+    private final Handler mHandler;
+
+    public HandlerExecutor(@NonNull Handler handler) {
+        mHandler = Objects.requireNonNull(handler);
+    }
+
+    @Override
+    public void execute(Runnable command) {
+        if (!mHandler.post(command)) {
+            throw new RejectedExecutionException(mHandler + " is shutting down");
+        }
+    }
+}
diff --git a/packages/CredentialManager/shared/src/com/android/credentialmanager/ktx/CredentialKtx.kt b/packages/CredentialManager/shared/src/com/android/credentialmanager/ktx/CredentialKtx.kt
index a5f227a..02320a1 100644
--- a/packages/CredentialManager/shared/src/com/android/credentialmanager/ktx/CredentialKtx.kt
+++ b/packages/CredentialManager/shared/src/com/android/credentialmanager/ktx/CredentialKtx.kt
@@ -127,10 +127,10 @@
                     userName = credentialEntry.username.toString(),
                     displayName = credentialEntry.displayName?.toString(),
                     icon = credentialEntry.icon.loadDrawable(context),
-                    shouldTintIcon = credentialEntry.isDefaultIcon,
+                    shouldTintIcon = credentialEntry.hasDefaultIcon,
                     lastUsedTimeMillis = credentialEntry.lastUsedTime,
                     isAutoSelectable = credentialEntry.isAutoSelectAllowed &&
-                            credentialEntry.autoSelectAllowedFromOption,
+                            credentialEntry.isAutoSelectAllowedFromOption,
                 )
                 )
             }
@@ -148,10 +148,10 @@
                     userName = credentialEntry.username.toString(),
                     displayName = credentialEntry.displayName?.toString(),
                     icon = credentialEntry.icon.loadDrawable(context),
-                    shouldTintIcon = credentialEntry.isDefaultIcon,
+                    shouldTintIcon = credentialEntry.hasDefaultIcon,
                     lastUsedTimeMillis = credentialEntry.lastUsedTime,
                     isAutoSelectable = credentialEntry.isAutoSelectAllowed &&
-                            credentialEntry.autoSelectAllowedFromOption,
+                            credentialEntry.isAutoSelectAllowedFromOption,
                 )
                 )
             }
@@ -170,10 +170,10 @@
                     userName = credentialEntry.title.toString(),
                     displayName = credentialEntry.subtitle?.toString(),
                     icon = credentialEntry.icon.loadDrawable(context),
-                    shouldTintIcon = credentialEntry.isDefaultIcon,
+                    shouldTintIcon = credentialEntry.hasDefaultIcon,
                     lastUsedTimeMillis = credentialEntry.lastUsedTime,
                     isAutoSelectable = credentialEntry.isAutoSelectAllowed &&
-                            credentialEntry.autoSelectAllowedFromOption,
+                            credentialEntry.isAutoSelectAllowedFromOption,
                 )
                 )
             }
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt b/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt
index 0f17217..28c42fb 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt
@@ -213,7 +213,7 @@
         autofillIdToProvidersMap.forEach { (autofillId, providers) ->
             validFillResponse = processProvidersForAutofillId(
                     filLRequest, autofillId, providers, entryIconMap, fillResponseBuilder,
-                    getCredResponse.pendingIntent)
+                    getCredResponse.intent)
                     .or(validFillResponse)
         }
         if (!validFillResponse) {
@@ -229,7 +229,7 @@
             providerDataList: ArrayList<GetCredentialProviderData>,
             entryIconMap: Map<String, Icon>,
             fillResponseBuilder: FillResponse.Builder,
-            bottomSheetPendingIntent: PendingIntent?
+            bottomSheetIntent: Intent
     ): Boolean {
         val providerList = GetFlowUtils.toProviderList(
             providerDataList,
@@ -267,6 +267,8 @@
                 }
             }
         }
+        bottomSheetIntent.putExtra(
+                ProviderData.EXTRA_ENABLED_PROVIDER_DATA_LIST, providerDataList)
         providerDisplayInfo.sortedUserNameToCredentialEntryList.forEach usernameLoop@{
             val primaryEntry = it.sortedCredentialEntryList.first()
             val pendingIntent = primaryEntry.pendingIntent
@@ -330,16 +332,16 @@
             datasetAdded = true
             i++
 
-            if (i == lastDropdownDatasetIndex && bottomSheetPendingIntent != null) {
-                addDropdownMoreOptionsPresentation(bottomSheetPendingIntent, autofillId,
+            if (i == lastDropdownDatasetIndex) {
+                addDropdownMoreOptionsPresentation(bottomSheetIntent, autofillId,
                         fillResponseBuilder)
             }
         }
         val pinnedSpec = getLastInlinePresentationSpec(inlinePresentationSpecs,
                 inlinePresentationSpecsCount)
-        if (datasetAdded && bottomSheetPendingIntent != null && pinnedSpec != null) {
-            addPinnedInlineSuggestion(bottomSheetPendingIntent, pinnedSpec, autofillId,
-                    fillResponseBuilder, providerDataList)
+        if (datasetAdded && pinnedSpec != null) {
+            addPinnedInlineSuggestion(pinnedSpec, autofillId,
+                    fillResponseBuilder, bottomSheetIntent)
         }
         return datasetAdded
     }
@@ -370,13 +372,14 @@
     }
 
     private fun addDropdownMoreOptionsPresentation(
-            bottomSheetPendingIntent: PendingIntent,
+            bottomSheetIntent: Intent,
             autofillId: AutofillId,
             fillResponseBuilder: FillResponse.Builder
     ) {
         val presentationBuilder = Presentations.Builder()
                 .setMenuPresentation(
                         RemoteViewsFactory.createMoreSignInOptionsPresentation(this))
+        val pendingIntent = setUpBottomSheetPendingIntent(bottomSheetIntent)
 
         fillResponseBuilder.addDataset(
                 Dataset.Builder()
@@ -385,7 +388,7 @@
                                 Field.Builder().setPresentations(
                                         presentationBuilder.build())
                                         .build())
-                        .setAuthentication(bottomSheetPendingIntent.intentSender)
+                        .setAuthentication(pendingIntent.intentSender)
                         .build()
         )
     }
@@ -401,37 +404,41 @@
     }
 
     private fun addPinnedInlineSuggestion(
-            bottomSheetPendingIntent: PendingIntent,
             spec: InlinePresentationSpec,
             autofillId: AutofillId,
             fillResponseBuilder: FillResponse.Builder,
-            providerDataList: ArrayList<GetCredentialProviderData>
+            bottomSheetIntent: Intent
     ) {
+        val pendingIntent = setUpBottomSheetPendingIntent(bottomSheetIntent)
+
         val dataSetBuilder = Dataset.Builder()
         val sliceBuilder = InlineSuggestionUi
-                .newContentBuilder(bottomSheetPendingIntent)
+                .newContentBuilder(pendingIntent)
                 .setStartIcon(Icon.createWithResource(this,
                         com.android.credentialmanager.R.drawable.more_horiz_24px))
         val presentationBuilder = Presentations.Builder()
                 .setInlinePresentation(InlinePresentation(
                         sliceBuilder.build().slice, spec, /* pinned= */ true))
 
-        val extrasIntent = Intent()
-        extrasIntent.putExtra(ProviderData.EXTRA_ENABLED_PROVIDER_DATA_LIST, providerDataList)
-
         fillResponseBuilder.addDataset(
                 dataSetBuilder
                         .setField(
                                 autofillId,
                                 Field.Builder().setPresentations(
-                                        presentationBuilder.build())
-                                        .build())
-                        .setAuthentication(bottomSheetPendingIntent.intentSender)
-                        .setCredentialFillInIntent(extrasIntent)
+                                        presentationBuilder.build()
+                                ).build()
+                        )
+                        .setAuthentication(pendingIntent.intentSender)
                         .build()
         )
     }
 
+    private fun setUpBottomSheetPendingIntent(intent: Intent): PendingIntent {
+        intent.setAction(java.util.UUID.randomUUID().toString())
+        return PendingIntent.getActivity(this, /*requestCode=*/0, intent,
+                PendingIntent.FLAG_MUTABLE, /*options=*/null)
+    }
+
     /**
      *  Maps Autofill Id to provider list. For example, passing in a provider info
      *
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index bed95a5..e63232a 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -230,6 +230,7 @@
         extra_check_modules: ["SystemUILintChecker"],
         warning_checks: ["MissingApacheLicenseDetector"],
     },
+    skip_jarjar_repackage: true,
 }
 
 filegroup {
diff --git a/packages/SystemUI/compose/features/Android.bp b/packages/SystemUI/compose/features/Android.bp
index c12084d..dfb3a55 100644
--- a/packages/SystemUI/compose/features/Android.bp
+++ b/packages/SystemUI/compose/features/Android.bp
@@ -44,4 +44,5 @@
     ],
 
     kotlincflags: ["-Xjvm-default=all"],
+    skip_jarjar_repackage: true,
 }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
index 622a4f0..609f314 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
@@ -274,7 +274,7 @@
     widgetConfigurator: WidgetConfigurator?,
 ) {
     var gridModifier =
-        Modifier.align(Alignment.CenterStart).onGloballyPositioned { setGridCoordinates(it) }
+        Modifier.align(Alignment.TopStart).onGloballyPositioned { setGridCoordinates(it) }
     var list = communalContent
     var dragDropState: GridDragDropState? = null
     if (viewModel.isEditMode && viewModel is CommunalEditModeViewModel) {
@@ -309,8 +309,8 @@
         state = gridState,
         rows = GridCells.Fixed(CommunalContentSize.FULL.span),
         contentPadding = contentPadding,
-        horizontalArrangement = Arrangement.spacedBy(Dimensions.Spacing),
-        verticalArrangement = Arrangement.spacedBy(Dimensions.Spacing),
+        horizontalArrangement = Arrangement.spacedBy(32.dp),
+        verticalArrangement = Arrangement.spacedBy(32.dp),
     ) {
         items(
             count = list.size,
@@ -681,19 +681,20 @@
     Box(
         modifier = modifier,
     ) {
-        val paddingInPx = with(LocalDensity.current) { CardOutlineWidth.toPx().toInt() }
+        val paddingInPx =
+            if (selected) with(LocalDensity.current) { CardOutlineWidth.toPx().toInt() } else 0
         AndroidView(
             modifier = Modifier.fillMaxSize().allowGestures(allowed = !viewModel.isEditMode),
             factory = { context ->
-                val view =
-                    model.appWidgetHost
-                        .createViewForCommunal(context, model.appWidgetId, model.providerInfo)
-                        .apply { updateAppWidgetSize(Bundle.EMPTY, listOf(size)) }
+                model.appWidgetHost
+                    .createViewForCommunal(context, model.appWidgetId, model.providerInfo)
+                    .apply { updateAppWidgetSize(Bundle.EMPTY, listOf(size)) }
+            },
+            update = { view ->
                 // Remove the extra padding applied to AppWidgetHostView to allow widgets to
                 // occupy the entire box. The added padding is now adjusted to leave only sufficient
                 // space for displaying the outline around the box when the widget is selected.
                 view.setPadding(paddingInPx)
-                view
             },
             // For reusing composition in lazy lists.
             onReset = {},
@@ -795,7 +796,7 @@
 @Composable
 private fun gridContentPadding(isEditMode: Boolean, toolbarSize: IntSize?): PaddingValues {
     if (!isEditMode || toolbarSize == null) {
-        return PaddingValues(horizontal = Dimensions.Spacing)
+        return PaddingValues(start = 48.dp, end = 48.dp, top = Dimensions.GridTopSpacing)
     }
     val configuration = LocalConfiguration.current
     val density = LocalDensity.current
@@ -858,12 +859,13 @@
 }
 
 object Dimensions {
-    val CardWidth = 464.dp
-    val CardHeightFull = 630.dp
-    val CardHeightHalf = 307.dp
-    val CardHeightThird = 199.dp
+    val CardWidth = 424.dp
+    val CardHeightFull = 596.dp
+    val CardHeightHalf = 282.dp
+    val CardHeightThird = 177.33.dp
     val CardOutlineWidth = 3.dp
-    val GridHeight = CardHeightFull
+    val GridTopSpacing = 72.dp
+    val GridHeight = CardHeightFull + GridTopSpacing
     val Spacing = 16.dp
 
     // The sizing/padding of the toolbar in glanceable hub edit mode
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/LockSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/LockSection.kt
index be6f022..31d3fa0 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/LockSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/LockSection.kt
@@ -18,6 +18,7 @@
 
 import android.content.Context
 import android.util.DisplayMetrics
+import android.view.View
 import android.view.WindowManager
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
@@ -45,6 +46,7 @@
 import com.android.systemui.keyguard.ui.viewmodel.DeviceEntryIconViewModel
 import com.android.systemui.plugins.FalsingManager
 import com.android.systemui.res.R
+import com.android.systemui.shade.NotificationPanelView
 import com.android.systemui.statusbar.VibratorHelper
 import dagger.Lazy
 import javax.inject.Inject
@@ -63,6 +65,7 @@
     private val deviceEntryBackgroundViewModel: Lazy<DeviceEntryBackgroundViewModel>,
     private val falsingManager: Lazy<FalsingManager>,
     private val vibratorHelper: Lazy<VibratorHelper>,
+    private val notificationPanelView: NotificationPanelView,
 ) {
     @Composable
     fun SceneScope.LockIcon(modifier: Modifier = Modifier) {
@@ -70,6 +73,10 @@
             return
         }
 
+        notificationPanelView.findViewById<View?>(R.id.lock_icon_view)?.let {
+            notificationPanelView.removeView(it)
+        }
+
         val context = LocalContext.current
 
         AndroidView(
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/CommunalWidgetHostTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/CommunalWidgetHostTest.kt
index 12611cb..88f5e1b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/CommunalWidgetHostTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/CommunalWidgetHostTest.kt
@@ -17,8 +17,10 @@
 package com.android.systemui.communal.widgets
 
 import android.appwidget.AppWidgetManager
+import android.appwidget.AppWidgetProviderInfo
 import android.content.ComponentName
 import android.content.pm.UserInfo
+import android.os.Bundle
 import android.os.UserHandle
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
@@ -33,8 +35,8 @@
 import com.android.systemui.user.domain.interactor.SelectedUserInteractor
 import com.android.systemui.user.domain.interactor.selectedUserInteractor
 import com.android.systemui.util.mockito.any
-import com.android.systemui.util.mockito.nullable
 import com.android.systemui.util.mockito.whenever
+import com.android.systemui.util.mockito.withArgCaptor
 import com.google.common.truth.Truth.assertThat
 import java.util.Optional
 import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -43,6 +45,7 @@
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.eq
 import org.mockito.Mock
 import org.mockito.Mockito.verify
 import org.mockito.MockitoAnnotations
@@ -91,7 +94,7 @@
                         any<Int>(),
                         any<UserHandle>(),
                         any<ComponentName>(),
-                        nullable()
+                        any<Bundle>(),
                     )
                 )
                 .thenReturn(true)
@@ -100,8 +103,14 @@
             val result = underTest.allocateIdAndBindWidget(provider)
 
             verify(appWidgetHost).allocateAppWidgetId()
-            verify(appWidgetManager).bindAppWidgetIdIfAllowed(widgetId, user, provider, null)
+            val bundle =
+                withArgCaptor<Bundle> {
+                    verify(appWidgetManager)
+                        .bindAppWidgetIdIfAllowed(eq(widgetId), eq(user), eq(provider), capture())
+                }
             assertThat(result).isEqualTo(widgetId)
+            assertThat(bundle.getInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY))
+                .isEqualTo(AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD)
         }
 
     @Test
@@ -117,7 +126,7 @@
                         any<Int>(),
                         any<UserHandle>(),
                         any<ComponentName>(),
-                        nullable()
+                        any<Bundle>()
                     )
                 )
                 .thenReturn(true)
@@ -126,8 +135,14 @@
             val result = underTest.allocateIdAndBindWidget(provider, user)
 
             verify(appWidgetHost).allocateAppWidgetId()
-            verify(appWidgetManager).bindAppWidgetIdIfAllowed(widgetId, user, provider, null)
+            val bundle =
+                withArgCaptor<Bundle> {
+                    verify(appWidgetManager)
+                        .bindAppWidgetIdIfAllowed(eq(widgetId), eq(user), eq(provider), capture())
+                }
             assertThat(result).isEqualTo(widgetId)
+            assertThat(bundle.getInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY))
+                .isEqualTo(AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD)
         }
 
     @Test
@@ -144,14 +159,15 @@
                         any<Int>(),
                         any<UserHandle>(),
                         any<ComponentName>(),
-                        nullable()
+                        any<Bundle>()
                     )
                 )
                 .thenReturn(false)
             val result = underTest.allocateIdAndBindWidget(provider, user)
 
             verify(appWidgetHost).allocateAppWidgetId()
-            verify(appWidgetManager).bindAppWidgetIdIfAllowed(widgetId, user, provider, null)
+            verify(appWidgetManager)
+                .bindAppWidgetIdIfAllowed(eq(widgetId), eq(user), eq(provider), any())
             verify(appWidgetHost).deleteAppWidgetId(widgetId)
             assertThat(result).isNull()
         }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java
index 87d25dd..6456669 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java
@@ -19,8 +19,6 @@
 import static android.app.Notification.FLAG_FSI_REQUESTED_BUT_DENIED;
 
 import static com.android.systemui.log.LogBufferHelperKt.logcatLogBuffer;
-import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_CONTRACTED;
-import static com.android.systemui.util.concurrency.MockExecutorHandlerKt.mockExecutorHandler;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -41,31 +39,23 @@
 import android.app.Notification;
 import android.app.PendingIntent;
 import android.app.Person;
-import android.content.Context;
 import android.content.Intent;
-import android.graphics.Region;
 import android.os.UserHandle;
 import android.service.notification.StatusBarNotification;
 import android.testing.TestableLooper;
 
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.test.filters.SmallTest;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
 
-import com.android.internal.logging.UiEventLogger;
 import com.android.internal.logging.testing.UiEventLoggerFake;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.res.R;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
-import com.android.systemui.util.concurrency.DelayableExecutor;
 import com.android.systemui.util.concurrency.FakeExecutor;
 import com.android.systemui.util.settings.FakeGlobalSettings;
-import com.android.systemui.util.settings.GlobalSettings;
 import com.android.systemui.util.time.FakeSystemClock;
-import com.android.systemui.util.time.SystemClock;
 
 import org.junit.Rule;
 import org.junit.Test;
@@ -83,8 +73,8 @@
 
     private static final String TEST_PACKAGE_NAME = "BaseHeadsUpManagerTest";
 
-    private static final int TEST_TOUCH_ACCEPTANCE_TIME = 200;
-    private static final int TEST_A11Y_AUTO_DISMISS_TIME = 1_000;
+    static final int TEST_TOUCH_ACCEPTANCE_TIME = 200;
+    static final int TEST_A11Y_AUTO_DISMISS_TIME = 1_000;
 
     private UiEventLoggerFake mUiEventLoggerFake = new UiEventLoggerFake();
     private final HeadsUpManagerLogger mLogger = spy(new HeadsUpManagerLogger(logcatLogBuffer()));
@@ -110,143 +100,6 @@
         assertThat(TEST_STICKY_AUTO_DISMISS_TIME).isLessThan(TEST_A11Y_AUTO_DISMISS_TIME);
     }
 
-    private final class TestableHeadsUpManager extends BaseHeadsUpManager {
-
-        private HeadsUpEntry mLastCreatedEntry;
-
-        TestableHeadsUpManager(Context context,
-                HeadsUpManagerLogger logger,
-                DelayableExecutor executor,
-                GlobalSettings globalSettings,
-                SystemClock systemClock,
-                AccessibilityManagerWrapper accessibilityManagerWrapper,
-                UiEventLogger uiEventLogger) {
-            super(context, logger, mockExecutorHandler(executor), globalSettings, systemClock,
-                    executor, accessibilityManagerWrapper, uiEventLogger);
-
-            mTouchAcceptanceDelay = TEST_TOUCH_ACCEPTANCE_TIME;
-            mMinimumDisplayTime = TEST_MINIMUM_DISPLAY_TIME;
-            mAutoDismissTime = TEST_AUTO_DISMISS_TIME;
-            mStickyForSomeTimeAutoDismissTime = TEST_STICKY_AUTO_DISMISS_TIME;
-
-        }
-
-        @Override
-        protected HeadsUpEntry createHeadsUpEntry() {
-            mLastCreatedEntry = spy(super.createHeadsUpEntry());
-            return mLastCreatedEntry;
-        }
-
-        @Override
-        public int getContentFlag() {
-            return FLAG_CONTENT_VIEW_CONTRACTED;
-        }
-
-        // The following are only implemented by HeadsUpManagerPhone. If you need them, use that.
-        @Override
-        public void addHeadsUpPhoneListener(@NonNull OnHeadsUpPhoneListenerChange listener) {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public void addSwipedOutNotification(@NonNull String key) {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public void extendHeadsUp() {
-            throw new UnsupportedOperationException();
-        }
-
-        @Nullable
-        @Override
-        public Region getTouchableRegion() {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public boolean isHeadsUpGoingAway() {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public void onExpandingFinished() {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public boolean removeNotification(@NonNull String key, boolean releaseImmediately,
-                boolean animate) {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public void setAnimationStateHandler(@NonNull AnimationStateHandler handler) {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public void setGutsShown(@NonNull NotificationEntry entry, boolean gutsShown) {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public void setHeadsUpGoingAway(boolean headsUpGoingAway) {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public void setRemoteInputActive(@NonNull NotificationEntry entry,
-                boolean remoteInputActive) {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public void setTrackingHeadsUp(boolean tracking) {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public boolean shouldSwallowClick(@NonNull String key) {
-            throw new UnsupportedOperationException();
-        }
-    }
-
-    protected StatusBarNotification createSbn(int id, Notification n) {
-        return new StatusBarNotification(
-                TEST_PACKAGE_NAME /* pkg */,
-                TEST_PACKAGE_NAME,
-                id,
-                null /* tag */,
-                TEST_UID,
-                0 /* initialPid */,
-                n,
-                new UserHandle(ActivityManager.getCurrentUser()),
-                null /* overrideGroupKey */,
-                0 /* postTime */);
-    }
-
-    protected StatusBarNotification createSbn(int id, Notification.Builder n) {
-        return createSbn(id, n.build());
-    }
-
-    protected StatusBarNotification createSbn(int id) {
-        final Notification.Builder b = new Notification.Builder(mContext, "")
-                .setSmallIcon(R.drawable.ic_person)
-                .setContentTitle("Title")
-                .setContentText("Text");
-        return createSbn(id, b);
-    }
-
-    protected NotificationEntry createEntry(int id, Notification n) {
-        return new NotificationEntryBuilder().setSbn(createSbn(id, n)).build();
-    }
-
-    protected NotificationEntry createEntry(int id) {
-        return new NotificationEntryBuilder().setSbn(createSbn(id)).build();
-    }
-
-
     private BaseHeadsUpManager createHeadsUpManager() {
         return new TestableHeadsUpManager(mContext, mLogger, mExecutor, mGlobalSettings,
                 mSystemClock, mAccessibilityMgr, mUiEventLoggerFake);
@@ -257,7 +110,7 @@
                 .setSmallIcon(R.drawable.ic_person)
                 .setFullScreenIntent(mock(PendingIntent.class), /* highPriority */ true)
                 .build();
-        return createEntry(id, notif);
+        return HeadsUpManagerTestUtil.createEntry(id, notif);
     }
 
     private NotificationEntry createStickyForSomeTimeEntry(int id) {
@@ -265,7 +118,7 @@
                 .setSmallIcon(R.drawable.ic_person)
                 .setFlag(FLAG_FSI_REQUESTED_BUT_DENIED, true)
                 .build();
-        return createEntry(id, notif);
+        return HeadsUpManagerTestUtil.createEntry(id, notif);
     }
 
     private PendingIntent createFullScreenIntent() {
@@ -279,7 +132,7 @@
                 .setSmallIcon(R.drawable.ic_person)
                 .setFullScreenIntent(createFullScreenIntent(), /* highPriority */ true)
                 .build();
-        return createEntry(id, notif);
+        return HeadsUpManagerTestUtil.createEntry(id, notif);
     }
 
 
@@ -296,7 +149,7 @@
     @Test
     public void testShowNotification_addsEntry() {
         final BaseHeadsUpManager alm = createHeadsUpManager();
-        final NotificationEntry entry = createEntry(/* id = */ 0);
+        final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
 
         alm.showNotification(entry);
 
@@ -308,7 +161,7 @@
     @Test
     public void testShowNotification_autoDismisses() {
         final BaseHeadsUpManager alm = createHeadsUpManager();
-        final NotificationEntry entry = createEntry(/* id = */ 0);
+        final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
 
         alm.showNotification(entry);
         mSystemClock.advanceTime(TEST_AUTO_DISMISS_TIME * 3 / 2);
@@ -319,7 +172,7 @@
     @Test
     public void testRemoveNotification_removeDeferred() {
         final BaseHeadsUpManager alm = createHeadsUpManager();
-        final NotificationEntry entry = createEntry(/* id = */ 0);
+        final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
 
         alm.showNotification(entry);
 
@@ -332,7 +185,7 @@
     @Test
     public void testRemoveNotification_forceRemove() {
         final BaseHeadsUpManager alm = createHeadsUpManager();
-        final NotificationEntry entry = createEntry(/* id = */ 0);
+        final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
 
         alm.showNotification(entry);
 
@@ -346,7 +199,7 @@
     public void testReleaseAllImmediately() {
         final BaseHeadsUpManager alm = createHeadsUpManager();
         for (int i = 0; i < TEST_NUM_NOTIFICATIONS; i++) {
-            final NotificationEntry entry = createEntry(i);
+            final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(i, mContext);
             entry.setRow(mRow);
             alm.showNotification(entry);
         }
@@ -359,7 +212,7 @@
     @Test
     public void testCanRemoveImmediately_notShownLongEnough() {
         final BaseHeadsUpManager alm = createHeadsUpManager();
-        final NotificationEntry entry = createEntry(/* id = */ 0);
+        final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
 
         alm.showNotification(entry);
 
@@ -370,7 +223,8 @@
     @Test
     public void testHunRemovedLogging() {
         final BaseHeadsUpManager hum = createHeadsUpManager();
-        final NotificationEntry notifEntry = createEntry(/* id = */ 0);
+        final NotificationEntry notifEntry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0,
+                mContext);
         final BaseHeadsUpManager.HeadsUpEntry headsUpEntry = mock(
                 BaseHeadsUpManager.HeadsUpEntry.class);
         headsUpEntry.mEntry = notifEntry;
@@ -413,7 +267,7 @@
     @Test
     public void testShouldHeadsUpBecomePinned_noFSI_false() {
         final BaseHeadsUpManager hum = createHeadsUpManager();
-        final NotificationEntry entry = createEntry(/* id = */ 0);
+        final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
 
         assertFalse(hum.shouldHeadsUpBecomePinned(entry));
     }
@@ -422,7 +276,7 @@
     @Test
     public void testShowNotification_autoDismissesIncludingTouchAcceptanceDelay() {
         final BaseHeadsUpManager hum = createHeadsUpManager();
-        final NotificationEntry entry = createEntry(/* id = */ 0);
+        final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
         useAccessibilityTimeout(false);
 
         hum.showNotification(entry);
@@ -435,7 +289,7 @@
     @Test
     public void testShowNotification_autoDismissesWithDefaultTimeout() {
         final BaseHeadsUpManager hum = createHeadsUpManager();
-        final NotificationEntry entry = createEntry(/* id = */ 0);
+        final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
         useAccessibilityTimeout(false);
 
         hum.showNotification(entry);
@@ -476,7 +330,7 @@
     @Test
     public void testShowNotification_autoDismissesWithAccessibilityTimeout() {
         final BaseHeadsUpManager hum = createHeadsUpManager();
-        final NotificationEntry entry = createEntry(/* id = */ 0);
+        final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
         useAccessibilityTimeout(true);
 
         hum.showNotification(entry);
@@ -504,7 +358,7 @@
     @Test
     public void testRemoveNotification_beforeMinimumDisplayTime() {
         final BaseHeadsUpManager hum = createHeadsUpManager();
-        final NotificationEntry entry = createEntry(/* id = */ 0);
+        final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
         useAccessibilityTimeout(false);
 
         hum.showNotification(entry);
@@ -523,7 +377,7 @@
     @Test
     public void testRemoveNotification_afterMinimumDisplayTime() {
         final BaseHeadsUpManager hum = createHeadsUpManager();
-        final NotificationEntry entry = createEntry(/* id = */ 0);
+        final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
         useAccessibilityTimeout(false);
 
         hum.showNotification(entry);
@@ -541,7 +395,7 @@
     @Test
     public void testRemoveNotification_releaseImmediately() {
         final BaseHeadsUpManager hum = createHeadsUpManager();
-        final NotificationEntry entry = createEntry(/* id = */ 0);
+        final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
 
         hum.showNotification(entry);
 
@@ -555,7 +409,8 @@
     @Test
     public void testIsSticky_rowPinnedAndExpanded_true() {
         final BaseHeadsUpManager hum = createHeadsUpManager();
-        final NotificationEntry notifEntry = createEntry(/* id = */ 0);
+        final NotificationEntry notifEntry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0,
+                mContext);
         when(mRow.isPinned()).thenReturn(true);
         notifEntry.setRow(mRow);
 
@@ -571,7 +426,8 @@
     @Test
     public void testIsSticky_remoteInputActive_true() {
         final BaseHeadsUpManager hum = createHeadsUpManager();
-        final NotificationEntry notifEntry = createEntry(/* id = */ 0);
+        final NotificationEntry notifEntry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0,
+                mContext);
 
         hum.showNotification(notifEntry);
 
@@ -607,7 +463,8 @@
     @Test
     public void testIsSticky_false() {
         final BaseHeadsUpManager hum = createHeadsUpManager();
-        final NotificationEntry notifEntry = createEntry(/* id = */ 0);
+        final NotificationEntry notifEntry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0,
+                mContext);
 
         hum.showNotification(notifEntry);
 
@@ -653,14 +510,14 @@
 
         final BaseHeadsUpManager.HeadsUpEntry ongoingCall = hum.new HeadsUpEntry();
         ongoingCall.setEntry(new NotificationEntryBuilder()
-                .setSbn(createSbn(/* id = */ 0,
+                .setSbn(HeadsUpManagerTestUtil.createSbn(/* id = */ 0,
                         new Notification.Builder(mContext, "")
                                 .setCategory(Notification.CATEGORY_CALL)
                                 .setOngoing(true)))
                 .build());
 
         final BaseHeadsUpManager.HeadsUpEntry activeRemoteInput = hum.new HeadsUpEntry();
-        activeRemoteInput.setEntry(createEntry(/* id = */ 1));
+        activeRemoteInput.setEntry(HeadsUpManagerTestUtil.createEntry(/* id = */ 1, mContext));
         activeRemoteInput.mRemoteInputActive = true;
 
         assertThat(ongoingCall.compareTo(activeRemoteInput)).isLessThan(0);
@@ -675,14 +532,14 @@
         final Person person = new Person.Builder().setName("person").build();
         final PendingIntent intent = mock(PendingIntent.class);
         incomingCall.setEntry(new NotificationEntryBuilder()
-                .setSbn(createSbn(/* id = */ 0,
+                .setSbn(HeadsUpManagerTestUtil.createSbn(/* id = */ 0,
                         new Notification.Builder(mContext, "")
                                 .setStyle(Notification.CallStyle
                                         .forIncomingCall(person, intent, intent))))
                 .build());
 
         final BaseHeadsUpManager.HeadsUpEntry activeRemoteInput = hum.new HeadsUpEntry();
-        activeRemoteInput.setEntry(createEntry(/* id = */ 1));
+        activeRemoteInput.setEntry(HeadsUpManagerTestUtil.createEntry(/* id = */ 1, mContext));
         activeRemoteInput.mRemoteInputActive = true;
 
         assertThat(incomingCall.compareTo(activeRemoteInput)).isLessThan(0);
@@ -712,7 +569,8 @@
     @Test
     public void testSetUserActionMayIndirectlyRemove() {
         final BaseHeadsUpManager hum = createHeadsUpManager();
-        final NotificationEntry notifEntry = createEntry(/* id = */ 0);
+        final NotificationEntry notifEntry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0,
+                mContext);
 
         hum.showNotification(notifEntry);
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerPhoneTest.java
similarity index 88%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerPhoneTest.java
index c350de2..ec23f76 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerPhoneTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar.phone;
+package com.android.systemui.statusbar.policy;
 
 import static com.android.systemui.log.LogBufferHelperKt.logcatLogBuffer;
 import static com.android.systemui.util.concurrency.MockExecutorHandlerKt.mockExecutorHandler;
@@ -26,10 +26,10 @@
 import static org.mockito.Mockito.when;
 
 import android.content.Context;
-import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 
 import androidx.test.filters.SmallTest;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 
 import com.android.internal.logging.UiEventLogger;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -39,11 +39,9 @@
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider;
 import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
-import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
-import com.android.systemui.statusbar.policy.BaseHeadsUpManagerTest;
-import com.android.systemui.statusbar.policy.ConfigurationController;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
-import com.android.systemui.statusbar.policy.HeadsUpManagerLogger;
+import com.android.systemui.statusbar.phone.ConfigurationControllerImpl;
+import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
+import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.util.concurrency.DelayableExecutor;
 import com.android.systemui.util.kotlin.JavaAdapter;
 import com.android.systemui.util.settings.GlobalSettings;
@@ -61,7 +59,7 @@
 import kotlinx.coroutines.flow.StateFlowKt;
 
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 @TestableLooper.RunWithLooper
 public class HeadsUpManagerPhoneTest extends BaseHeadsUpManagerTest {
     @Rule public MockitoRule rule = MockitoJUnit.rule();
@@ -152,7 +150,7 @@
     @Test
     public void testSnooze() {
         final HeadsUpManager hmp = createHeadsUpManagerPhone();
-        final NotificationEntry entry = createEntry(/* id = */ 0);
+        final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
 
         hmp.showNotification(entry);
         hmp.snooze();
@@ -163,7 +161,7 @@
     @Test
     public void testSwipedOutNotification() {
         final HeadsUpManager hmp = createHeadsUpManagerPhone();
-        final NotificationEntry entry = createEntry(/* id = */ 0);
+        final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
 
         hmp.showNotification(entry);
         hmp.addSwipedOutNotification(entry.getKey());
@@ -179,7 +177,7 @@
     @Test
     public void testCanRemoveImmediately_swipedOut() {
         final HeadsUpManager hmp = createHeadsUpManagerPhone();
-        final NotificationEntry entry = createEntry(/* id = */ 0);
+        final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
 
         hmp.showNotification(entry);
         hmp.addSwipedOutNotification(entry.getKey());
@@ -192,8 +190,10 @@
     @Test
     public void testCanRemoveImmediately_notTopEntry() {
         final HeadsUpManager hmp = createHeadsUpManagerPhone();
-        final NotificationEntry earlierEntry = createEntry(/* id = */ 0);
-        final NotificationEntry laterEntry = createEntry(/* id = */ 1);
+        final NotificationEntry earlierEntry =
+                HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
+        final NotificationEntry laterEntry =
+                HeadsUpManagerTestUtil.createEntry(/* id = */ 1, mContext);
         laterEntry.setRow(mRow);
 
         hmp.showNotification(earlierEntry);
@@ -206,7 +206,7 @@
     @Test
     public void testExtendHeadsUp() {
         final HeadsUpManagerPhone hmp = createHeadsUpManagerPhone();
-        final NotificationEntry entry = createEntry(/* id = */ 0);
+        final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
 
         hmp.showNotification(entry);
         hmp.extendHeadsUp();
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTestUtil.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTestUtil.java
new file mode 100644
index 0000000..c70b03b
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTestUtil.java
@@ -0,0 +1,70 @@
+/*
+ * 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.systemui.statusbar.policy;
+import android.app.ActivityManager;
+import android.os.UserHandle;
+
+import android.content.Context;
+import android.service.notification.StatusBarNotification;
+import android.app.Notification;
+
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
+
+/**
+ * Test helper class for HeadsUpEntry creation.
+ */
+public class HeadsUpManagerTestUtil {
+
+    private static final String TEST_PACKAGE_NAME = "HeadsUpManagerTestUtil";
+    private static final int TEST_UID = 0;
+
+    protected static StatusBarNotification createSbn(int id, Notification.Builder n) {
+        return createSbn(id, n.build());
+    }
+
+    protected static StatusBarNotification createSbn(int id, Context context) {
+        final Notification.Builder b = new Notification.Builder(context, "")
+                .setSmallIcon(com.android.systemui.res.R.drawable.ic_person)
+                .setContentTitle("Title")
+                .setContentText("Text");
+        return createSbn(id, b);
+    }
+
+    protected static StatusBarNotification createSbn(int id, Notification n) {
+        return new StatusBarNotification(
+                TEST_PACKAGE_NAME /* pkg */,
+                TEST_PACKAGE_NAME,
+                id,
+                null /* tag */,
+                TEST_UID,
+                0 /* initialPid */,
+                n,
+                new UserHandle(ActivityManager.getCurrentUser()),
+                null /* overrideGroupKey */,
+                0 /* postTime */);
+    }
+
+    protected static NotificationEntry createEntry(int id, Notification n) {
+        return new NotificationEntryBuilder().setSbn(createSbn(id, n)).build();
+    }
+
+    protected static NotificationEntry createEntry(int id, Context context) {
+        return new NotificationEntryBuilder().setSbn(
+                HeadsUpManagerTestUtil.createSbn(id, context)).build();
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/TestableHeadsUpManager.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/TestableHeadsUpManager.java
new file mode 100644
index 0000000..2747629
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/TestableHeadsUpManager.java
@@ -0,0 +1,135 @@
+/*
+ * 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.systemui.statusbar.policy;
+
+import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_CONTRACTED;
+import static com.android.systemui.util.concurrency.MockExecutorHandlerKt.mockExecutorHandler;
+
+import static org.mockito.Mockito.spy;
+
+import android.content.Context;
+import android.graphics.Region;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.internal.logging.UiEventLogger;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.util.concurrency.DelayableExecutor;
+import com.android.systemui.util.settings.GlobalSettings;
+import com.android.systemui.util.time.SystemClock;
+
+class TestableHeadsUpManager extends BaseHeadsUpManager {
+
+    private HeadsUpEntry mLastCreatedEntry;
+
+    TestableHeadsUpManager(Context context,
+            HeadsUpManagerLogger logger,
+            DelayableExecutor executor,
+            GlobalSettings globalSettings,
+            SystemClock systemClock,
+            AccessibilityManagerWrapper accessibilityManagerWrapper,
+            UiEventLogger uiEventLogger) {
+        super(context, logger, mockExecutorHandler(executor), globalSettings, systemClock,
+                executor, accessibilityManagerWrapper, uiEventLogger);
+
+        mTouchAcceptanceDelay = BaseHeadsUpManagerTest.TEST_TOUCH_ACCEPTANCE_TIME;
+        mMinimumDisplayTime = BaseHeadsUpManagerTest.TEST_MINIMUM_DISPLAY_TIME;
+        mAutoDismissTime = BaseHeadsUpManagerTest.TEST_AUTO_DISMISS_TIME;
+        mStickyForSomeTimeAutoDismissTime = BaseHeadsUpManagerTest.TEST_STICKY_AUTO_DISMISS_TIME;
+    }
+
+    @Override
+    protected HeadsUpEntry createHeadsUpEntry() {
+        mLastCreatedEntry = spy(super.createHeadsUpEntry());
+        return mLastCreatedEntry;
+    }
+
+    @Override
+    public int getContentFlag() {
+        return FLAG_CONTENT_VIEW_CONTRACTED;
+    }
+
+    // The following are only implemented by HeadsUpManagerPhone. If you need them, use that.
+    @Override
+    public void addHeadsUpPhoneListener(@NonNull OnHeadsUpPhoneListenerChange listener) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void addSwipedOutNotification(@NonNull String key) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void extendHeadsUp() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Nullable
+    @Override
+    public Region getTouchableRegion() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean isHeadsUpGoingAway() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void onExpandingFinished() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean removeNotification(@NonNull String key, boolean releaseImmediately,
+            boolean animate) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setAnimationStateHandler(@NonNull AnimationStateHandler handler) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setGutsShown(@NonNull NotificationEntry entry, boolean gutsShown) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setHeadsUpGoingAway(boolean headsUpGoingAway) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setRemoteInputActive(@NonNull NotificationEntry entry,
+            boolean remoteInputActive) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setTrackingHeadsUp(boolean tracking) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean shouldSwallowClick(@NonNull String key) {
+        throw new UnsupportedOperationException();
+    }
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
index 10393cf..ca63483 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
@@ -196,7 +196,7 @@
             final RecentsAnimationListener animationHandler, final Consumer<Boolean> resultCallback,
             Handler resultCallbackHandler) {
         boolean result = startRecentsActivity(intent, eventTime, animationHandler);
-        if (resultCallback != null) {
+        if (resultCallback != null && resultCallbackHandler != null) {
             resultCallbackHandler.post(new Runnable() {
                 @Override
                 public void run() {
diff --git a/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalWidgetHost.kt b/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalWidgetHost.kt
index 080dbed..93e2b37 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalWidgetHost.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalWidgetHost.kt
@@ -21,6 +21,7 @@
 import android.appwidget.AppWidgetProviderInfo.WIDGET_FEATURE_CONFIGURATION_OPTIONAL
 import android.appwidget.AppWidgetProviderInfo.WIDGET_FEATURE_RECONFIGURABLE
 import android.content.ComponentName
+import android.os.Bundle
 import android.os.UserHandle
 import com.android.systemui.log.LogBuffer
 import com.android.systemui.log.core.Logger
@@ -56,6 +57,7 @@
             return widgetInfo.configure != null && !configurationOptional
         }
     }
+
     private val logger = Logger(logBuffer, TAG)
 
     /**
@@ -84,9 +86,16 @@
 
     private fun bindWidget(widgetId: Int, user: UserHandle, provider: ComponentName): Boolean {
         if (appWidgetManager.isPresent) {
+            val options =
+                Bundle().apply {
+                    putInt(
+                        AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY,
+                        AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD,
+                    )
+                }
             return appWidgetManager
                 .get()
-                .bindAppWidgetIdIfAllowed(widgetId, user, provider, /* options */ null)
+                .bindAppWidgetIdIfAllowed(widgetId, user, provider, options)
         }
         return false
     }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepository.kt
index 59288a1..0ea5390 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepository.kt
@@ -41,7 +41,6 @@
 import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.asStateFlow
 import kotlinx.coroutines.flow.callbackFlow
-import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.mapNotNull
 import kotlinx.coroutines.flow.onStart
@@ -111,7 +110,6 @@
                 awaitClose { clockRegistry.unregisterClockChangeListener(listener) }
             }
             .mapNotNull { it }
-            .distinctUntilChanged()
 
     override val currentClock: StateFlow<ClockController?> =
         currentClockId
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt
index 873cc84..f46a207 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt
@@ -22,6 +22,7 @@
 import android.util.StateSet
 import android.view.HapticFeedbackConstants
 import android.view.View
+import androidx.core.view.isInvisible
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.repeatOnLifecycle
 import com.android.systemui.common.ui.view.LongPressHandlingView
@@ -82,6 +83,11 @@
             // of the transition.
             repeatOnLifecycle(Lifecycle.State.CREATED) {
                 launch {
+                    viewModel.isVisible.collect { isVisible ->
+                        longPressHandlingView.isInvisible = !isVisible
+                    }
+                }
+                launch {
                     viewModel.isLongPressEnabled.collect { isEnabled ->
                         longPressHandlingView.setLongPressHandlingEnabled(isEnabled)
                     }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModel.kt
index d657c24d..6281097 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModel.kt
@@ -33,6 +33,7 @@
 import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.onStart
 
@@ -70,12 +71,13 @@
 
     // While dozing, the display can show the AOD UI; show the AOD udfps when dozing
     private val useAodIconVariant: Flow<Boolean> =
-        combine(isShowingAodOrDozing, deviceEntryUdfpsInteractor.isUdfpsSupported) {
-                isTransitionToAodOrDozing,
-                isUdfps ->
-                isTransitionToAodOrDozing && isUdfps
+        deviceEntryUdfpsInteractor.isUdfpsEnrolledAndEnabled.flatMapLatest { udfspEnrolled ->
+            if (udfspEnrolled) {
+                isShowingAodOrDozing.distinctUntilChanged()
+            } else {
+                flowOf(false)
             }
-            .distinctUntilChanged()
+        }
 
     private val padding: Flow<Int> =
         deviceEntryUdfpsInteractor.isUdfpsSupported.flatMapLatest { udfpsSupported ->
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt
index c9cf0c3..31e8093 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt
@@ -37,6 +37,7 @@
 import kotlinx.coroutines.delay
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.flow.flatMapLatest
 import kotlinx.coroutines.flow.flow
 import kotlinx.coroutines.flow.flowOf
@@ -206,6 +207,7 @@
                 DeviceEntryIconView.IconType.LOCK
             }
         }
+    val isVisible: Flow<Boolean> = deviceEntryViewAlpha.map { it > 0f }.distinctUntilChanged()
     val isLongPressEnabled: Flow<Boolean> =
         combine(
             iconType,
@@ -217,6 +219,7 @@
                 DeviceEntryIconView.IconType.FINGERPRINT -> false
             }
         }
+
     val accessibilityDelegateHint: Flow<DeviceEntryIconView.AccessibilityHintType> =
         combine(iconType, isLongPressEnabled) { deviceEntryStatus, longPressEnabled ->
             if (longPressEnabled) {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 7068f5f..d5bbaa5 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -1539,6 +1539,7 @@
 
     @Override
     public void setOpenCloseListener(OpenCloseListener openCloseListener) {
+        SceneContainerFlag.assertInLegacyMode();
         mOpenCloseListener = openCloseListener;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java
index ea41912..e6555f2e 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java
@@ -32,6 +32,7 @@
 import com.android.systemui.log.dagger.ShadeTouchLog;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.scene.domain.interactor.WindowRootViewVisibilityInteractor;
+import com.android.systemui.scene.shared.flag.SceneContainerFlag;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.NotificationShadeWindowController;
 import com.android.systemui.statusbar.StatusBarState;
@@ -98,6 +99,7 @@
                 statusBarKeyguardViewManager,
                 notificationShadeWindowController,
                 assistManagerLazy);
+        SceneContainerFlag.assertInLegacyMode();
         mCommandQueue = commandQueue;
         mMainExecutor = mainExecutor;
         mWindowRootViewVisibilityInteractor = windowRootViewVisibilityInteractor;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
index b07ba3c..a155e94 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
@@ -67,7 +67,7 @@
     private static final String TAG = "HeadsUpManagerPhone";
 
     @VisibleForTesting
-    final int mExtensionTime;
+    public final int mExtensionTime;
     private final KeyguardBypassController mBypassController;
     private final GroupMembershipManager mGroupMembershipManager;
     private final List<OnHeadsUpPhoneListenerChange> mHeadsUpPhoneListeners = new ArrayList<>();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index 5a8b636..d975009 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -22,6 +22,7 @@
 import android.app.ActivityTaskManager;
 import android.app.AlarmManager;
 import android.app.AlarmManager.AlarmClockInfo;
+import android.app.NotificationManager;
 import android.app.admin.DevicePolicyManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -379,7 +380,7 @@
     }
 
     @Override
-    public void onConfigChanged(ZenModeConfig config) {
+    public void onConsolidatedPolicyChanged(NotificationManager.Policy policy) {
         updateVolumeZen();
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/ui/viewmodel/UdfpsAccessibilityOverlayViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/ui/viewmodel/UdfpsAccessibilityOverlayViewModelTest.kt
index e97edcb..9b8cf59 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/ui/viewmodel/UdfpsAccessibilityOverlayViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/ui/viewmodel/UdfpsAccessibilityOverlayViewModelTest.kt
@@ -27,7 +27,7 @@
 import com.android.systemui.flags.Flags.FULL_SCREEN_USER_SWITCHER
 import com.android.systemui.flags.fakeFeatureFlagsClassic
 import com.android.systemui.keyguard.data.repository.deviceEntryFingerprintAuthRepository
-import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
+import com.android.systemui.keyguard.data.repository.fakeBiometricSettingsRepository
 import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
 import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.keyguard.shared.model.TransitionState
@@ -39,6 +39,7 @@
 import com.google.common.truth.Truth.assertThat
 import kotlin.test.Test
 import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
 import org.junit.runner.RunWith
 
@@ -52,7 +53,7 @@
         }
     private val deviceEntryIconTransition = kosmos.fakeDeviceEntryIconViewModelTransition
     private val testScope = kosmos.testScope
-    private val keyguardRepository = kosmos.fakeKeyguardRepository
+    private val biometricSettingsRepository = kosmos.fakeBiometricSettingsRepository
     private val accessibilityRepository = kosmos.fakeAccessibilityRepository
     private val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository
     private val fingerprintPropertyRepository = kosmos.fingerprintPropertyRepository
@@ -85,22 +86,12 @@
             setupVisibleStateOnLockscreen()
 
             // AOD
-            keyguardTransitionRepository.sendTransitionStep(
-                TransitionStep(
-                    from = KeyguardState.LOCKSCREEN,
-                    to = KeyguardState.AOD,
-                    value = 0f,
-                    transitionState = TransitionState.STARTED,
-                )
+            keyguardTransitionRepository.sendTransitionSteps(
+                from = KeyguardState.LOCKSCREEN,
+                to = KeyguardState.AOD,
+                this,
             )
-            keyguardTransitionRepository.sendTransitionStep(
-                TransitionStep(
-                    from = KeyguardState.LOCKSCREEN,
-                    to = KeyguardState.AOD,
-                    value = 1f,
-                    transitionState = TransitionState.FINISHED,
-                )
-            )
+            runCurrent()
             assertThat(visible).isFalse()
         }
     fun fpNotRunning_overlayNotVisible() =
@@ -129,6 +120,7 @@
 
         // Listening for UDFPS
         fingerprintPropertyRepository.supportsUdfps()
+        biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true)
         deviceEntryFingerprintAuthRepository.setIsRunning(true)
         deviceEntryRepository.setUnlocked(false)
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModelTest.kt
new file mode 100644
index 0000000..02bd810
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModelTest.kt
@@ -0,0 +1,110 @@
+/*
+ * 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.systemui.keyguard.ui.viewmodel
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository
+import com.android.systemui.biometrics.data.repository.fingerprintPropertyRepository
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository
+import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
+import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFingerprintAuthRepository
+import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
+import com.android.systemui.keyguard.data.repository.keyguardRepository
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlin.test.Test
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.runner.RunWith
+
+@ExperimentalCoroutinesApi
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class DeviceEntryIconViewModelTest : SysuiTestCase() {
+    private val kosmos = testKosmos()
+    private val testScope = kosmos.testScope
+    private lateinit var keyguardRepository: FakeKeyguardRepository
+    private lateinit var fingerprintPropertyRepository: FakeFingerprintPropertyRepository
+    private lateinit var fingerprintAuthRepository: FakeDeviceEntryFingerprintAuthRepository
+    private lateinit var deviceEntryIconTransition: FakeDeviceEntryIconTransition
+    private lateinit var underTest: DeviceEntryIconViewModel
+
+    @Before
+    fun setUp() {
+        keyguardRepository = kosmos.fakeKeyguardRepository
+        fingerprintPropertyRepository = kosmos.fingerprintPropertyRepository
+        fingerprintAuthRepository = kosmos.fakeDeviceEntryFingerprintAuthRepository
+        deviceEntryIconTransition = kosmos.fakeDeviceEntryIconViewModelTransition
+        underTest = kosmos.deviceEntryIconViewModel
+    }
+
+    @Test
+    fun isLongPressEnabled_udfpsRunning() =
+        testScope.runTest {
+            val isLongPressEnabled by collectLastValue(underTest.isLongPressEnabled)
+            fingerprintPropertyRepository.supportsUdfps()
+            fingerprintAuthRepository.setIsRunning(true)
+            keyguardRepository.setKeyguardDismissible(false)
+            assertThat(isLongPressEnabled).isFalse()
+        }
+
+    @Test
+    fun isLongPressEnabled_unlocked() =
+        testScope.runTest {
+            val isLongPressEnabled by collectLastValue(underTest.isLongPressEnabled)
+            keyguardRepository.setKeyguardDismissible(true)
+            assertThat(isLongPressEnabled).isTrue()
+        }
+
+    @Test
+    fun isLongPressEnabled_lock() =
+        testScope.runTest {
+            val isLongPressEnabled by collectLastValue(underTest.isLongPressEnabled)
+            keyguardRepository.setKeyguardDismissible(false)
+
+            // udfps supported
+            fingerprintPropertyRepository.supportsUdfps()
+            assertThat(isLongPressEnabled).isTrue()
+
+            // udfps isn't supported
+            fingerprintPropertyRepository.supportsRearFps()
+            assertThat(isLongPressEnabled).isFalse()
+        }
+
+    @Test
+    fun isVisible() =
+        testScope.runTest {
+            val isVisible by collectLastValue(underTest.isVisible)
+            deviceEntryIconTransitionAlpha(1f)
+            assertThat(isVisible).isTrue()
+
+            deviceEntryIconTransitionAlpha(0f)
+            assertThat(isVisible).isFalse()
+
+            deviceEntryIconTransitionAlpha(.5f)
+            assertThat(isVisible).isTrue()
+        }
+
+    private fun deviceEntryIconTransitionAlpha(alpha: Float) {
+        deviceEntryIconTransition.setDeviceEntryParentViewAlpha(alpha)
+    }
+}
diff --git a/rs/java/android/renderscript/ScriptC.java b/rs/java/android/renderscript/ScriptC.java
index 4a2f3da..e9f6031 100644
--- a/rs/java/android/renderscript/ScriptC.java
+++ b/rs/java/android/renderscript/ScriptC.java
@@ -38,12 +38,12 @@
     private static final String TAG = "ScriptC";
 
     /**
-     * In targetSdkVersion 35 and above, Renderscript's ScriptC stops being supported
+     * In targetSdkVersion 36 and above, Renderscript's ScriptC stops being supported
      * and an exception is thrown when the class is instantiated.
-     * In targetSdkVersion 34 and below, Renderscript's ScriptC still works.
+     * In targetSdkVersion 35 and below, Renderscript's ScriptC still works.
      */
     @ChangeId
-    @EnabledAfter(targetSdkVersion = 35)
+    @EnabledAfter(targetSdkVersion = 36)
     private static final long RENDERSCRIPT_SCRIPTC_DEPRECATION_CHANGE_ID = 297019750L;
 
     /**
@@ -113,9 +113,9 @@
             throw new UnsupportedOperationException(s);
         }
 
-        // Throw an exception if the target API is 35 or above
+        // Throw an exception if the target API is 36 or above
         String message =
-                "ScriptC scripts are not supported when targeting an API Level >= 35. Please refer "
+                "ScriptC scripts are not supported when targeting an API Level >= 36. Please refer "
                     + "to https://developer.android.com/guide/topics/renderscript/migration-guide "
                     + "for proposed alternatives.";
         Slog.w(TAG, message);
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index c7b844b..d779fbf 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -193,7 +193,6 @@
 import com.android.server.wm.ActivityTaskManagerInternal;
 
 import java.io.PrintWriter;
-import java.io.Serializable;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.ref.WeakReference;
@@ -2821,8 +2820,9 @@
         mSessionFlags.mExpiredResponse = false;
 
         final Parcelable result = data.getParcelable(AutofillManager.EXTRA_AUTHENTICATION_RESULT);
-        final Serializable exception = data.getSerializable(
-                CredentialProviderService.EXTRA_GET_CREDENTIAL_EXCEPTION);
+        final GetCredentialException exception = data.getSerializable(
+                CredentialProviderService.EXTRA_GET_CREDENTIAL_EXCEPTION,
+                GetCredentialException.class);
 
         final Bundle newClientState = data.getBundle(AutofillManager.EXTRA_CLIENT_STATE);
         if (sDebug) {
@@ -5126,6 +5126,10 @@
                 toIpcFriendlyResultReceiver(resultReceiver);
 
         Intent metadataIntent = dataset.getCredentialFillInIntent();
+        if (metadataIntent == null) {
+            metadataIntent = new Intent();
+        }
+
         metadataIntent.putExtra(
                 android.credentials.selection.Constants.EXTRA_FINAL_RESPONSE_RECEIVER,
                 ipcFriendlyResultReceiver);
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 0cc6494..fb62785 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -661,8 +661,12 @@
         @NonNull OpEntry createEntryLocked(String persistentDeviceId) {
             // TODO(b/308201969): Update this method when we introduce disk persistence of events
             // for accesses on external devices.
-            final ArrayMap<String, AttributedOp> attributedOps = mDeviceAttributedOps.get(
+            ArrayMap<String, AttributedOp> attributedOps = mDeviceAttributedOps.get(
                     persistentDeviceId);
+            if (attributedOps == null) {
+                attributedOps = new ArrayMap<>();
+            }
+
             final ArrayMap<String, AppOpsManager.AttributedOpEntry> attributionEntries =
                     new ArrayMap<>(attributedOps.size());
             for (int i = 0; i < attributedOps.size(); i++) {
@@ -680,8 +684,12 @@
         @NonNull OpEntry createSingleAttributionEntryLocked(@Nullable String attributionTag) {
             // TODO(b/308201969): Update this method when we introduce disk persistence of events
             // for accesses on external devices.
-            final ArrayMap<String, AttributedOp> attributedOps = mDeviceAttributedOps.get(
+            ArrayMap<String, AttributedOp> attributedOps = mDeviceAttributedOps.get(
                     PERSISTENT_DEVICE_ID_DEFAULT);
+            if (attributedOps == null) {
+                attributedOps = new ArrayMap<>();
+            }
+
             final ArrayMap<String, AttributedOpEntry> attributionEntries = new ArrayMap<>(1);
             if (attributedOps.get(attributionTag) != null) {
                 attributionEntries.put(attributionTag,
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index 8cc242c..5bd8ca6 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -17,6 +17,8 @@
 package com.android.server.pm;
 
 import static android.content.pm.Flags.disallowSdkLibsToBeApps;
+import static android.content.pm.PackageManager.APP_METADATA_SOURCE_APK;
+import static android.content.pm.PackageManager.APP_METADATA_SOURCE_INSTALLER;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
 import static android.content.pm.PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
@@ -43,11 +45,11 @@
 import static android.os.storage.StorageManager.FLAG_STORAGE_DE;
 import static android.os.storage.StorageManager.FLAG_STORAGE_EXTERNAL;
 
+import static com.android.internal.pm.pkg.parsing.ParsingPackageUtils.APP_METADATA_FILE_NAME;
 import static com.android.server.pm.DexOptHelper.useArtService;
 import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
 import static com.android.server.pm.InstructionSets.getDexCodeInstructionSet;
 import static com.android.server.pm.InstructionSets.getPreferredInstructionSet;
-import static com.android.server.pm.PackageManagerService.APP_METADATA_FILE_NAME;
 import static com.android.server.pm.PackageManagerService.DEBUG_COMPRESSION;
 import static com.android.server.pm.PackageManagerService.DEBUG_INSTALL;
 import static com.android.server.pm.PackageManagerService.DEBUG_PACKAGE_SCANNING;
@@ -2225,10 +2227,16 @@
                 if (appMetadataFile.exists()) {
                     ps.setAppMetadataFilePath(appMetadataFile.getAbsolutePath());
                     if (Flags.aslInApkAppMetadataSource()) {
-                        ps.setAppMetadataSource(PackageManager.APP_METADATA_SOURCE_INSTALLER);
+                        ps.setAppMetadataSource(APP_METADATA_SOURCE_INSTALLER);
                     }
                 } else {
-                    ps.setAppMetadataFilePath(null);
+                    if (Flags.aslInApkAppMetadataSource()
+                            && parsedPackage.isAppMetadataFileInApk()) {
+                        ps.setAppMetadataFilePath(appMetadataFile.getAbsolutePath());
+                        ps.setAppMetadataSource(APP_METADATA_SOURCE_APK);
+                    } else {
+                        ps.setAppMetadataFilePath(null);
+                    }
                 }
             }
             if (installRequest.getReturnCode() == PackageManager.INSTALL_SUCCEEDED) {
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 5792d86..ba90378 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -358,7 +358,7 @@
     /** Default byte size limit for app metadata */
     private static final long DEFAULT_APP_METADATA_BYTE_SIZE_LIMIT = 32000;
 
-    private static final int APP_METADATA_FILE_ACCESS_MODE = 0640;
+    static final int APP_METADATA_FILE_ACCESS_MODE = 0640;
 
     /**
      * Throws IllegalArgumentException if the {@link IntentSender} from an immutable
@@ -964,7 +964,7 @@
 
     private boolean isEmergencyInstallerEnabled(String packageName, Computer snapshot) {
         final PackageStateInternal ps = snapshot.getPackageStateInternal(packageName);
-        if (ps == null || ps.getPkg() == null || !ps.isSystem()) {
+        if (ps == null || ps.getPkg() == null) {
             return false;
         }
         String emergencyInstaller = ps.getPkg().getEmergencyInstaller();
@@ -1782,8 +1782,7 @@
     }
 
     private File getStagedAppMetadataFile() {
-        File file = new File(stageDir, APP_METADATA_FILE_NAME);
-        return file.exists() ? file : null;
+        return new File(stageDir, APP_METADATA_FILE_NAME);
     }
 
     private static boolean isAppMetadata(String name) {
@@ -1799,7 +1798,7 @@
         assertCallerIsOwnerOrRoot();
         synchronized (mLock) {
             assertPreparedAndNotCommittedOrDestroyedLocked("getAppMetadataFd");
-            if (getStagedAppMetadataFile() == null) {
+            if (!getStagedAppMetadataFile().exists()) {
                 return null;
             }
             try {
@@ -1813,12 +1812,12 @@
     @Override
     public void removeAppMetadata() {
         File file = getStagedAppMetadataFile();
-        if (file != null) {
+        if (file.exists()) {
             file.delete();
         }
     }
 
-    private static long getAppMetadataSizeLimit() {
+    static long getAppMetadataSizeLimit() {
         final long token = Binder.clearCallingIdentity();
         try {
             return DeviceConfig.getLong(NAMESPACE_PACKAGE_MANAGER_SERVICE,
@@ -2131,7 +2130,7 @@
         }
 
         File appMetadataFile = getStagedAppMetadataFile();
-        if (appMetadataFile != null) {
+        if (appMetadataFile.exists()) {
             long sizeLimit = getAppMetadataSizeLimit();
             if (appMetadataFile.length() > sizeLimit) {
                 appMetadataFile.delete();
@@ -3419,7 +3418,7 @@
 
         final List<ApkLite> addedFiles = getAddedApkLitesLocked();
         if (addedFiles.isEmpty()
-                && (removeSplitList.size() == 0 || getStagedAppMetadataFile() != null)) {
+                && (removeSplitList.size() == 0 || getStagedAppMetadataFile().exists())) {
             throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
                     TextUtils.formatSimple("Session: %d. No packages staged in %s", sessionId,
                           stageDir.getAbsolutePath()));
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 3c256b1..69f7906 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -18,6 +18,8 @@
 import static android.Manifest.permission.MANAGE_DEVICE_ADMINS;
 import static android.Manifest.permission.SET_HARMFUL_APP_WARNINGS;
 import static android.app.AppOpsManager.MODE_IGNORED;
+import static android.content.pm.PackageManager.APP_METADATA_SOURCE_APK;
+import static android.content.pm.PackageManager.APP_METADATA_SOURCE_UNKNOWN;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
@@ -596,7 +598,8 @@
     static final String RANDOM_DIR_PREFIX = "~~";
     static final char RANDOM_CODEPATH_PREFIX = '-';
 
-    static final String APP_METADATA_FILE_NAME = "app.metadata";
+    public static final String APP_METADATA_FILE_NAME = "app.metadata";
+    public static final String APP_METADATA_FILE_IN_APK_PATH = "assets/" + APP_METADATA_FILE_NAME;
 
     static final int DEFAULT_FILE_ACCESS_MODE = 0644;
 
@@ -5227,15 +5230,30 @@
                         new PackageManager.NameNotFoundException(packageName));
             }
             String filePath = ps.getAppMetadataFilePath();
-            if (filePath != null) {
-                File file = new File(filePath);
-                try {
-                    return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);
-                } catch (FileNotFoundException e) {
+            if (filePath == null) {
+                return null;
+            }
+            File file = new File(filePath);
+            if (Flags.aslInApkAppMetadataSource() && !file.exists()
+                    && ps.getAppMetadataSource() == APP_METADATA_SOURCE_APK) {
+                String apkPath = ps.getPkg().getSplits().get(0).getPath();
+                if (!PackageManagerServiceUtils.extractAppMetadataFromApk(apkPath, file)) {
+                    if (file.exists()) {
+                        file.delete();
+                    }
+                    synchronized (mLock) {
+                        PackageSetting pkgSetting = mSettings.getPackageLPr(packageName);
+                        pkgSetting.setAppMetadataFilePath(null);
+                        pkgSetting.setAppMetadataSource(APP_METADATA_SOURCE_UNKNOWN);
+                    }
                     return null;
                 }
             }
-            return null;
+            try {
+                return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);
+            } catch (FileNotFoundException e) {
+                return null;
+            }
         }
 
         @android.annotation.EnforcePermission(android.Manifest.permission.GET_APP_METADATA)
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index 0a3dfc0..189a138 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -27,6 +27,9 @@
 import static com.android.internal.content.NativeLibraryHelper.LIB_DIR_NAME;
 import static com.android.internal.util.FrameworkStatsLog.UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__EXPLICIT_INTENT_FILTER_UNMATCH;
 import static com.android.server.LocalManagerRegistry.ManagerNotFoundException;
+import static com.android.server.pm.PackageInstallerSession.APP_METADATA_FILE_ACCESS_MODE;
+import static com.android.server.pm.PackageInstallerSession.getAppMetadataSizeLimit;
+import static com.android.server.pm.PackageManagerService.APP_METADATA_FILE_IN_APK_PATH;
 import static com.android.server.pm.PackageManagerService.COMPRESSED_EXTENSION;
 import static com.android.server.pm.PackageManagerService.DEBUG_COMPRESSION;
 import static com.android.server.pm.PackageManagerService.DEBUG_INTENT_MATCHING;
@@ -142,6 +145,8 @@
 import java.util.function.Function;
 import java.util.function.Predicate;
 import java.util.zip.GZIPInputStream;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
 
 /**
  * Class containing helper methods for the PackageManagerService.
@@ -1559,6 +1564,35 @@
         return initiatingPackageName == null || SHELL_PACKAGE_NAME.equals(initiatingPackageName);
     }
 
+    /**
+     * Extract the app.metadata file from apk.
+     */
+    public static boolean extractAppMetadataFromApk(String apkPath, File appMetadataFile) {
+        boolean found = false;
+        try (ZipInputStream zipInputStream =
+                     new ZipInputStream(new FileInputStream(new File(apkPath)))) {
+            ZipEntry zipEntry = null;
+            while ((zipEntry = zipInputStream.getNextEntry()) != null) {
+                if (zipEntry.getName().equals(APP_METADATA_FILE_IN_APK_PATH)) {
+                    found = true;
+                    try (FileOutputStream out = new FileOutputStream(appMetadataFile)) {
+                        FileUtils.copy(zipInputStream, out);
+                    }
+                    if (appMetadataFile.length() > getAppMetadataSizeLimit()) {
+                        appMetadataFile.delete();
+                        return false;
+                    }
+                    Os.chmod(appMetadataFile.getAbsolutePath(), APP_METADATA_FILE_ACCESS_MODE);
+                    break;
+                }
+            }
+        } catch (Exception e) {
+            Slog.e(TAG, e.getMessage());
+            return false;
+        }
+        return found;
+    }
+
     public static void linkFilesToOldDirs(@NonNull Installer installer,
                                            @NonNull String packageName,
                                            @NonNull File newPath,
diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java
index f15646f..98499417 100644
--- a/services/core/java/com/android/server/policy/PermissionPolicyService.java
+++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java
@@ -237,7 +237,7 @@
         mAppOpsCallback = new IAppOpsCallback.Stub() {
             public void opChanged(int op, int uid, @Nullable String packageName,
                     String persistentDeviceId) {
-                if (Objects.equals(persistentDeviceId,
+                if (!Objects.equals(persistentDeviceId,
                         VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT)) {
                     return;
                 }
diff --git a/services/core/java/com/android/server/wm/DragDropController.java b/services/core/java/com/android/server/wm/DragDropController.java
index b68e67e..34ea4ac 100644
--- a/services/core/java/com/android/server/wm/DragDropController.java
+++ b/services/core/java/com/android/server/wm/DragDropController.java
@@ -18,6 +18,7 @@
 
 import static android.view.View.DRAG_FLAG_GLOBAL;
 import static android.view.View.DRAG_FLAG_GLOBAL_SAME_APPLICATION;
+import static android.view.View.DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG;
 
 import static com.android.input.flags.Flags.enablePointerChoreographer;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DRAG;
@@ -373,8 +374,11 @@
     boolean notifyUnhandledDrop(DragEvent dropEvent, String reason) {
         final boolean isLocalDrag =
                 (mDragState.mFlags & (DRAG_FLAG_GLOBAL_SAME_APPLICATION | DRAG_FLAG_GLOBAL)) == 0;
+        final boolean shouldDelegateUnhandledDrag =
+                (mDragState.mFlags & DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG) != 0;
         if (!com.android.window.flags.Flags.delegateUnhandledDrags()
                 || mGlobalDragListener == null
+                || !shouldDelegateUnhandledDrag
                 || isLocalDrag) {
             // Skip if the flag is disabled, there is no unhandled-drag listener, or if this is a
             // purely local drag
diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java b/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java
index 9d45cfb..027337f 100644
--- a/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java
+++ b/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java
@@ -18,7 +18,6 @@
 import static android.credentials.selection.Constants.EXTRA_FINAL_RESPONSE_RECEIVER;
 
 import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.app.PendingIntent;
 import android.content.ComponentName;
 import android.content.Context;
@@ -161,26 +160,6 @@
      */
     public PendingIntent createPendingIntent(
             RequestInfo requestInfo, ArrayList<ProviderData> providerDataList) {
-        return createPendingIntent(requestInfo, providerDataList, /*forAutofill=*/ false);
-    }
-
-    /**
-     * Creates a {@link PendingIntent} to be used to invoke the credential manager selector UI,
-     * by the calling app process. This intent is invoked from the Autofill flow, when the user
-     * requests to bring up the 'All Options' page of the credential bottom-sheet. When the user
-     * clicks on the pinned entry, the intent will bring up the 'All Options' page of the
-     * bottom-sheet. The provider data list is processed by the credential autofill service for
-     * each autofill id and passed in as an auth extra.
-     *
-     * @param requestInfo            the information about the request
-     */
-    public PendingIntent createPendingIntentForAutofill(RequestInfo requestInfo) {
-        return createPendingIntent(requestInfo, /*providerDataList=*/ null, /*forAutofill=*/ true);
-    }
-
-    private PendingIntent createPendingIntent(
-            RequestInfo requestInfo, @Nullable ArrayList<ProviderData> providerDataList,
-            boolean forAutofill) {
         List<CredentialProviderInfo> allProviders =
                 CredentialProviderInfoFactory.getCredentialProviderServices(
                         mContext,
@@ -196,15 +175,9 @@
                         disabledProvider.getComponentName().flattenToString())).toList();
 
         Intent intent;
-        if (forAutofill) {
-            intent = IntentFactory.createCredentialSelectorIntentForAutofill(
-                    mContext, requestInfo, new ArrayList<>(disabledProviderDataList),
-                    mResultReceiver);
-        } else {
-            intent = IntentFactory.createCredentialSelectorIntent(
-                    mContext, requestInfo, providerDataList,
-                    new ArrayList<>(disabledProviderDataList), mResultReceiver);
-        }
+        intent = IntentFactory.createCredentialSelectorIntent(
+                mContext, requestInfo, providerDataList,
+                new ArrayList<>(disabledProviderDataList), mResultReceiver);
         intent.setAction(UUID.randomUUID().toString());
         //TODO: Create unique pending intent using request code and cancel any pre-existing pending
         // intents
@@ -213,4 +186,21 @@
                 PendingIntent.FLAG_MUTABLE, /*options=*/null,
                 UserHandle.of(mUserId));
     }
+
+    /**
+     * Creates an {@link Intent} to be used to invoke the credential manager selector UI,
+     * by the calling app process. This intent is invoked from the Autofill flow, when the user
+     * requests to bring up the 'All Options' page of the credential bottom-sheet. When the user
+     * clicks on the pinned entry, the intent will bring up the 'All Options' page of the
+     * bottom-sheet. The provider data list is processed by the credential autofill service for
+     * each autofill id and passed in as extras in the pending intent set as authentication
+     * of the pinned entry.
+     *
+     * @param requestInfo            the information about the request
+     */
+    public Intent createIntentForAutofill(RequestInfo requestInfo) {
+        return IntentFactory.createCredentialSelectorIntentForAutofill(
+                mContext, requestInfo, new ArrayList<>(),
+                mResultReceiver);
+    }
 }
diff --git a/services/credentials/java/com/android/server/credentials/GetCandidateRequestSession.java b/services/credentials/java/com/android/server/credentials/GetCandidateRequestSession.java
index ca72638..3cb98eb 100644
--- a/services/credentials/java/com/android/server/credentials/GetCandidateRequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/GetCandidateRequestSession.java
@@ -20,6 +20,7 @@
 import android.annotation.Nullable;
 import android.content.ComponentName;
 import android.content.Context;
+import android.content.Intent;
 import android.credentials.Constants;
 import android.credentials.CredentialProviderInfo;
 import android.credentials.GetCandidateCredentialsException;
@@ -114,8 +115,7 @@
             return;
         }
 
-        cancelExistingPendingIntent();
-        mPendingIntent = mCredentialManagerUi.createPendingIntentForAutofill(
+        Intent intent = mCredentialManagerUi.createIntentForAutofill(
                 RequestInfo.newGetRequestInfo(
                         mRequestId, mClientRequest, mClientAppInfo.getPackageName(),
                         PermissionUtils.hasPermission(mContext, mClientAppInfo.getPackageName(),
@@ -129,7 +129,7 @@
 
         try {
             invokeClientCallbackSuccess(new GetCandidateCredentialsResponse(
-                    candidateProviderDataList, mPendingIntent));
+                    candidateProviderDataList, intent));
         } catch (RemoteException e) {
             Slog.e(TAG, "Issue while responding to client with error : " + e);
         }
diff --git a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
index fa63bc8..cad9a09 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
@@ -93,7 +93,7 @@
         android.credentials.GetCredentialRequest filteredRequest =
                 filterOptions(providerInfo.getCapabilities(),
                         getRequestSession.mClientRequest,
-                        providerInfo);
+                        providerInfo, getRequestSession.mHybridService);
         if (filteredRequest != null) {
             Map<String, CredentialOption> beginGetOptionToCredentialOptionMap =
                     new HashMap<>();
@@ -129,7 +129,7 @@
         android.credentials.GetCredentialRequest filteredRequest =
                 filterOptions(providerInfo.getCapabilities(),
                         getRequestSession.mClientRequest,
-                        providerInfo);
+                        providerInfo, getRequestSession.mHybridService);
         if (filteredRequest != null) {
             Map<String, CredentialOption> beginGetOptionToCredentialOptionMap =
                     new HashMap<>();
@@ -179,9 +179,19 @@
     private static android.credentials.GetCredentialRequest filterOptions(
             List<String> providerCapabilities,
             android.credentials.GetCredentialRequest clientRequest,
-            CredentialProviderInfo info
-    ) {
+            CredentialProviderInfo info,
+            String hybridService) {
         Slog.i(TAG, "Filtering request options for: " + info.getComponentName());
+        if (android.credentials.flags.Flags.hybridFilterFixEnabled()) {
+            ComponentName hybridComponentName = ComponentName.unflattenFromString(hybridService);
+            if (hybridComponentName != null && hybridComponentName
+                    .equals(info.getComponentName())) {
+                Slog.i(TAG, "Skipping filtering of options for hybrid service");
+                return clientRequest;
+            }
+            Slog.w(TAG, "Could not parse hybrid service while filtering options");
+        }
+
         List<CredentialOption> filteredOptions = new ArrayList<>();
         for (CredentialOption option : clientRequest.getCredentialOptions()) {
             if (providerCapabilities.contains(option.getType())
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/EnterpriseSpecificIdCalculator.java b/services/devicepolicy/java/com/android/server/devicepolicy/EnterpriseSpecificIdCalculator.java
index df7f308..1000bfa 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/EnterpriseSpecificIdCalculator.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/EnterpriseSpecificIdCalculator.java
@@ -53,7 +53,17 @@
         TelephonyManager telephonyService = context.getSystemService(TelephonyManager.class);
         Preconditions.checkState(telephonyService != null, "Unable to access telephony service");
         mImei = telephonyService.getImei(0);
-        mMeid = telephonyService.getMeid(0);
+        String meid;
+        try {
+            meid = telephonyService.getMeid(0);
+        } catch (UnsupportedOperationException doesNotSupportCdma) {
+            // Instead of catching the exception, we could check for FEATURE_TELEPHONY_CDMA.
+            // However that runs the risk of changing a device's existing ESID if on these devices
+            // telephonyService.getMeid() actually returns non-null even when the device does not
+            // declare FEATURE_TELEPHONY_CDMA.
+            meid = null;
+        }
+        mMeid = meid;
         mSerialNumber = Build.getSerial();
         WifiManager wifiManager = context.getSystemService(WifiManager.class);
         Preconditions.checkState(wifiManager != null, "Unable to access WiFi service");
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
index d4b57f1..96e9ca0 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
@@ -275,6 +275,7 @@
         AndroidPackage::isUpdatableSystem,
         AndroidPackage::getEmergencyInstaller,
         AndroidPackage::isAllowCrossUidActivitySwitchFromBelow,
+        PackageImpl::isAppMetadataFileInApk,
     )
 
     override fun extraParams() = listOf(
diff --git a/services/tests/mockingservicestests/src/com/android/server/rollback/RollbackPackageHealthObserverTest.java b/services/tests/mockingservicestests/src/com/android/server/rollback/RollbackPackageHealthObserverTest.java
index d6e246f..6e41685 100644
--- a/services/tests/mockingservicestests/src/com/android/server/rollback/RollbackPackageHealthObserverTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/rollback/RollbackPackageHealthObserverTest.java
@@ -25,6 +25,8 @@
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
@@ -42,6 +44,7 @@
 import android.crashrecovery.flags.Flags;
 import android.os.Handler;
 import android.os.MessageQueue;
+import android.os.SystemProperties;
 import android.platform.test.flag.junit.SetFlagsRule;
 
 import androidx.test.runner.AndroidJUnit4;
@@ -65,6 +68,7 @@
 import org.mockito.stubbing.Answer;
 
 import java.time.Duration;
+import java.util.HashMap;
 import java.util.List;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
@@ -90,7 +94,7 @@
 
     @Rule
     public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
-
+    private HashMap<String, String> mSystemSettingsMap;
     private MockitoSession mSession;
     private static final String APP_A = "com.package.a";
     private static final String APP_B = "com.package.b";
@@ -99,6 +103,9 @@
     private static final long VERSION_CODE_2 = 2L;
     private static final String LOG_TAG = "RollbackPackageHealthObserverTest";
 
+    private static final String PROP_DISABLE_HIGH_IMPACT_ROLLBACK_FLAG =
+            "persist.device_config.configuration.disable_high_impact_rollback";
+
     private SystemConfig mSysConfig;
 
     @Rule public TemporaryFolder mTemporaryFolder = new TemporaryFolder();
@@ -111,11 +118,34 @@
                 .initMocks(this)
                 .strictness(Strictness.LENIENT)
                 .spyStatic(PackageWatchdog.class)
+                .spyStatic(SystemProperties.class)
                 .startMocking();
+        mSystemSettingsMap = new HashMap<>();
 
         // Mock PackageWatchdog
         doAnswer((Answer<PackageWatchdog>) invocationOnMock -> mMockPackageWatchdog)
                 .when(() -> PackageWatchdog.getInstance(mMockContext));
+
+        // Mock SystemProperties setter and various getters
+        doAnswer((Answer<Void>) invocationOnMock -> {
+                    String key = invocationOnMock.getArgument(0);
+                    String value = invocationOnMock.getArgument(1);
+
+                    mSystemSettingsMap.put(key, value);
+                    return null;
+                }
+        ).when(() -> SystemProperties.set(anyString(), anyString()));
+
+        doAnswer((Answer<Boolean>) invocationOnMock -> {
+                    String key = invocationOnMock.getArgument(0);
+                    boolean defaultValue = invocationOnMock.getArgument(1);
+
+                    String storedValue = mSystemSettingsMap.get(key);
+                    return storedValue == null ? defaultValue : Boolean.parseBoolean(storedValue);
+                }
+        ).when(() -> SystemProperties.getBoolean(anyString(), anyBoolean()));
+
+        SystemProperties.set(PROP_DISABLE_HIGH_IMPACT_ROLLBACK_FLAG, Boolean.toString(false));
     }
 
     @After
@@ -609,6 +639,32 @@
                 observer.onBootLoop(1));
     }
 
+    @Test
+    public void onBootLoop_impactLevelHighDisableHighImpactRollback_onePackage()
+            throws PackageManager.NameNotFoundException {
+        mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
+        SystemProperties.set(PROP_DISABLE_HIGH_IMPACT_ROLLBACK_FLAG, Boolean.toString(true));
+        VersionedPackage appAFrom = new VersionedPackage(APP_A, VERSION_CODE_2);
+        VersionedPackage appATo = new VersionedPackage(APP_A, VERSION_CODE);
+        PackageRollbackInfo packageRollbackInfo = new PackageRollbackInfo(appAFrom, appATo,
+                null, null, false, false,
+                null);
+        RollbackInfo rollbackInfo1 = new RollbackInfo(1, List.of(packageRollbackInfo),
+                false, null, 111,
+                PackageManager.ROLLBACK_USER_IMPACT_HIGH);
+        RollbackPackageHealthObserver observer =
+                spy(new RollbackPackageHealthObserver(mMockContext, mApexManager));
+
+        when(mMockContext.getSystemService(RollbackManager.class)).thenReturn(mRollbackManager);
+        // Make the rollbacks available
+        when(mRollbackManager.getAvailableRollbacks()).thenReturn(List.of(rollbackInfo1));
+        when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager);
+        when(mMockPackageManager.getModuleInfo(any(), eq(0))).thenReturn(null);
+
+        assertEquals(PackageWatchdog.PackageHealthObserverImpact.USER_IMPACT_LEVEL_0,
+                observer.onBootLoop(1));
+    }
+
     /**
      * When the rollback impact level is manual only return user impact level 0. (User impact level
      * 0 is ignored by package watchdog)
@@ -924,6 +980,50 @@
         assertThat(argument.getAllValues()).isEqualTo(List.of(rollbackId2));
     }
 
+    /**
+     * Don't roll back if kill switch is enabled.
+     */
+    @Test
+    public void executeBootLoopMitigation_impactLevelHighKillSwitchTrue_rollbackHigh()
+            throws PackageManager.NameNotFoundException {
+        mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
+        SystemProperties.set(PROP_DISABLE_HIGH_IMPACT_ROLLBACK_FLAG, Boolean.toString(true));
+        int rollbackId1 = 1;
+        VersionedPackage appBFrom = new VersionedPackage(APP_B, VERSION_CODE_2);
+        VersionedPackage appBTo = new VersionedPackage(APP_B, VERSION_CODE);
+        PackageRollbackInfo packageRollbackInfoB = new PackageRollbackInfo(appBFrom, appBTo,
+                null, null , false, false,
+                null);
+        RollbackInfo rollbackInfo1 = new RollbackInfo(rollbackId1, List.of(packageRollbackInfoB),
+                false, null, 111,
+                PackageManager.ROLLBACK_USER_IMPACT_HIGH);
+        int rollbackId2 = 2;
+        VersionedPackage appAFrom = new VersionedPackage(APP_A, VERSION_CODE_2);
+        VersionedPackage appATo = new VersionedPackage(APP_A, VERSION_CODE);
+        PackageRollbackInfo packageRollbackInfoA = new PackageRollbackInfo(appAFrom, appATo,
+                null, null , false, false,
+                null);
+        RollbackInfo rollbackInfo2 = new RollbackInfo(rollbackId2, List.of(packageRollbackInfoA),
+                false, null, 111,
+                PackageManager.ROLLBACK_USER_IMPACT_HIGH);
+        RollbackPackageHealthObserver observer =
+                spy(new RollbackPackageHealthObserver(mMockContext, mApexManager));
+        ArgumentCaptor<Integer> argument = ArgumentCaptor.forClass(Integer.class);
+
+        when(mMockContext.getSystemService(RollbackManager.class)).thenReturn(mRollbackManager);
+        // Make the rollbacks available
+        when(mRollbackManager.getAvailableRollbacks()).thenReturn(
+                List.of(rollbackInfo1, rollbackInfo2));
+        when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager);
+        when(mMockPackageManager.getModuleInfo(any(), eq(0))).thenReturn(null);
+
+        observer.executeBootLoopMitigation(1);
+        waitForIdleHandler(observer.getHandler(), Duration.ofSeconds(10));
+
+        verify(mRollbackManager, never()).commitRollback(
+                argument.capture(), any(), any());
+    }
+
     private void waitForIdleHandler(Handler handler, Duration timeout) {
         final MessageQueue queue = handler.getLooper().getQueue();
         final CountDownLatch latch = new CountDownLatch(1);
diff --git a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
index 4c32a58..a0461a6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
@@ -42,6 +42,7 @@
 import static org.junit.Assume.assumeTrue;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
@@ -541,7 +542,7 @@
     }
 
     @Test
-    public void testUnhandledDragListenerNotCalledForNormalDrags() throws RemoteException {
+    public void testUnhandledDragNotCalledForNormalDrags() throws RemoteException {
         assumeTrue(com.android.window.flags.Flags.delegateUnhandledDrags());
 
         final IGlobalDragListener listener = mock(IGlobalDragListener.class);
@@ -552,15 +553,16 @@
     }
 
     @Test
-    public void testUnhandledDragListenerReceivesUnhandledDropOverWindow() {
+    public void testUnhandledDragReceivesUnhandledDropOverWindow() {
         assumeTrue(com.android.window.flags.Flags.delegateUnhandledDrags());
 
         final IGlobalDragListener listener = mock(IGlobalDragListener.class);
         doReturn(mock(Binder.class)).when(listener).asBinder();
         mTarget.setGlobalDragListener(listener);
         final int invalidXY = 100_000;
-        startDrag(View.DRAG_FLAG_GLOBAL, ClipData.newPlainText("label", "Test"), () -> {
-            // Notify the unhandled drag listener
+        startDrag(View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG,
+                ClipData.newPlainText("label", "Test"), () -> {
+            // Trigger an unhandled drop and verify the global drag listener was called
             mTarget.reportDropWindow(mWindow.mInputChannelToken, invalidXY, invalidXY);
             mTarget.handleMotionEvent(false /* keepHandling */, invalidXY, invalidXY);
             mTarget.reportDropResult(mWindow.mClient, false);
@@ -575,15 +577,16 @@
     }
 
     @Test
-    public void testUnhandledDragListenerReceivesUnhandledDropOverNoValidWindow() {
+    public void testUnhandledDragReceivesUnhandledDropOverNoValidWindow() {
         assumeTrue(com.android.window.flags.Flags.delegateUnhandledDrags());
 
         final IGlobalDragListener listener = mock(IGlobalDragListener.class);
         doReturn(mock(Binder.class)).when(listener).asBinder();
         mTarget.setGlobalDragListener(listener);
         final int invalidXY = 100_000;
-        startDrag(View.DRAG_FLAG_GLOBAL, ClipData.newPlainText("label", "Test"), () -> {
-            // Notify the unhandled drag listener
+        startDrag(View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG,
+                ClipData.newPlainText("label", "Test"), () -> {
+            // Trigger an unhandled drop and verify the global drag listener was called
             mTarget.reportDropWindow(mock(IBinder.class), invalidXY, invalidXY);
             mTarget.handleMotionEvent(false /* keepHandling */, invalidXY, invalidXY);
             mTarget.onUnhandledDropCallback(true);
@@ -597,15 +600,38 @@
     }
 
     @Test
-    public void testUnhandledDragListenerCallbackTimeout() {
+    public void testUnhandledDragDoesNotReceiveUnhandledDropWithoutDragFlag() {
         assumeTrue(com.android.window.flags.Flags.delegateUnhandledDrags());
 
         final IGlobalDragListener listener = mock(IGlobalDragListener.class);
         doReturn(mock(Binder.class)).when(listener).asBinder();
         mTarget.setGlobalDragListener(listener);
         final int invalidXY = 100_000;
-        startDrag(View.DRAG_FLAG_GLOBAL, ClipData.newPlainText("label", "Test"), () -> {
-            // Notify the unhandled drag listener
+        startDrag(View.DRAG_FLAG_GLOBAL,
+                ClipData.newPlainText("label", "Test"), () -> {
+                    // Trigger an unhandled drop and verify the global drag listener was not called
+                    mTarget.reportDropWindow(mock(IBinder.class), invalidXY, invalidXY);
+                    mTarget.handleMotionEvent(false /* keepHandling */, invalidXY, invalidXY);
+                    mToken = null;
+                    try {
+                        verify(listener, never()).onUnhandledDrop(any(), any());
+                    } catch (RemoteException e) {
+                        fail("Failed to verify unhandled drop: " + e);
+                    }
+                });
+    }
+
+    @Test
+    public void testUnhandledDragCallbackTimeout() {
+        assumeTrue(com.android.window.flags.Flags.delegateUnhandledDrags());
+
+        final IGlobalDragListener listener = mock(IGlobalDragListener.class);
+        doReturn(mock(Binder.class)).when(listener).asBinder();
+        mTarget.setGlobalDragListener(listener);
+        final int invalidXY = 100_000;
+        startDrag(View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG,
+                ClipData.newPlainText("label", "Test"), () -> {
+            // Trigger an unhandled drop and verify the global drag listener was called
             mTarget.reportDropWindow(mock(IBinder.class), invalidXY, invalidXY);
             mTarget.handleMotionEvent(false /* keepHandling */, invalidXY, invalidXY);