Merge "UsageStats: detach dedicated handler thread flag" into main
diff --git a/core/api/current.txt b/core/api/current.txt
index 5772fb4..2d10c05 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -19675,6 +19675,7 @@
 
   public final class CaptureRequest extends android.hardware.camera2.CameraMetadata<android.hardware.camera2.CaptureRequest.Key<?>> implements android.os.Parcelable {
     method public int describeContents();
+    method @FlaggedApi("com.android.internal.camera.flags.surface_leak_fix") protected void finalize();
     method @Nullable public <T> T get(android.hardware.camera2.CaptureRequest.Key<T>);
     method @NonNull public java.util.List<android.hardware.camera2.CaptureRequest.Key<?>> getKeys();
     method @Nullable public Object getTag();
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 66efccd1..c0db77c 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -309,6 +309,8 @@
 
     private Object mUserTag;
 
+    private boolean mReleaseSurfaces = false;
+
     /**
      * Construct empty request.
      *
@@ -610,6 +612,9 @@
             Parcelable[] parcelableArray = in.readParcelableArray(Surface.class.getClassLoader(),
                     Surface.class);
             if (parcelableArray != null) {
+                if (Flags.surfaceLeakFix()) {
+                    mReleaseSurfaces = true;
+                }
                 for (Parcelable p : parcelableArray) {
                     Surface s = (Surface) p;
                     mSurfaceSet.add(s);
@@ -792,6 +797,17 @@
         }
     }
 
+    @SuppressWarnings("Finalize")
+    @FlaggedApi(Flags.FLAG_SURFACE_LEAK_FIX)
+    @Override
+    protected void finalize() {
+        if (mReleaseSurfaces) {
+            for (Surface s : mSurfaceSet) {
+                s.release();
+            }
+        }
+    }
+
     /**
      * A builder for capture requests.
      *
diff --git a/core/java/android/hardware/camera2/extension/SessionProcessor.java b/core/java/android/hardware/camera2/extension/SessionProcessor.java
index 2e428e5..0ec5c0a 100644
--- a/core/java/android/hardware/camera2/extension/SessionProcessor.java
+++ b/core/java/android/hardware/camera2/extension/SessionProcessor.java
@@ -363,11 +363,20 @@
 
     private final class SessionProcessorImpl extends ISessionProcessorImpl.Stub {
         private long mVendorId = -1;
+        OutputSurface mImageCaptureSurface;
+        OutputSurface mPreviewSurface;
+        OutputSurface mPostviewSurface;
+
         @Override
         public CameraSessionConfig initSession(IBinder token, String cameraId,
                 Map<String, CameraMetadataNative> charsMap, OutputSurface previewSurface,
                 OutputSurface imageCaptureSurface, OutputSurface postviewSurface)
                 throws RemoteException {
+            if (Flags.surfaceLeakFix()) {
+                mPreviewSurface = previewSurface;
+                mPostviewSurface = postviewSurface;
+                mImageCaptureSurface = imageCaptureSurface;
+            }
             ExtensionConfiguration config = SessionProcessor.this.initSession(token, cameraId,
                     new CharacteristicsMap(charsMap),
                     new CameraOutputSurface(previewSurface),
@@ -390,6 +399,17 @@
         @Override
         public void deInitSession(IBinder token) throws RemoteException {
             SessionProcessor.this.deInitSession(token);
+            if (Flags.surfaceLeakFix()) {
+                if ((mPreviewSurface != null) && (mPreviewSurface.surface != null)) {
+                    mPreviewSurface.surface.release();
+                }
+                if ((mImageCaptureSurface != null) && (mImageCaptureSurface.surface != null)) {
+                    mImageCaptureSurface.surface.release();
+                }
+                if ((mPostviewSurface != null) && (mPostviewSurface.surface != null)) {
+                    mPostviewSurface.surface.release();
+                }
+            }
         }
 
         @Override
diff --git a/core/java/android/hardware/input/InputSettings.java b/core/java/android/hardware/input/InputSettings.java
index 62473c5..4328d9f 100644
--- a/core/java/android/hardware/input/InputSettings.java
+++ b/core/java/android/hardware/input/InputSettings.java
@@ -28,6 +28,7 @@
 import android.annotation.RequiresPermission;
 import android.annotation.SuppressLint;
 import android.annotation.TestApi;
+import android.app.AppGlobals;
 import android.content.Context;
 import android.os.UserHandle;
 import android.provider.Settings;
@@ -393,15 +394,34 @@
      *
      * @hide
      */
-    public static boolean isStylusPointerIconEnabled(@NonNull Context context) {
+    public static boolean isStylusPointerIconEnabled(@NonNull Context context,
+            boolean forceReloadSetting) {
         if (InputProperties.force_enable_stylus_pointer_icon().orElse(false)) {
+            // Sysprop override is set
             return true;
         }
-        return context.getResources()
-                        .getBoolean(com.android.internal.R.bool.config_enableStylusPointerIcon)
-                && Settings.Secure.getIntForUser(context.getContentResolver(),
-                        Settings.Secure.STYLUS_POINTER_ICON_ENABLED,
-                        DEFAULT_STYLUS_POINTER_ICON_ENABLED, UserHandle.USER_CURRENT_OR_SELF) != 0;
+        if (!context.getResources().getBoolean(
+                com.android.internal.R.bool.config_enableStylusPointerIcon)) {
+            // Stylus pointer icons are disabled for the build
+            return false;
+        }
+        if (forceReloadSetting) {
+            return Settings.Secure.getIntForUser(context.getContentResolver(),
+                    Settings.Secure.STYLUS_POINTER_ICON_ENABLED,
+                    DEFAULT_STYLUS_POINTER_ICON_ENABLED, UserHandle.USER_CURRENT_OR_SELF) != 0;
+        }
+        return AppGlobals.getIntCoreSetting(Settings.Secure.STYLUS_POINTER_ICON_ENABLED,
+                DEFAULT_STYLUS_POINTER_ICON_ENABLED) != 0;
+    }
+
+    /**
+     * Whether a pointer icon will be shown over the location of a stylus pointer.
+     *
+     * @hide
+     * @see #isStylusPointerIconEnabled(Context, boolean)
+     */
+    public static boolean isStylusPointerIconEnabled(@NonNull Context context) {
+        return isStylusPointerIconEnabled(context, false /* forceReloadSetting */);
     }
 
     /**
diff --git a/core/java/android/os/OWNERS b/core/java/android/os/OWNERS
index b1c24a7..90279c6 100644
--- a/core/java/android/os/OWNERS
+++ b/core/java/android/os/OWNERS
@@ -103,3 +103,6 @@
 
 # ProfilingService
 per-file ProfilingServiceManager.java = file:/PERFORMANCE_OWNERS
+
+# Memory
+per-file OomKillRecord.java = file:/MEMORY_OWNERS
\ No newline at end of file
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index b669814..8a17742 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -1259,6 +1259,24 @@
     }
 
     /**
+     * Reboot into recovery and wipe the data partition with ext4
+     *
+     * @throws IOException if something goes wrong.
+     *
+     * @hide
+     */
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.RECOVERY,
+            android.Manifest.permission.REBOOT
+    })
+    public void wipePartitionToExt4()
+            throws IOException {
+        // Reformat /data partition with ext4
+        String command = "--wipe_data\n--reformat_data=ext4";
+        rebootRecoveryWithCommand(command);
+    }
+
+    /**
      * Reboot into the recovery system with the supplied argument.
      * @param args to pass to the recovery utility.
      * @throws IOException if something goes wrong.
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index fbefbf3..52ff142 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -3732,6 +3732,11 @@
         return afm.shouldAlwaysIncludeWebviewInAssistStructure();
     }
 
+    private boolean shouldIncludeInvisibleView(AutofillManager afm) {
+        if (afm == null) return false;
+        return afm.shouldIncludeInvisibleViewInAssistStructure();
+    }
+
     /** @hide */
     private void populateChildrenForAutofill(ArrayList<View> list, @AutofillFlags int flags) {
         final int childrenCount = mChildrenCount;
@@ -3754,7 +3759,7 @@
                     || (shouldIncludeAllChildrenViewWithAutofillTypeNotNone(afm)
                         && child.getAutofillType() != AUTOFILL_TYPE_NONE)
                     || shouldIncludeAllChildrenViews(afm)
-                    || (Flags.includeInvisibleViewGroupInAssistStructure()
+                    || (shouldIncludeInvisibleView(afm)
                     && child instanceof ViewGroup && child.getVisibility() != View.VISIBLE)) {
                 // If the child is a ViewGroup object and its visibility is not visible, include
                 // it as part of the assist structure. The children of these invisible ViewGroup
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index ae4a7d3..9708591 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -48,6 +48,7 @@
 import android.content.res.Resources;
 import android.os.Binder;
 import android.os.Build;
+import android.os.Bundle;
 import android.os.Handler;
 import android.os.HandlerExecutor;
 import android.os.IBinder;
@@ -67,6 +68,8 @@
 import android.view.accessibility.AccessibilityEvent.EventType;
 
 import com.android.internal.R;
+import com.android.internal.accessibility.common.ShortcutConstants;
+import com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.IntPair;
 
@@ -78,6 +81,8 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.Executor;
 
 /**
@@ -189,11 +194,13 @@
      * <p>Note: Keep in sync with {@link #SHORTCUT_TYPES}.</p>
      * @hide
      */
+    // TODO(b/323686675): reuse the one defined in ShortcutConstants
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(value = {
             // LINT.IfChange(shortcut_type_intdef)
             ACCESSIBILITY_BUTTON,
-            ACCESSIBILITY_SHORTCUT_KEY
+            ACCESSIBILITY_SHORTCUT_KEY,
+            UserShortcutType.QUICK_SETTINGS,
             // LINT.ThenChange(:shortcut_type_array)
     })
     public @interface ShortcutType {}
@@ -207,6 +214,7 @@
             // LINT.IfChange(shortcut_type_array)
             ACCESSIBILITY_BUTTON,
             ACCESSIBILITY_SHORTCUT_KEY,
+            UserShortcutType.QUICK_SETTINGS,
             // LINT.ThenChange(:shortcut_type_intdef)
     };
 
@@ -1631,6 +1639,74 @@
     }
 
     /**
+     * Turns on or off a shortcut type of the accessibility features. The shortcut type is one
+     * of the shortcut defined in the {@link ShortcutConstants.USER_SHORTCUT_TYPES}.
+     *
+     * @throws SecurityException if the app does not hold the
+     *                           {@link Manifest.permission#MANAGE_ACCESSIBILITY} permission
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.MANAGE_ACCESSIBILITY)
+    public void enableShortcutsForTargets(boolean enable,
+            @UserShortcutType int shortcutTypes, @NonNull Set<String> targets,
+            @UserIdInt int userId) {
+        final IAccessibilityManager service;
+        synchronized (mLock) {
+            service = getServiceLocked();
+            if (service == null) {
+                return;
+            }
+        }
+        try {
+            service.enableShortcutsForTargets(
+                    enable, shortcutTypes, targets.stream().toList(), userId);
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Returns accessibility feature's component and the provided tile map. This includes the
+     * TileService provided by the AccessibilityService or Accessibility Activity and the tile
+     * component provided by the framework's feature.
+     *
+     * @return a map of a feature's component name, and its provided tile's component name. The
+     * returned map's keys and values are not null. If a feature doesn't provide a tile, it won't
+     * have an entry in this map.
+     * @hide
+     * @see ShortcutConstants.A11Y_FEATURE_TO_FRAMEWORK_TILE
+     */
+    @RequiresPermission(Manifest.permission.MANAGE_ACCESSIBILITY)
+    @NonNull
+    public Map<ComponentName, ComponentName> getA11yFeatureToTileMap(@UserIdInt int userId) {
+        final IAccessibilityManager service;
+        Map<ComponentName, ComponentName> a11yFeatureToTileMap = new ArrayMap<>();
+        synchronized (mLock) {
+            service = getServiceLocked();
+            if (service == null) {
+                return a11yFeatureToTileMap;
+            }
+        }
+        try {
+            Bundle a11yFeatureToTile = service.getA11yFeatureToTileMap(userId);
+            for (String key : a11yFeatureToTile.keySet()) {
+                ComponentName feature = ComponentName.unflattenFromString(key);
+                if (feature == null) {
+                    continue;
+                }
+                ComponentName tileService = a11yFeatureToTile.getParcelable(key,
+                        ComponentName.class);
+                if (tileService != null) {
+                    a11yFeatureToTileMap.put(feature, tileService);
+                }
+            }
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+        return a11yFeatureToTileMap;
+    }
+
+    /**
      * Register the provided {@link RemoteAction} with the given actionId
      * <p>
      * To perform established system actions, an accessibility service uses the GLOBAL_ACTION
diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl
index 9617606..e215950 100644
--- a/core/java/android/view/accessibility/IAccessibilityManager.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl
@@ -22,6 +22,7 @@
 import android.accessibilityservice.IAccessibilityServiceClient;
 import android.content.ComponentName;
 import android.content.pm.ParceledListSlice;
+import android.os.Bundle;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.accessibility.IAccessibilityInteractionConnection;
@@ -143,4 +144,10 @@
 
     @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.STATUS_BAR_SERVICE)")
     oneway void notifyQuickSettingsTilesChanged(int userId, in List<ComponentName> tileComponentNames);
+
+    @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MANAGE_ACCESSIBILITY)")
+    oneway void enableShortcutsForTargets(boolean enable, int shortcutTypes, in List<String> shortcutTargets, int userId);
+
+    @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MANAGE_ACCESSIBILITY)")
+    Bundle getA11yFeatureToTileMap(int userId);
 }
diff --git a/core/java/android/view/autofill/AutofillFeatureFlags.java b/core/java/android/view/autofill/AutofillFeatureFlags.java
index 334c2b77..1acfc1b 100644
--- a/core/java/android/view/autofill/AutofillFeatureFlags.java
+++ b/core/java/android/view/autofill/AutofillFeatureFlags.java
@@ -220,6 +220,19 @@
             DEVICE_CONFIG_ALWAYS_INCLUDE_WEBVIEW_IN_ASSIST_STRUCTURE =
             "always_include_webview_in_assist_structure";
 
+    /**
+     * Whether to include invisible views in the assist structure. Including invisible views can fix
+     * some cases in which Session is destroyed earlier than it is suppose to.
+     *
+     * <p>See
+     * frameworks/base/services/autofill/bugfixes.aconfig#include_invisible_view_group_in_assist_structure
+     * for more information.
+     *
+     * @hide
+     */
+    public static final String DEVICE_CONFIG_INCLUDE_INVISIBLE_VIEW_GROUP_IN_ASSIST_STRUCTURE =
+            "include_invisible_view_group_in_assist_structure";
+
     // END AUTOFILL FOR ALL APPS FLAGS //
 
 
@@ -473,6 +486,13 @@
                 DEVICE_CONFIG_ALWAYS_INCLUDE_WEBVIEW_IN_ASSIST_STRUCTURE, true);
     }
 
+    /** @hide */
+    public static boolean shouldIncludeInvisibleViewInAssistStructure() {
+        return DeviceConfig.getBoolean(
+                DeviceConfig.NAMESPACE_AUTOFILL,
+                DEVICE_CONFIG_INCLUDE_INVISIBLE_VIEW_GROUP_IN_ASSIST_STRUCTURE,
+                false);
+    }
 
     /**
      * Whether should enable multi-line filter
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 3ee8307..1484bfb 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -739,6 +739,9 @@
     // Indicate whether WebView should always be included in the assist structure
     private boolean mShouldAlwaysIncludeWebviewInAssistStructure;
 
+    // Indicate whether invisibles views should be included in the assist structure
+    private boolean mShouldIncludeInvisibleViewInAssistStructure;
+
     // Controls logic around apps changing some properties of their views when activity loses
     // focus due to autofill showing biometric activity, password manager, or password breach check.
     private boolean mRelayoutFix;
@@ -968,6 +971,9 @@
         mShouldAlwaysIncludeWebviewInAssistStructure =
                 AutofillFeatureFlags.shouldAlwaysIncludeWebviewInAssistStructure();
 
+        mShouldIncludeInvisibleViewInAssistStructure =
+                AutofillFeatureFlags.shouldIncludeInvisibleViewInAssistStructure();
+
         mRelayoutFix = Flags.relayout();
         mIsCredmanIntegrationEnabled = Flags.autofillCredmanIntegration();
     }
@@ -1055,6 +1061,13 @@
     }
 
     /**
+     * @hide
+     */
+    public boolean shouldIncludeInvisibleViewInAssistStructure() {
+        return mShouldIncludeInvisibleViewInAssistStructure;
+    }
+
+    /**
      * Get the denied or allowed activitiy names under specified package from the list string and
      * set it in fields accordingly
      *
diff --git a/core/java/com/android/internal/accessibility/common/ShortcutConstants.java b/core/java/com/android/internal/accessibility/common/ShortcutConstants.java
index 7ec8838..c08968d 100644
--- a/core/java/com/android/internal/accessibility/common/ShortcutConstants.java
+++ b/core/java/com/android/internal/accessibility/common/ShortcutConstants.java
@@ -16,10 +16,23 @@
 
 package com.android.internal.accessibility.common;
 
+import static com.android.internal.accessibility.AccessibilityShortcutController.COLOR_INVERSION_COMPONENT_NAME;
+import static com.android.internal.accessibility.AccessibilityShortcutController.COLOR_INVERSION_TILE_COMPONENT_NAME;
+import static com.android.internal.accessibility.AccessibilityShortcutController.DALTONIZER_COMPONENT_NAME;
+import static com.android.internal.accessibility.AccessibilityShortcutController.DALTONIZER_TILE_COMPONENT_NAME;
+import static com.android.internal.accessibility.AccessibilityShortcutController.FONT_SIZE_COMPONENT_NAME;
+import static com.android.internal.accessibility.AccessibilityShortcutController.FONT_SIZE_TILE_COMPONENT_NAME;
+import static com.android.internal.accessibility.AccessibilityShortcutController.ONE_HANDED_COMPONENT_NAME;
+import static com.android.internal.accessibility.AccessibilityShortcutController.ONE_HANDED_TILE_COMPONENT_NAME;
+import static com.android.internal.accessibility.AccessibilityShortcutController.REDUCE_BRIGHT_COLORS_COMPONENT_NAME;
+import static com.android.internal.accessibility.AccessibilityShortcutController.REDUCE_BRIGHT_COLORS_TILE_SERVICE_COMPONENT_NAME;
+
 import android.annotation.IntDef;
+import android.content.ComponentName;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.Map;
 
 /**
  * Collection of common constants for accessibility shortcut.
@@ -44,6 +57,10 @@
      * choose accessibility shortcut as preferred shortcut.
      * {@code TRIPLETAP} for displaying specifying magnification to be toggled via quickly
      * tapping screen 3 times as preferred shortcut.
+     * {@code TWOFINGER_DOUBLETAP} for displaying specifying magnification to be toggled via
+     * quickly tapping screen 2 times with two fingers as preferred shortcut.
+     * {@code QUICK_SETTINGS} for displaying specifying the accessibility services or features which
+     * choose Quick Settings as preferred shortcut.
      */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({
@@ -51,12 +68,18 @@
             UserShortcutType.SOFTWARE,
             UserShortcutType.HARDWARE,
             UserShortcutType.TRIPLETAP,
+            UserShortcutType.TWOFINGER_DOUBLETAP,
+            UserShortcutType.QUICK_SETTINGS,
     })
     public @interface UserShortcutType {
         int DEFAULT = 0;
-        int SOFTWARE = 1; // 1 << 0
-        int HARDWARE = 2; // 1 << 1
-        int TRIPLETAP = 4; // 1 << 2
+        // LINT.IfChange(shortcut_type_intdef)
+        int SOFTWARE = 1 << 0;
+        int HARDWARE = 1 << 1;
+        int TRIPLETAP = 1 << 2;
+        int TWOFINGER_DOUBLETAP = 1 << 3;
+        int QUICK_SETTINGS = 1 << 4;
+        // LINT.ThenChange(:shortcut_type_array)
     }
 
     /**
@@ -64,9 +87,13 @@
      * non-default IntDef types.
      */
     public static final int[] USER_SHORTCUT_TYPES = {
+            // LINT.IfChange(shortcut_type_array)
             UserShortcutType.SOFTWARE,
             UserShortcutType.HARDWARE,
-            UserShortcutType.TRIPLETAP
+            UserShortcutType.TRIPLETAP,
+            UserShortcutType.TWOFINGER_DOUBLETAP,
+            UserShortcutType.QUICK_SETTINGS,
+            // LINT.ThenChange(:shortcut_type_intdef)
     };
 
 
@@ -109,4 +136,30 @@
         int LAUNCH = 0;
         int EDIT = 1;
     }
+
+    /**
+     * Annotation for different FAB shortcut type's menu size
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({
+            FloatingMenuSize.UNKNOWN,
+            FloatingMenuSize.SMALL,
+            FloatingMenuSize.LARGE,
+    })
+    public @interface FloatingMenuSize {
+        int UNKNOWN = -1;
+        int SMALL = 0;
+        int LARGE = 1;
+    }
+
+    /**
+     * A map of a11y feature to its qs tile component
+     */
+    public static final Map<ComponentName, ComponentName> A11Y_FEATURE_TO_FRAMEWORK_TILE = Map.of(
+            COLOR_INVERSION_COMPONENT_NAME, COLOR_INVERSION_TILE_COMPONENT_NAME,
+            DALTONIZER_COMPONENT_NAME, DALTONIZER_TILE_COMPONENT_NAME,
+            ONE_HANDED_COMPONENT_NAME, ONE_HANDED_TILE_COMPONENT_NAME,
+            REDUCE_BRIGHT_COLORS_COMPONENT_NAME, REDUCE_BRIGHT_COLORS_TILE_SERVICE_COMPONENT_NAME,
+            FONT_SIZE_COMPONENT_NAME, FONT_SIZE_TILE_COMPONENT_NAME
+    );
 }
diff --git a/core/java/com/android/internal/accessibility/util/AccessibilityUtils.java b/core/java/com/android/internal/accessibility/util/AccessibilityUtils.java
index 4f9fc39..e8472d4 100644
--- a/core/java/com/android/internal/accessibility/util/AccessibilityUtils.java
+++ b/core/java/com/android/internal/accessibility/util/AccessibilityUtils.java
@@ -70,6 +70,13 @@
     public @interface A11yTextChangeType {
     }
 
+    /** Denotes the accessibility enabled status */
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface State {
+        int OFF = 0;
+        int ON = 1;
+    }
+
     /** Specifies no content has been changed for accessibility. */
     public static final int NONE = 0;
     /** Specifies some readable sequence has been changed. */
diff --git a/core/java/com/android/internal/accessibility/util/ShortcutUtils.java b/core/java/com/android/internal/accessibility/util/ShortcutUtils.java
index 3fd3030..f9c4d37 100644
--- a/core/java/com/android/internal/accessibility/util/ShortcutUtils.java
+++ b/core/java/com/android/internal/accessibility/util/ShortcutUtils.java
@@ -53,10 +53,13 @@
      * Opts in component id into colon-separated {@link UserShortcutType}
      * key's string from Settings.
      *
-     * @param context The current context.
+     * @param context      The current context.
      * @param shortcutType The preferred shortcut type user selected.
-     * @param componentId The component id that need to be opted in Settings.
+     * @param componentId  The component id that need to be opted in Settings.
+     * @deprecated Use
+     * {@link AccessibilityManager#enableShortcutsForTargets(boolean, int, Set, int)}
      */
+    @Deprecated
     public static void optInValueToSettings(Context context, @UserShortcutType int shortcutType,
             @NonNull String componentId) {
         final StringJoiner joiner = new StringJoiner(String.valueOf(SERVICES_SEPARATOR));
@@ -83,7 +86,11 @@
      * @param context The current context.
      * @param shortcutType The preferred shortcut type user selected.
      * @param componentId The component id that need to be opted out of Settings.
+     *
+     * @deprecated Use
+     * {@link AccessibilityManager#enableShortcutForTargets(boolean, int, Set, int)}
      */
+    @Deprecated
     public static void optOutValueFromSettings(
             Context context, @UserShortcutType int shortcutType, @NonNull String componentId) {
         final StringJoiner joiner = new StringJoiner(String.valueOf(SERVICES_SEPARATOR));
@@ -166,6 +173,10 @@
                 return Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE;
             case UserShortcutType.TRIPLETAP:
                 return Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED;
+            case UserShortcutType.TWOFINGER_DOUBLETAP:
+                return Settings.Secure.ACCESSIBILITY_MAGNIFICATION_TWO_FINGER_TRIPLE_TAP_ENABLED;
+            case UserShortcutType.QUICK_SETTINGS:
+                return Settings.Secure.ACCESSIBILITY_QS_TARGETS;
             default:
                 throw new IllegalArgumentException(
                         "Unsupported user shortcut type: " + type);
@@ -252,10 +263,13 @@
      * If you just want to know the current state, you can use
      * {@link AccessibilityManager#getAccessibilityShortcutTargets(int)}
      */
+    @NonNull
     public static Set<String> getShortcutTargetsFromSettings(
             Context context, @UserShortcutType int shortcutType, int userId) {
         final String targetKey = convertToKey(shortcutType);
-        if (Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED.equals(targetKey)) {
+        if (Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED.equals(targetKey)
+                || Settings.Secure.ACCESSIBILITY_MAGNIFICATION_TWO_FINGER_TRIPLE_TAP_ENABLED
+                .equals(targetKey)) {
             boolean magnificationEnabled = Settings.Secure.getIntForUser(
                     context.getContentResolver(), targetKey, /* def= */ 0, userId) == 1;
             return magnificationEnabled ? Set.of(MAGNIFICATION_CONTROLLER_NAME)
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityManagerTest.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityManagerTest.java
index e2f2554..1013bf5 100644
--- a/core/tests/coretests/src/android/view/accessibility/AccessibilityManagerTest.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityManagerTest.java
@@ -16,13 +16,24 @@
 
 package android.view.accessibility;
 
+import static com.android.internal.accessibility.AccessibilityShortcutController.COLOR_INVERSION_COMPONENT_NAME;
+import static com.android.internal.accessibility.AccessibilityShortcutController.COLOR_INVERSION_TILE_COMPONENT_NAME;
+import static com.android.internal.accessibility.AccessibilityShortcutController.DALTONIZER_COMPONENT_NAME;
+import static com.android.internal.accessibility.AccessibilityShortcutController.DALTONIZER_TILE_COMPONENT_NAME;
+
+import static com.google.common.truth.Truth.assertThat;
+
 import static junit.framework.TestCase.assertFalse;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyList;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyInt;
+import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -34,6 +45,8 @@
 import android.content.Intent;
 import android.content.pm.ParceledListSlice;
 import android.graphics.drawable.Icon;
+import android.os.Bundle;
+import android.os.RemoteException;
 import android.os.UserHandle;
 
 import androidx.annotation.NonNull;
@@ -41,6 +54,7 @@
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.internal.R;
+import com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType;
 import com.android.internal.util.IntPair;
 import com.android.server.accessibility.test.MessageCapturingHandler;
 
@@ -54,6 +68,8 @@
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.Executors;
 
 /**
@@ -263,6 +279,75 @@
         verify(mMockService).unregisterProxyForDisplay(proxy.getDisplayId());
     }
 
+    @Test
+    public void getA11yFeatureToTileMap_catchRemoteExceptionAndRethrow() throws Exception {
+        AccessibilityManager manager = createManager(WITH_A11Y_ENABLED);
+        doThrow(new RemoteException(new SecurityException()))
+                .when(mMockService)
+                .getA11yFeatureToTileMap(anyInt());
+
+        Throwable rethrownException = assertThrows(RuntimeException.class,
+                () -> manager.getA11yFeatureToTileMap(UserHandle.USER_CURRENT));
+        assertThat(rethrownException.getCause().getCause()).isInstanceOf(SecurityException.class);
+    }
+
+    @Test
+    public void getA11yFeatureToTileMap_verifyServiceMethodCalled() throws Exception {
+        AccessibilityManager manager = createManager(WITH_A11Y_ENABLED);
+        Bundle bundle = new Bundle();
+        bundle.putParcelable(
+                COLOR_INVERSION_COMPONENT_NAME.flattenToString(),
+                COLOR_INVERSION_TILE_COMPONENT_NAME);
+        bundle.putParcelable(
+                DALTONIZER_COMPONENT_NAME.flattenToString(),
+                DALTONIZER_TILE_COMPONENT_NAME);
+        when(mMockService.getA11yFeatureToTileMap(UserHandle.USER_CURRENT)).thenReturn(bundle);
+
+        assertThat(manager.getA11yFeatureToTileMap(UserHandle.USER_CURRENT))
+                .containsExactlyEntriesIn(Map.of(
+                        COLOR_INVERSION_COMPONENT_NAME, COLOR_INVERSION_TILE_COMPONENT_NAME,
+                        DALTONIZER_COMPONENT_NAME, DALTONIZER_TILE_COMPONENT_NAME
+                ));
+        verify(mMockService).getA11yFeatureToTileMap(UserHandle.USER_CURRENT);
+    }
+
+    @Test
+    public void enableShortcutsForTargets_catchRemoteExceptionAndRethrow() throws Exception {
+        AccessibilityManager manager = createManager(WITH_A11Y_ENABLED);
+        doThrow(new RemoteException(new SecurityException()))
+                .when(mMockService)
+                .enableShortcutsForTargets(anyBoolean(), anyInt(), anyList(), anyInt());
+
+        Throwable rethrownException = assertThrows(RuntimeException.class,
+                () -> manager.enableShortcutsForTargets(
+                        /* enable= */ false,
+                        UserShortcutType.HARDWARE,
+                        Set.of(DALTONIZER_COMPONENT_NAME.flattenToString()),
+                        UserHandle.USER_CURRENT
+                ));
+        assertThat(rethrownException.getCause().getCause()).isInstanceOf(SecurityException.class);
+    }
+
+    @Test
+    public void enableShortcutsForTargets_verifyServiceMethodCalled() throws Exception {
+        AccessibilityManager manager = createManager(WITH_A11Y_ENABLED);
+        int shortcutTypes = UserShortcutType.HARDWARE | UserShortcutType.TRIPLETAP;
+
+        manager.enableShortcutsForTargets(
+                /* enable= */ false,
+                shortcutTypes,
+                Set.of(DALTONIZER_COMPONENT_NAME.flattenToString()),
+                UserHandle.USER_CURRENT
+        );
+
+        verify(mMockService).enableShortcutsForTargets(
+                /* enable= */ false,
+                shortcutTypes,
+                List.of(DALTONIZER_COMPONENT_NAME.flattenToString()),
+                UserHandle.USER_CURRENT
+        );
+    }
+
     private class MyAccessibilityProxy extends AccessibilityDisplayProxy {
         MyAccessibilityProxy(int displayId,
                 @NonNull List<AccessibilityServiceInfo> serviceInfos) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
index 39803e2..c9669a7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
@@ -318,11 +318,12 @@
         relayoutParams.mCaptionHeightId = getCaptionHeightIdStatic(taskInfo.getWindowingMode());
         relayoutParams.mCaptionWidthId = getCaptionWidthId(relayoutParams.mLayoutResId);
 
-        if (captionLayoutId == R.layout.desktop_mode_app_controls_window_decor
-                && TaskInfoKt.isTransparentCaptionBarAppearance(taskInfo)) {
-            // App is requesting to customize the caption bar. Allow input to fall through to the
-            // windows below so that the app can respond to input events on their custom content.
-            relayoutParams.mAllowCaptionInputFallthrough = true;
+        if (captionLayoutId == R.layout.desktop_mode_app_controls_window_decor) {
+            // If the app is requesting to customize the caption bar, allow input to fall through
+            // to the windows below so that the app can respond to input events on their custom
+            // content.
+            relayoutParams.mAllowCaptionInputFallthrough =
+                    TaskInfoKt.isTransparentCaptionBarAppearance(taskInfo);
             // Report occluding elements as bounding rects to the insets system so that apps can
             // draw in the empty space in the center:
             //   First, the "app chip" section of the caption bar (+ some extra margins).
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java
index ba3f6dd..f9b5882 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java
@@ -173,7 +173,7 @@
     }
 
     @Test
-    public void updateRelayoutParams_freeformAndTransparent_allowsInputFallthrough() {
+    public void updateRelayoutParams_freeformAndTransparentAppearance_allowsInputFallthrough() {
         final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
         taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM);
         taskInfo.taskDescription.setSystemBarsAppearance(
@@ -191,7 +191,7 @@
     }
 
     @Test
-    public void updateRelayoutParams_freeformButOpaque_disallowsInputFallthrough() {
+    public void updateRelayoutParams_freeformButOpaqueAppearance_disallowsInputFallthrough() {
         final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
         taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM);
         taskInfo.taskDescription.setSystemBarsAppearance(0);
diff --git a/packages/CredentialManager/res/drawable/fill_dialog_dynamic_list_item_one_dark.xml b/packages/CredentialManager/res/drawable/fill_dialog_dynamic_list_item_middle.xml
similarity index 60%
rename from packages/CredentialManager/res/drawable/fill_dialog_dynamic_list_item_one_dark.xml
rename to packages/CredentialManager/res/drawable/fill_dialog_dynamic_list_item_middle.xml
index 39f49ca..781373d 100644
--- a/packages/CredentialManager/res/drawable/fill_dialog_dynamic_list_item_one_dark.xml
+++ b/packages/CredentialManager/res/drawable/fill_dialog_dynamic_list_item_middle.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-  ~ Copyright (C) 2023 The Android Open Source Project
+  ~ 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.
@@ -15,16 +15,10 @@
   ~ limitations under the License.
   -->
 
-<ripple xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:tools="http://schemas.android.com/tools" tools:ignore="NewApi"
-        android:color="@android:color/transparent">
-    <item
-        android:bottom="1dp"
-        android:shape="rectangle"
-        android:top="1dp">
-        <shape>
-            <corners android:radius="28dp" />
-            <solid android:color="@android:color/system_surface_container_high_dark" />
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+        xmlns:tools="http://schemas.android.com/tools" tools:ignore="NewApi">
+        <shape android:shape="rectangle">
+            <solid android:color="?androidprv:attr/materialColorSurfaceContainer" />
         </shape>
-    </item>
-</ripple>
\ No newline at end of file
+</inset>
\ No newline at end of file
diff --git a/packages/CredentialManager/res/drawable/fill_dialog_dynamic_list_item_one.xml b/packages/CredentialManager/res/drawable/fill_dialog_dynamic_list_item_one.xml
index f13402c..f28c354 100644
--- a/packages/CredentialManager/res/drawable/fill_dialog_dynamic_list_item_one.xml
+++ b/packages/CredentialManager/res/drawable/fill_dialog_dynamic_list_item_one.xml
@@ -15,16 +15,12 @@
   ~ limitations under the License.
   -->
 
-<ripple xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:tools="http://schemas.android.com/tools" tools:ignore="NewApi"
-        android:color="@android:color/transparent">
-    <item
-        android:bottom="1dp"
-        android:shape="rectangle"
-        android:top="1dp">
-        <shape>
-            <corners android:radius="4dp" />
-            <solid android:color="@color/dropdown_container" />
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+        xmlns:tools="http://schemas.android.com/tools" tools:ignore="NewApi">
+        <shape android:shape="rectangle">
+            <corners android:topLeftRadius="4dp" android:topRightRadius="4dp"
+            android:bottomLeftRadius="0dp" android:bottomRightRadius="0dp"/>
+            <solid android:color="?androidprv:attr/materialColorSurfaceContainer" />
         </shape>
-    </item>
-</ripple>
\ No newline at end of file
+</inset>
\ No newline at end of file
diff --git a/packages/CredentialManager/res/drawable/more_options_list_item.xml b/packages/CredentialManager/res/drawable/more_options_list_item.xml
index d7b509e..3f9d815 100644
--- a/packages/CredentialManager/res/drawable/more_options_list_item.xml
+++ b/packages/CredentialManager/res/drawable/more_options_list_item.xml
@@ -15,17 +15,16 @@
   ~ limitations under the License.
   -->
 
-<ripple xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:tools="http://schemas.android.com/tools" tools:ignore="NewApi"
-        android:color="@android:color/transparent">
-    <item
-        android:bottom="1dp"
-        android:shape="rectangle"
-        android:top="1dp">
-        <shape>
-            <corners android:bottomLeftRadius="4dp"
-                     android:bottomRightRadius="4dp"/>
-            <solid android:color="@color/sign_in_options_container" />
-        </shape>
-    </item>
-</ripple>
\ No newline at end of file
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+    xmlns:tools="http://schemas.android.com/tools" tools:ignore="NewApi"
+    android:insetLeft="-2dp"
+    android:insetRight="-2dp"
+    android:insetBottom="-2dp">
+    <shape>
+        <corners android:topLeftRadius="0dp" android:topRightRadius="0dp"
+            android:bottomLeftRadius="4dp" android:bottomRightRadius="4dp"/>
+        <solid android:color="?androidprv:attr/materialColorSurfaceContainer"/>
+        <stroke android:color="?androidprv:attr/materialColorOutlineVariant" android:width="1dp"/>
+    </shape>
+</inset>
\ No newline at end of file
diff --git a/packages/CredentialManager/res/layout/credman_dropdown_bottom_sheet.xml b/packages/CredentialManager/res/layout/credman_dropdown_bottom_sheet.xml
index 910ff96..7f09dd5 100644
--- a/packages/CredentialManager/res/layout/credman_dropdown_bottom_sheet.xml
+++ b/packages/CredentialManager/res/layout/credman_dropdown_bottom_sheet.xml
@@ -14,30 +14,52 @@
   ~ limitations under the License.
   -->
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
                 android:id="@android:id/content"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:minHeight="@dimen/dropdown_touch_target_min_height"
                 android:orientation="horizontal"
-                android:layout_marginEnd="@dimen/dropdown_layout_horizontal_margin"
                 android:elevation="3dp">
 
-    <ImageView
-        android:id="@android:id/icon1"
+    <LinearLayout
+        android:id="@+id/credential_card"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_centerVertical="true"
-        android:layout_alignParentStart="true"
-        android:contentDescription="@string/more_options_content_description"
-        android:background="@null"/>
-    <TextView
-        android:id="@android:id/text1"
-        android:layout_width="wrap_content"
+        android:orientation="horizontal">
+
+        <ImageView
+            android:id="@android:id/icon1"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center"
+            android:paddingLeft="@dimen/autofill_view_left_padding"
+            android:src="@drawable/more_horiz_24px"
+            android:tint="?androidprv:attr/materialColorOnSurface"
+            android:layout_alignParentStart="true"
+            android:contentDescription="@string/more_options_content_description"
+            android:background="@null"/>
+
+    <LinearLayout
+        android:id="@+id/text_container"
+        android:layout_width="@dimen/autofill_dropdown_textview_max_width"
         android:layout_height="wrap_content"
-        android:layout_alignParentTop="true"
-        android:layout_toEndOf="@android:id/icon1"
-        android:minWidth="@dimen/autofill_dropdown_textview_min_width"
-        android:maxWidth="@dimen/autofill_dropdown_textview_max_width"
-        style="@style/autofill.TextTitle"/>
+        android:paddingLeft="@dimen/autofill_view_left_padding"
+        android:paddingRight="@dimen/autofill_view_right_padding"
+        android:paddingTop="@dimen/more_options_item_vertical_padding"
+        android:paddingBottom="@dimen/more_options_item_vertical_padding"
+        android:orientation="vertical">
+
+        <TextView
+            android:id="@android:id/text1"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignParentTop="true"
+            android:textColor="?androidprv:attr/materialColorOnSurface"
+            android:layout_toEndOf="@android:id/icon1"
+            style="@style/autofill.TextTitle"/>
+    </LinearLayout>
+
+    </LinearLayout>
 
 </RelativeLayout>
diff --git a/packages/CredentialManager/res/layout/credman_dropdown_presentation_layout.xml b/packages/CredentialManager/res/layout/credman_dropdown_presentation_layout.xml
index 4bf0e99..08948d7 100644
--- a/packages/CredentialManager/res/layout/credman_dropdown_presentation_layout.xml
+++ b/packages/CredentialManager/res/layout/credman_dropdown_presentation_layout.xml
@@ -14,37 +14,60 @@
   ~ limitations under the License.
   -->
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
                 android:id="@android:id/content"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:minHeight="@dimen/dropdown_touch_target_min_height"
-                android:layout_marginEnd="@dimen/dropdown_layout_horizontal_margin"
                 android:elevation="3dp">
 
-        <ImageView
-            android:id="@android:id/icon1"
+        <LinearLayout
+            android:id="@+id/credential_card"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:layout_centerVertical="true"
-            android:layout_alignParentStart="true"
-            android:background="@null"/>
-        <TextView
-            android:id="@android:id/text1"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_alignParentTop="true"
-            android:layout_toEndOf="@android:id/icon1"
-            android:minWidth="@dimen/autofill_dropdown_textview_min_width"
-            android:maxWidth="@dimen/autofill_dropdown_textview_max_width"
-            style="@style/autofill.TextTitle"/>
-        <TextView
-            android:id="@android:id/text2"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_below="@android:id/text1"
-            android:layout_toEndOf="@android:id/icon1"
-            android:minWidth="@dimen/autofill_dropdown_textview_min_width"
-            android:maxWidth="@dimen/autofill_dropdown_textview_max_width"
-            style="@style/autofill.TextSubtitle"/>
+            android:orientation="horizontal">
+
+                <ImageView
+                    android:id="@android:id/icon1"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_gravity="center"
+                    android:layout_alignParentStart="true"
+                    android:paddingLeft="@dimen/autofill_view_left_padding"
+                    app:tint="?androidprv:attr/materialColorOnSurface"
+                    android:background="@null"/>
+
+                <LinearLayout
+                    android:id="@+id/text_container"
+                    android:layout_width="@dimen/autofill_dropdown_textview_max_width"
+                    android:layout_height="wrap_content"
+                    android:paddingLeft="@dimen/autofill_view_left_padding"
+                    android:paddingRight="@dimen/autofill_view_right_padding"
+                    android:paddingTop="@dimen/autofill_view_top_padding"
+                    android:paddingBottom="@dimen/autofill_view_bottom_padding"
+                    android:orientation="vertical">
+
+                        <TextView
+                            android:id="@android:id/text1"
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:layout_alignParentTop="true"
+                            android:layout_toEndOf="@android:id/icon1"
+                            android:textColor="?androidprv:attr/materialColorOnSurface"
+                            style="@style/autofill.TextTitle"/>
+
+                        <TextView
+                            android:id="@android:id/text2"
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:layout_below="@android:id/text1"
+                            android:layout_toEndOf="@android:id/icon1"
+                            android:textColor="?androidprv:attr/materialColorOnSurfaceVariant"
+                            style="@style/autofill.TextSubtitle"/>
+
+                </LinearLayout>
+
+        </LinearLayout>
 
 </RelativeLayout>
diff --git a/packages/CredentialManager/res/values/colors.xml b/packages/CredentialManager/res/values/colors.xml
index b4d2eeb..9d31b35 100644
--- a/packages/CredentialManager/res/values/colors.xml
+++ b/packages/CredentialManager/res/values/colors.xml
@@ -15,14 +15,12 @@
   -->
 
 <!-- Color palette -->
-<resources>
-    <!-- These colors are used for Remote Views. -->
-    <color name="text_primary">#1A1B20</color>
-    <color name="text_secondary">#44474F</color>
-    <color name="dropdown_container">#F3F3FA</color>
-    <color name="sign_in_options_container">#DADADA</color>
-    <color name="sign_in_options_icon_color">#1B1B1B</color>
+<resources
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
 
-    <!-- These colors are used for Inline Suggestions. -->
-    <color name="inline_background">#FFFFFF</color>
+    <!-- These colors are used for Remote Views. -->
+    <color name="onSurface">?androidprv:attr/materialColorOnSurface</color>
+    <color name="onSurfaceVariant">?androidprv:attr/materialColorOnSurfaceVariant</color>
+    <color name="surfaceDim">?androidprv:attr/materialColorSurfaceDim</color>
+    <color name="surfaceContainer">?androidprv:attr/materialColorSurfaceContainer</color>
 </resources>
\ No newline at end of file
diff --git a/packages/CredentialManager/res/values/dimens.xml b/packages/CredentialManager/res/values/dimens.xml
index 82dee5c..314437e 100644
--- a/packages/CredentialManager/res/values/dimens.xml
+++ b/packages/CredentialManager/res/values/dimens.xml
@@ -18,16 +18,18 @@
 
 <resources>
     <dimen name="autofill_view_top_padding">12dp</dimen>
-    <dimen name="autofill_view_right_padding">12dp</dimen>
+    <dimen name="autofill_view_right_padding">16dp</dimen>
     <dimen name="autofill_view_bottom_padding">12dp</dimen>
     <dimen name="autofill_view_left_padding">16dp</dimen>
-    <dimen name="autofill_view_icon_to_text_padding">10dp</dimen>
+    <dimen name="autofill_view_icon_to_text_padding">16dp</dimen>
+    <dimen name="autofill_view_end_items_padding">8dp</dimen>
+    <dimen name="more_options_item_vertical_padding">14dp</dimen>
     <dimen name="autofill_icon_size">24dp</dimen>
     <dimen name="autofill_dropdown_textview_min_width">112dp</dimen>
     <dimen name="autofill_dropdown_textview_max_width">230dp</dimen>
     <dimen name="dropdown_layout_horizontal_margin">24dp</dimen>
     <integer name="autofill_max_visible_datasets">4</integer>
-    <dimen name="dropdown_touch_target_min_height">48dp</dimen>
+    <dimen name="dropdown_touch_target_min_height">49dp</dimen>
     <dimen name="horizontal_chip_padding">8dp</dimen>
     <dimen name="vertical_chip_padding">6dp</dimen>
 </resources>
\ No newline at end of file
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt b/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt
index 271cccb..4f2fa79 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt
@@ -295,8 +295,9 @@
             }
             var dropdownPresentation: RemoteViews? = null
             if (i < maxDatasetDisplayLimit) {
-                dropdownPresentation = RemoteViewsFactory
-                        .createDropdownPresentation(this, icon, primaryEntry)
+                dropdownPresentation = RemoteViewsFactory.createDropdownPresentation(
+                    this, icon, primaryEntry, /*isFirstEntry= */ i == 0,
+                    /*isLastEntry= */ (totalEntryCount - i == 1))
             }
 
             val dataSetBuilder = Dataset.Builder()
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/RemoteViewsFactory.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/RemoteViewsFactory.kt
index 7966a86..a46e358 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/RemoteViewsFactory.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/RemoteViewsFactory.kt
@@ -31,12 +31,13 @@
         private const val setMaxHeightMethodName = "setMaxHeight"
         private const val setBackgroundResourceMethodName = "setBackgroundResource"
         private const val bulletPoint = "\u2022"
-        private const val passwordCharacterLength = 15
 
         fun createDropdownPresentation(
             context: Context,
             icon: Icon,
-            credentialEntryInfo: CredentialEntryInfo
+            credentialEntryInfo: CredentialEntryInfo,
+            isFirstEntry: Boolean,
+            isLastEntry: Boolean,
         ): RemoteViews {
             var layoutId: Int = com.android.credentialmanager.R.layout
                     .credman_dropdown_presentation_layout
@@ -44,7 +45,6 @@
             if (credentialEntryInfo.credentialType == CredentialType.UNKNOWN) {
                 return remoteViews
             }
-            setRemoteViewsPaddings(remoteViews, context, /* primaryTextBottomPadding=*/0)
             val displayName = credentialEntryInfo.displayName ?: credentialEntryInfo.userName
             remoteViews.setTextViewText(android.R.id.text1, displayName)
             val secondaryText =
@@ -56,12 +56,6 @@
                 else (credentialEntryInfo.credentialTypeDisplayName + " " + bulletPoint + " "
                         + credentialEntryInfo.providerDisplayName)
             remoteViews.setTextViewText(android.R.id.text2, secondaryText)
-            val textColorPrimary = ContextCompat.getColor(context,
-                com.android.credentialmanager.R.color.text_primary)
-            remoteViews.setTextColor(android.R.id.text1, textColorPrimary)
-            val textColorSecondary = ContextCompat.getColor(context, com.android
-                    .credentialmanager.R.color.text_secondary)
-            remoteViews.setTextColor(android.R.id.text2, textColorSecondary)
             remoteViews.setImageViewIcon(android.R.id.icon1, icon);
             remoteViews.setBoolean(
                 android.R.id.icon1, setAdjustViewBoundsMethodName, true);
@@ -73,9 +67,23 @@
             remoteViews.setContentDescription(android.R.id.icon1, credentialEntryInfo
                     .providerDisplayName);
             val drawableId =
-                com.android.credentialmanager.R.drawable.fill_dialog_dynamic_list_item_one
+                if (isFirstEntry)
+                    com.android.credentialmanager.R.drawable.fill_dialog_dynamic_list_item_one else
+                    com.android.credentialmanager.R.drawable.fill_dialog_dynamic_list_item_middle
             remoteViews.setInt(
                 android.R.id.content, setBackgroundResourceMethodName, drawableId);
+            if (isFirstEntry) remoteViews.setViewPadding(
+                com.android.credentialmanager.R.id.credential_card,
+                /* left=*/0,
+                /* top=*/8,
+                /* right=*/0,
+                /* bottom=*/0)
+            if (isLastEntry) remoteViews.setViewPadding(
+                com.android.credentialmanager.R.id.credential_card,
+                /*left=*/0,
+                /* top=*/0,
+                /* right=*/0,
+                /* bottom=*/8)
             return remoteViews
         }
 
@@ -83,19 +91,9 @@
             var layoutId: Int = com.android.credentialmanager.R.layout
                     .credman_dropdown_bottom_sheet
             val remoteViews = RemoteViews(context.packageName, layoutId)
-            setRemoteViewsPaddings(remoteViews, context)
             remoteViews.setTextViewText(android.R.id.text1, ContextCompat.getString(context,
                 com.android.credentialmanager
                         .R.string.dropdown_presentation_more_sign_in_options_text))
-
-            val textColorPrimary = ContextCompat.getColor(context,
-                com.android.credentialmanager.R.color.text_primary)
-            remoteViews.setTextColor(android.R.id.text1, textColorPrimary)
-            val icon = Icon.createWithResource(context, com
-                    .android.credentialmanager.R.drawable.more_horiz_24px)
-            icon.setTint(ContextCompat.getColor(context,
-                com.android.credentialmanager.R.color.sign_in_options_icon_color))
-            remoteViews.setImageViewIcon(android.R.id.icon1, icon)
             remoteViews.setBoolean(
                 android.R.id.icon1, setAdjustViewBoundsMethodName, true);
             remoteViews.setInt(
@@ -109,50 +107,5 @@
                 android.R.id.content, setBackgroundResourceMethodName, drawableId);
             return remoteViews
         }
-
-        private fun setRemoteViewsPaddings(
-            remoteViews: RemoteViews, context: Context) {
-            val bottomPadding = context.resources.getDimensionPixelSize(
-                com.android.credentialmanager.R.dimen.autofill_view_bottom_padding)
-            setRemoteViewsPaddings(remoteViews, context, bottomPadding)
-        }
-
-        private fun setRemoteViewsPaddings(
-            remoteViews: RemoteViews, context: Context, primaryTextBottomPadding: Int) {
-            val leftPadding = context.resources.getDimensionPixelSize(
-                com.android.credentialmanager.R.dimen.autofill_view_left_padding)
-            val iconToTextPadding = context.resources.getDimensionPixelSize(
-                com.android.credentialmanager.R.dimen.autofill_view_icon_to_text_padding)
-            val rightPadding = context.resources.getDimensionPixelSize(
-                com.android.credentialmanager.R.dimen.autofill_view_right_padding)
-            val topPadding = context.resources.getDimensionPixelSize(
-                com.android.credentialmanager.R.dimen.autofill_view_top_padding)
-            val bottomPadding = context.resources.getDimensionPixelSize(
-                com.android.credentialmanager.R.dimen.autofill_view_bottom_padding)
-            remoteViews.setViewPadding(
-                android.R.id.icon1,
-                leftPadding,
-                /* top=*/0,
-                /* right=*/0,
-                /* bottom=*/0)
-            remoteViews.setViewPadding(
-                android.R.id.text1,
-                iconToTextPadding,
-                /* top=*/topPadding,
-                /* right=*/rightPadding,
-                primaryTextBottomPadding)
-            remoteViews.setViewPadding(
-                android.R.id.text2,
-                iconToTextPadding,
-                /* top=*/0,
-                /* right=*/rightPadding,
-                /* bottom=*/bottomPadding)
-        }
-
-        private fun isDarkMode(context: Context): Boolean {
-            val currentNightMode = context.resources.configuration.uiMode and
-                    Configuration.UI_MODE_NIGHT_MASK
-            return currentNightMode == Configuration.UI_MODE_NIGHT_YES
-        }
     }
 }
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index a490b6f..30d5d4b 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -268,6 +268,7 @@
         Settings.Secure.EVEN_DIMMER_MIN_NITS,
         Settings.Secure.STYLUS_POINTER_ICON_ENABLED,
         Settings.Secure.CAMERA_EXTENSIONS_FALLBACK,
-        Settings.Secure.VISUAL_QUERY_ACCESSIBILITY_DETECTION_ENABLED
+        Settings.Secure.VISUAL_QUERY_ACCESSIBILITY_DETECTION_ENABLED,
+        Settings.Secure.IMMERSIVE_MODE_CONFIRMATIONS
     };
 }
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index 4cdf98cb..893932f 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -423,5 +423,6 @@
         VALIDATORS.put(Secure.AUTOFILL_SERVICE, AUTOFILL_SERVICE_VALIDATOR);
         VALIDATORS.put(Secure.STYLUS_POINTER_ICON_ENABLED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.CAMERA_EXTENSIONS_FALLBACK, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.IMMERSIVE_MODE_CONFIRMATIONS, ANY_STRING_VALIDATOR);
     }
 }
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 09d076e..46c89900 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -702,7 +702,6 @@
                  Settings.Secure.ENABLED_PRINT_SERVICES,
                  Settings.Secure.GLOBAL_ACTIONS_PANEL_AVAILABLE,
                  Settings.Secure.GLOBAL_ACTIONS_PANEL_DEBUG_ENABLED,
-                 Settings.Secure.IMMERSIVE_MODE_CONFIRMATIONS,
                  Settings.Secure.INCALL_BACK_BUTTON_BEHAVIOR,
                  Settings.Secure.INPUT_METHOD_SELECTOR_VISIBILITY,
                  Settings.Secure.INPUT_METHODS_SUBTYPE_HISTORY,
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index 40e39e9..617df74 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -155,6 +155,7 @@
         "jsr330",
         "lottie",
         "LowLightDreamLib",
+        "TraceurCommon",
         "motion_tool_lib",
         "notification_flags_lib",
         "PlatformComposeCore",
@@ -301,6 +302,7 @@
         "androidx.compose.material_material-icons-extended",
         "androidx.activity_activity-compose",
         "androidx.compose.animation_animation-graphics",
+        "TraceurCommon",
     ],
     skip_jarjar_repackage: true,
 }
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index d05d40d..da06830 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -610,3 +610,10 @@
     description: "Refactors media code to follow the recommended architecture"
     bug: "326408371"
 }
+
+flag {
+    name: "qs_tile_focus_state"
+    namespace: "systemui"
+    description: "enables new focus outline for qs tiles when focused on with physical keyboard"
+    bug: "312899524"
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractorTest.kt
index 97c407c..970ce1f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractorTest.kt
@@ -47,6 +47,17 @@
     private val displayRepository by lazy { kosmos.displayRepository }
 
     @Test
+    fun propertiesInitialized() =
+        testScope.runTest {
+            val propertiesInitialized by collectLastValue(underTest.propertiesInitialized)
+            assertThat(propertiesInitialized).isFalse()
+
+            repository.supportsUdfps()
+            runCurrent()
+            assertThat(propertiesInitialized).isTrue()
+        }
+
+    @Test
     fun sensorLocation_resolution1f() =
         testScope.runTest {
             val currSensorLocation by collectLastValue(underTest.sensorLocation)
diff --git a/packages/SystemUI/res/drawable/qs_tile_background_flagged.xml b/packages/SystemUI/res/drawable/qs_tile_background_flagged.xml
new file mode 100644
index 0000000..cf7a730
--- /dev/null
+++ b/packages/SystemUI/res/drawable/qs_tile_background_flagged.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
+    <!-- Since this layer list has just one layer, we can remove it and replace with the inner
+         layer drawable. However this should only be done when the flag
+         com.android.systemui.qs_tile_focus_state has completed all its stages and this drawable
+         fully replaces the previous one to ensure consistency with code sections searching for
+         specific ids in drawable hierarchy -->
+    <item
+        android:id="@id/background">
+        <layer-list>
+            <item
+                android:id="@+id/qs_tile_background_base"
+                android:drawable="@drawable/qs_tile_background_shape" />
+            <item android:id="@+id/qs_tile_background_overlay">
+                <selector>
+                    <item
+                        android:state_hovered="true"
+                        android:drawable="@drawable/qs_tile_background_shape" />
+                </selector>
+            </item>
+            <!-- In the layer below we have negative insets because we need the focus outline
+                 to draw outside the bounds, around the main background. We use 5dp because
+                 the outline stroke is 3dp and the required padding is 2dp.-->
+            <item
+                android:top="-5dp"
+                android:right="-5dp"
+                android:left="-5dp"
+                android:bottom="-5dp">
+                <selector>
+                    <item
+                        android:state_focused="true"
+                        android:drawable="@drawable/qs_tile_focused_background"/>
+                </selector>
+            </item>
+        </layer-list>
+    </item>
+</layer-list>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/qs_tile_focused_background.xml b/packages/SystemUI/res/drawable/qs_tile_focused_background.xml
new file mode 100644
index 0000000..fd456df
--- /dev/null
+++ b/packages/SystemUI/res/drawable/qs_tile_focused_background.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<shape
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+    android:shape="rectangle">
+    <corners android:radius="30dp"/>
+    <stroke android:width="3dp" android:color="?androidprv:attr/materialColorSecondaryFixed"/>
+</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/xml/fileprovider.xml b/packages/SystemUI/res/xml/fileprovider.xml
index b67378e..71cc05d 100644
--- a/packages/SystemUI/res/xml/fileprovider.xml
+++ b/packages/SystemUI/res/xml/fileprovider.xml
@@ -19,4 +19,5 @@
     <cache-path name="leak" path="leak/"/>
     <external-path name="screenrecord" path="."/>
     <cache-path name="multi_user" path="multi_user/" />
-</paths>
\ No newline at end of file
+    <root-path name="traces" path="/data/local/traces"/>
+</paths>
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIAppComponentFactoryBase.kt b/packages/SystemUI/src/com/android/systemui/SystemUIAppComponentFactoryBase.kt
index e88aaf01..aab0b1e 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIAppComponentFactoryBase.kt
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIAppComponentFactoryBase.kt
@@ -22,7 +22,6 @@
 import android.content.ContentProvider
 import android.content.Context
 import android.content.Intent
-import android.util.Log
 import androidx.core.app.AppComponentFactory
 import com.android.systemui.dagger.ContextComponentHelper
 import com.android.systemui.dagger.SysUIComponent
@@ -91,7 +90,8 @@
         return app
     }
 
-    @UsesReflection(KeepTarget(instanceOfClassConstant = SysUIComponent::class, methodName = "inject"))
+    @UsesReflection(
+            KeepTarget(instanceOfClassConstant = SysUIComponent::class, methodName = "inject"))
     override fun instantiateProviderCompat(cl: ClassLoader, className: String): ContentProvider {
         val contentProvider = super.instantiateProviderCompat(cl, className)
         if (contentProvider is ContextInitializer) {
@@ -103,11 +103,12 @@
                         .getMethod("inject", contentProvider.javaClass)
                     injectMethod.invoke(rootComponent, contentProvider)
                 } catch (e: NoSuchMethodException) {
-                    Log.w(TAG, "No injector for class: " + contentProvider.javaClass, e)
+                    throw RuntimeException("No injector for class: " + contentProvider.javaClass, e)
                 } catch (e: IllegalAccessException) {
-                    Log.w(TAG, "No injector for class: " + contentProvider.javaClass, e)
+                    throw RuntimeException("Injector inaccessible for class: " +
+                            contentProvider.javaClass, e)
                 } catch (e: InvocationTargetException) {
-                    Log.w(TAG, "No injector for class: " + contentProvider.javaClass, e)
+                    throw RuntimeException("Error while injecting: " + contentProvider.javaClass, e)
                 }
                 initializer
             }
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java
index 6d4baf4..cd3b8a6 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java
@@ -17,6 +17,7 @@
 package com.android.systemui.accessibility.floatingmenu;
 
 import static android.view.WindowInsets.Type.ime;
+import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_BUTTON;
 import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY;
 
 import static androidx.core.view.WindowInsetsCompat.Type;
@@ -48,6 +49,7 @@
 import android.os.Looper;
 import android.os.UserHandle;
 import android.provider.Settings;
+import android.util.ArraySet;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewTreeObserver;
@@ -64,6 +66,7 @@
 import androidx.recyclerview.widget.RecyclerView;
 import androidx.recyclerview.widget.RecyclerViewAccessibilityDelegate;
 
+import com.android.internal.accessibility.common.ShortcutConstants;
 import com.android.internal.accessibility.dialog.AccessibilityTarget;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.messages.nano.SystemMessageProto;
@@ -162,35 +165,45 @@
     final Runnable mDismissMenuAction = new Runnable() {
         @Override
         public void run() {
-            mSecureSettings.putStringForUser(
-                    Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, /* value= */ "",
-                    UserHandle.USER_CURRENT);
+            if (android.view.accessibility.Flags.a11yQsShortcut()) {
+                mAccessibilityManager.enableShortcutsForTargets(
+                        /* enable= */ false,
+                        ShortcutConstants.UserShortcutType.SOFTWARE,
+                        new ArraySet<>(mAccessibilityManager.getAccessibilityShortcutTargets(
+                                ACCESSIBILITY_BUTTON)),
+                        mSecureSettings.getRealUserHandle(UserHandle.USER_CURRENT)
+                );
+            } else {
+                mSecureSettings.putStringForUser(
+                        Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, /* value= */ "",
+                        UserHandle.USER_CURRENT);
 
-            final List<ComponentName> hardwareKeyShortcutComponents =
-                    mAccessibilityManager.getAccessibilityShortcutTargets(
-                                    ACCESSIBILITY_SHORTCUT_KEY)
-                            .stream()
-                            .map(ComponentName::unflattenFromString)
-                            .toList();
+                final List<ComponentName> hardwareKeyShortcutComponents =
+                        mAccessibilityManager.getAccessibilityShortcutTargets(
+                                        ACCESSIBILITY_SHORTCUT_KEY)
+                                .stream()
+                                .map(ComponentName::unflattenFromString)
+                                .toList();
 
-            // Should disable the corresponding service when the fragment type is
-            // INVISIBLE_TOGGLE, which will enable service when the shortcut is on.
-            final List<AccessibilityServiceInfo> serviceInfoList =
-                    mAccessibilityManager.getEnabledAccessibilityServiceList(
-                            AccessibilityServiceInfo.FEEDBACK_ALL_MASK);
-            serviceInfoList.forEach(info -> {
-                if (getAccessibilityServiceFragmentType(info) != INVISIBLE_TOGGLE) {
-                    return;
-                }
+                // Should disable the corresponding service when the fragment type is
+                // INVISIBLE_TOGGLE, which will enable service when the shortcut is on.
+                final List<AccessibilityServiceInfo> serviceInfoList =
+                        mAccessibilityManager.getEnabledAccessibilityServiceList(
+                                AccessibilityServiceInfo.FEEDBACK_ALL_MASK);
+                serviceInfoList.forEach(info -> {
+                    if (getAccessibilityServiceFragmentType(info) != INVISIBLE_TOGGLE) {
+                        return;
+                    }
 
-                final ComponentName serviceComponentName = info.getComponentName();
-                if (hardwareKeyShortcutComponents.contains(serviceComponentName)) {
-                    return;
-                }
+                    final ComponentName serviceComponentName = info.getComponentName();
+                    if (hardwareKeyShortcutComponents.contains(serviceComponentName)) {
+                        return;
+                    }
 
-                setAccessibilityServiceState(getContext(), serviceComponentName, /* enabled= */
-                        false);
-            });
+                    setAccessibilityServiceState(getContext(), serviceComponentName, /* enabled= */
+                            false);
+                });
+            }
 
             mFloatingMenu.hide();
         }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FingerprintPropertyRepository.kt b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FingerprintPropertyRepository.kt
index 0c0ed77..40d38dd 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FingerprintPropertyRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FingerprintPropertyRepository.kt
@@ -51,6 +51,8 @@
  * There is never more than one instance of the FingerprintProperty at any given time.
  */
 interface FingerprintPropertyRepository {
+    /** Whether the fingerprint properties have been initialized yet. */
+    val propertiesInitialized: StateFlow<Boolean>
 
     /** The id of fingerprint sensor. */
     val sensorId: Flow<Int>
@@ -59,7 +61,7 @@
     val strength: Flow<SensorStrength>
 
     /** The types of fingerprint sensor (rear, ultrasonic, optical, etc.). */
-    val sensorType: Flow<FingerprintSensorType>
+    val sensorType: StateFlow<FingerprintSensorType>
 
     /** The sensor location relative to each physical display. */
     val sensorLocations: Flow<Map<String, SensorLocationInternal>>
@@ -105,15 +107,30 @@
             .stateIn(
                 applicationScope,
                 started = SharingStarted.Eagerly,
-                initialValue = DEFAULT_PROPS,
+                initialValue = UNINITIALIZED_PROPS,
+            )
+
+    override val propertiesInitialized: StateFlow<Boolean> =
+        props
+            .map { it != UNINITIALIZED_PROPS }
+            .stateIn(
+                applicationScope,
+                started = SharingStarted.WhileSubscribed(),
+                initialValue = props.value != UNINITIALIZED_PROPS,
             )
 
     override val sensorId: Flow<Int> = props.map { it.sensorId }
 
     override val strength: Flow<SensorStrength> = props.map { it.sensorStrength.toSensorStrength() }
 
-    override val sensorType: Flow<FingerprintSensorType> =
-        props.map { it.sensorType.toSensorType() }
+    override val sensorType: StateFlow<FingerprintSensorType> =
+        props
+            .map { it.sensorType.toSensorType() }
+            .stateIn(
+                scope = applicationScope,
+                started = SharingStarted.WhileSubscribed(),
+                initialValue = props.value.sensorType.toSensorType(),
+            )
 
     override val sensorLocations: Flow<Map<String, SensorLocationInternal>> =
         props.map {
@@ -124,6 +141,17 @@
 
     companion object {
         private const val TAG = "FingerprintPropertyRepositoryImpl"
+        private val UNINITIALIZED_PROPS =
+            FingerprintSensorPropertiesInternal(
+                -2 /* sensorId */,
+                SensorProperties.STRENGTH_CONVENIENCE,
+                0 /* maxEnrollmentsPerUser */,
+                listOf<ComponentInfoInternal>(),
+                FingerprintSensorProperties.TYPE_UNKNOWN,
+                false /* halControlsIllumination */,
+                true /* resetLockoutRequiresHardwareAuthToken */,
+                listOf<SensorLocationInternal>(SensorLocationInternal.DEFAULT)
+            )
         private val DEFAULT_PROPS =
             FingerprintSensorPropertiesInternal(
                 -1 /* sensorId */,
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractor.kt
index ff9cdbd..5ae2ff0 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractor.kt
@@ -24,22 +24,35 @@
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.flow.filterNotNull
 import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.stateIn
 
 @SysUISingleton
 class FingerprintPropertyInteractor
 @Inject
 constructor(
+    @Application private val applicationScope: CoroutineScope,
     @Application private val context: Context,
     repository: FingerprintPropertyRepository,
     configurationInteractor: ConfigurationInteractor,
     displayStateInteractor: DisplayStateInteractor,
 ) {
-    val isUdfps: Flow<Boolean> = repository.sensorType.map { it.isUdfps() }
+    val propertiesInitialized: StateFlow<Boolean> = repository.propertiesInitialized
+    val isUdfps: StateFlow<Boolean> =
+        repository.sensorType
+            .map { it.isUdfps() }
+            .stateIn(
+                scope = applicationScope,
+                started = SharingStarted.WhileSubscribed(),
+                initialValue = repository.sensorType.value.isUdfps(),
+            )
 
     /**
      * Devices with multiple physical displays use unique display ids to determine which sensor is
diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryUdfpsInteractor.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryUdfpsInteractor.kt
index 72b9da6..80b52ed 100644
--- a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryUdfpsInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryUdfpsInteractor.kt
@@ -16,17 +16,17 @@
 
 package com.android.systemui.deviceentry.domain.interactor
 
-import com.android.systemui.biometrics.data.repository.FingerprintPropertyRepository
+import com.android.systemui.biometrics.domain.interactor.FingerprintPropertyInteractor
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository
 import com.android.systemui.keyguard.data.repository.DeviceEntryFingerprintAuthRepository
 import javax.inject.Inject
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.flatMapLatest
 import kotlinx.coroutines.flow.flowOf
-import kotlinx.coroutines.flow.map
 
 /** Encapsulates business logic for device entry under-display fingerprint state changes. */
 @ExperimentalCoroutinesApi
@@ -34,14 +34,13 @@
 class DeviceEntryUdfpsInteractor
 @Inject
 constructor(
+    fingerprintPropertyInteractor: FingerprintPropertyInteractor,
     // TODO (b/309655554): create & use interactors for these repositories
-    fingerprintPropertyRepository: FingerprintPropertyRepository,
     fingerprintAuthRepository: DeviceEntryFingerprintAuthRepository,
     biometricSettingsRepository: BiometricSettingsRepository,
 ) {
     /** Whether the device supports an under display fingerprint sensor. */
-    val isUdfpsSupported: Flow<Boolean> =
-        fingerprintPropertyRepository.sensorType.map { it.isUdfps() }
+    val isUdfpsSupported: StateFlow<Boolean> = fingerprintPropertyInteractor.isUdfps
 
     /** Whether the under-display fingerprint sensor is enrolled and enabled for device entry. */
     val isUdfpsEnrolledAndEnabled: Flow<Boolean> =
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepository.kt
index 0659c7c..a49b3ae 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepository.kt
@@ -19,7 +19,6 @@
 
 import android.os.Handler
 import android.util.Log
-import com.android.systemui.common.ui.data.repository.ConfigurationRepository
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.keyguard.shared.model.KeyguardBlueprint
@@ -30,7 +29,6 @@
 import java.io.PrintWriter
 import java.util.TreeMap
 import javax.inject.Inject
-import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.MutableSharedFlow
 import kotlinx.coroutines.flow.MutableStateFlow
 
@@ -49,7 +47,6 @@
 class KeyguardBlueprintRepository
 @Inject
 constructor(
-    configurationRepository: ConfigurationRepository,
     blueprints: Set<@JvmSuppressWildcards KeyguardBlueprint>,
     @Main val handler: Handler,
     val assert: ThreadAssert,
@@ -60,7 +57,6 @@
         TreeMap<String, KeyguardBlueprint>().apply { putAll(blueprints.associateBy { it.id }) }
     val blueprint: MutableStateFlow<KeyguardBlueprint> = MutableStateFlow(blueprintIdMap[DEFAULT]!!)
     val refreshTransition = MutableSharedFlow<Config>(extraBufferCapacity = 1)
-    val configurationChange: Flow<Unit> = configurationRepository.onAnyConfigurationChange
     private var targetTransitionConfig: Config? = null
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractor.kt
index bc3f0cc..c877192 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractor.kt
@@ -20,6 +20,8 @@
 package com.android.systemui.keyguard.domain.interactor
 
 import android.content.Context
+import com.android.systemui.biometrics.domain.interactor.FingerprintPropertyInteractor
+import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.keyguard.data.repository.KeyguardBlueprintRepository
@@ -34,7 +36,9 @@
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.collect
+import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.merge
 import kotlinx.coroutines.flow.onStart
 import kotlinx.coroutines.launch
 
@@ -47,6 +51,8 @@
     private val context: Context,
     private val splitShadeStateController: SplitShadeStateController,
     private val clockInteractor: KeyguardClockInteractor,
+    configurationInteractor: ConfigurationInteractor,
+    fingerprintPropertyInteractor: FingerprintPropertyInteractor,
 ) {
 
     /** The current blueprint for the lockscreen. */
@@ -58,11 +64,14 @@
      */
     val refreshTransition = keyguardBlueprintRepository.refreshTransition
 
+    private val configOrPropertyChange =
+        merge(
+            configurationInteractor.onAnyConfigurationChange,
+            fingerprintPropertyInteractor.propertiesInitialized.filter { it }.map {}, // map to Unit
+        )
     init {
         applicationScope.launch {
-            keyguardBlueprintRepository.configurationChange
-                .onStart { emit(Unit) }
-                .collect { updateBlueprint() }
+            configOrPropertyChange.onStart { emit(Unit) }.collect { updateBlueprint() }
         }
         applicationScope.launch { clockInteractor.currentClock.collect { updateBlueprint() } }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt
index 3fc9b42..1085f94 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt
@@ -26,7 +26,6 @@
 import androidx.annotation.VisibleForTesting
 import androidx.constraintlayout.widget.ConstraintLayout
 import androidx.constraintlayout.widget.ConstraintSet
-import com.android.keyguard.KeyguardUpdateMonitor
 import com.android.keyguard.LockIconView
 import com.android.keyguard.LockIconViewController
 import com.android.systemui.Flags.keyguardBottomAreaRefactor
@@ -56,7 +55,6 @@
 @Inject
 constructor(
     @Application private val applicationScope: CoroutineScope,
-    private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
     private val authController: AuthController,
     private val windowManager: WindowManager,
     private val context: Context,
@@ -111,7 +109,12 @@
     }
 
     override fun applyConstraints(constraintSet: ConstraintSet) {
-        val isUdfpsSupported = keyguardUpdateMonitor.isUdfpsSupported
+        val isUdfpsSupported =
+            if (DeviceEntryUdfpsRefactor.isEnabled) {
+                deviceEntryIconViewModel.get().isUdfpsSupported.value
+            } else {
+                authController.isUdfpsSupported
+            }
         val scaleFactor: Float = authController.scaleFactor
         val mBottomPaddingPx =
             context.resources.getDimensionPixelSize(R.dimen.lock_icon_margin_bottom)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt
index 662a77e..4c0a949 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt
@@ -20,6 +20,8 @@
 import android.content.Context
 import com.android.settingslib.Utils
 import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
+import com.android.systemui.keyguard.shared.model.KeyguardState
 import javax.inject.Inject
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.Flow
@@ -30,12 +32,14 @@
 import kotlinx.coroutines.flow.onStart
 
 /** Models the UI state for the device entry icon background view. */
+@Suppress("WHEN_ENUM_CAN_BE_NULL_IN_JAVA")
 @ExperimentalCoroutinesApi
 class DeviceEntryBackgroundViewModel
 @Inject
 constructor(
     val context: Context,
     val deviceEntryIconViewModel: DeviceEntryIconViewModel,
+    keyguardTransitionInteractor: KeyguardTransitionInteractor,
     configurationInteractor: ConfigurationInteractor,
     lockscreenToAodTransitionViewModel: LockscreenToAodTransitionViewModel,
     aodToLockscreenTransitionViewModel: AodToLockscreenTransitionViewModel,
@@ -94,6 +98,23 @@
                         alternateBouncerToDozingTransitionViewModel.deviceEntryBackgroundViewAlpha,
                     )
                     .merge()
+                    .onStart {
+                        when (
+                            keyguardTransitionInteractor.currentKeyguardState.replayCache.last()
+                        ) {
+                            KeyguardState.GLANCEABLE_HUB,
+                            KeyguardState.DREAMING_LOCKSCREEN_HOSTED,
+                            KeyguardState.GONE,
+                            KeyguardState.OCCLUDED,
+                            KeyguardState.OFF,
+                            KeyguardState.DOZING,
+                            KeyguardState.DREAMING,
+                            KeyguardState.PRIMARY_BOUNCER,
+                            KeyguardState.AOD -> emit(0f)
+                            KeyguardState.ALTERNATE_BOUNCER,
+                            KeyguardState.LOCKSCREEN -> emit(1f)
+                        }
+                    }
             } else {
                 flowOf(0f)
             }
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 bd19c80..1a01897 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
@@ -36,6 +36,7 @@
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.delay
 import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.flow.flatMapLatest
@@ -62,6 +63,7 @@
     private val deviceEntryInteractor: DeviceEntryInteractor,
     private val deviceEntrySourceInteractor: DeviceEntrySourceInteractor,
 ) {
+    val isUdfpsSupported: StateFlow<Boolean> = deviceEntryUdfpsInteractor.isUdfpsSupported
     private val intEvaluator = IntEvaluator()
     private val floatEvaluator = FloatEvaluator()
     private val showingAlternateBouncer: Flow<Boolean> =
@@ -137,7 +139,7 @@
         ) { alpha, alphaMultiplier ->
             alpha * alphaMultiplier
         }
-    val useBackgroundProtection: Flow<Boolean> = deviceEntryUdfpsInteractor.isUdfpsSupported
+    val useBackgroundProtection: StateFlow<Boolean> = isUdfpsSupported
     val burnInOffsets: Flow<BurnInOffsets> =
         deviceEntryUdfpsInteractor.isUdfpsEnrolledAndEnabled.flatMapLatest { udfpsEnrolled ->
             if (udfpsEnrolled) {
@@ -211,7 +213,7 @@
     val isLongPressEnabled: Flow<Boolean> =
         combine(
             iconType,
-            deviceEntryUdfpsInteractor.isUdfpsSupported,
+            isUdfpsSupported,
         ) { deviceEntryStatus, isUdfps ->
             when (deviceEntryStatus) {
                 DeviceEntryIconView.IconType.LOCK -> isUdfps
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
index e5af8e6..58858df 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
@@ -46,7 +46,6 @@
 import com.android.systemui.FontSizeUtils;
 import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.flags.Flags;
-import com.android.systemui.res.R;
 import com.android.systemui.qs.QSEditEvent;
 import com.android.systemui.qs.QSHost;
 import com.android.systemui.qs.TileLayout;
@@ -57,6 +56,7 @@
 import com.android.systemui.qs.dagger.QSThemedContext;
 import com.android.systemui.qs.external.CustomTile;
 import com.android.systemui.qs.tileimpl.QSTileViewImpl;
+import com.android.systemui.res.R;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -319,6 +319,9 @@
         }
         FrameLayout frame = (FrameLayout) inflater.inflate(R.layout.qs_customize_tile_frame, parent,
                 false);
+        if (com.android.systemui.Flags.qsTileFocusState()) {
+            frame.setClipChildren(false);
+        }
         View view = new CustomizeTileView(context);
         frame.addView(view);
         return new Holder(frame);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
index 9fefcbd..6cc682a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
@@ -47,6 +47,7 @@
 import androidx.annotation.VisibleForTesting
 import com.android.app.tracing.traceSection
 import com.android.settingslib.Utils
+import com.android.systemui.Flags
 import com.android.systemui.FontSizeUtils
 import com.android.systemui.animation.LaunchableView
 import com.android.systemui.animation.LaunchableViewDelegate
@@ -134,7 +135,7 @@
      */
     protected var showRippleEffect = true
 
-    private lateinit var ripple: RippleDrawable
+    private lateinit var qsTileBackground: LayerDrawable
     private lateinit var backgroundDrawable: LayerDrawable
     private lateinit var backgroundBaseDrawable: Drawable
     private lateinit var backgroundOverlayDrawable: Drawable
@@ -283,15 +284,20 @@
         addView(sideView)
     }
 
-    fun createTileBackground(): Drawable {
-        ripple = mContext.getDrawable(R.drawable.qs_tile_background) as RippleDrawable
-        backgroundDrawable = ripple.findDrawableByLayerId(R.id.background) as LayerDrawable
+    private fun createTileBackground(): Drawable {
+        qsTileBackground = if (Flags.qsTileFocusState()) {
+            mContext.getDrawable(R.drawable.qs_tile_background_flagged) as LayerDrawable
+        } else {
+            mContext.getDrawable(R.drawable.qs_tile_background) as RippleDrawable
+        }
+        backgroundDrawable =
+            qsTileBackground.findDrawableByLayerId(R.id.background) as LayerDrawable
         backgroundBaseDrawable =
             backgroundDrawable.findDrawableByLayerId(R.id.qs_tile_background_base)
         backgroundOverlayDrawable =
             backgroundDrawable.findDrawableByLayerId(R.id.qs_tile_background_overlay)
         backgroundOverlayDrawable.mutate().setTintMode(PorterDuff.Mode.SRC)
-        return ripple
+        return qsTileBackground
     }
 
     override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
@@ -366,14 +372,16 @@
 
     override fun setClickable(clickable: Boolean) {
         super.setClickable(clickable)
-        background = if (clickable && showRippleEffect) {
-            ripple.also {
-                // In case that the colorBackgroundDrawable was used as the background, make sure
-                // it has the correct callback instead of null
-                backgroundDrawable.callback = it
+        if (!Flags.qsTileFocusState()){
+            background = if (clickable && showRippleEffect) {
+                qsTileBackground.also {
+                    // In case that the colorBackgroundDrawable was used as the background, make sure
+                    // it has the correct callback instead of null
+                    backgroundDrawable.callback = it
+                }
+            } else {
+                backgroundDrawable
             }
-        } else {
-            backgroundDrawable
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/RecordIssueTile.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/RecordIssueTile.kt
index 20f3c4d..bd66843 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/RecordIssueTile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RecordIssueTile.kt
@@ -103,14 +103,27 @@
     public override fun handleClick(view: View?) {
         if (isRecording) {
             isRecording = false
-            stopScreenRecord()
+            stopIssueRecordingService()
         } else {
             mUiHandler.post { showPrompt(view) }
         }
         refreshState()
     }
 
-    private fun stopScreenRecord() =
+    private fun startIssueRecordingService(screenRecord: Boolean, winscopeTracing: Boolean) =
+        PendingIntent.getForegroundService(
+                userContextProvider.userContext,
+                RecordingService.REQUEST_CODE,
+                IssueRecordingService.getStartIntent(
+                    userContextProvider.userContext,
+                    screenRecord,
+                    winscopeTracing
+                ),
+                PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
+            )
+            .send(BroadcastOptions.makeBasic().apply { isInteractive = true }.toBundle())
+
+    private fun stopIssueRecordingService() =
         PendingIntent.getService(
                 userContextProvider.userContext,
                 RecordingService.REQUEST_CODE,
@@ -124,6 +137,7 @@
             delegateFactory
                 .create {
                     isRecording = true
+                    startIssueRecordingService(it.screenRecord, it.winscopeTracing)
                     refreshState()
                 }
                 .createDialog()
diff --git a/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingConfig.kt b/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingConfig.kt
new file mode 100644
index 0000000..bb3b654
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingConfig.kt
@@ -0,0 +1,19 @@
+/*
+ * 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.recordissue
+
+data class IssueRecordingConfig(val screenRecord: Boolean, val winscopeTracing: Boolean)
diff --git a/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingService.kt b/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingService.kt
index f487258..55d7f8e 100644
--- a/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingService.kt
+++ b/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingService.kt
@@ -20,7 +20,9 @@
 import android.content.Context
 import android.content.Intent
 import android.content.res.Resources
+import android.net.Uri
 import android.os.Handler
+import android.os.UserHandle
 import com.android.internal.logging.UiEventLogger
 import com.android.systemui.dagger.qualifiers.LongRunning
 import com.android.systemui.dagger.qualifiers.Main
@@ -30,6 +32,8 @@
 import com.android.systemui.screenrecord.RecordingServiceStrings
 import com.android.systemui.settings.UserContextProvider
 import com.android.systemui.statusbar.phone.KeyguardDismissUtil
+import com.android.traceur.FileSender
+import com.android.traceur.TraceUtils
 import java.util.concurrent.Executor
 import javax.inject.Inject
 
@@ -60,9 +64,89 @@
 
     override fun provideRecordingServiceStrings(): RecordingServiceStrings = IrsStrings(resources)
 
+    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
+        when (intent?.action) {
+            ACTION_START -> {
+                TraceUtils.traceStart(
+                    contentResolver,
+                    DEFAULT_TRACE_TAGS,
+                    DEFAULT_BUFFER_SIZE,
+                    DEFAULT_IS_INCLUDING_WINSCOPE,
+                    DEFAULT_IS_INCLUDING_APP_TRACE,
+                    DEFAULT_IS_LONG_TRACE,
+                    DEFAULT_ATTACH_TO_BUGREPORT,
+                    DEFAULT_MAX_TRACE_SIZE,
+                    DEFAULT_MAX_TRACE_DURATION_IN_MINUTES
+                )
+                if (!intent.getBooleanExtra(EXTRA_SCREEN_RECORD, false)) {
+                    // If we don't want to record the screen, the ACTION_SHOW_START_NOTIF action
+                    // will circumvent the RecordingService's screen recording start code.
+                    return super.onStartCommand(Intent(ACTION_SHOW_START_NOTIF), flags, startId)
+                }
+            }
+            ACTION_STOP,
+            ACTION_STOP_NOTIF -> {
+                TraceUtils.traceStop(contentResolver)
+            }
+            ACTION_SHARE -> {
+                shareRecording(intent)
+
+                // Unlike all other actions, action_share has different behavior for the screen
+                // recording qs tile than it does for the record issue qs tile. Return sticky to
+                // avoid running any of the base class' code for this action.
+                return START_STICKY
+            }
+            else -> {}
+        }
+        return super.onStartCommand(intent, flags, startId)
+    }
+
+    private fun shareRecording(intent: Intent) {
+        val files = TraceUtils.traceDump(contentResolver, TRACE_FILE_NAME).get()
+        val traceUris: MutableList<Uri> = FileSender.getUriForFiles(this, files, AUTHORITY)
+
+        if (
+            intent.hasExtra(EXTRA_PATH) && intent.getStringExtra(EXTRA_PATH)?.isNotEmpty() == true
+        ) {
+            traceUris.add(Uri.parse(intent.getStringExtra(EXTRA_PATH)))
+        }
+
+        val sendIntent =
+            FileSender.buildSendIntent(this, traceUris).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+
+        if (mNotificationId != NOTIF_BASE_ID) {
+            val currentUserId = mUserContextTracker.userContext.userId
+            mNotificationManager.cancelAsUser(null, mNotificationId, UserHandle(currentUserId))
+        }
+
+        // TODO: Debug why the notification shade isn't closing upon starting the BetterBug activity
+        mKeyguardDismissUtil.executeWhenUnlocked(
+            {
+                startActivity(sendIntent)
+                false
+            },
+            false,
+            false
+        )
+    }
+
     companion object {
         private const val TAG = "IssueRecordingService"
         private const val CHANNEL_ID = "issue_record"
+        private const val EXTRA_SCREEN_RECORD = "extra_screenRecord"
+        private const val EXTRA_WINSCOPE_TRACING = "extra_winscopeTracing"
+
+        private val DEFAULT_TRACE_TAGS = listOf<String>()
+        private const val DEFAULT_BUFFER_SIZE = 16384
+        private const val DEFAULT_IS_INCLUDING_WINSCOPE = true
+        private const val DEFAULT_IS_LONG_TRACE = false
+        private const val DEFAULT_IS_INCLUDING_APP_TRACE = true
+        private const val DEFAULT_ATTACH_TO_BUGREPORT = true
+        private const val DEFAULT_MAX_TRACE_SIZE = 10240
+        private const val DEFAULT_MAX_TRACE_DURATION_IN_MINUTES = 30
+
+        private val TRACE_FILE_NAME = TraceUtils.getOutputFilename(TraceUtils.RecordingType.TRACE)
+        private const val AUTHORITY = "com.android.systemui.fileprovider"
 
         /**
          * Get an intent to stop the issue recording service.
@@ -71,7 +155,7 @@
          * @return
          */
         fun getStopIntent(context: Context): Intent =
-            Intent(context, RecordingService::class.java)
+            Intent(context, IssueRecordingService::class.java)
                 .setAction(ACTION_STOP)
                 .putExtra(Intent.EXTRA_USER_HANDLE, context.userId)
 
@@ -80,8 +164,15 @@
          *
          * @param context Context from the requesting activity
          */
-        fun getStartIntent(context: Context): Intent =
-            Intent(context, RecordingService::class.java).setAction(ACTION_START)
+        fun getStartIntent(
+            context: Context,
+            screenRecord: Boolean,
+            winscopeTracing: Boolean
+        ): Intent =
+            Intent(context, IssueRecordingService::class.java)
+                .setAction(ACTION_START)
+                .putExtra(EXTRA_SCREEN_RECORD, screenRecord)
+                .putExtra(EXTRA_WINSCOPE_TRACING, winscopeTracing)
     }
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/recordissue/RecordIssueDialogDelegate.kt b/packages/SystemUI/src/com/android/systemui/recordissue/RecordIssueDialogDelegate.kt
index 1c07d00..ff18a11 100644
--- a/packages/SystemUI/src/com/android/systemui/recordissue/RecordIssueDialogDelegate.kt
+++ b/packages/SystemUI/src/com/android/systemui/recordissue/RecordIssueDialogDelegate.kt
@@ -17,8 +17,6 @@
 package com.android.systemui.recordissue
 
 import android.annotation.SuppressLint
-import android.app.BroadcastOptions
-import android.app.PendingIntent
 import android.content.Context
 import android.content.res.ColorStateList
 import android.graphics.Color
@@ -43,8 +41,6 @@
 import com.android.systemui.mediaprojection.devicepolicy.ScreenCaptureDisabledDialogDelegate
 import com.android.systemui.qs.tiles.RecordIssueTile
 import com.android.systemui.res.R
-import com.android.systemui.screenrecord.RecordingService
-import com.android.systemui.settings.UserContextProvider
 import com.android.systemui.settings.UserFileManager
 import com.android.systemui.settings.UserTracker
 import com.android.systemui.statusbar.phone.SystemUIDialog
@@ -52,12 +48,12 @@
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
 import java.util.concurrent.Executor
+import java.util.function.Consumer
 
 class RecordIssueDialogDelegate
 @AssistedInject
 constructor(
     private val factory: SystemUIDialog.Factory,
-    private val userContextProvider: UserContextProvider,
     private val userTracker: UserTracker,
     private val flags: FeatureFlagsClassic,
     @Background private val bgExecutor: Executor,
@@ -66,14 +62,14 @@
     private val mediaProjectionMetricsLogger: MediaProjectionMetricsLogger,
     private val userFileManager: UserFileManager,
     private val screenCaptureDisabledDialogDelegate: ScreenCaptureDisabledDialogDelegate,
-    @Assisted private val onStarted: Runnable,
+    @Assisted private val onStarted: Consumer<IssueRecordingConfig>,
 ) : SystemUIDialog.Delegate {
 
     /** To inject dependencies and allow for easier testing */
     @AssistedFactory
     interface Factory {
         /** Create a dialog object */
-        fun create(onStarted: Runnable): RecordIssueDialogDelegate
+        fun create(onStarted: Consumer<IssueRecordingConfig>): RecordIssueDialogDelegate
     }
 
     @SuppressLint("UseSwitchCompatOrMaterialCode") private lateinit var screenRecordSwitch: Switch
@@ -87,10 +83,12 @@
             setIcon(R.drawable.qs_record_issue_icon_off)
             setNegativeButton(R.string.cancel) { _, _ -> dismiss() }
             setPositiveButton(R.string.qs_record_issue_start) { _, _ ->
-                onStarted.run()
-                if (screenRecordSwitch.isChecked) {
-                    requestScreenCapture()
-                }
+                onStarted.accept(
+                    IssueRecordingConfig(
+                        screenRecordSwitch.isChecked,
+                        true /* TODO: Base this on issueType selected */
+                    )
+                )
                 dismiss()
             }
         }
@@ -177,13 +175,4 @@
             show()
         }
     }
-
-    private fun requestScreenCapture() =
-        PendingIntent.getForegroundService(
-                userContextProvider.userContext,
-                RecordingService.REQUEST_CODE,
-                IssueRecordingService.getStartIntent(userContextProvider.userContext),
-                PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
-            )
-            .send(BroadcastOptions.makeBasic().apply { isInteractive = true }.toBundle())
 }
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
index b355d2d..ac94f39 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
@@ -60,25 +60,27 @@
     public static final int REQUEST_CODE = 2;
 
     private static final int USER_ID_NOT_SPECIFIED = -1;
-    private static final int NOTIF_BASE_ID = 4273;
+    protected static final int NOTIF_BASE_ID = 4273;
     private static final String TAG = "RecordingService";
     private static final String CHANNEL_ID = "screen_record";
     private static final String GROUP_KEY = "screen_record_saved";
     private static final String EXTRA_RESULT_CODE = "extra_resultCode";
-    private static final String EXTRA_PATH = "extra_path";
+    protected static final String EXTRA_PATH = "extra_path";
     private static final String EXTRA_AUDIO_SOURCE = "extra_useAudio";
     private static final String EXTRA_SHOW_TAPS = "extra_showTaps";
     private static final String EXTRA_CAPTURE_TARGET = "extra_captureTarget";
 
     protected static final String ACTION_START = "com.android.systemui.screenrecord.START";
+    protected static final String ACTION_SHOW_START_NOTIF =
+            "com.android.systemui.screenrecord.START_NOTIF";
     protected static final String ACTION_STOP = "com.android.systemui.screenrecord.STOP";
-    private static final String ACTION_STOP_NOTIF =
+    protected static final String ACTION_STOP_NOTIF =
             "com.android.systemui.screenrecord.STOP_FROM_NOTIF";
-    private static final String ACTION_SHARE = "com.android.systemui.screenrecord.SHARE";
+    protected static final String ACTION_SHARE = "com.android.systemui.screenrecord.SHARE";
     private static final String PERMISSION_SELF = "com.android.systemui.permission.SELF";
 
     private final RecordingController mController;
-    private final KeyguardDismissUtil mKeyguardDismissUtil;
+    protected final KeyguardDismissUtil mKeyguardDismissUtil;
     private final Handler mMainHandler;
     private ScreenRecordingAudioSource mAudioSource;
     private boolean mShowTaps;
@@ -86,9 +88,9 @@
     private ScreenMediaRecorder mRecorder;
     private final Executor mLongExecutor;
     private final UiEventLogger mUiEventLogger;
-    private final NotificationManager mNotificationManager;
-    private final UserContextProvider mUserContextTracker;
-    private int mNotificationId = NOTIF_BASE_ID;
+    protected final NotificationManager mNotificationManager;
+    protected final UserContextProvider mUserContextTracker;
+    protected int mNotificationId = NOTIF_BASE_ID;
     private RecordingServiceStrings mStrings;
 
     @Inject
@@ -185,7 +187,10 @@
                     return Service.START_NOT_STICKY;
                 }
                 break;
-
+            case ACTION_SHOW_START_NOTIF:
+                createRecordingNotification();
+                mUiEventLogger.log(Events.ScreenRecordEvent.SCREEN_RECORD_START);
+                break;
             case ACTION_STOP_NOTIF:
             case ACTION_STOP:
                 // only difference for actions is the log event
@@ -232,6 +237,7 @@
         super.onCreate();
     }
 
+    @Nullable
     @VisibleForTesting
     protected ScreenMediaRecorder getRecorder() {
         return mRecorder;
@@ -337,8 +343,9 @@
     }
 
     @VisibleForTesting
-    protected Notification createSaveNotification(ScreenMediaRecorder.SavedRecording recording) {
-        Uri uri = recording.getUri();
+    protected Notification createSaveNotification(
+            @Nullable ScreenMediaRecorder.SavedRecording recording) {
+        Uri uri = recording != null ? recording.getUri() : null;
         Intent viewIntent = new Intent(Intent.ACTION_VIEW)
                 .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_GRANT_READ_URI_PERMISSION)
                 .setDataAndType(uri, "video/mp4");
@@ -349,7 +356,7 @@
                 PendingIntent.getService(
                         this,
                         REQUEST_CODE,
-                        getShareIntent(this, uri.toString()),
+                        getShareIntent(this, uri != null ? uri.toString() : null),
                         PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE))
                 .build();
 
@@ -371,9 +378,10 @@
                 .addExtras(extras);
 
         // Add thumbnail if available
-        if (recording.getThumbnail() != null) {
+        Icon thumbnail = recording != null ? recording.getThumbnail() : null;
+        if (thumbnail != null) {
             Notification.BigPictureStyle pictureStyle = new Notification.BigPictureStyle()
-                    .bigPicture(recording.getThumbnail())
+                    .bigPicture(thumbnail)
                     .showBigPictureWhenCollapsed(true);
             builder.setStyle(pictureStyle);
         }
@@ -408,27 +416,29 @@
         }
         Log.d(getTag(), "notifying for user " + userId);
         setTapsVisible(mOriginalShowTaps);
-        if (getRecorder() != null) {
-            try {
+        try {
+            if (getRecorder() != null) {
                 getRecorder().end();
-                saveRecording(userId);
-            } catch (RuntimeException exception) {
+            }
+            saveRecording(userId);
+        } catch (RuntimeException exception) {
+            if (getRecorder() != null) {
                 // RuntimeException could happen if the recording stopped immediately after starting
                 // let's release the recorder and delete all temporary files in this case
                 getRecorder().release();
-                showErrorToast(R.string.screenrecord_start_error);
-                Log.e(getTag(), "stopRecording called, but there was an error when ending"
-                        + "recording");
-                exception.printStackTrace();
-                createErrorNotification();
-            } catch (Throwable throwable) {
+            }
+            showErrorToast(R.string.screenrecord_start_error);
+            Log.e(getTag(), "stopRecording called, but there was an error when ending"
+                    + "recording");
+            exception.printStackTrace();
+            createErrorNotification();
+        } catch (Throwable throwable) {
+            if (getRecorder() != null) {
                 // Something unexpected happen, SystemUI will crash but let's delete
                 // the temporary files anyway
                 getRecorder().release();
-                throw new RuntimeException(throwable);
             }
-        } else {
-            Log.e(getTag(), "stopRecording called, but recorder was null");
+            throw new RuntimeException(throwable);
         }
         updateState(false);
         stopForeground(STOP_FOREGROUND_DETACH);
@@ -443,7 +453,8 @@
         mLongExecutor.execute(() -> {
             try {
                 Log.d(getTag(), "saving recording");
-                Notification notification = createSaveNotification(getRecorder().save());
+                Notification notification = createSaveNotification(
+                        getRecorder() != null ? getRecorder().save() : null);
                 postGroupNotification(currentUser);
                 mNotificationManager.notifyAsUser(null, mNotificationId,  notification,
                         currentUser);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
index 81f644f..4b16126 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
@@ -594,6 +594,7 @@
                 }
             }
             val cancelHandler = Runnable {
+                statusBarStateController.setLeaveOpenOnKeyguardHide(false)
                 draggedDownEntry?.apply {
                     setUserLocked(false)
                     notifyHeightChanged(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
index db15144..6602a97 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -2790,6 +2790,9 @@
                         || mKeyguardStateController.isKeyguardGoingAway()
                         || mKeyguardViewMediator.requestedShowSurfaceBehindKeyguard()
                         || mKeyguardViewMediator.isAnimatingBetweenKeyguardAndSurfaceBehind());
+        boolean dreaming =
+                mKeyguardStateController.isShowing() && mKeyguardUpdateMonitor.isDreaming()
+                        && !unlocking;
 
         mScrimController.setExpansionAffectsAlpha(!unlocking);
 
@@ -2834,13 +2837,16 @@
             // this as otherwise it can remain pending and leave keyguard in a weird state.
             mUnlockScrimCallback.onCancelled();
         } else if (mIsIdleOnCommunal) {
-            mScrimController.transitionTo(ScrimState.GLANCEABLE_HUB);
+            if (dreaming) {
+                mScrimController.transitionTo(ScrimState.GLANCEABLE_HUB_OVER_DREAM);
+            } else {
+                mScrimController.transitionTo(ScrimState.GLANCEABLE_HUB);
+            }
         } else if (mKeyguardStateController.isShowing()
                 && !mKeyguardStateController.isOccluded()
                 && !unlocking) {
             mScrimController.transitionTo(ScrimState.KEYGUARD);
-        } else if (mKeyguardStateController.isShowing() && mKeyguardUpdateMonitor.isDreaming()
-                && !unlocking) {
+        } else if (dreaming) {
             mScrimController.transitionTo(ScrimState.DREAMING);
         } else {
             mScrimController.transitionTo(ScrimState.UNLOCKED, mUnlockScrimCallback);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 088f894..02293a2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -536,6 +536,16 @@
         mAnimateChange = state.getAnimateChange();
         mAnimationDuration = state.getAnimationDuration();
 
+        if (mState == ScrimState.GLANCEABLE_HUB_OVER_DREAM) {
+            // When the device is docked while on GLANCEABLE_HUB, the dream starts underneath the
+            // hub and the ScrimState transitions to GLANCEABLE_HUB_OVER_DREAM. To prevent the
+            // scrims from flickering in during this transition, we set the panel expansion
+            // fraction, which is 1 when idle on GLANCEABLE_HUB, to 0. This only occurs when the hub
+            // is open because the hub lives in the same window as the shade, which is not visible
+            // when transitioning from KEYGUARD to DREAMING.
+            mPanelExpansionFraction = 0f;
+        }
+
         applyState();
 
         mScrimInFront.setBlendWithMainColor(state.shouldBlendWithMainColor());
@@ -738,6 +748,7 @@
             boolean relevantState = (mState == ScrimState.UNLOCKED
                     || mState == ScrimState.KEYGUARD
                     || mState == ScrimState.DREAMING
+                    || mState == ScrimState.GLANCEABLE_HUB_OVER_DREAM
                     || mState == ScrimState.SHADE_LOCKED
                     || mState == ScrimState.PULSING);
             if (!(relevantState && mExpansionAffectsAlpha) || mAnimatingPanelExpansionOnUnlock) {
@@ -844,7 +855,8 @@
             return;
         }
         mBouncerHiddenFraction = bouncerHiddenAmount;
-        if (mState == ScrimState.DREAMING || mState == ScrimState.GLANCEABLE_HUB) {
+        if (mState == ScrimState.DREAMING || mState == ScrimState.GLANCEABLE_HUB
+                || mState == ScrimState.GLANCEABLE_HUB_OVER_DREAM) {
             // The dreaming and glanceable hub states requires this for the scrim calculation, so we
             // should only trigger an update in those states.
             applyAndDispatchState();
@@ -926,7 +938,8 @@
             return;
         }
 
-        if (mState == ScrimState.UNLOCKED || mState == ScrimState.DREAMING) {
+        if (mState == ScrimState.UNLOCKED || mState == ScrimState.DREAMING
+                || mState == ScrimState.GLANCEABLE_HUB_OVER_DREAM) {
             final boolean occluding =
                     mOccludeAnimationPlaying || mState.mLaunchingAffordanceWithPreview;
             // Darken scrim as it's pulled down while unlocked. If we're unlocked but playing the
@@ -954,8 +967,9 @@
                 mInFrontAlpha = 0;
             }
 
-            if (mState == ScrimState.DREAMING
+            if ((mState == ScrimState.DREAMING || mState == ScrimState.GLANCEABLE_HUB_OVER_DREAM)
                     && mBouncerHiddenFraction != KeyguardBouncerConstants.EXPANSION_HIDDEN) {
+                // Bouncer is opening over dream or glanceable hub over dream.
                 final float interpolatedFraction =
                         BouncerPanelExpansionCalculator.aboutToShowBouncerProgress(
                                 mBouncerHiddenFraction);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
index f2a649b..d4960d7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
@@ -299,9 +299,9 @@
     },
 
     /**
-     * Device is locked or on dream and user has swiped from the right edge to enter the glanceable
-     * hub UI. From this state, the user can swipe from the left edge to go back to the lock screen
-     * or dream, as well as swipe down for the notifications and up for the bouncer.
+     * Device is on the lockscreen and user has swiped from the right edge to enter the glanceable
+     * hub UI. From this state, the user can swipe from the left edge to go back to the lock screen,
+     * as well as swipe down for the notifications and up for the bouncer.
      */
     GLANCEABLE_HUB {
         @Override
@@ -310,6 +310,25 @@
             mBehindAlpha = 0;
             mNotifAlpha = 0;
             mFrontAlpha = 0;
+
+            mFrontTint = Color.TRANSPARENT;
+            mBehindTint = mBackgroundColor;
+            mNotifTint = mClipQsScrim ? mBackgroundColor : Color.TRANSPARENT;
+        }
+    },
+
+    /**
+     * Device is dreaming and user has swiped from the right edge to enter the glanceable hub UI.
+     * From this state, the user can swipe from the left edge to go back to the  dream, as well as
+     * swipe down for the notifications and up for the bouncer.
+     *
+     * This is a separate state from {@link #GLANCEABLE_HUB} because the scrims behave differently
+     * when the dream is running.
+     */
+    GLANCEABLE_HUB_OVER_DREAM {
+        @Override
+        public void prepare(ScrimState previousState) {
+            GLANCEABLE_HUB.prepare(previousState);
         }
     };
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java
index 3862b0f..de795a7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java
@@ -61,6 +61,7 @@
 import android.provider.Settings;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
+import android.util.ArraySet;
 import android.view.View;
 import android.view.WindowInsets;
 import android.view.WindowManager;
@@ -71,6 +72,7 @@
 import androidx.dynamicanimation.animation.SpringAnimation;
 import androidx.test.filters.SmallTest;
 
+import com.android.internal.accessibility.common.ShortcutConstants;
 import com.android.internal.accessibility.dialog.AccessibilityTarget;
 import com.android.internal.messages.nano.SystemMessageProto;
 import com.android.systemui.Flags;
@@ -220,6 +222,24 @@
     }
 
     @Test
+    @EnableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)
+    public void triggerDismissMenuAction_callsA11yManagerEnableShortcutsForTargets() {
+        final List<String> stubShortcutTargets = new ArrayList<>();
+        stubShortcutTargets.add(TEST_SELECT_TO_SPEAK_COMPONENT_NAME.flattenToString());
+        when(mStubAccessibilityManager.getAccessibilityShortcutTargets(
+                AccessibilityManager.ACCESSIBILITY_BUTTON)).thenReturn(stubShortcutTargets);
+
+        mMenuViewLayer.mDismissMenuAction.run();
+
+        verify(mStubAccessibilityManager).enableShortcutsForTargets(
+                /* enable= */ false,
+                ShortcutConstants.UserShortcutType.SOFTWARE,
+                new ArraySet<>(stubShortcutTargets),
+                mSecureSettings.getRealUserHandle(UserHandle.USER_CURRENT));
+    }
+
+    @Test
+    @DisableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)
     public void triggerDismissMenuAction_matchA11yButtonTargetsResult() {
         mMenuViewLayer.mDismissMenuAction.run();
         verify(mSecureSettings).putStringForUser(
@@ -228,6 +248,7 @@
     }
 
     @Test
+    @DisableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)
     public void triggerDismissMenuAction_matchEnabledA11yServicesResult() {
         setupEnabledAccessibilityServiceList();
 
@@ -239,6 +260,7 @@
     }
 
     @Test
+    @DisableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)
     public void triggerDismissMenuAction_hasHardwareKeyShortcut_keepEnabledStatus() {
         setupEnabledAccessibilityServiceList();
         final List<String> stubShortcutTargets = new ArrayList<>();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthDialogPanelInteractionDetectorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthDialogPanelInteractionDetectorTest.kt
index 54d6b53..67ca9a4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthDialogPanelInteractionDetectorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthDialogPanelInteractionDetectorTest.kt
@@ -20,6 +20,7 @@
 import com.android.systemui.SysUITestComponent
 import com.android.systemui.SysUITestModule
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.domain.BiometricsDomainLayerModule
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.flags.FakeFeatureFlagsClassicModule
 import com.android.systemui.flags.Flags
@@ -45,6 +46,7 @@
             [
                 SysUITestModule::class,
                 UserDomainLayerModule::class,
+                BiometricsDomainLayerModule::class,
             ]
     )
     interface TestComponent : SysUITestComponent<AuthDialogPanelInteractionDetector> {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/FingerprintRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/FingerprintRepositoryImplTest.kt
index dc438d7..7808c41 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/FingerprintRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/FingerprintRepositoryImplTest.kt
@@ -84,8 +84,8 @@
             val sensorType by collectLastValue(repository.sensorType)
             val sensorLocations by collectLastValue(repository.sensorLocations)
 
-            // Assert default properties.
-            assertThat(sensorId).isEqualTo(-1)
+            // Assert non-initialized properties.
+            assertThat(sensorId).isEqualTo(-2)
             assertThat(strength).isEqualTo(SensorStrength.CONVENIENCE)
             assertThat(sensorType).isEqualTo(FingerprintSensorType.UNKNOWN)
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/DefaultUdfpsTouchOverlayViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/DefaultUdfpsTouchOverlayViewModelTest.kt
index fa17672..5caa146 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/DefaultUdfpsTouchOverlayViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/DefaultUdfpsTouchOverlayViewModelTest.kt
@@ -21,6 +21,7 @@
 import com.android.systemui.SysUITestModule
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.TestMocksModule
+import com.android.systemui.biometrics.domain.BiometricsDomainLayerModule
 import com.android.systemui.collectLastValue
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.flags.FakeFeatureFlagsClassicModule
@@ -65,6 +66,7 @@
             [
                 SysUITestModule::class,
                 UserDomainLayerModule::class,
+                BiometricsDomainLayerModule::class,
             ]
     )
     interface TestComponent : SysUITestComponent<DefaultUdfpsTouchOverlayViewModel> {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryUdfpsInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryUdfpsInteractorTest.kt
index e8eda80..d5839b5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryUdfpsInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryUdfpsInteractorTest.kt
@@ -21,9 +21,15 @@
 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.fakeFingerprintPropertyRepository
+import com.android.systemui.biometrics.domain.interactor.fingerprintPropertyInteractor
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
 import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository
+import com.android.systemui.keyguard.data.repository.fakeBiometricSettingsRepository
+import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFingerprintAuthRepository
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.testKosmos
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.test.runTest
@@ -35,6 +41,8 @@
 @SmallTest
 @RunWith(AndroidJUnit4::class)
 class DeviceEntryUdfpsInteractorTest : SysuiTestCase() {
+    private val kosmos = testKosmos()
+    private val testScope = kosmos.testScope
     private lateinit var fingerprintPropertyRepository: FakeFingerprintPropertyRepository
     private lateinit var fingerprintAuthRepository: FakeDeviceEntryFingerprintAuthRepository
     private lateinit var biometricsRepository: FakeBiometricSettingsRepository
@@ -43,77 +51,85 @@
 
     @Before
     fun setUp() {
-        fingerprintPropertyRepository = FakeFingerprintPropertyRepository()
-        fingerprintAuthRepository = FakeDeviceEntryFingerprintAuthRepository()
-        biometricsRepository = FakeBiometricSettingsRepository()
+        fingerprintPropertyRepository = kosmos.fakeFingerprintPropertyRepository
+        fingerprintAuthRepository = kosmos.fakeDeviceEntryFingerprintAuthRepository
+        biometricsRepository = kosmos.fakeBiometricSettingsRepository
 
         underTest =
             DeviceEntryUdfpsInteractor(
-                fingerprintPropertyRepository = fingerprintPropertyRepository,
+                fingerprintPropertyInteractor = kosmos.fingerprintPropertyInteractor,
                 fingerprintAuthRepository = fingerprintAuthRepository,
                 biometricSettingsRepository = biometricsRepository,
             )
     }
 
     @Test
-    fun udfpsSupported_rearFp_false() = runTest {
-        val isUdfpsSupported by collectLastValue(underTest.isUdfpsSupported)
-        fingerprintPropertyRepository.supportsRearFps()
-        assertThat(isUdfpsSupported).isFalse()
-    }
+    fun udfpsSupported_rearFp_false() =
+        testScope.runTest {
+            val isUdfpsSupported by collectLastValue(underTest.isUdfpsSupported)
+            fingerprintPropertyRepository.supportsRearFps()
+            assertThat(isUdfpsSupported).isFalse()
+        }
 
     @Test
-    fun udfpsSupoprted() = runTest {
-        val isUdfpsSupported by collectLastValue(underTest.isUdfpsSupported)
-        fingerprintPropertyRepository.supportsUdfps()
-        assertThat(isUdfpsSupported).isTrue()
-    }
+    fun udfpsSupoprted() =
+        testScope.runTest {
+            val isUdfpsSupported by collectLastValue(underTest.isUdfpsSupported)
+            fingerprintPropertyRepository.supportsUdfps()
+            assertThat(isUdfpsSupported).isTrue()
+        }
 
     @Test
-    fun udfpsEnrolledAndEnabled() = runTest {
-        val isUdfpsEnrolledAndEnabled by collectLastValue(underTest.isUdfpsEnrolledAndEnabled)
-        fingerprintPropertyRepository.supportsUdfps()
-        biometricsRepository.setIsFingerprintAuthEnrolledAndEnabled(true)
-        assertThat(isUdfpsEnrolledAndEnabled).isTrue()
-    }
+    fun udfpsEnrolledAndEnabled() =
+        testScope.runTest {
+            val isUdfpsEnrolledAndEnabled by collectLastValue(underTest.isUdfpsEnrolledAndEnabled)
+            fingerprintPropertyRepository.supportsUdfps()
+            biometricsRepository.setIsFingerprintAuthEnrolledAndEnabled(true)
+            assertThat(isUdfpsEnrolledAndEnabled).isTrue()
+        }
 
     @Test
-    fun udfpsEnrolledAndEnabled_rearFp_false() = runTest {
-        val isUdfpsEnrolledAndEnabled by collectLastValue(underTest.isUdfpsEnrolledAndEnabled)
-        fingerprintPropertyRepository.supportsRearFps()
-        biometricsRepository.setIsFingerprintAuthEnrolledAndEnabled(true)
-        assertThat(isUdfpsEnrolledAndEnabled).isFalse()
-    }
+    fun udfpsEnrolledAndEnabled_rearFp_false() =
+        testScope.runTest {
+            val isUdfpsEnrolledAndEnabled by collectLastValue(underTest.isUdfpsEnrolledAndEnabled)
+            fingerprintPropertyRepository.supportsRearFps()
+            biometricsRepository.setIsFingerprintAuthEnrolledAndEnabled(true)
+            assertThat(isUdfpsEnrolledAndEnabled).isFalse()
+        }
 
     @Test
-    fun udfpsEnrolledAndEnabled_notEnrolledOrEnabled_false() = runTest {
-        val isUdfpsEnrolledAndEnabled by collectLastValue(underTest.isUdfpsEnrolledAndEnabled)
-        fingerprintPropertyRepository.supportsUdfps()
-        biometricsRepository.setIsFingerprintAuthEnrolledAndEnabled(false)
-        assertThat(isUdfpsEnrolledAndEnabled).isFalse()
-    }
+    fun udfpsEnrolledAndEnabled_notEnrolledOrEnabled_false() =
+        testScope.runTest {
+            val isUdfpsEnrolledAndEnabled by collectLastValue(underTest.isUdfpsEnrolledAndEnabled)
+            fingerprintPropertyRepository.supportsUdfps()
+            biometricsRepository.setIsFingerprintAuthEnrolledAndEnabled(false)
+            assertThat(isUdfpsEnrolledAndEnabled).isFalse()
+        }
 
     @Test
-    fun isListeningForUdfps() = runTest {
-        val isListeningForUdfps by collectLastValue(underTest.isListeningForUdfps)
-        fingerprintPropertyRepository.supportsUdfps()
-        fingerprintAuthRepository.setIsRunning(true)
-        assertThat(isListeningForUdfps).isTrue()
-    }
+    fun isListeningForUdfps() =
+        testScope.runTest {
+            val isListeningForUdfps by collectLastValue(underTest.isListeningForUdfps)
+            fingerprintPropertyRepository.supportsUdfps()
+            fingerprintAuthRepository.setIsRunning(true)
+            assertThat(isListeningForUdfps).isTrue()
+        }
 
     @Test
-    fun isListeningForUdfps_rearFp_false() = runTest {
-        val isListeningForUdfps by collectLastValue(underTest.isListeningForUdfps)
-        fingerprintPropertyRepository.supportsRearFps()
-        fingerprintAuthRepository.setIsRunning(true)
-        assertThat(isListeningForUdfps).isFalse()
-    }
+    fun isListeningForUdfps_rearFp_false() =
+        testScope.runTest {
+            val isListeningForUdfps by collectLastValue(underTest.isListeningForUdfps)
+            fingerprintPropertyRepository.supportsRearFps()
+            fingerprintAuthRepository.setIsRunning(true)
+            assertThat(isListeningForUdfps).isFalse()
+        }
 
     @Test
-    fun isListeningForUdfps_notRunning_false() = runTest {
-        val isListeningForUdfps by collectLastValue(underTest.isListeningForUdfps)
-        fingerprintPropertyRepository.supportsUdfps()
-        fingerprintAuthRepository.setIsRunning(false)
-        assertThat(isListeningForUdfps).isFalse()
-    }
+    fun isListeningForUdfps_notRunning_false() =
+        testScope.runTest {
+            val isListeningForUdfps by collectLastValue(underTest.isListeningForUdfps)
+            fingerprintPropertyRepository.supportsUdfps()
+            fingerprintAuthRepository.setIsRunning(false)
+            assertThat(isListeningForUdfps).isFalse()
+        }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepositoryTest.kt
index 37836a5..bcaad01 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepositoryTest.kt
@@ -62,7 +62,6 @@
             whenever(defaultLockscreenBlueprint.id).thenReturn(DEFAULT)
             underTest =
                 KeyguardBlueprintRepository(
-                    configurationRepository,
                     setOf(defaultLockscreenBlueprint),
                     fakeExecutorHandler,
                     threadAssert,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorTest.kt
index b0d8de3..170d348 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorTest.kt
@@ -21,95 +21,80 @@
 import androidx.test.filters.SmallTest
 import com.android.systemui.Flags
 import com.android.systemui.SysuiTestCase
-import com.android.systemui.keyguard.data.repository.KeyguardBlueprintRepository
+import com.android.systemui.biometrics.data.repository.fakeFingerprintPropertyRepository
+import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.keyguard.data.repository.fakeKeyguardClockRepository
 import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor.Companion.SPLIT_SHADE_WEATHER_CLOCK_BLUEPRINT_ID
 import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor.Companion.WEATHER_CLOCK_BLUEPRINT_ID
 import com.android.systemui.keyguard.ui.view.layout.blueprints.DefaultKeyguardBlueprint
 import com.android.systemui.keyguard.ui.view.layout.blueprints.SplitShadeKeyguardBlueprint
-import com.android.systemui.keyguard.ui.view.layout.blueprints.transitions.IntraBlueprintTransition
-import com.android.systemui.keyguard.ui.view.layout.blueprints.transitions.IntraBlueprintTransition.Config
-import com.android.systemui.keyguard.ui.view.layout.blueprints.transitions.IntraBlueprintTransition.Type
+import com.android.systemui.kosmos.testScope
 import com.android.systemui.plugins.clocks.ClockConfig
 import com.android.systemui.plugins.clocks.ClockController
-import com.android.systemui.statusbar.policy.SplitShadeStateController
-import com.android.systemui.util.mockito.any
+import com.android.systemui.res.R
+import com.android.systemui.testKosmos
 import com.android.systemui.util.mockito.whenever
-import kotlinx.coroutines.flow.MutableSharedFlow
-import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.test.StandardTestDispatcher
-import kotlinx.coroutines.test.TestScope
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.Mock
-import org.mockito.Mockito.never
-import org.mockito.Mockito.reset
-import org.mockito.Mockito.verify
 import org.mockito.MockitoAnnotations
 
+@ExperimentalCoroutinesApi
 @SmallTest
 @RunWith(AndroidJUnit4::class)
 class KeyguardBlueprintInteractorTest : SysuiTestCase() {
-    private val configurationFlow = MutableSharedFlow<Unit>(extraBufferCapacity = 1)
-    private lateinit var underTest: KeyguardBlueprintInteractor
-    private lateinit var testScope: TestScope
+    private val kosmos = testKosmos()
+    private val testScope = kosmos.testScope
+    private val underTest by lazy { kosmos.keyguardBlueprintInteractor }
+    private val clockRepository by lazy { kosmos.fakeKeyguardClockRepository }
+    private val configurationRepository by lazy { kosmos.fakeConfigurationRepository }
+    private val fingerprintPropertyRepository by lazy { kosmos.fakeFingerprintPropertyRepository }
 
-    val refreshTransition: MutableSharedFlow<IntraBlueprintTransition.Config> =
-        MutableSharedFlow(extraBufferCapacity = 1)
-
-    @Mock private lateinit var splitShadeStateController: SplitShadeStateController
-    @Mock private lateinit var keyguardBlueprintRepository: KeyguardBlueprintRepository
-    @Mock private lateinit var clockInteractor: KeyguardClockInteractor
     @Mock private lateinit var clockController: ClockController
 
     @Before
     fun setup() {
         MockitoAnnotations.initMocks(this)
-        testScope = TestScope(StandardTestDispatcher())
-        whenever(keyguardBlueprintRepository.configurationChange).thenReturn(configurationFlow)
-        whenever(keyguardBlueprintRepository.refreshTransition).thenReturn(refreshTransition)
-        whenever(clockInteractor.currentClock).thenReturn(MutableStateFlow(clockController))
-        clockInteractor.currentClock
-
-        underTest =
-            KeyguardBlueprintInteractor(
-                keyguardBlueprintRepository,
-                testScope.backgroundScope,
-                mContext,
-                splitShadeStateController,
-                clockInteractor,
-            )
     }
 
     @Test
     fun testAppliesDefaultBlueprint() {
         testScope.runTest {
-            whenever(splitShadeStateController.shouldUseSplitNotificationShade(any()))
-                .thenReturn(false)
-
-            reset(keyguardBlueprintRepository)
-            configurationFlow.tryEmit(Unit)
+            val blueprint by collectLastValue(underTest.blueprint)
+            overrideResource(R.bool.config_use_split_notification_shade, false)
+            configurationRepository.onConfigurationChange()
             runCurrent()
 
-            verify(keyguardBlueprintRepository)
-                .applyBlueprint(DefaultKeyguardBlueprint.Companion.DEFAULT)
+            assertThat(blueprint?.id).isEqualTo(DefaultKeyguardBlueprint.Companion.DEFAULT)
         }
     }
 
     @Test
     fun testAppliesSplitShadeBlueprint() {
         testScope.runTest {
-            whenever(splitShadeStateController.shouldUseSplitNotificationShade(any()))
-                .thenReturn(true)
-
-            reset(keyguardBlueprintRepository)
-            configurationFlow.tryEmit(Unit)
+            val blueprint by collectLastValue(underTest.blueprint)
+            overrideResource(R.bool.config_use_split_notification_shade, true)
+            configurationRepository.onConfigurationChange()
             runCurrent()
 
-            verify(keyguardBlueprintRepository)
-                .applyBlueprint(SplitShadeKeyguardBlueprint.Companion.ID)
+            assertThat(blueprint?.id).isEqualTo(SplitShadeKeyguardBlueprint.Companion.ID)
+        }
+    }
+
+    @Test
+    fun fingerprintPropertyInitialized_updatesBlueprint() {
+        testScope.runTest {
+            val blueprint by collectLastValue(underTest.blueprint)
+            overrideResource(R.bool.config_use_split_notification_shade, true)
+            fingerprintPropertyRepository.supportsUdfps() // initialize properties
+            runCurrent()
+            assertThat(blueprint?.id).isEqualTo(SplitShadeKeyguardBlueprint.Companion.ID)
         }
     }
 
@@ -117,6 +102,7 @@
     fun composeLockscreenOff_DoesAppliesSplitShadeWeatherClockBlueprint() {
         testScope.runTest {
             mSetFlagsRule.disableFlags(Flags.FLAG_COMPOSE_LOCKSCREEN)
+            val blueprint by collectLastValue(underTest.blueprint)
             whenever(clockController.config)
                 .thenReturn(
                     ClockConfig(
@@ -125,15 +111,12 @@
                         description = "clock",
                     )
                 )
-            whenever(splitShadeStateController.shouldUseSplitNotificationShade(any()))
-                .thenReturn(true)
-
-            reset(keyguardBlueprintRepository)
-            configurationFlow.tryEmit(Unit)
+            clockRepository.setCurrentClock(clockController)
+            overrideResource(R.bool.config_use_split_notification_shade, true)
+            configurationRepository.onConfigurationChange()
             runCurrent()
 
-            verify(keyguardBlueprintRepository, never())
-                .applyBlueprint(SPLIT_SHADE_WEATHER_CLOCK_BLUEPRINT_ID)
+            assertThat(blueprint?.id).isNotEqualTo(SPLIT_SHADE_WEATHER_CLOCK_BLUEPRINT_ID)
         }
     }
 
@@ -141,6 +124,7 @@
     fun testDoesAppliesSplitShadeWeatherClockBlueprint() {
         testScope.runTest {
             mSetFlagsRule.enableFlags(Flags.FLAG_COMPOSE_LOCKSCREEN)
+            val blueprint by collectLastValue(underTest.blueprint)
             whenever(clockController.config)
                 .thenReturn(
                     ClockConfig(
@@ -149,15 +133,12 @@
                         description = "clock",
                     )
                 )
-            whenever(splitShadeStateController.shouldUseSplitNotificationShade(any()))
-                .thenReturn(true)
-
-            reset(keyguardBlueprintRepository)
-            configurationFlow.tryEmit(Unit)
+            clockRepository.setCurrentClock(clockController)
+            overrideResource(R.bool.config_use_split_notification_shade, true)
+            configurationRepository.onConfigurationChange()
             runCurrent()
 
-            verify(keyguardBlueprintRepository)
-                .applyBlueprint(SPLIT_SHADE_WEATHER_CLOCK_BLUEPRINT_ID)
+            assertThat(blueprint?.id).isEqualTo(SPLIT_SHADE_WEATHER_CLOCK_BLUEPRINT_ID)
         }
     }
 
@@ -165,6 +146,7 @@
     fun testAppliesWeatherClockBlueprint() {
         testScope.runTest {
             mSetFlagsRule.enableFlags(Flags.FLAG_COMPOSE_LOCKSCREEN)
+            val blueprint by collectLastValue(underTest.blueprint)
             whenever(clockController.config)
                 .thenReturn(
                     ClockConfig(
@@ -173,33 +155,12 @@
                         description = "clock",
                     )
                 )
-            whenever(splitShadeStateController.shouldUseSplitNotificationShade(any()))
-                .thenReturn(false)
-
-            reset(keyguardBlueprintRepository)
-            configurationFlow.tryEmit(Unit)
+            clockRepository.setCurrentClock(clockController)
+            overrideResource(R.bool.config_use_split_notification_shade, false)
+            configurationRepository.onConfigurationChange()
             runCurrent()
 
-            verify(keyguardBlueprintRepository).applyBlueprint(WEATHER_CLOCK_BLUEPRINT_ID)
+            assertThat(blueprint?.id).isEqualTo(WEATHER_CLOCK_BLUEPRINT_ID)
         }
     }
-
-    @Test
-    fun testRefreshBlueprint() {
-        underTest.refreshBlueprint()
-        verify(keyguardBlueprintRepository).refreshBlueprint()
-    }
-
-    @Test
-    fun testTransitionToBlueprint() {
-        underTest.transitionToBlueprint("abc")
-        verify(keyguardBlueprintRepository).applyBlueprint("abc")
-    }
-
-    @Test
-    fun testRefreshBlueprintWithTransition() {
-        underTest.refreshBlueprint(Type.DefaultTransition)
-        verify(keyguardBlueprintRepository)
-            .refreshBlueprint(Config(Type.DefaultTransition, true, true))
-    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySectionTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySectionTest.kt
index 699284e..09c56b0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySectionTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySectionTest.kt
@@ -22,7 +22,6 @@
 import androidx.constraintlayout.widget.ConstraintLayout
 import androidx.constraintlayout.widget.ConstraintSet
 import androidx.test.filters.SmallTest
-import com.android.keyguard.KeyguardUpdateMonitor
 import com.android.keyguard.LockIconViewController
 import com.android.systemui.Flags as AConfigFlags
 import com.android.systemui.SysuiTestCase
@@ -37,8 +36,10 @@
 import com.android.systemui.res.R
 import com.android.systemui.shade.NotificationPanelView
 import com.android.systemui.statusbar.VibratorHelper
+import com.android.systemui.util.mockito.whenever
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.test.TestScope
 import org.junit.Before
 import org.junit.Test
@@ -53,13 +54,13 @@
 @RunWith(JUnit4::class)
 @SmallTest
 class DefaultDeviceEntrySectionTest : SysuiTestCase() {
-    @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
     @Mock private lateinit var authController: AuthController
     @Mock(answer = Answers.RETURNS_DEEP_STUBS) private lateinit var windowManager: WindowManager
     @Mock private lateinit var notificationPanelView: NotificationPanelView
     private lateinit var featureFlags: FakeFeatureFlags
     @Mock private lateinit var lockIconViewController: LockIconViewController
     @Mock private lateinit var falsingManager: FalsingManager
+    @Mock private lateinit var deviceEntryIconViewModel: DeviceEntryIconViewModel
     private lateinit var underTest: DefaultDeviceEntrySection
 
     @Before
@@ -73,14 +74,13 @@
         underTest =
             DefaultDeviceEntrySection(
                 TestScope().backgroundScope,
-                keyguardUpdateMonitor,
                 authController,
                 windowManager,
                 context,
                 notificationPanelView,
                 featureFlags,
                 { lockIconViewController },
-                { mock(DeviceEntryIconViewModel::class.java) },
+                { deviceEntryIconViewModel },
                 { mock(DeviceEntryForegroundViewModel::class.java) },
                 { mock(DeviceEntryBackgroundViewModel::class.java) },
                 { falsingManager },
@@ -129,6 +129,7 @@
     @Test
     fun applyConstraints_udfps_refactor_on() {
         mSetFlagsRule.enableFlags(AConfigFlags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR)
+        whenever(deviceEntryIconViewModel.isUdfpsSupported).thenReturn(MutableStateFlow(false))
         val cs = ConstraintSet()
         underTest.applyConstraints(cs)
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/recordissue/RecordIssueDialogDelegateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/recordissue/RecordIssueDialogDelegateTest.kt
index ada93db..2e8160b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/recordissue/RecordIssueDialogDelegateTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/recordissue/RecordIssueDialogDelegateTest.kt
@@ -37,7 +37,6 @@
 import com.android.systemui.model.SysUiState
 import com.android.systemui.qs.tiles.RecordIssueTile
 import com.android.systemui.res.R
-import com.android.systemui.settings.UserContextProvider
 import com.android.systemui.settings.UserFileManager
 import com.android.systemui.settings.UserTracker
 import com.android.systemui.statusbar.phone.SystemUIDialog
@@ -71,12 +70,11 @@
     @Mock private lateinit var devicePolicyResolver: ScreenCaptureDevicePolicyResolver
     @Mock private lateinit var dprLazy: dagger.Lazy<ScreenCaptureDevicePolicyResolver>
     @Mock private lateinit var mediaProjectionMetricsLogger: MediaProjectionMetricsLogger
-    @Mock private lateinit var userContextProvider: UserContextProvider
     @Mock private lateinit var userTracker: UserTracker
     @Mock private lateinit var userFileManager: UserFileManager
     @Mock private lateinit var sharedPreferences: SharedPreferences
-    @Mock private lateinit var screenCaptureDisabledDialogDelegate:
-            ScreenCaptureDisabledDialogDelegate
+    @Mock
+    private lateinit var screenCaptureDisabledDialogDelegate: ScreenCaptureDisabledDialogDelegate
     @Mock private lateinit var screenCaptureDisabledDialog: SystemUIDialog
 
     @Mock private lateinit var sysuiState: SysUiState
@@ -96,9 +94,8 @@
         MockitoAnnotations.initMocks(this)
         whenever(dprLazy.get()).thenReturn(devicePolicyResolver)
         whenever(sysuiState.setFlag(anyInt(), anyBoolean())).thenReturn(sysuiState)
-        whenever(userContextProvider.userContext).thenReturn(mContext)
         whenever(screenCaptureDisabledDialogDelegate.createDialog())
-                .thenReturn(screenCaptureDisabledDialog)
+            .thenReturn(screenCaptureDisabledDialog)
         whenever(
                 userFileManager.getSharedPreferences(
                     eq(RecordIssueTile.TILE_SPEC),
@@ -123,7 +120,6 @@
         dialog =
             RecordIssueDialogDelegate(
                     factory,
-                    userContextProvider,
                     userTracker,
                     flags,
                     bgExecutor,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
index cdff4d1..43fcdf3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
@@ -38,6 +38,7 @@
 import static org.mockito.Mockito.when;
 
 import static kotlinx.coroutines.flow.FlowKt.emptyFlow;
+import static kotlinx.coroutines.flow.StateFlowKt.MutableStateFlow;
 
 import android.annotation.IdRes;
 import android.content.ContentResolver;
@@ -213,7 +214,6 @@
 import java.util.Optional;
 
 import kotlinx.coroutines.CoroutineDispatcher;
-import kotlinx.coroutines.flow.StateFlowKt;
 import kotlinx.coroutines.test.TestScope;
 
 public class NotificationPanelViewControllerBaseTest extends SysuiTestCase {
@@ -409,10 +409,10 @@
                 new ShadeAnimationRepository(), mShadeRepository);
         mPowerInteractor = keyguardInteractorDeps.getPowerInteractor();
         when(mKeyguardTransitionInteractor.isInTransitionToStateWhere(any())).thenReturn(
-                StateFlowKt.MutableStateFlow(false));
+                MutableStateFlow(false));
         DeviceEntryUdfpsInteractor deviceEntryUdfpsInteractor =
                 mock(DeviceEntryUdfpsInteractor.class);
-        when(deviceEntryUdfpsInteractor.isUdfpsSupported()).thenReturn(emptyFlow());
+        when(deviceEntryUdfpsInteractor.isUdfpsSupported()).thenReturn(MutableStateFlow(false));
 
         mShadeInteractor = new ShadeInteractorImpl(
                 mTestScope.getBackgroundScope(),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
index 3808d30..c31c625 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
@@ -36,7 +36,7 @@
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 
-import static kotlinx.coroutines.flow.FlowKt.emptyFlow;
+import static kotlinx.coroutines.flow.StateFlowKt.MutableStateFlow;
 
 import android.app.IActivityManager;
 import android.content.pm.ActivityInfo;
@@ -205,7 +205,7 @@
 
         DeviceEntryUdfpsInteractor deviceEntryUdfpsInteractor =
                 mock(DeviceEntryUdfpsInteractor.class);
-        when(deviceEntryUdfpsInteractor.isUdfpsSupported()).thenReturn(emptyFlow());
+        when(deviceEntryUdfpsInteractor.isUdfpsSupported()).thenReturn(MutableStateFlow(false));
 
         mShadeInteractor = new ShadeInteractorImpl(
                 mTestScope.getBackgroundScope(),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerImplBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerImplBaseTest.java
index 4809a47..a077164 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerImplBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerImplBaseTest.java
@@ -22,7 +22,7 @@
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
-import static kotlinx.coroutines.flow.FlowKt.emptyFlow;
+import static kotlinx.coroutines.flow.StateFlowKt.MutableStateFlow;
 import static kotlinx.coroutines.test.TestCoroutineDispatchersKt.StandardTestDispatcher;
 
 import android.content.res.Resources;
@@ -234,7 +234,8 @@
 
         DeviceEntryUdfpsInteractor deviceEntryUdfpsInteractor =
                 mock(DeviceEntryUdfpsInteractor.class);
-        when(deviceEntryUdfpsInteractor.isUdfpsSupported()).thenReturn(emptyFlow());
+        when(deviceEntryUdfpsInteractor.isUdfpsSupported()).thenReturn(
+                MutableStateFlow(false));
 
         mShadeInteractor = new ShadeInteractorImpl(
                 mTestScope.getBackgroundScope(),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
index 86116a0..d35c7dd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
@@ -9,6 +9,7 @@
 import com.android.systemui.SysUITestModule
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.TestMocksModule
+import com.android.systemui.biometrics.domain.BiometricsDomainLayerModule
 import com.android.systemui.classifier.FalsingCollectorFake
 import com.android.systemui.classifier.FalsingManagerFake
 import com.android.systemui.dagger.SysUISingleton
@@ -35,6 +36,8 @@
 import com.android.systemui.statusbar.policy.FakeConfigurationController
 import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController
 import com.android.systemui.user.domain.UserDomainLayerModule
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.argumentCaptor
 import com.android.systemui.util.mockito.mock
 import dagger.BindsInstance
 import dagger.Component
@@ -55,6 +58,7 @@
 import org.mockito.ArgumentMatchers.anyInt
 import org.mockito.ArgumentMatchers.anyLong
 import org.mockito.ArgumentMatchers.eq
+import org.mockito.ArgumentMatchers.isNull
 import org.mockito.Mock
 import org.mockito.Mockito
 import org.mockito.Mockito.clearInvocations
@@ -310,6 +314,17 @@
     }
 
     @Test
+    fun testGoToLockedShadeCancelDoesntLeaveShadeOpenOnKeyguardHide() {
+        whenever(lockScreenUserManager.shouldShowLockscreenNotifications()).thenReturn(false)
+        whenever(lockScreenUserManager.isLockscreenPublicMode(any())).thenReturn(true)
+        transitionController.goToLockedShade(null)
+        val captor = argumentCaptor<Runnable>()
+        verify(centralSurfaces).showBouncerWithDimissAndCancelIfKeyguard(isNull(), captor.capture())
+        captor.value.run()
+        verify(statusbarStateController).setLeaveOpenOnKeyguardHide(false)
+    }
+
+    @Test
     fun testDragDownAmountDoesntCallOutInLockedDownShade() {
         whenever(nsslController.isInLockedDownShade).thenReturn(true)
         transitionController.dragDownAmount = 10f
@@ -611,6 +626,7 @@
             [
                 SysUITestModule::class,
                 UserDomainLayerModule::class,
+                BiometricsDomainLayerModule::class,
             ]
     )
     interface TestComponent {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
index dfbb6ea..103dcb7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
@@ -54,6 +54,7 @@
 import com.android.systemui.power.domain.interactor.PowerInteractor
 import com.android.systemui.scene.domain.interactor.sceneInteractor
 import com.android.systemui.scene.shared.flag.FakeSceneContainerFlags
+import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.shade.LargeScreenHeaderHelper
 import com.android.systemui.shade.data.repository.FakeShadeRepository
 import com.android.systemui.shade.domain.interactor.ShadeInteractor
@@ -69,7 +70,7 @@
 import com.android.systemui.util.mockito.mock
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.flow.emptyFlow
+import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
 import org.junit.Assert.assertEquals
@@ -85,9 +86,8 @@
 import org.mockito.Mockito
 import org.mockito.Mockito.mock
 import org.mockito.Mockito.verify
-import org.mockito.Mockito.`when` as whenever
-import com.android.systemui.scene.shared.model.Scenes
 import org.mockito.MockitoAnnotations
+import org.mockito.Mockito.`when` as whenever
 
 @SmallTest
 @RunWith(AndroidTestingRunner::class)
@@ -155,7 +155,7 @@
                 { kosmos.sceneInteractor },
             )
 
-        whenever(deviceEntryUdfpsInteractor.isUdfpsSupported).thenReturn(emptyFlow())
+        whenever(deviceEntryUdfpsInteractor.isUdfpsSupported).thenReturn(MutableStateFlow(false))
         shadeInteractor =
             ShadeInteractorImpl(
                 testScope.backgroundScope,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
index 84156ee1..c8c54dbd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
@@ -859,6 +859,29 @@
     }
 
     @Test
+    public void testEnteringGlanceableHub_whenDreaming_updatesScrim() {
+        when(mKeyguardStateController.isShowing()).thenReturn(true);
+        when(mKeyguardStateController.isOccluded()).thenReturn(true);
+        when(mKeyguardUpdateMonitor.isDreaming()).thenReturn(true);
+
+        // Transition to the glanceable hub.
+        mCommunalRepository.setTransitionState(flowOf(new ObservableTransitionState.Idle(
+                CommunalScenes.Communal)));
+        mTestScope.getTestScheduler().runCurrent();
+
+        // ScrimState also transitions.
+        verify(mScrimController).transitionTo(ScrimState.GLANCEABLE_HUB_OVER_DREAM);
+
+        // Transition away from the glanceable hub.
+        mCommunalRepository.setTransitionState(flowOf(new ObservableTransitionState.Idle(
+                CommunalScenes.Blank)));
+        mTestScope.getTestScheduler().runCurrent();
+
+        // ScrimState goes back to UNLOCKED.
+        verify(mScrimController).transitionTo(eq(ScrimState.DREAMING));
+    }
+
+    @Test
     public void testShowKeyguardImplementation_setsState() {
         when(mLockscreenUserManager.getCurrentProfiles()).thenReturn(new SparseArray<>());
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index 99c2dc7..cdbbc93 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -794,6 +794,73 @@
     }
 
     @Test
+    public void transitionToHubOverDream() {
+        mScrimController.setRawPanelExpansionFraction(0f);
+        mScrimController.setBouncerHiddenFraction(KeyguardBouncerConstants.EXPANSION_HIDDEN);
+        mScrimController.transitionTo(ScrimState.GLANCEABLE_HUB_OVER_DREAM);
+        finishAnimationsImmediately();
+
+        // All scrims transparent on the hub.
+        assertScrimAlpha(Map.of(
+                mScrimInFront, TRANSPARENT,
+                mNotificationsScrim, TRANSPARENT,
+                mScrimBehind, TRANSPARENT));
+    }
+
+    @Test
+    public void openBouncerOnHubOverDream() {
+        mScrimController.transitionTo(ScrimState.GLANCEABLE_HUB_OVER_DREAM);
+
+        // Open the bouncer.
+        mScrimController.setRawPanelExpansionFraction(0f);
+        mScrimController.setBouncerHiddenFraction(KeyguardBouncerConstants.EXPANSION_VISIBLE);
+        finishAnimationsImmediately();
+
+        // Only behind widget is visible.
+        assertScrimAlpha(Map.of(
+                mScrimInFront, TRANSPARENT,
+                mNotificationsScrim, TRANSPARENT,
+                mScrimBehind, OPAQUE));
+
+        // Bouncer is closed.
+        mScrimController.setBouncerHiddenFraction(KeyguardBouncerConstants.EXPANSION_HIDDEN);
+        mScrimController.transitionTo(ScrimState.GLANCEABLE_HUB_OVER_DREAM);
+        finishAnimationsImmediately();
+
+        // All scrims are transparent.
+        assertScrimAlpha(Map.of(
+                mScrimInFront, TRANSPARENT,
+                mNotificationsScrim, TRANSPARENT,
+                mScrimBehind, TRANSPARENT));
+    }
+
+    @Test
+    public void openShadeOnHubOverDream() {
+        mScrimController.transitionTo(ScrimState.GLANCEABLE_HUB_OVER_DREAM);
+
+        // Open the shade.
+        mScrimController.transitionTo(SHADE_LOCKED);
+        mScrimController.setQsPosition(1f, 0);
+        mScrimController.setRawPanelExpansionFraction(1f);
+        finishAnimationsImmediately();
+
+        // Shade scrims are visible.
+        assertScrimAlpha(Map.of(
+                mNotificationsScrim, OPAQUE,
+                mScrimInFront, TRANSPARENT,
+                mScrimBehind, OPAQUE));
+
+        mScrimController.transitionTo(ScrimState.GLANCEABLE_HUB_OVER_DREAM);
+        finishAnimationsImmediately();
+
+        // All scrims are transparent.
+        assertScrimAlpha(Map.of(
+                mScrimInFront, TRANSPARENT,
+                mNotificationsScrim, TRANSPARENT,
+                mScrimBehind, TRANSPARENT));
+    }
+
+    @Test
     public void onThemeChange_bouncerBehindTint_isUpdatedToSurfaceColor() {
         assertEquals(BOUNCER.getBehindTint(), 0x112233);
         mSurfaceColor = 0x223344;
@@ -1432,7 +1499,8 @@
                 ScrimState.UNINITIALIZED, ScrimState.KEYGUARD, BOUNCER,
                 ScrimState.DREAMING, ScrimState.BOUNCER_SCRIMMED, ScrimState.BRIGHTNESS_MIRROR,
                 ScrimState.UNLOCKED, SHADE_LOCKED, ScrimState.AUTH_SCRIMMED,
-                ScrimState.AUTH_SCRIMMED_SHADE, ScrimState.GLANCEABLE_HUB));
+                ScrimState.AUTH_SCRIMMED_SHADE, ScrimState.GLANCEABLE_HUB,
+                ScrimState.GLANCEABLE_HUB_OVER_DREAM));
 
         for (ScrimState state : ScrimState.values()) {
             if (!lowPowerModeStates.contains(state) && !regularStates.contains(state)) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
index c0d3d27..19f31d5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -50,7 +50,7 @@
 import static org.mockito.Mockito.verifyZeroInteractions;
 import static org.mockito.Mockito.when;
 
-import static kotlinx.coroutines.flow.FlowKt.emptyFlow;
+import static kotlinx.coroutines.flow.StateFlowKt.MutableStateFlow;
 
 import android.app.ActivityManager;
 import android.app.IActivityManager;
@@ -452,7 +452,7 @@
 
         DeviceEntryUdfpsInteractor deviceEntryUdfpsInteractor =
                 mock(DeviceEntryUdfpsInteractor.class);
-        when(deviceEntryUdfpsInteractor.isUdfpsSupported()).thenReturn(emptyFlow());
+        when(deviceEntryUdfpsInteractor.isUdfpsSupported()).thenReturn(MutableStateFlow(false));
 
         mShadeInteractor =
                 new ShadeInteractorImpl(
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeDisplayStateRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeDisplayStateRepository.kt
index 1b951d9..9765d53 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeDisplayStateRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeDisplayStateRepository.kt
@@ -19,12 +19,17 @@
 
 import android.util.Size
 import com.android.systemui.biometrics.shared.model.DisplayRotation
+import com.android.systemui.dagger.SysUISingleton
+import dagger.Binds
+import dagger.Module
+import javax.inject.Inject
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.asStateFlow
 
-class FakeDisplayStateRepository : DisplayStateRepository {
+@SysUISingleton
+class FakeDisplayStateRepository @Inject constructor() : DisplayStateRepository {
     private val _isInRearDisplayMode = MutableStateFlow<Boolean>(false)
     override val isInRearDisplayMode: StateFlow<Boolean> = _isInRearDisplayMode.asStateFlow()
 
@@ -51,3 +56,8 @@
         _currentDisplaySize.value = size
     }
 }
+
+@Module
+interface FakeDisplayStateRepositoryModule {
+    @Binds fun bindFake(fake: FakeDisplayStateRepository): DisplayStateRepository
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeFingerprintPropertyRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeFingerprintPropertyRepository.kt
index 005cac4..bd30fb4 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeFingerprintPropertyRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeFingerprintPropertyRepository.kt
@@ -28,6 +28,7 @@
 
 @SysUISingleton
 class FakeFingerprintPropertyRepository @Inject constructor() : FingerprintPropertyRepository {
+    override val propertiesInitialized: MutableStateFlow<Boolean> = MutableStateFlow(false)
 
     private val _sensorId: MutableStateFlow<Int> = MutableStateFlow(-1)
     override val sensorId = _sensorId.asStateFlow()
@@ -54,6 +55,7 @@
         _strength.value = strength
         _sensorType.value = sensorType
         _sensorLocations.value = sensorLocations
+        propertiesInitialized.value = true
     }
 
     /** setProperties as if the device supports UDFPS_OPTICAL. */
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractorKosmos.kt
index e262066..34a9c8a 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractorKosmos.kt
@@ -21,9 +21,11 @@
 import com.android.systemui.common.ui.domain.interactor.configurationInteractor
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.kosmos.applicationCoroutineScope
 
 val Kosmos.fingerprintPropertyInteractor by Fixture {
     FingerprintPropertyInteractor(
+        applicationScope = applicationCoroutineScope,
         context = applicationContext,
         repository = fingerprintPropertyRepository,
         configurationInteractor = configurationInteractor,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/data/FakeDeviceEntryDataLayerModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/data/FakeDeviceEntryDataLayerModule.kt
index 8ff04a63..1c8190e 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/data/FakeDeviceEntryDataLayerModule.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/data/FakeDeviceEntryDataLayerModule.kt
@@ -15,8 +15,10 @@
 
 package com.android.systemui.deviceentry.data
 
+import com.android.systemui.biometrics.data.repository.FakeDisplayStateRepositoryModule
 import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepositoryModule
 import com.android.systemui.deviceentry.data.repository.FakeDeviceEntryRepositoryModule
+import com.android.systemui.display.data.repository.FakeDisplayRepositoryModule
 import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepositoryModule
 import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFaceAuthRepositoryModule
 import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepositoryModule
@@ -30,6 +32,8 @@
             FakeDeviceEntryRepositoryModule::class,
             FakeDeviceEntryFaceAuthRepositoryModule::class,
             FakeDeviceEntryFingerprintAuthRepositoryModule::class,
+            FakeDisplayRepositoryModule::class,
+            FakeDisplayStateRepositoryModule::class,
             FakeFingerprintPropertyRepositoryModule::class,
             FakeTrustRepositoryModule::class,
         ]
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryUdfpsInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryUdfpsInteractorKosmos.kt
index b04161a..81123d0 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryUdfpsInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryUdfpsInteractorKosmos.kt
@@ -18,7 +18,7 @@
 
 package com.android.systemui.deviceentry.domain.interactor
 
-import com.android.systemui.biometrics.data.repository.fingerprintPropertyRepository
+import com.android.systemui.biometrics.domain.interactor.fingerprintPropertyInteractor
 import com.android.systemui.keyguard.data.repository.biometricSettingsRepository
 import com.android.systemui.keyguard.data.repository.deviceEntryFingerprintAuthRepository
 import com.android.systemui.kosmos.Kosmos
@@ -27,7 +27,7 @@
 
 val Kosmos.deviceEntryUdfpsInteractor by Fixture {
     DeviceEntryUdfpsInteractor(
-        fingerprintPropertyRepository = fingerprintPropertyRepository,
+        fingerprintPropertyInteractor = fingerprintPropertyInteractor,
         fingerprintAuthRepository = deviceEntryFingerprintAuthRepository,
         biometricSettingsRepository = biometricSettingsRepository,
     )
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/FakeDisplayRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/FakeDisplayRepository.kt
index d8098b7..0fc0a3c 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/FakeDisplayRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/FakeDisplayRepository.kt
@@ -16,7 +16,11 @@
 package com.android.systemui.display.data.repository
 
 import android.view.Display
+import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.util.mockito.mock
+import dagger.Binds
+import dagger.Module
+import javax.inject.Inject
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.MutableSharedFlow
 import org.mockito.Mockito.`when` as whenever
@@ -42,8 +46,9 @@
 fun createPendingDisplay(id: Int = 0): DisplayRepository.PendingDisplay =
     mock<DisplayRepository.PendingDisplay> { whenever(this.id).thenReturn(id) }
 
+@SysUISingleton
 /** Fake [DisplayRepository] implementation for testing. */
-class FakeDisplayRepository : DisplayRepository {
+class FakeDisplayRepository @Inject constructor() : DisplayRepository {
     private val flow = MutableSharedFlow<Set<Display>>(replay = 1)
     private val pendingDisplayFlow =
         MutableSharedFlow<DisplayRepository.PendingDisplay?>(replay = 1)
@@ -71,3 +76,8 @@
     override val displayChangeEvent: Flow<Int> = _displayChangeEvent
     suspend fun emitDisplayChangeEvent(displayId: Int) = _displayChangeEvent.emit(displayId)
 }
+
+@Module
+interface FakeDisplayRepositoryModule {
+    @Binds fun bindFake(fake: FakeDisplayRepository): DisplayRepository
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardClockRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardClockRepository.kt
index 592fa38..5b642ea 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardClockRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardClockRepository.kt
@@ -42,7 +42,7 @@
     private val _currentClockId = MutableStateFlow(DEFAULT_CLOCK_ID)
     override val currentClockId: Flow<ClockId> = _currentClockId
 
-    private val _currentClock = MutableStateFlow(null)
+    private val _currentClock: MutableStateFlow<ClockController?> = MutableStateFlow(null)
     override val currentClock = _currentClock
 
     private val _previewClockPair =
@@ -60,6 +60,10 @@
     override fun setClockSize(@ClockSize size: Int) {
         _clockSize.value = size
     }
+
+    fun setCurrentClock(clockController: ClockController) {
+        _currentClock.value = clockController
+    }
 }
 
 @Module
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepositoryKosmos.kt
index 8452963..75489b6 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepositoryKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepositoryKosmos.kt
@@ -17,10 +17,12 @@
 package com.android.systemui.keyguard.data.repository
 
 import android.os.fakeExecutorHandler
-import com.android.systemui.common.ui.data.repository.configurationRepository
+import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor.Companion.SPLIT_SHADE_WEATHER_CLOCK_BLUEPRINT_ID
+import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor.Companion.WEATHER_CLOCK_BLUEPRINT_ID
 import com.android.systemui.keyguard.shared.model.KeyguardBlueprint
 import com.android.systemui.keyguard.shared.model.KeyguardSection
 import com.android.systemui.keyguard.ui.view.layout.blueprints.DefaultKeyguardBlueprint.Companion.DEFAULT
+import com.android.systemui.keyguard.ui.view.layout.blueprints.SplitShadeKeyguardBlueprint
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.util.ThreadAssert
 import com.android.systemui.util.mockito.mock
@@ -28,8 +30,13 @@
 val Kosmos.keyguardBlueprintRepository by
     Kosmos.Fixture {
         KeyguardBlueprintRepository(
-            configurationRepository = configurationRepository,
-            blueprints = setOf(defaultBlueprint),
+            blueprints =
+                setOf(
+                    defaultBlueprint,
+                    splitShadeBlueprint,
+                    weatherClockBlueprint,
+                    splitShadeWeatherClockBlueprint,
+                ),
             handler = fakeExecutorHandler,
             assert = mock<ThreadAssert>(),
         )
@@ -42,3 +49,27 @@
         override val sections: List<KeyguardSection>
             get() = listOf()
     }
+
+private val weatherClockBlueprint =
+    object : KeyguardBlueprint {
+        override val id: String
+            get() = WEATHER_CLOCK_BLUEPRINT_ID
+        override val sections: List<KeyguardSection>
+            get() = listOf()
+    }
+
+private val splitShadeWeatherClockBlueprint =
+    object : KeyguardBlueprint {
+        override val id: String
+            get() = SPLIT_SHADE_WEATHER_CLOCK_BLUEPRINT_ID
+        override val sections: List<KeyguardSection>
+            get() = listOf()
+    }
+
+private val splitShadeBlueprint =
+    object : KeyguardBlueprint {
+        override val id: String
+            get() = SplitShadeKeyguardBlueprint.Companion.ID
+        override val sections: List<KeyguardSection>
+            get() = listOf()
+    }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorKosmos.kt
index 8b0bba1..87d6c17 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorKosmos.kt
@@ -17,6 +17,8 @@
 package com.android.systemui.keyguard.domain.interactor
 
 import android.content.applicationContext
+import com.android.systemui.biometrics.domain.interactor.fingerprintPropertyInteractor
+import com.android.systemui.common.ui.domain.interactor.configurationInteractor
 import com.android.systemui.keyguard.data.repository.keyguardBlueprintRepository
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.kosmos.applicationCoroutineScope
@@ -30,5 +32,7 @@
             context = applicationContext,
             splitShadeStateController = splitShadeStateController,
             clockInteractor = keyguardClockInteractor,
+            configurationInteractor = configurationInteractor,
+            fingerprintPropertyInteractor = fingerprintPropertyInteractor,
         )
     }
diff --git a/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java b/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java
index e0fe88a..10e6ed4 100644
--- a/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java
+++ b/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java
@@ -1566,6 +1566,10 @@
         private String mCameraId = null;
         private IBinder mToken;
 
+        OutputSurfaceImplStub mOutputPreviewSurfaceImpl;
+        OutputSurfaceImplStub mOutputImageCaptureSurfaceImpl;
+        OutputSurfaceImplStub mOutputPostviewSurfaceImpl;
+
         public SessionProcessorImplStub(SessionProcessorImpl sessionProcessor) {
             mSessionProcessor = sessionProcessor;
         }
@@ -1574,21 +1578,18 @@
         public CameraSessionConfig initSession(IBinder token, String cameraId,
                 Map<String, CameraMetadataNative> charsMapNative, OutputSurface previewSurface,
                 OutputSurface imageCaptureSurface, OutputSurface postviewSurface) {
-            OutputSurfaceImplStub outputPreviewSurfaceImpl =
-                    new OutputSurfaceImplStub(previewSurface);
-            OutputSurfaceImplStub outputImageCaptureSurfaceImpl =
-                    new OutputSurfaceImplStub(imageCaptureSurface);
-            OutputSurfaceImplStub outputPostviewSurfaceImpl =
-                    new OutputSurfaceImplStub(postviewSurface);
+            mOutputPreviewSurfaceImpl = new OutputSurfaceImplStub(previewSurface);
+            mOutputImageCaptureSurfaceImpl = new OutputSurfaceImplStub(imageCaptureSurface);
+            mOutputPostviewSurfaceImpl = new OutputSurfaceImplStub(postviewSurface);
 
             Camera2SessionConfigImpl sessionConfig;
 
             if (LATENCY_IMPROVEMENTS_SUPPORTED) {
                 OutputSurfaceConfigurationImplStub outputSurfaceConfigs =
-                        new OutputSurfaceConfigurationImplStub(outputPreviewSurfaceImpl,
+                        new OutputSurfaceConfigurationImplStub(mOutputPreviewSurfaceImpl,
                         // Image Analysis Output is currently only supported in CameraX
-                        outputImageCaptureSurfaceImpl, null /*imageAnalysisSurfaceConfig*/,
-                        outputPostviewSurfaceImpl);
+                        mOutputImageCaptureSurfaceImpl, null /*imageAnalysisSurfaceConfig*/,
+                        mOutputPostviewSurfaceImpl);
 
                 sessionConfig = mSessionProcessor.initSession(cameraId,
                         getCharacteristicsMap(charsMapNative),
@@ -1596,8 +1597,8 @@
             } else {
                 sessionConfig = mSessionProcessor.initSession(cameraId,
                         getCharacteristicsMap(charsMapNative),
-                        getApplicationContext(), outputPreviewSurfaceImpl,
-                        outputImageCaptureSurfaceImpl, null /*imageAnalysisSurfaceConfig*/);
+                        getApplicationContext(), mOutputPreviewSurfaceImpl,
+                        mOutputImageCaptureSurfaceImpl, null /*imageAnalysisSurfaceConfig*/);
             }
 
             List<Camera2OutputConfigImpl> outputConfigs = sessionConfig.getOutputConfigs();
@@ -1632,6 +1633,18 @@
         public void deInitSession(IBinder token) {
             CameraExtensionsProxyService.unregisterDeathRecipient(mToken, this);
             mSessionProcessor.deInitSession();
+
+            if (Flags.surfaceLeakFix()) {
+                if (mOutputImageCaptureSurfaceImpl.mSurface != null) {
+                    mOutputImageCaptureSurfaceImpl.mSurface.release();
+                }
+                if (mOutputPreviewSurfaceImpl.mSurface != null) {
+                    mOutputPreviewSurfaceImpl.mSurface.release();
+                }
+                if (mOutputPostviewSurfaceImpl.mSurface != null) {
+                    mOutputPostviewSurfaceImpl.mSurface.release();
+                }
+            }
         }
 
         @Override
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index cbb66dc..ff48c9d 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -40,6 +40,7 @@
 import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_COMPONENT_NAME;
 import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME;
 import static com.android.internal.accessibility.common.ShortcutConstants.CHOOSER_PACKAGE_NAME;
+import static com.android.internal.accessibility.common.ShortcutConstants.USER_SHORTCUT_TYPES;
 import static com.android.internal.accessibility.util.AccessibilityStatsLogUtils.logAccessibilityShortcutActivated;
 import static com.android.internal.util.FunctionalUtils.ignoreRemoteException;
 import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
@@ -111,6 +112,7 @@
 import android.safetycenter.SafetyCenterManager;
 import android.text.TextUtils;
 import android.text.TextUtils.SimpleStringSplitter;
+import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.IntArray;
 import android.util.Log;
@@ -145,9 +147,13 @@
 import com.android.internal.accessibility.AccessibilityShortcutController;
 import com.android.internal.accessibility.AccessibilityShortcutController.FrameworkFeatureInfo;
 import com.android.internal.accessibility.AccessibilityShortcutController.LaunchableFrameworkFeatureInfo;
+import com.android.internal.accessibility.common.ShortcutConstants;
+import com.android.internal.accessibility.common.ShortcutConstants.FloatingMenuSize;
+import com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType;
 import com.android.internal.accessibility.dialog.AccessibilityButtonChooserActivity;
 import com.android.internal.accessibility.dialog.AccessibilityShortcutChooserActivity;
 import com.android.internal.accessibility.util.AccessibilityUtils;
+import com.android.internal.accessibility.util.ShortcutUtils;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.content.PackageMonitor;
@@ -168,6 +174,7 @@
 import com.android.server.inputmethod.InputMethodManagerInternal;
 import com.android.server.pm.UserManagerInternal;
 import com.android.server.policy.WindowManagerPolicy;
+import com.android.server.statusbar.StatusBarManagerInternal;
 import com.android.server.utils.Slogf;
 import com.android.server.wm.ActivityTaskManagerInternal;
 import com.android.server.wm.WindowManagerInternal;
@@ -191,6 +198,7 @@
 import java.util.function.Consumer;
 import java.util.function.Function;
 import java.util.function.Predicate;
+import java.util.stream.Collectors;
 
 /**
  * This class is instantiated by the system as a system level service and can be
@@ -2334,6 +2342,7 @@
         if (!parsedAccessibilityServiceInfos.equals(userState.mInstalledServices)) {
             userState.mInstalledServices.clear();
             userState.mInstalledServices.addAll(parsedAccessibilityServiceInfos);
+            userState.updateTileServiceMapForAccessibilityServiceLocked();
             return true;
         }
         return false;
@@ -2359,6 +2368,7 @@
         if (!parsedAccessibilityShortcutInfos.equals(userState.mInstalledShortcuts)) {
             userState.mInstalledShortcuts.clear();
             userState.mInstalledShortcuts.addAll(parsedAccessibilityShortcutInfos);
+            userState.updateTileServiceMapForAccessibilityActivityLocked();
             return true;
         }
         return false;
@@ -2621,6 +2631,12 @@
 
     private <T> void persistColonDelimitedSetToSettingLocked(String settingName, int userId,
             Set<T> set, Function<T, String> toString) {
+        persistColonDelimitedSetToSettingLocked(settingName, userId, set,
+                toString, /* defaultEmptyString= */ null);
+    }
+
+    private <T> void persistColonDelimitedSetToSettingLocked(String settingName, int userId,
+            Set<T> set, Function<T, String> toString, String defaultEmptyString) {
         final StringBuilder builder = new StringBuilder();
         for (T item : set) {
             final String str = (item != null ? toString.apply(item) : null);
@@ -2636,7 +2652,18 @@
         try {
             final String settingValue = builder.toString();
             Settings.Secure.putStringForUser(mContext.getContentResolver(),
-                    settingName, TextUtils.isEmpty(settingValue) ? null : settingValue, userId);
+                    settingName,
+                    TextUtils.isEmpty(settingValue) ? defaultEmptyString : settingValue, userId);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    private void persistIntToSetting(int userId, String settingName, int settingValue) {
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            Settings.Secure.putIntForUser(
+                    mContext.getContentResolver(), settingName, settingValue, userId);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -3005,6 +3032,7 @@
         scheduleUpdateClientsIfNeededLocked(userState, forceUpdate);
         updateAccessibilityShortcutKeyTargetsLocked(userState);
         updateAccessibilityButtonTargetsLocked(userState);
+        updateAccessibilityQsTargetsLocked(userState);
         // Update the capabilities before the mode because we will check the current mode is
         // invalid or not..
         updateMagnificationCapabilitiesSettingsChangeLocked(userState);
@@ -3132,6 +3160,7 @@
         somethingChanged |= readMagnificationEnabledSettingsLocked(userState);
         somethingChanged |= readAutoclickEnabledSettingLocked(userState);
         somethingChanged |= readAccessibilityShortcutKeySettingLocked(userState);
+        somethingChanged |= readAccessibilityQsTargetsLocked(userState);
         somethingChanged |= readAccessibilityButtonTargetsLocked(userState);
         somethingChanged |= readAccessibilityButtonTargetComponentLocked(userState);
         somethingChanged |= readUserRecommendedUiTimeoutSettingsLocked(userState);
@@ -3305,6 +3334,21 @@
         return true;
     }
 
+    private boolean readAccessibilityQsTargetsLocked(AccessibilityUserState userState) {
+        final Set<String> targetsFromSetting = new ArraySet<>();
+        readColonDelimitedSettingToSet(Settings.Secure.ACCESSIBILITY_QS_TARGETS,
+                userState.mUserId, str -> str, targetsFromSetting);
+
+        final Set<String> currentTargets =
+                userState.getShortcutTargetsLocked(UserShortcutType.QUICK_SETTINGS);
+        if (targetsFromSetting.equals(currentTargets)) {
+            return false;
+        }
+        userState.updateA11yQsTargetLocked(targetsFromSetting);
+        scheduleNotifyClientsOfServicesStateChangeLocked(userState);
+        return true;
+    }
+
     private boolean readAccessibilityButtonTargetsLocked(AccessibilityUserState userState) {
         final Set<String> targetsFromSetting = new ArraySet<>();
         readColonDelimitedSettingToSet(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS,
@@ -3636,6 +3680,8 @@
 
         final Set<String> shortcutKeyTargets =
                 userState.getShortcutTargetsLocked(ACCESSIBILITY_SHORTCUT_KEY);
+        final Set<String> qsShortcutTargets =
+                userState.getShortcutTargetsLocked(UserShortcutType.QUICK_SETTINGS);
         userState.mEnabledServices.forEach(componentName -> {
             if (packageName != null && componentName != null
                     && !packageName.equals(componentName.getPackageName())) {
@@ -3657,7 +3703,8 @@
                 return;
             }
             if (doesShortcutTargetsStringContain(buttonTargets, serviceName)
-                    || doesShortcutTargetsStringContain(shortcutKeyTargets, serviceName)) {
+                    || doesShortcutTargetsStringContain(shortcutKeyTargets, serviceName)
+                    || doesShortcutTargetsStringContain(qsShortcutTargets, serviceName)) {
                 return;
             }
             // For enabled a11y services targeting sdk version > Q and requesting a11y button should
@@ -3678,6 +3725,33 @@
     }
 
     /**
+     * Update the Settings.Secure.ACCESSIBILITY_QS_TARGETS so that it only contains valid content,
+     * and a side loaded service can't spoof the package name of the default service.
+     */
+    private void updateAccessibilityQsTargetsLocked(AccessibilityUserState userState) {
+        final Set<String> targets =
+                userState.getShortcutTargetsLocked(UserShortcutType.QUICK_SETTINGS);
+        final int lastSize = targets.size();
+        if (lastSize == 0) {
+            return;
+        }
+
+        // Removes the targets that are no longer installed on the device.
+        boolean somethingChanged = targets.removeIf(
+                name -> !userState.isShortcutTargetInstalledLocked(name));
+        if (!somethingChanged) {
+            return;
+        }
+        userState.updateA11yQsTargetLocked(targets);
+
+        // Update setting key with new value.
+        persistColonDelimitedSetToSettingLocked(
+                Settings.Secure.ACCESSIBILITY_QS_TARGETS,
+                userState.mUserId, targets, str -> str);
+        scheduleNotifyClientsOfServicesStateChangeLocked(userState);
+    }
+
+    /**
      * Remove the shortcut target for the unbound service which is requesting accessibility button
      * and targeting sdk > Q from the accessibility button and shortcut.
      *
@@ -3691,19 +3765,42 @@
                 .targetSdkVersion <= Build.VERSION_CODES.Q) {
             return;
         }
+
+        final List<Pair<Integer, String>> shortcutTypeAndShortcutSetting = List.of(
+                new Pair<>(ACCESSIBILITY_SHORTCUT_KEY,
+                        Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE),
+                new Pair<>(ACCESSIBILITY_BUTTON,
+                        Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS),
+                new Pair<>(UserShortcutType.QUICK_SETTINGS,
+                        Settings.Secure.ACCESSIBILITY_QS_TARGETS)
+        );
+
         final ComponentName serviceName = service.getComponentName();
-        if (userState.removeShortcutTargetLocked(ACCESSIBILITY_SHORTCUT_KEY, serviceName)) {
-            final Set<String> currentTargets = userState.getShortcutTargetsLocked(
-                    ACCESSIBILITY_SHORTCUT_KEY);
-            persistColonDelimitedSetToSettingLocked(
-                    Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE,
-                    userState.mUserId, currentTargets, str -> str);
-        }
-        if (userState.removeShortcutTargetLocked(ACCESSIBILITY_BUTTON, serviceName)) {
-            final Set<String> currentTargets = userState.getShortcutTargetsLocked(
-                    ACCESSIBILITY_BUTTON);
-            persistColonDelimitedSetToSettingLocked(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS,
-                    userState.mUserId, currentTargets, str -> str);
+        for (Pair<Integer, String> shortcutTypePair : shortcutTypeAndShortcutSetting) {
+            int shortcutType = shortcutTypePair.first;
+            String shortcutSettingName = shortcutTypePair.second;
+            if (userState.removeShortcutTargetLocked(shortcutType, serviceName)) {
+                final Set<String> currentTargets = userState.getShortcutTargetsLocked(shortcutType);
+                persistColonDelimitedSetToSettingLocked(
+                        shortcutSettingName,
+                        userState.mUserId, currentTargets, str -> str);
+
+                if (shortcutType != UserShortcutType.QUICK_SETTINGS) {
+                    continue;
+                }
+
+                ComponentName tileService =
+                        userState.getA11yFeatureToTileService().getOrDefault(serviceName, null);
+
+                final StatusBarManagerInternal statusBarManagerInternal =
+                        LocalServices.getService(StatusBarManagerInternal.class);
+                // In case it's not initialized yet
+                if (statusBarManagerInternal == null || tileService == null) {
+                    continue;
+                }
+                mMainHandler.sendMessage(obtainMessage(StatusBarManagerInternal::removeQsTile,
+                        statusBarManagerInternal, tileService));
+            }
         }
     }
 
@@ -3967,6 +4064,262 @@
         }
     }
 
+    /**
+     * Turns on or off a shortcut type of the accessibility features. The {@code shortcutTypes} is a
+     * flag that contains values defined in the
+     * {@link ShortcutConstants.USER_SHORTCUT_TYPES}.
+     *
+     * @hide
+     */
+    @Override
+    public void enableShortcutsForTargets(
+            boolean enable, @UserShortcutType int shortcutTypes,
+            @NonNull List<String> shortcutTargets, @UserIdInt int userId) {
+        mContext.enforceCallingPermission(
+                Manifest.permission.MANAGE_ACCESSIBILITY, "enableShortcutsForTargets");
+        for (int shortcutType : USER_SHORTCUT_TYPES) {
+            if ((shortcutTypes & shortcutType) == shortcutType) {
+                enableShortcutForTargets(enable, shortcutType, shortcutTargets, userId);
+            }
+        }
+    }
+
+    private void enableShortcutForTargets(
+            boolean enable, @UserShortcutType int shortcutType,
+            @NonNull List<String> shortcutTargets, @UserIdInt int userId) {
+        final String shortcutTypeSettingKey = ShortcutUtils.convertToKey(shortcutType);
+        if (shortcutType == UserShortcutType.TRIPLETAP
+                || shortcutType == UserShortcutType.TWOFINGER_DOUBLETAP) {
+            for (String target : shortcutTargets) {
+                if (MAGNIFICATION_CONTROLLER_NAME.equals(target)) {
+                    persistIntToSetting(
+                            userId,
+                            shortcutTypeSettingKey,
+                            enable ? AccessibilityUtils.State.ON : AccessibilityUtils.State.OFF);
+                } else {
+                    Slog.w(LOG_TAG,
+                            "Triple tap or two-fingers double-tap is not supported for " + target);
+                }
+            }
+            return;
+        }
+        Set<String> validNewTargets;
+        Set<String> currentTargets;
+
+        Map<ComponentName, ComponentName> featureToTileMap =
+                getA11yFeatureToTileMapInternal(userId);
+        synchronized (mLock) {
+            AccessibilityUserState userState = getUserStateLocked(userId);
+            currentTargets =
+                    ShortcutUtils.getShortcutTargetsFromSettings(mContext, shortcutType, userId);
+
+            Set<String> newTargets = new ArraySet<>(currentTargets);
+            if (enable) {
+                newTargets.addAll(shortcutTargets);
+            } else {
+                newTargets.removeAll(shortcutTargets);
+            }
+            validNewTargets = newTargets;
+
+            // filter out targets that doesn't have qs shortcut
+            if (shortcutType == UserShortcutType.QUICK_SETTINGS) {
+                validNewTargets = newTargets.stream().filter(target -> {
+                    ComponentName targetComponent = ComponentName.unflattenFromString(target);
+                    return featureToTileMap.containsKey(targetComponent);
+                }).collect(Collectors.toUnmodifiableSet());
+            }
+
+            if (currentTargets.equals(validNewTargets)) {
+                return;
+            }
+            persistColonDelimitedSetToSettingLocked(
+                    shortcutTypeSettingKey,
+                    userId,
+                    validNewTargets,
+                    str -> str,
+                    /* defaultEmptyString= */ ""
+            );
+
+            if (shortcutType == UserShortcutType.QUICK_SETTINGS) {
+                userState.updateA11yQsTargetLocked(validNewTargets);
+                scheduleNotifyClientsOfServicesStateChangeLocked(userState);
+                onUserStateChangedLocked(userState);
+            }
+        }
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            ShortcutUtils.updateInvisibleToggleAccessibilityServiceEnableState(
+                    mContext, new ArraySet<>(shortcutTargets), userId);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+
+        // Add or Remove tile in QS Panel
+        if (shortcutType == UserShortcutType.QUICK_SETTINGS) {
+            mMainHandler.sendMessage(obtainMessage(
+                    AccessibilityManagerService::updateA11yTileServicesInQuickSettingsPanel,
+                    this, validNewTargets, currentTargets, userId));
+        }
+
+        if (!enable) {
+            return;
+        }
+        if (shortcutType == UserShortcutType.HARDWARE) {
+            skipVolumeShortcutDialogTimeoutRestriction(userId);
+        } else if (shortcutType == UserShortcutType.SOFTWARE) {
+            // Update the A11y FAB size to large when the Magnification shortcut is
+            // enabled and the user hasn't changed the floating button size
+            if (shortcutTargets.contains(MAGNIFICATION_CONTROLLER_NAME)
+                    && Settings.Secure.getIntForUser(mContext.getContentResolver(),
+                    Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE,
+                    FloatingMenuSize.UNKNOWN, userId) == FloatingMenuSize.UNKNOWN) {
+                persistIntToSetting(
+                        userId,
+                        Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE,
+                        FloatingMenuSize.LARGE);
+            }
+        }
+    }
+
+    /**
+     * Add or remove the TileServices of the a11y features in the Quick Settings panel based on the
+     * changes in the new targets and current targets.
+     *
+     * <p>
+     * The framework tiles implemented in the SysUi are automatically added/removed via the
+     * SystemUI's AutoAddable framework. This method only handles updating the TileServices
+     * provided by AccessibilityService or Accessibility Activity.
+     * </p>
+     *
+     * @see com.android.systemui.qs.pipeline.domain.model.AutoAddable AutoAddable QS Tiles
+     */
+    private void updateA11yTileServicesInQuickSettingsPanel(
+            Set<String> newQsTargets,
+            Set<String> currentQsTargets, @UserIdInt int userId) {
+        // Call StatusBarManager to add/remove tiles
+        final StatusBarManagerInternal statusBarManagerInternal =
+                LocalServices.getService(StatusBarManagerInternal.class);
+        // In case it's not initialized yet
+        if (statusBarManagerInternal == null) {
+            return;
+        }
+
+        Map<ComponentName, ComponentName> a11yFeatureToTileMap =
+                getA11yFeatureToTileMapInternal(userId);
+        Set<String> targetWithNoTile = new ArraySet<>();
+
+        // Add TileServices to QS Panel that are added to the new targets
+        newQsTargets.stream()
+                .filter(target -> !currentQsTargets.contains(target))
+                .forEach(
+                        target -> {
+                            ComponentName targetComponent =
+                                    ComponentName.unflattenFromString(target);
+                            if (targetComponent == null
+                                    || !a11yFeatureToTileMap.containsKey(targetComponent)) {
+                                targetWithNoTile.add(target);
+                                return;
+                            }
+
+                            if (ShortcutConstants.A11Y_FEATURE_TO_FRAMEWORK_TILE.containsKey(
+                                    targetComponent)) {
+                                // a11y framework tile is handled by the SysUi autoaddable framework
+                                return;
+                            }
+                            statusBarManagerInternal.addQsTileToFrontOrEnd(
+                                    a11yFeatureToTileMap.get(targetComponent), /* end= */ true);
+                        }
+                );
+
+        // Remove TileServices from QS Panel that are no longer in the new targets.
+        currentQsTargets.stream()
+                .filter(target -> !newQsTargets.contains(target))
+                .forEach(
+                        target -> {
+                            ComponentName targetComponent =
+                                    ComponentName.unflattenFromString(target);
+                            if (targetComponent == null
+                                    || !a11yFeatureToTileMap.containsKey(targetComponent)) {
+                                targetWithNoTile.add(target);
+                                return;
+                            }
+
+                            if (ShortcutConstants.A11Y_FEATURE_TO_FRAMEWORK_TILE.containsKey(
+                                    targetComponent)) {
+                                // a11y framework tile is handled by the SysUi autoaddable framework
+                                return;
+                            }
+                            statusBarManagerInternal.removeQsTile(
+                                    a11yFeatureToTileMap.get(targetComponent));
+                        }
+                );
+
+        if (!targetWithNoTile.isEmpty()) {
+            throw new IllegalArgumentException(
+                    "Unable to add/remove Tiles for a11y features: " + targetWithNoTile
+                            + "as the Tiles aren't provided");
+        }
+    }
+
+    @Override
+    public Bundle getA11yFeatureToTileMap(@UserIdInt int userId) {
+        mContext.enforceCallingPermission(
+                Manifest.permission.MANAGE_ACCESSIBILITY, "getA11yFeatureToTileMap");
+
+        Bundle bundle = new Bundle();
+        Map<ComponentName, ComponentName> a11yFeatureToTile =
+                getA11yFeatureToTileMapInternal(userId);
+        for (Map.Entry<ComponentName, ComponentName> entry : a11yFeatureToTile.entrySet()) {
+            bundle.putParcelable(entry.getKey().flattenToString(), entry.getValue());
+        }
+        return bundle;
+    }
+
+
+
+    /**
+     * Returns accessibility feature's component and the provided tile map. This includes the
+     * TileService provided by the AccessibilityService or Accessibility Activity and the tile
+     * component provided by the framework's feature.
+     *
+     * @return a map of a feature's component name, and its provided tile's component name. The
+     * returned map's keys and values are not null. If a feature doesn't provide a tile, it won't
+     * have an entry in this map.
+     *
+     * @see ShortcutConstants.A11Y_FEATURE_TO_FRAMEWORK_TILE
+     */
+    @NonNull
+    private Map<ComponentName, ComponentName> getA11yFeatureToTileMapInternal(
+            @UserIdInt int userId) {
+        final Map<ComponentName, ComponentName> a11yFeatureToTileService;
+        Map<ComponentName, ComponentName> a11yFeatureToTile = new ArrayMap<>();
+        final int resolvedUserId;
+
+        synchronized (mLock) {
+            resolvedUserId = mSecurityPolicy
+                    .resolveCallingUserIdEnforcingPermissionsLocked(userId);
+            AccessibilityUserState userState = getUserStateLocked(resolvedUserId);
+            a11yFeatureToTileService = userState.getA11yFeatureToTileService();
+        }
+        final boolean shouldFilterAppAccess = Binder.getCallingPid() != OWN_PROCESS_ID;
+        final int callingUid = Binder.getCallingUid();
+        final PackageManagerInternal pm = LocalServices.getService(
+                PackageManagerInternal.class);
+
+        for (Map.Entry<ComponentName, ComponentName> entry :
+                a11yFeatureToTileService.entrySet()) {
+            if (shouldFilterAppAccess
+                    && pm.filterAppAccess(
+                    entry.getKey().getPackageName(), callingUid, resolvedUserId)) {
+                continue;
+            }
+            a11yFeatureToTile.put(entry.getKey(), entry.getValue());
+        }
+
+        a11yFeatureToTile.putAll(ShortcutConstants.A11Y_FEATURE_TO_FRAMEWORK_TILE);
+        return a11yFeatureToTile;
+    }
+
     @Override
     public List<String> getAccessibilityShortcutTargets(@ShortcutType int shortcutType) {
         if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) {
@@ -5836,4 +6189,15 @@
             }
         }
     }
+
+
+    /**
+     * Bypasses the timeout restriction if volume key shortcut assigned.
+     */
+    private void skipVolumeShortcutDialogTimeoutRestriction(int userId) {
+        persistIntToSetting(
+                userId,
+                Settings.Secure.SKIP_ACCESSIBILITY_SHORTCUT_DIALOG_TIMEOUT_RESTRICTION,
+                /* true */ 1);
+    }
 }
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java
index 68ee780..063eafe 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java
@@ -38,10 +38,12 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
 import android.os.Binder;
 import android.os.RemoteCallbackList;
 import android.provider.Settings;
 import android.text.TextUtils;
+import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Slog;
 import android.util.SparseArray;
@@ -51,6 +53,7 @@
 
 import com.android.internal.R;
 import com.android.internal.accessibility.AccessibilityShortcutController;
+import com.android.internal.accessibility.common.ShortcutConstants;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -99,6 +102,7 @@
     final ArraySet<String> mAccessibilityShortcutKeyTargets = new ArraySet<>();
 
     final ArraySet<String> mAccessibilityButtonTargets = new ArraySet<>();
+    private final ArraySet<String> mAccessibilityQsTargets = new ArraySet<>();
 
     private final ServiceInfoChangeListener mServiceInfoChangeListener;
 
@@ -146,6 +150,8 @@
     private final int mFocusStrokeWidthDefaultValue;
     // The default value of the focus color.
     private final int mFocusColorDefaultValue;
+    private final Map<ComponentName, ComponentName> mA11yServiceToTileService = new ArrayMap<>();
+    private final Map<ComponentName, ComponentName> mA11yActivityToTileService = new ArrayMap<>();
 
     private Context mContext;
 
@@ -560,6 +566,8 @@
         pw.println("}");
         pw.append("     button target:{").append(mTargetAssignedToAccessibilityButton);
         pw.println("}");
+        pw.append("     qs shortcut targets:" + mAccessibilityQsTargets);
+        pw.println();
         pw.append("     Bound services:{");
         final int serviceCount = mBoundServices.size();
         for (int j = 0; j < serviceCount; j++) {
@@ -762,6 +770,8 @@
             return mAccessibilityShortcutKeyTargets;
         } else if (shortcutType == ACCESSIBILITY_BUTTON) {
             return mAccessibilityButtonTargets;
+        } else if (shortcutType == ShortcutConstants.UserShortcutType.QUICK_SETTINGS) {
+            return getA11yQsTargets();
         }
         return null;
     }
@@ -808,7 +818,8 @@
      */
     public boolean removeShortcutTargetLocked(@ShortcutType int shortcutType,
             ComponentName target) {
-        return getShortcutTargetsLocked(shortcutType).removeIf(name -> {
+        Set<String> targets = getShortcutTargetsLocked(shortcutType);
+        boolean result = targets.removeIf(name -> {
             ComponentName componentName;
             if (name == null
                     || (componentName = ComponentName.unflattenFromString(name)) == null) {
@@ -816,6 +827,11 @@
             }
             return componentName.equals(target);
         });
+        if (shortcutType == ShortcutConstants.UserShortcutType.QUICK_SETTINGS) {
+            updateA11yQsTargetLocked(targets);
+        }
+
+        return result;
     }
 
     /**
@@ -1034,4 +1050,60 @@
         }
         return false;
     }
+
+    public void updateTileServiceMapForAccessibilityServiceLocked() {
+        mA11yServiceToTileService.clear();
+        mInstalledServices.forEach(
+                a11yServiceInfo -> {
+                    String tileServiceName = a11yServiceInfo.getTileServiceName();
+                    if (!TextUtils.isEmpty(tileServiceName)) {
+                        ResolveInfo resolveInfo = a11yServiceInfo.getResolveInfo();
+                        ComponentName a11yFeature = new ComponentName(
+                                resolveInfo.serviceInfo.packageName,
+                                resolveInfo.serviceInfo.name
+                        );
+                        ComponentName tileService = new ComponentName(
+                                a11yFeature.getPackageName(),
+                                tileServiceName
+                        );
+                        mA11yServiceToTileService.put(a11yFeature, tileService);
+                    }
+                }
+        );
+    }
+
+    public void updateTileServiceMapForAccessibilityActivityLocked() {
+        mA11yActivityToTileService.clear();
+        mInstalledShortcuts.forEach(
+                a11yShortcutInfo -> {
+                    String tileServiceName = a11yShortcutInfo.getTileServiceName();
+                    if (!TextUtils.isEmpty(tileServiceName)) {
+                        ComponentName a11yFeature = a11yShortcutInfo.getComponentName();
+                        ComponentName tileService = new ComponentName(
+                                a11yFeature.getPackageName(),
+                                tileServiceName);
+                        mA11yActivityToTileService.put(a11yFeature, tileService);
+                    }
+                }
+        );
+    }
+
+    public void updateA11yQsTargetLocked(Set<String> targets) {
+        mAccessibilityQsTargets.clear();
+        mAccessibilityQsTargets.addAll(targets);
+    }
+
+    /**
+     * Returns a copy of the targets which has qs shortcut turned on
+     */
+    public ArraySet<String> getA11yQsTargets() {
+        return new ArraySet<>(mAccessibilityQsTargets);
+    }
+
+    public Map<ComponentName, ComponentName> getA11yFeatureToTileService() {
+        Map<ComponentName, ComponentName> featureToTileServiceMap = new ArrayMap<>();
+        featureToTileServiceMap.putAll(mA11yServiceToTileService);
+        featureToTileServiceMap.putAll(mA11yActivityToTileService);
+        return featureToTileServiceMap;
+    }
 }
diff --git a/services/core/java/com/android/server/am/CoreSettingsObserver.java b/services/core/java/com/android/server/am/CoreSettingsObserver.java
index 982076d..91b64f8 100644
--- a/services/core/java/com/android/server/am/CoreSettingsObserver.java
+++ b/services/core/java/com/android/server/am/CoreSettingsObserver.java
@@ -80,6 +80,7 @@
         sSecureSettingToTypeMap.put(Settings.Secure.MULTI_PRESS_TIMEOUT, int.class);
         sSecureSettingToTypeMap.put(Settings.Secure.KEY_REPEAT_TIMEOUT_MS, int.class);
         sSecureSettingToTypeMap.put(Settings.Secure.KEY_REPEAT_DELAY_MS, int.class);
+        sSecureSettingToTypeMap.put(Settings.Secure.STYLUS_POINTER_ICON_ENABLED, int.class);
         // add other secure settings here...
 
         sSystemSettingToTypeMap.put(Settings.System.TIME_12_24, String.class);
diff --git a/services/core/java/com/android/server/input/InputSettingsObserver.java b/services/core/java/com/android/server/input/InputSettingsObserver.java
index c02d524..a1341b7 100644
--- a/services/core/java/com/android/server/input/InputSettingsObserver.java
+++ b/services/core/java/com/android/server/input/InputSettingsObserver.java
@@ -258,6 +258,7 @@
     }
 
     private void updateStylusPointerIconEnabled() {
-        mNative.setStylusPointerIconEnabled(InputSettings.isStylusPointerIconEnabled(mContext));
+        mNative.setStylusPointerIconEnabled(
+                InputSettings.isStylusPointerIconEnabled(mContext, true /* forceReloadSetting */));
     }
 }
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 19f0298..996477d 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -1247,6 +1247,14 @@
          */
         private boolean mImePackageAppeared = false;
 
+        /**
+         * Remembers package names passed to {@link #onPackageDataCleared(String, int)}.
+         *
+         * <p>This field must be accessed only from callback methods in {@link PackageMonitor},
+         * which should be bound to {@link #getRegisteredHandler()}.</p>
+         */
+        private ArrayList<String> mDataClearedPackages = new ArrayList<>();
+
         @GuardedBy("ImfLock.class")
         void clearKnownImePackageNamesLocked() {
             mKnownImePackageNames.clear();
@@ -1350,36 +1358,8 @@
 
         @Override
         public void onPackageDataCleared(String packageName, int uid) {
-            final int userId = getChangingUserId();
-            synchronized (ImfLock.class) {
-                final boolean isCurrentUser = (userId == mSettings.getUserId());
-                final AdditionalSubtypeMap additionalSubtypeMap =
-                        AdditionalSubtypeMapRepository.get(userId);
-                final InputMethodSettings settings;
-                if (isCurrentUser) {
-                    settings = mSettings;
-                } else {
-                    settings = queryInputMethodServicesInternal(mContext, userId,
-                            additionalSubtypeMap, DirectBootAwareness.AUTO);
-                }
-
-                // Note that one package may implement multiple IMEs.
-                final ArrayList<String> changedImes = new ArrayList<>();
-                for (InputMethodInfo imi : settings.getMethodList()) {
-                    if (imi.getPackageName().equals(packageName)) {
-                        changedImes.add(imi.getId());
-                    }
-                }
-                final AdditionalSubtypeMap newMap =
-                        additionalSubtypeMap.cloneWithRemoveOrSelf(changedImes);
-                if (newMap != additionalSubtypeMap) {
-                    AdditionalSubtypeMapRepository.putAndSave(userId, newMap,
-                            settings.getMethodMap());
-                }
-                if (!changedImes.isEmpty()) {
-                    mChangedPackages.add(packageName);
-                }
-            }
+            mChangedPackages.add(packageName);
+            mDataClearedPackages.add(packageName);
         }
 
         @Override
@@ -1391,6 +1371,7 @@
         private void clearPackageChangeState() {
             // No need to lock them because we access these fields only on getRegisteredHandler().
             mChangedPackages.clear();
+            mDataClearedPackages.clear();
             mImePackageAppeared = false;
         }
 
@@ -1421,7 +1402,7 @@
             synchronized (ImfLock.class) {
                 final int userId = getChangingUserId();
                 final boolean isCurrentUser = (userId == mSettings.getUserId());
-                AdditionalSubtypeMap additionalSubtypeMap =
+                final AdditionalSubtypeMap additionalSubtypeMap =
                         AdditionalSubtypeMapRepository.get(userId);
                 final InputMethodSettings settings;
                 if (isCurrentUser) {
@@ -1434,6 +1415,8 @@
                 InputMethodInfo curIm = null;
                 String curInputMethodId = settings.getSelectedInputMethod();
                 final List<InputMethodInfo> methodList = settings.getMethodList();
+
+                final ArrayList<String> imesToClearAdditionalSubtypes = new ArrayList<>();
                 final int numImes = methodList.size();
                 for (int i = 0; i < numImes; i++) {
                     InputMethodInfo imi = methodList.get(i);
@@ -1441,6 +1424,9 @@
                     if (imiId.equals(curInputMethodId)) {
                         curIm = imi;
                     }
+                    if (mDataClearedPackages.contains(imi.getPackageName())) {
+                        imesToClearAdditionalSubtypes.add(imiId);
+                    }
                     int change = isPackageDisappearing(imi.getPackageName());
                     if (change == PACKAGE_TEMPORARY_CHANGE || change == PACKAGE_PERMANENT_CHANGE) {
                         Slog.i(TAG, "Input method uninstalled, disabling: " + imi.getComponent());
@@ -1455,14 +1441,22 @@
                     } else if (change == PACKAGE_UPDATING) {
                         Slog.i(TAG, "Input method reinstalling, clearing additional subtypes: "
                                 + imi.getComponent());
-                        additionalSubtypeMap =
-                                additionalSubtypeMap.cloneWithRemoveOrSelf(imi.getId());
-                        AdditionalSubtypeMapRepository.putAndSave(userId,
-                                additionalSubtypeMap, settings.getMethodMap());
+                        imesToClearAdditionalSubtypes.add(imiId);
                     }
                 }
 
-                if (!isCurrentUser || !shouldRebuildInputMethodListLocked()) {
+                // Clear additional subtypes as a batch operation.
+                final AdditionalSubtypeMap newAdditionalSubtypeMap =
+                        additionalSubtypeMap.cloneWithRemoveOrSelf(imesToClearAdditionalSubtypes);
+                final boolean additionalSubtypeChanged =
+                        (newAdditionalSubtypeMap != additionalSubtypeMap);
+                if (additionalSubtypeChanged) {
+                    AdditionalSubtypeMapRepository.putAndSave(userId, newAdditionalSubtypeMap,
+                            settings.getMethodMap());
+                }
+
+                if (!isCurrentUser
+                        || !(additionalSubtypeChanged || shouldRebuildInputMethodListLocked())) {
                     return;
                 }
 
diff --git a/services/core/java/com/android/server/location/contexthub/OWNERS b/services/core/java/com/android/server/location/contexthub/OWNERS
index 90c2330..c62e323 100644
--- a/services/core/java/com/android/server/location/contexthub/OWNERS
+++ b/services/core/java/com/android/server/location/contexthub/OWNERS
@@ -1,3 +1,3 @@
-arthuri@google.com
 bduddie@google.com
+matthewsedam@google.com
 stange@google.com
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 18b495b..97ce77c 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -340,6 +340,8 @@
     static final String TAG = NetworkPolicyLogger.TAG;
     private static final boolean LOGD = NetworkPolicyLogger.LOGD;
     private static final boolean LOGV = NetworkPolicyLogger.LOGV;
+    // TODO: b/304347838 - Remove once the feature is in staging.
+    private static final boolean ALWAYS_RESTRICT_BACKGROUND_NETWORK = false;
 
     /**
      * No opportunistic quota could be calculated from user data plan or data settings.
@@ -1068,7 +1070,8 @@
                     }
 
                     // The flag is boot-stable.
-                    mBackgroundNetworkRestricted = Flags.networkBlockedForTopSleepingAndAbove();
+                    mBackgroundNetworkRestricted = ALWAYS_RESTRICT_BACKGROUND_NETWORK
+                            && Flags.networkBlockedForTopSleepingAndAbove();
                     if (mBackgroundNetworkRestricted) {
                         // Firewall rules and UidBlockedState will get updated in
                         // updateRulesForGlobalChangeAL below.
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 59d6219..e35a169 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -2710,7 +2710,8 @@
 
         } catch (java.io.IOException e) {
             mReadMessages.append("Error reading: " + e.toString());
-            PackageManagerService.reportSettingsProblem(Log.ERROR, "Error reading settings: " + e);
+            PackageManagerService.reportSettingsProblem(Log.ERROR,
+                    "Error reading stopped packages: " + e);
             Slog.wtf(PackageManagerService.TAG, "Error reading package manager stopped packages",
                     e);
 
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
index 95cfc2a..7ea722b 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
@@ -61,7 +61,9 @@
 import android.graphics.drawable.Icon;
 import android.hardware.display.DisplayManagerGlobal;
 import android.net.Uri;
+import android.os.Build;
 import android.os.Bundle;
+import android.os.Handler;
 import android.os.IBinder;
 import android.os.LocaleList;
 import android.os.UserHandle;
@@ -70,20 +72,28 @@
 import android.platform.test.flag.junit.CheckFlagsRule;
 import android.platform.test.flag.junit.DeviceFlagsValueProvider;
 import android.provider.Settings;
+import android.testing.AndroidTestingRunner;
 import android.testing.TestableContext;
+import android.testing.TestableLooper;
 import android.util.ArraySet;
 import android.view.Display;
 import android.view.DisplayAdjustments;
 import android.view.DisplayInfo;
 import android.view.WindowManager;
+import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.AccessibilityWindowAttributes;
+import android.view.accessibility.IAccessibilityManager;
 
-import androidx.test.InstrumentationRegistry;
 import androidx.test.core.app.ApplicationProvider;
 import androidx.test.filters.SmallTest;
 
 import com.android.compatibility.common.util.TestUtils;
 import com.android.internal.R;
+import com.android.internal.accessibility.common.ShortcutConstants;
+import com.android.internal.accessibility.common.ShortcutConstants.FloatingMenuSize;
+import com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType;
+import com.android.internal.accessibility.util.AccessibilityUtils;
+import com.android.internal.accessibility.util.ShortcutUtils;
 import com.android.internal.compat.IPlatformCompat;
 import com.android.server.LocalServices;
 import com.android.server.accessibility.AccessibilityManagerService.AccessibilityDisplayListener;
@@ -91,31 +101,38 @@
 import com.android.server.accessibility.magnification.MagnificationConnectionManager;
 import com.android.server.accessibility.magnification.MagnificationController;
 import com.android.server.accessibility.magnification.MagnificationProcessor;
-import com.android.server.accessibility.test.MessageCapturingHandler;
 import com.android.server.pm.UserManagerInternal;
+import com.android.server.statusbar.StatusBarManagerInternal;
 import com.android.server.wm.ActivityTaskManagerInternal;
 import com.android.server.wm.WindowManagerInternal;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
 import org.mockito.ArgumentMatchers;
 import org.mockito.Captor;
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
+import org.mockito.internal.util.reflection.FieldReader;
+import org.mockito.internal.util.reflection.FieldSetter;
 import org.mockito.stubbing.Answer;
 
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicReference;
 
 /**
  * APCT tests for {@link AccessibilityManagerService}.
  */
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
 public class AccessibilityManagerServiceTest {
     @Rule
     public final A11yTestableContext mTestableContext = new A11yTestableContext(
@@ -140,6 +157,12 @@
             TEST_PENDING_INTENT);
 
     private static final int TEST_DISPLAY = Display.DEFAULT_DISPLAY + 1;
+    private static final String TARGET_MAGNIFICATION = MAGNIFICATION_CONTROLLER_NAME;
+    private static final ComponentName TARGET_ALWAYS_ON_A11Y_SERVICE =
+            new ComponentName("FakePackage", "AlwaysOnA11yService");
+    private static final String TARGET_ALWAYS_ON_A11Y_SERVICE_TILE_CLASS = "TileService";
+    private static final ComponentName TARGET_STANDARD_A11Y_SERVICE =
+            new ComponentName("FakePackage", "StandardA11yService");
 
     static final ComponentName COMPONENT_NAME = new ComponentName(
             "com.android.server.accessibility", "AccessibilityManagerServiceTest");
@@ -163,24 +186,33 @@
     @Mock private MagnificationController mMockMagnificationController;
     @Mock private FullScreenMagnificationController mMockFullScreenMagnificationController;
     @Mock private ProxyManager mProxyManager;
+    @Mock private StatusBarManagerInternal mStatusBarManagerInternal;
     @Captor private ArgumentCaptor<Intent> mIntentArgumentCaptor;
-    private MessageCapturingHandler mHandler = new MessageCapturingHandler(null);
+    private IAccessibilityManager mA11yManagerServiceOnDevice;
     private AccessibilityServiceConnection mAccessibilityServiceConnection;
     private AccessibilityInputFilter mInputFilter;
     private AccessibilityManagerService mA11yms;
+    private TestableLooper mTestableLooper;
+    private Handler mHandler;
 
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
+        mTestableLooper = TestableLooper.get(this);
+        mHandler = new Handler(mTestableLooper.getLooper());
+
         LocalServices.removeServiceForTest(WindowManagerInternal.class);
         LocalServices.removeServiceForTest(ActivityTaskManagerInternal.class);
         LocalServices.removeServiceForTest(UserManagerInternal.class);
+        LocalServices.removeServiceForTest(StatusBarManagerInternal.class);
         LocalServices.addService(
                 WindowManagerInternal.class, mMockWindowManagerService);
         LocalServices.addService(
                 ActivityTaskManagerInternal.class, mMockActivityTaskManagerInternal);
         LocalServices.addService(
                 UserManagerInternal.class, mMockUserManagerInternal);
+        LocalServices.addService(
+                StatusBarManagerInternal.class, mStatusBarManagerInternal);
         mInputFilter = Mockito.mock(FakeInputFilter.class);
 
         when(mMockMagnificationController.getMagnificationConnectionManager()).thenReturn(
@@ -218,6 +250,19 @@
         final AccessibilityUserState userState = new AccessibilityUserState(
                 mA11yms.getCurrentUserIdLocked(), mTestableContext, mA11yms);
         mA11yms.mUserStates.put(mA11yms.getCurrentUserIdLocked(), userState);
+        AccessibilityManager am = mTestableContext.getSystemService(AccessibilityManager.class);
+        mA11yManagerServiceOnDevice = (IAccessibilityManager) new FieldReader(am,
+                AccessibilityManager.class.getDeclaredField("mService")).read();
+        FieldSetter.setField(am, AccessibilityManager.class.getDeclaredField("mService"), mA11yms);
+    }
+
+    @After
+    public void cleanUp() throws Exception {
+        mTestableLooper.processAllMessages();
+        AccessibilityManager am = mTestableContext.getSystemService(AccessibilityManager.class);
+        FieldSetter.setField(
+                am, AccessibilityManager.class.getDeclaredField("mService"),
+                mA11yManagerServiceOnDevice);
     }
 
     private void setupAccessibilityServiceConnection(int serviceInfoFlag) {
@@ -297,7 +342,8 @@
                 mA11yms.getCurrentUserIdLocked());
 
         mA11yms.notifySystemActionsChangedLocked(userState);
-        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+        mTestableLooper.processAllMessages();
+
         verify(mMockServiceClient).onSystemActionsChanged();
     }
 
@@ -415,7 +461,7 @@
         );
 
         mA11yms.onMagnificationTransitionEndedLocked(Display.DEFAULT_DISPLAY, true);
-        mHandler.sendAllMessages();
+        mTestableLooper.processAllMessages();
 
         ArgumentCaptor<Display> displayCaptor = ArgumentCaptor.forClass(Display.class);
         verify(mInputFilter, timeout(100)).refreshMagnificationMode(displayCaptor.capture());
@@ -730,7 +776,7 @@
 
         mA11yms.performAccessibilityShortcut(
                 ACCESSIBILITY_HEARING_AIDS_COMPONENT_NAME.flattenToString());
-        mHandler.sendAllMessages();
+        mTestableLooper.processAllMessages();
 
         assertStartActivityWithExpectedComponentName(mTestableContext.getMockContext(),
                 ACCESSIBILITY_HEARING_AIDS_COMPONENT_NAME.flattenToString());
@@ -907,11 +953,14 @@
     public void testIsAccessibilityServiceWarningRequired_notRequiredIfAllowlisted() {
         mockManageAccessibilityGranted(mTestableContext);
         final AccessibilityServiceInfo info_a = mockAccessibilityServiceInfo(
-                new ComponentName("package_a", "class_a"), true);
+                new ComponentName("package_a", "class_a"),
+                /* isSystemApp= */ true, /* isAlwaysOnService= */ false);
         final AccessibilityServiceInfo info_b = mockAccessibilityServiceInfo(
-                new ComponentName("package_b", "class_b"), false);
+                new ComponentName("package_b", "class_b"),
+                /* isSystemApp= */ false, /* isAlwaysOnService= */ false);
         final AccessibilityServiceInfo info_c = mockAccessibilityServiceInfo(
-                new ComponentName("package_c", "class_c"), true);
+                new ComponentName("package_c", "class_c"),
+                /* isSystemApp= */ true, /* isAlwaysOnService= */ false);
         mTestableContext.getOrCreateTestableResources().addOverride(
                 R.array.config_trustedAccessibilityServices,
                 new String[]{
@@ -926,14 +975,380 @@
         assertThat(mA11yms.isAccessibilityServiceWarningRequired(info_c)).isFalse();
     }
 
+    @Test
+    public void enableShortcutsForTargets_permissionNotGranted_throwsException() {
+        mTestableContext.getTestablePermissions().setPermission(
+                Manifest.permission.MANAGE_ACCESSIBILITY, PackageManager.PERMISSION_DENIED);
+
+        assertThrows(SecurityException.class,
+                () -> mA11yms.enableShortcutsForTargets(
+                        /* enable= */true,
+                        UserShortcutType.SOFTWARE,
+                        List.of(TARGET_MAGNIFICATION),
+                        mA11yms.getCurrentUserIdLocked()));
+    }
+
+    @Test
+    public void enableShortcutsForTargets_enableSoftwareShortcut_shortcutTurnedOn()
+            throws Exception {
+        mockManageAccessibilityGranted(mTestableContext);
+        setupShortcutTargetServices();
+        String target = TARGET_ALWAYS_ON_A11Y_SERVICE.flattenToString();
+
+        mA11yms.enableShortcutsForTargets(
+                /* enable= */ true,
+                UserShortcutType.SOFTWARE,
+                List.of(target),
+                mA11yms.getCurrentUserIdLocked());
+        mTestableLooper.processAllMessages();
+
+        assertThat(ShortcutUtils.isComponentIdExistingInSettings(
+                mTestableContext, UserShortcutType.SOFTWARE, target
+        )).isTrue();
+    }
+
+    @Test
+    public void enableShortcutsForTargets_disableSoftwareShortcut_shortcutTurnedOff()
+            throws Exception {
+        String target = TARGET_ALWAYS_ON_A11Y_SERVICE.flattenToString();
+        enableShortcutsForTargets_enableSoftwareShortcut_shortcutTurnedOn();
+
+        mA11yms.enableShortcutsForTargets(
+                /* enable= */ false,
+                UserShortcutType.SOFTWARE,
+                List.of(target),
+                mA11yms.getCurrentUserIdLocked());
+        mTestableLooper.processAllMessages();
+
+        assertThat(ShortcutUtils.isComponentIdExistingInSettings(
+                mTestableContext, UserShortcutType.SOFTWARE, target
+        )).isFalse();
+    }
+
+    @Test
+    public void enableShortcutsForTargets_enableSoftwareShortcutWithMagnification_menuSizeIncreased() {
+        mockManageAccessibilityGranted(mTestableContext);
+
+        mA11yms.enableShortcutsForTargets(
+                /* enable= */ true,
+                UserShortcutType.SOFTWARE,
+                List.of(MAGNIFICATION_CONTROLLER_NAME),
+                mA11yms.getCurrentUserIdLocked());
+        mTestableLooper.processAllMessages();
+
+        assertThat(
+                Settings.Secure.getInt(
+                        mTestableContext.getContentResolver(),
+                        Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE,
+                        FloatingMenuSize.UNKNOWN))
+                .isEqualTo(FloatingMenuSize.LARGE);
+    }
+
+    @Test
+    public void enableShortcutsForTargets_enableSoftwareShortcutWithMagnification_userConfigureSmallMenuSize_menuSizeNotChanged() {
+        mockManageAccessibilityGranted(mTestableContext);
+        Settings.Secure.putInt(
+                mTestableContext.getContentResolver(),
+                Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE,
+                FloatingMenuSize.SMALL);
+
+        mA11yms.enableShortcutsForTargets(
+                /* enable= */ true,
+                UserShortcutType.SOFTWARE,
+                List.of(MAGNIFICATION_CONTROLLER_NAME),
+                mA11yms.getCurrentUserIdLocked());
+        mTestableLooper.processAllMessages();
+
+        assertThat(
+                Settings.Secure.getInt(
+                        mTestableContext.getContentResolver(),
+                        Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE,
+                        FloatingMenuSize.UNKNOWN))
+                .isEqualTo(FloatingMenuSize.SMALL);
+    }
+
+    @Test
+    public void enableShortcutsForTargets_enableAlwaysOnServiceSoftwareShortcut_turnsOnAlwaysOnService()
+            throws Exception {
+        mockManageAccessibilityGranted(mTestableContext);
+        setupShortcutTargetServices();
+
+        mA11yms.enableShortcutsForTargets(
+                /* enable= */ true,
+                UserShortcutType.SOFTWARE,
+                List.of(TARGET_ALWAYS_ON_A11Y_SERVICE.flattenToString()),
+                mA11yms.getCurrentUserIdLocked());
+        mTestableLooper.processAllMessages();
+
+        assertThat(
+                AccessibilityUtils.getEnabledServicesFromSettings(
+                        mTestableContext,
+                        mA11yms.getCurrentUserIdLocked())
+        ).contains(TARGET_ALWAYS_ON_A11Y_SERVICE);
+    }
+
+    @Test
+    public void enableShortcutsForTargets_disableAlwaysOnServiceSoftwareShortcut_turnsOffAlwaysOnService()
+            throws Exception {
+        enableShortcutsForTargets_enableAlwaysOnServiceSoftwareShortcut_turnsOnAlwaysOnService();
+
+        mA11yms.enableShortcutsForTargets(
+                /* enable= */ false,
+                UserShortcutType.SOFTWARE,
+                List.of(TARGET_ALWAYS_ON_A11Y_SERVICE.flattenToString()),
+                mA11yms.getCurrentUserIdLocked());
+        mTestableLooper.processAllMessages();
+
+        assertThat(
+                AccessibilityUtils.getEnabledServicesFromSettings(
+                        mTestableContext,
+                        mA11yms.getCurrentUserIdLocked())
+        ).doesNotContain(TARGET_ALWAYS_ON_A11Y_SERVICE);
+    }
+
+    @Test
+    public void enableShortcutsForTargets_enableStandardServiceSoftwareShortcut_wontTurnOnService()
+            throws Exception {
+        mockManageAccessibilityGranted(mTestableContext);
+        setupShortcutTargetServices();
+
+        mA11yms.enableShortcutsForTargets(
+                /* enable= */ true,
+                UserShortcutType.SOFTWARE,
+                List.of(TARGET_STANDARD_A11Y_SERVICE.flattenToString()),
+                mA11yms.getCurrentUserIdLocked());
+        mTestableLooper.processAllMessages();
+
+        assertThat(
+                AccessibilityUtils.getEnabledServicesFromSettings(
+                        mTestableContext,
+                        mA11yms.getCurrentUserIdLocked())
+        ).doesNotContain(TARGET_STANDARD_A11Y_SERVICE);
+    }
+
+    @Test
+    public void enableShortcutsForTargets_disableStandardServiceSoftwareShortcutWithServiceOn_wontTurnOffService()
+            throws Exception {
+        enableShortcutsForTargets_enableStandardServiceSoftwareShortcut_wontTurnOnService();
+        AccessibilityUtils.setAccessibilityServiceState(
+                mTestableContext, TARGET_STANDARD_A11Y_SERVICE, /* enabled= */ true);
+
+        mA11yms.enableShortcutsForTargets(
+                /* enable= */ false,
+                UserShortcutType.SOFTWARE,
+                List.of(TARGET_STANDARD_A11Y_SERVICE.flattenToString()),
+                mA11yms.getCurrentUserIdLocked());
+        mTestableLooper.processAllMessages();
+
+        assertThat(
+                AccessibilityUtils.getEnabledServicesFromSettings(
+                        mTestableContext,
+                        mA11yms.getCurrentUserIdLocked())
+        ).contains(TARGET_STANDARD_A11Y_SERVICE);
+    }
+
+    @Test
+    public void enableShortcutsForTargets_enableTripleTapShortcut_settingUpdated() {
+        mockManageAccessibilityGranted(mTestableContext);
+
+        mA11yms.enableShortcutsForTargets(
+                /* enable= */ true,
+                UserShortcutType.TRIPLETAP,
+                List.of(TARGET_MAGNIFICATION),
+                mA11yms.getCurrentUserIdLocked());
+        mTestableLooper.processAllMessages();
+
+        assertThat(
+                Settings.Secure.getInt(
+                        mTestableContext.getContentResolver(),
+                        Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED,
+                        AccessibilityUtils.State.OFF)
+        ).isEqualTo(AccessibilityUtils.State.ON);
+    }
+
+    @Test
+    public void enableShortcutsForTargets_disableTripleTapShortcut_settingUpdated() {
+        enableShortcutsForTargets_enableTripleTapShortcut_settingUpdated();
+
+        mA11yms.enableShortcutsForTargets(
+                /* enable= */ false,
+                UserShortcutType.TRIPLETAP,
+                List.of(TARGET_MAGNIFICATION),
+                mA11yms.getCurrentUserIdLocked());
+
+        assertThat(
+                Settings.Secure.getInt(
+                        mTestableContext.getContentResolver(),
+                        Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED,
+                        AccessibilityUtils.State.OFF)
+        ).isEqualTo(AccessibilityUtils.State.OFF);
+    }
+
+    @Test
+    public void enableShortcutsForTargets_enableMultiFingerMultiTapsShortcut_settingUpdated() {
+        mockManageAccessibilityGranted(mTestableContext);
+
+        mA11yms.enableShortcutsForTargets(
+                /* enable= */ true,
+                UserShortcutType.TWOFINGER_DOUBLETAP,
+                List.of(TARGET_MAGNIFICATION),
+                mA11yms.getCurrentUserIdLocked());
+        mTestableLooper.processAllMessages();
+
+        assertThat(
+                Settings.Secure.getInt(
+                        mTestableContext.getContentResolver(),
+                        Settings.Secure.ACCESSIBILITY_MAGNIFICATION_TWO_FINGER_TRIPLE_TAP_ENABLED,
+                        AccessibilityUtils.State.OFF)
+        ).isEqualTo(AccessibilityUtils.State.ON);
+    }
+
+    @Test
+    public void enableShortcutsForTargets_disableMultiFingerMultiTapsShortcut_settingUpdated() {
+        enableShortcutsForTargets_enableMultiFingerMultiTapsShortcut_settingUpdated();
+
+        mA11yms.enableShortcutsForTargets(
+                /* enable= */ false,
+                UserShortcutType.TWOFINGER_DOUBLETAP,
+                List.of(TARGET_MAGNIFICATION),
+                mA11yms.getCurrentUserIdLocked());
+        mTestableLooper.processAllMessages();
+
+        assertThat(
+                Settings.Secure.getInt(
+                        mTestableContext.getContentResolver(),
+                        Settings.Secure.ACCESSIBILITY_MAGNIFICATION_TWO_FINGER_TRIPLE_TAP_ENABLED,
+                        AccessibilityUtils.State.OFF)
+        ).isEqualTo(AccessibilityUtils.State.OFF);
+    }
+
+    @Test
+    public void enableShortcutsForTargets_enableVolumeKeysShortcut_shortcutSet() {
+        mockManageAccessibilityGranted(mTestableContext);
+        setupShortcutTargetServices();
+
+        mA11yms.enableShortcutsForTargets(
+                /* enable= */ true,
+                UserShortcutType.HARDWARE,
+                List.of(TARGET_STANDARD_A11Y_SERVICE.flattenToString()),
+                mA11yms.getCurrentUserIdLocked());
+        mTestableLooper.processAllMessages();
+
+        assertThat(
+                ShortcutUtils.isComponentIdExistingInSettings(
+                        mTestableContext, ShortcutConstants.UserShortcutType.HARDWARE,
+                        TARGET_STANDARD_A11Y_SERVICE.flattenToString())
+        ).isTrue();
+    }
+
+    @Test
+    public void enableShortcutsForTargets_disableVolumeKeysShortcut_shortcutNotSet() {
+        enableShortcutsForTargets_enableVolumeKeysShortcut_shortcutSet();
+
+        mA11yms.enableShortcutsForTargets(
+                /* enable= */ false,
+                UserShortcutType.HARDWARE,
+                List.of(TARGET_STANDARD_A11Y_SERVICE.flattenToString()),
+                mA11yms.getCurrentUserIdLocked());
+        mTestableLooper.processAllMessages();
+
+        assertThat(
+                ShortcutUtils.isComponentIdExistingInSettings(
+                        mTestableContext, ShortcutConstants.UserShortcutType.HARDWARE,
+                        TARGET_STANDARD_A11Y_SERVICE.flattenToString())
+        ).isFalse();
+    }
+
+    @Test
+    public void enableShortcutsForTargets_enableQuickSettings_shortcutSet() {
+        mockManageAccessibilityGranted(mTestableContext);
+        setupShortcutTargetServices();
+
+        mA11yms.enableShortcutsForTargets(
+                /* enable= */ true,
+                UserShortcutType.QUICK_SETTINGS,
+                List.of(TARGET_ALWAYS_ON_A11Y_SERVICE.flattenToString()),
+                mA11yms.getCurrentUserIdLocked());
+        mTestableLooper.processAllMessages();
+
+        assertThat(
+                ShortcutUtils.isComponentIdExistingInSettings(
+                        mTestableContext, UserShortcutType.QUICK_SETTINGS,
+                        TARGET_ALWAYS_ON_A11Y_SERVICE.flattenToString())
+        ).isTrue();
+        verify(mStatusBarManagerInternal)
+                .addQsTileToFrontOrEnd(
+                        new ComponentName(
+                                TARGET_ALWAYS_ON_A11Y_SERVICE.getPackageName(),
+                                TARGET_ALWAYS_ON_A11Y_SERVICE_TILE_CLASS),
+                        /* end= */ true);
+    }
+
+    @Test
+    public void enableShortcutsForTargets_disableQuickSettings_shortcutNotSet() {
+        enableShortcutsForTargets_enableQuickSettings_shortcutSet();
+
+        mA11yms.enableShortcutsForTargets(
+                /* enable= */ false,
+                UserShortcutType.QUICK_SETTINGS,
+                List.of(TARGET_ALWAYS_ON_A11Y_SERVICE.flattenToString()),
+                mA11yms.getCurrentUserIdLocked());
+        mTestableLooper.processAllMessages();
+
+        assertThat(
+                ShortcutUtils.isComponentIdExistingInSettings(
+                        mTestableContext, UserShortcutType.QUICK_SETTINGS,
+                        TARGET_ALWAYS_ON_A11Y_SERVICE.flattenToString())
+        ).isFalse();
+        verify(mStatusBarManagerInternal)
+                .removeQsTile(
+                        new ComponentName(
+                                TARGET_ALWAYS_ON_A11Y_SERVICE.getPackageName(),
+                                TARGET_ALWAYS_ON_A11Y_SERVICE_TILE_CLASS));
+    }
+
+    @Test
+    public void getA11yFeatureToTileMap_permissionNotGranted_throwsException() {
+        mTestableContext.getTestablePermissions().setPermission(
+                Manifest.permission.MANAGE_ACCESSIBILITY, PackageManager.PERMISSION_DENIED);
+
+        assertThrows(SecurityException.class,
+                () -> mA11yms.getA11yFeatureToTileMap(mA11yms.getCurrentUserIdLocked()));
+    }
+
+    @Test
+    public void getA11yFeatureToTileMap() {
+        mockManageAccessibilityGranted(mTestableContext);
+        setupShortcutTargetServices();
+
+        Bundle bundle = mA11yms.getA11yFeatureToTileMap(mA11yms.getCurrentUserIdLocked());
+
+        // Framework tile size + TARGET_ALWAYS_ON_A11Y_SERVICE_TILE_CLASS
+        assertThat(bundle.size())
+                .isEqualTo(ShortcutConstants.A11Y_FEATURE_TO_FRAMEWORK_TILE.size() + 1);
+        assertThat(
+                bundle.getParcelable(TARGET_ALWAYS_ON_A11Y_SERVICE.flattenToString(),
+                        ComponentName.class)
+        ).isEqualTo(
+                new ComponentName(
+                        TARGET_ALWAYS_ON_A11Y_SERVICE.getPackageName(),
+                        TARGET_ALWAYS_ON_A11Y_SERVICE_TILE_CLASS));
+        for (Map.Entry<ComponentName, ComponentName> entry :
+                ShortcutConstants.A11Y_FEATURE_TO_FRAMEWORK_TILE.entrySet()) {
+            assertThat(bundle.getParcelable(entry.getKey().flattenToString(), ComponentName.class))
+                    .isEqualTo(entry.getValue());
+        }
+    }
+
     private static AccessibilityServiceInfo mockAccessibilityServiceInfo(
             ComponentName componentName) {
-        return mockAccessibilityServiceInfo(componentName, false);
+        return mockAccessibilityServiceInfo(
+                componentName, /* isSystemApp= */ false, /* isAlwaysOnService=*/ false);
     }
 
     private static AccessibilityServiceInfo mockAccessibilityServiceInfo(
             ComponentName componentName,
-            boolean isSystemApp) {
+            boolean isSystemApp, boolean isAlwaysOnService) {
         AccessibilityServiceInfo accessibilityServiceInfo =
                 Mockito.spy(new AccessibilityServiceInfo());
         accessibilityServiceInfo.setComponentName(componentName);
@@ -941,7 +1356,15 @@
         when(accessibilityServiceInfo.getResolveInfo()).thenReturn(mockResolveInfo);
         mockResolveInfo.serviceInfo = Mockito.mock(ServiceInfo.class);
         mockResolveInfo.serviceInfo.applicationInfo = Mockito.mock(ApplicationInfo.class);
+        mockResolveInfo.serviceInfo.packageName = componentName.getPackageName();
+        mockResolveInfo.serviceInfo.name = componentName.getClassName();
         when(mockResolveInfo.serviceInfo.applicationInfo.isSystemApp()).thenReturn(isSystemApp);
+        if (isAlwaysOnService) {
+            accessibilityServiceInfo.flags |=
+                    AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON;
+            mockResolveInfo.serviceInfo.applicationInfo.targetSdkVersion =
+                    Build.VERSION_CODES.R;
+        }
         return accessibilityServiceInfo;
     }
 
@@ -974,6 +1397,22 @@
                 Intent.EXTRA_COMPONENT_NAME)).isEqualTo(componentName);
     }
 
+    private void setupShortcutTargetServices() {
+        AccessibilityServiceInfo alwaysOnServiceInfo = mockAccessibilityServiceInfo(
+                TARGET_ALWAYS_ON_A11Y_SERVICE,
+                /* isSystemApp= */ false,
+                /* isAlwaysOnService= */ true);
+        when(alwaysOnServiceInfo.getTileServiceName())
+                .thenReturn(TARGET_ALWAYS_ON_A11Y_SERVICE_TILE_CLASS);
+        AccessibilityServiceInfo standardServiceInfo = mockAccessibilityServiceInfo(
+                TARGET_STANDARD_A11Y_SERVICE,
+                /* isSystemApp= */ false,
+                /* isAlwaysOnService= */ false);
+        mA11yms.getCurrentUserState().mInstalledServices.addAll(
+                List.of(alwaysOnServiceInfo, standardServiceInfo));
+        mA11yms.getCurrentUserState().updateTileServiceMapForAccessibilityServiceLocked();
+    }
+
     public static class FakeInputFilter extends AccessibilityInputFilter {
         FakeInputFilter(Context context,
                 AccessibilityManagerService service) {
diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
index 1249707..67b131f 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
@@ -206,6 +206,7 @@
 import org.junit.After;
 import org.junit.Assume;
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.MethodRule;
@@ -2150,12 +2151,14 @@
         assertFalse(mService.isUidNetworkingBlocked(UID_E, false));
     }
 
+    @Ignore("Temporarily disabled until the feature is enabled")
     @Test
     @RequiresFlagsEnabled(Flags.FLAG_NETWORK_BLOCKED_FOR_TOP_SLEEPING_AND_ABOVE)
     public void testBackgroundChainEnabled() throws Exception {
         verify(mNetworkManager).setFirewallChainEnabled(FIREWALL_CHAIN_BACKGROUND, true);
     }
 
+    @Ignore("Temporarily disabled until the feature is enabled")
     @Test
     @RequiresFlagsEnabled(Flags.FLAG_NETWORK_BLOCKED_FOR_TOP_SLEEPING_AND_ABOVE)
     public void testBackgroundChainOnProcStateChange() throws Exception {
@@ -2185,6 +2188,7 @@
         assertTrue(mService.isUidNetworkingBlocked(UID_A, false));
     }
 
+    @Ignore("Temporarily disabled until the feature is enabled")
     @Test
     @RequiresFlagsEnabled(Flags.FLAG_NETWORK_BLOCKED_FOR_TOP_SLEEPING_AND_ABOVE)
     public void testBackgroundChainOnAllowlistChange() throws Exception {
@@ -2223,6 +2227,7 @@
         assertFalse(mService.isUidNetworkingBlocked(UID_B, false));
     }
 
+    @Ignore("Temporarily disabled until the feature is enabled")
     @Test
     @RequiresFlagsEnabled(Flags.FLAG_NETWORK_BLOCKED_FOR_TOP_SLEEPING_AND_ABOVE)
     public void testBackgroundChainOnTempAllowlistChange() throws Exception {
@@ -2261,6 +2266,7 @@
                 && uidState.procState == procState && uidState.capability == capability;
     }
 
+    @Ignore("Temporarily disabled until the feature is enabled")
     @Test
     @RequiresFlagsEnabled(Flags.FLAG_NETWORK_BLOCKED_FOR_TOP_SLEEPING_AND_ABOVE)
     public void testUidObserverFiltersProcStateChanges() throws Exception {
@@ -2323,6 +2329,7 @@
         waitForUidEventHandlerIdle();
     }
 
+    @Ignore("Temporarily disabled until the feature is enabled")
     @Test
     @RequiresFlagsEnabled(Flags.FLAG_NETWORK_BLOCKED_FOR_TOP_SLEEPING_AND_ABOVE)
     public void testUidObserverFiltersStaleChanges() throws Exception {
@@ -2343,6 +2350,7 @@
         waitForUidEventHandlerIdle();
     }
 
+    @Ignore("Temporarily disabled until the feature is enabled")
     @Test
     @RequiresFlagsEnabled(Flags.FLAG_NETWORK_BLOCKED_FOR_TOP_SLEEPING_AND_ABOVE)
     public void testUidObserverFiltersCapabilityChanges() throws Exception {
@@ -2422,6 +2430,7 @@
         assertFalse(mService.isUidNetworkingBlocked(UID_A, false));
     }
 
+    @Ignore("Temporarily disabled until the feature is enabled")
     @Test
     @RequiresFlagsEnabled(Flags.FLAG_NETWORK_BLOCKED_FOR_TOP_SLEEPING_AND_ABOVE)
     public void testObsoleteHandleUidChanged() throws Exception {
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index 5a52968..ae4faa8 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -16,6 +16,7 @@
 
 package com.android.server.voiceinteraction;
 
+import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
 import static android.content.Intent.FLAG_ACTIVITY_NO_ANIMATION;
 import static android.content.Intent.FLAG_ACTIVITY_NO_USER_ACTION;
@@ -1072,8 +1073,10 @@
                         // If visEnabledKey is set to true (or absent), we try following VIS path.
                         String csPkgName = mContext.getResources()
                                 .getString(R.string.config_defaultContextualSearchPackageName);
-                        if (!csPkgName.equals(getCurInteractor(
-                                Binder.getCallingUserHandle().getIdentifier()).getPackageName())) {
+                        ComponentName currInteractor =
+                                getCurInteractor(Binder.getCallingUserHandle().getIdentifier());
+                        if (currInteractor == null
+                                || !csPkgName.equals(currInteractor.getPackageName())) {
                             // Check if the interactor can handle Contextual Search.
                             // If not, return failure.
                             Slog.w(TAG, "Contextual Search not supported yet. Returning failure.");
@@ -2718,7 +2721,7 @@
             }
             launchIntent.setComponent(resolveInfo.getComponentInfo().getComponentName());
             launchIntent.addFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_NO_ANIMATION
-                    | FLAG_ACTIVITY_NO_USER_ACTION);
+                    | FLAG_ACTIVITY_NO_USER_ACTION | FLAG_ACTIVITY_CLEAR_TASK);
             launchIntent.putExtras(args);
             boolean isAssistDataAllowed = mAtmInternal.isAssistDataAllowed();
             final List<ActivityAssistInfo> records = mAtmInternal.getTopVisibleActivities();
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt
index 78f277e..f70a17d 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt
@@ -1051,6 +1051,9 @@
       LocalVariableTable:
         Start  Length  Slot  Name   Signature
             0      10     0  name   Ljava/lang/String;
+    MethodParameters:
+      Name                           Flags
+      <no name>                      mandated
 
   private com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex(java.lang.String, java.lang.String);
     descriptor: (Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V
@@ -1074,6 +1077,12 @@
             0      18     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
             0      18     3 longName   Ljava/lang/String;
             0      18     4 shortName   Ljava/lang/String;
+    MethodParameters:
+      Name                           Flags
+      <no name>                      synthetic
+      <no name>                      synthetic
+      <no name>
+      <no name>
     Signature: #x                          // (Ljava/lang/String;Ljava/lang/String;)V
     RuntimeInvisibleAnnotations:
       x: #x()
@@ -1224,6 +1233,9 @@
       LocalVariableTable:
         Start  Length  Slot  Name   Signature
             0      10     0  name   Ljava/lang/String;
+    MethodParameters:
+      Name                           Flags
+      <no name>                      mandated
 
   private com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple();
     descriptor: (Ljava/lang/String;I)V
@@ -1239,6 +1251,10 @@
       LocalVariableTable:
         Start  Length  Slot  Name   Signature
             0       7     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+    MethodParameters:
+      Name                           Flags
+      <no name>                      synthetic
+      <no name>                      synthetic
     Signature: #x                          // ()V
 
   private static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple[] $values();
@@ -2031,6 +2047,9 @@
         Start  Length  Slot  Name   Signature
             0      10     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1;
             0      10     1 this$0   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+    MethodParameters:
+      Name                           Flags
+      <no name>                      final mandated
 
   public java.lang.Integer get();
     descriptor: ()Ljava/lang/Integer;
@@ -2147,6 +2166,9 @@
         Start  Length  Slot  Name   Signature
             0      10     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3;
             0      10     1 this$0   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+    MethodParameters:
+      Name                           Flags
+      <no name>                      final mandated
 
   public java.lang.Integer get();
     descriptor: ()Ljava/lang/Integer;
@@ -2304,6 +2326,9 @@
         Start  Length  Slot  Name   Signature
             0      15     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass;
             0      15     1 this$0   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+    MethodParameters:
+      Name                           Flags
+      <no name>                      final mandated
 }
 SourceFile: "TinyFrameworkNestedClasses.java"
 RuntimeInvisibleAnnotations:
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt
index 406cb74..37de857 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt
@@ -795,6 +795,9 @@
         com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
       x: #x()
         com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+    MethodParameters:
+      Name                           Flags
+      <no name>                      mandated
 
   private com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex(java.lang.String, java.lang.String);
     descriptor: (Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V
@@ -815,6 +818,12 @@
     RuntimeInvisibleAnnotations:
       x: #x()
         android.hosttest.annotation.HostSideTestStub
+    MethodParameters:
+      Name                           Flags
+      <no name>                      synthetic
+      <no name>                      synthetic
+      <no name>
+      <no name>
 
   public java.lang.String getLongName();
     descriptor: ()Ljava/lang/String;
@@ -969,6 +978,9 @@
         com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
       x: #x()
         com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+    MethodParameters:
+      Name                           Flags
+      <no name>                      mandated
 
   private com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple();
     descriptor: (Ljava/lang/String;I)V
@@ -986,6 +998,10 @@
         com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
       x: #x()
         com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+    MethodParameters:
+      Name                           Flags
+      <no name>                      synthetic
+      <no name>                      synthetic
 
   private static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple[] $values();
     descriptor: ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
@@ -1769,6 +1785,9 @@
         com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
       x: #x()
         com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+    MethodParameters:
+      Name                           Flags
+      <no name>                      final mandated
 }
 InnerClasses:
   public #x= #x of #x;                   // InnerClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-impl-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-impl-dump.txt
index c673262..c9c607c 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-impl-dump.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-impl-dump.txt
@@ -1225,6 +1225,9 @@
         com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
       x: #x()
         com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+    MethodParameters:
+      Name                           Flags
+      <no name>                      mandated
 
   private com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex(java.lang.String, java.lang.String);
     descriptor: (Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V
@@ -1257,6 +1260,12 @@
     RuntimeInvisibleAnnotations:
       x: #x()
         android.hosttest.annotation.HostSideTestStub
+    MethodParameters:
+      Name                           Flags
+      <no name>                      synthetic
+      <no name>                      synthetic
+      <no name>
+      <no name>
 
   public java.lang.String getLongName();
     descriptor: ()Ljava/lang/String;
@@ -1453,6 +1462,9 @@
         com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
       x: #x()
         com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+    MethodParameters:
+      Name                           Flags
+      <no name>                      mandated
 
   private com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple();
     descriptor: (Ljava/lang/String;I)V
@@ -1474,6 +1486,10 @@
         com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
       x: #x()
         com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+    MethodParameters:
+      Name                           Flags
+      <no name>                      synthetic
+      <no name>                      synthetic
 
   private static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple[] $values();
     descriptor: ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
@@ -2578,6 +2594,9 @@
     RuntimeVisibleAnnotations:
       x: #x()
         com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+    MethodParameters:
+      Name                           Flags
+      <no name>                      final mandated
 
   public java.lang.Integer get();
     descriptor: ()Ljava/lang/Integer;
@@ -2745,6 +2764,9 @@
     RuntimeVisibleAnnotations:
       x: #x()
         com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+    MethodParameters:
+      Name                           Flags
+      <no name>                      final mandated
 
   public java.lang.Integer get();
     descriptor: ()Ljava/lang/Integer;
@@ -2977,6 +2999,9 @@
         com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
       x: #x()
         com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+    MethodParameters:
+      Name                           Flags
+      <no name>                      final mandated
 }
 InnerClasses:
   public #x= #x of #x;                   // InnerClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt
index 406cb74..37de857 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt
@@ -795,6 +795,9 @@
         com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
       x: #x()
         com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+    MethodParameters:
+      Name                           Flags
+      <no name>                      mandated
 
   private com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex(java.lang.String, java.lang.String);
     descriptor: (Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V
@@ -815,6 +818,12 @@
     RuntimeInvisibleAnnotations:
       x: #x()
         android.hosttest.annotation.HostSideTestStub
+    MethodParameters:
+      Name                           Flags
+      <no name>                      synthetic
+      <no name>                      synthetic
+      <no name>
+      <no name>
 
   public java.lang.String getLongName();
     descriptor: ()Ljava/lang/String;
@@ -969,6 +978,9 @@
         com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
       x: #x()
         com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+    MethodParameters:
+      Name                           Flags
+      <no name>                      mandated
 
   private com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple();
     descriptor: (Ljava/lang/String;I)V
@@ -986,6 +998,10 @@
         com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
       x: #x()
         com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+    MethodParameters:
+      Name                           Flags
+      <no name>                      synthetic
+      <no name>                      synthetic
 
   private static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple[] $values();
     descriptor: ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
@@ -1769,6 +1785,9 @@
         com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
       x: #x()
         com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+    MethodParameters:
+      Name                           Flags
+      <no name>                      final mandated
 }
 InnerClasses:
   public #x= #x of #x;                   // InnerClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-impl-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-impl-dump.txt
index 4fd5701..a57907d 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-impl-dump.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-impl-dump.txt
@@ -1532,6 +1532,9 @@
         com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
       x: #x()
         com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+    MethodParameters:
+      Name                           Flags
+      <no name>                      mandated
 
   private com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex(java.lang.String, java.lang.String);
     descriptor: (Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V
@@ -1569,6 +1572,12 @@
     RuntimeInvisibleAnnotations:
       x: #x()
         android.hosttest.annotation.HostSideTestStub
+    MethodParameters:
+      Name                           Flags
+      <no name>                      synthetic
+      <no name>                      synthetic
+      <no name>
+      <no name>
 
   public java.lang.String getLongName();
     descriptor: ()Ljava/lang/String;
@@ -1798,6 +1807,9 @@
         com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
       x: #x()
         com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+    MethodParameters:
+      Name                           Flags
+      <no name>                      mandated
 
   private com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple();
     descriptor: (Ljava/lang/String;I)V
@@ -1824,6 +1836,10 @@
         com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
       x: #x()
         com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+    MethodParameters:
+      Name                           Flags
+      <no name>                      synthetic
+      <no name>                      synthetic
 
   private static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple[] $values();
     descriptor: ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
@@ -3190,6 +3206,9 @@
     RuntimeVisibleAnnotations:
       x: #x()
         com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+    MethodParameters:
+      Name                           Flags
+      <no name>                      final mandated
 
   public java.lang.Integer get();
     descriptor: ()Ljava/lang/Integer;
@@ -3407,6 +3426,9 @@
     RuntimeVisibleAnnotations:
       x: #x()
         com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+    MethodParameters:
+      Name                           Flags
+      <no name>                      final mandated
 
   public java.lang.Integer get();
     descriptor: ()Ljava/lang/Integer;
@@ -3704,6 +3726,9 @@
         com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
       x: #x()
         com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+    MethodParameters:
+      Name                           Flags
+      <no name>                      final mandated
 }
 InnerClasses:
   public #x= #x of #x;                  // InnerClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses