Merge "Add "Sensitive Content" public view" into main
diff --git a/MEMORY_OWNERS b/MEMORY_OWNERS
index 89ce5140..12aa295 100644
--- a/MEMORY_OWNERS
+++ b/MEMORY_OWNERS
@@ -2,5 +2,4 @@
 tjmercier@google.com
 kaleshsingh@google.com
 jyescas@google.com
-carlosgalo@google.com
 jji@google.com
diff --git a/core/java/android/hardware/input/input_framework.aconfig b/core/java/android/hardware/input/input_framework.aconfig
index 313bad5..c4d11cd 100644
--- a/core/java/android/hardware/input/input_framework.aconfig
+++ b/core/java/android/hardware/input/input_framework.aconfig
@@ -204,3 +204,10 @@
     description: "Allows the user to disable input scrolling acceleration for mouse."
     bug: "383555305"
 }
+
+flag {
+  name: "remove_fallback_modifiers"
+  namespace: "input"
+  description: "Removes modifiers from the original key event that activated the fallback, ensuring that only the intended fallback event is sent."
+  bug: "382545048"
+}
diff --git a/core/java/android/service/quickaccesswallet/QuickAccessWalletService.java b/core/java/android/service/quickaccesswallet/QuickAccessWalletService.java
index 90136ae..ffe8086 100644
--- a/core/java/android/service/quickaccesswallet/QuickAccessWalletService.java
+++ b/core/java/android/service/quickaccesswallet/QuickAccessWalletService.java
@@ -93,6 +93,10 @@
  * must do its own state management (keeping in mind that the service's process might be killed
  * by the Android System when unbound; for example, if the device is running low in memory).
  *
+ * <p> The service also provides pending intents to override the system's Quick Access activities
+ * via the {@link #getTargetActivityPendingIntent} and the
+ * {@link #getGestureTargetActivityPendingIntent} method.
+ *
  * <p>
  * <a name="ErrorHandling"></a>
  * <h3>Error handling</h3>
@@ -384,6 +388,10 @@
      *
      * <p>The pending intent will be sent when the user performs a gesture to open Wallet.
      * The pending intent should launch an activity.
+     *
+     * <p> If the gesture is performed and this method returns null, the system will launch the
+     * activity specified by the {@link #getTargetActivityPendingIntent} method. If that method
+     * also returns null, the system will launch the system-provided card switcher activity.
      */
     @Nullable
     @FlaggedApi(Flags.FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP)
diff --git a/core/java/android/view/KeyCharacterMap.java b/core/java/android/view/KeyCharacterMap.java
index a8d4e2d..48dfdd4 100644
--- a/core/java/android/view/KeyCharacterMap.java
+++ b/core/java/android/view/KeyCharacterMap.java
@@ -16,6 +16,9 @@
 
 package android.view;
 
+
+import static com.android.hardware.input.Flags.removeFallbackModifiers;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.compat.annotation.UnsupportedAppUsage;
@@ -458,7 +461,15 @@
         FallbackAction action = FallbackAction.obtain();
         metaState = KeyEvent.normalizeMetaState(metaState);
         if (nativeGetFallbackAction(mPtr, keyCode, metaState, action)) {
-            action.metaState = KeyEvent.normalizeMetaState(action.metaState);
+            if (removeFallbackModifiers()) {
+                // Strip all modifiers. This is safe to do since only exact keyCode + metaState
+                // modifiers will trigger a fallback.
+                // E.g. Ctrl + Space -> language_switch (fallback generated)
+                //      Ctrl + Alt + Space -> Ctrl + Alt + Space (no fallback generated)
+                action.metaState = 0;
+            } else {
+                action.metaState = KeyEvent.normalizeMetaState(action.metaState);
+            }
             return action;
         }
         action.recycle();
diff --git a/core/java/android/window/flags/windowing_sdk.aconfig b/core/java/android/window/flags/windowing_sdk.aconfig
index c97d3ec..abd93cf 100644
--- a/core/java/android/window/flags/windowing_sdk.aconfig
+++ b/core/java/android/window/flags/windowing_sdk.aconfig
@@ -105,6 +105,13 @@
 
 flag {
     namespace: "windowing_sdk"
+    name: "activity_embedding_support_for_connected_displays"
+    description: "Enables activity embedding support for connected displays, including enabling AE optimization for Settings."
+    bug: "369438353"
+}
+
+flag {
+    namespace: "windowing_sdk"
     name: "wlinfo_oncreate"
     description: "Makes WindowLayoutInfo accessible without racing in the Activity#onCreate()"
     bug: "337820752"
diff --git a/libs/WindowManager/Shell/multivalentTests/Android.bp b/libs/WindowManager/Shell/multivalentTests/Android.bp
index 41d1b5c..eecf199 100644
--- a/libs/WindowManager/Shell/multivalentTests/Android.bp
+++ b/libs/WindowManager/Shell/multivalentTests/Android.bp
@@ -55,6 +55,7 @@
         "truth",
         "flag-junit-base",
         "flag-junit",
+        "testables",
     ],
     auto_gen_config: true,
 }
@@ -77,6 +78,7 @@
         "truth",
         "platform-test-annotations",
         "platform-test-rules",
+        "testables",
     ],
     libs: [
         "android.test.base.stubs.system",
diff --git a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelperTest.kt b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelperTest.kt
index 0d8f809..3e01256 100644
--- a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelperTest.kt
+++ b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelperTest.kt
@@ -16,6 +16,8 @@
 
 package com.android.wm.shell.bubbles.bar
 
+import android.animation.AnimatorTestRule
+import android.app.ActivityManager
 import android.content.Context
 import android.graphics.Insets
 import android.graphics.Rect
@@ -23,7 +25,6 @@
 import android.view.ViewGroup
 import android.view.WindowManager
 import android.widget.FrameLayout
-import androidx.core.animation.AnimatorTestRule
 import androidx.test.core.app.ApplicationProvider
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
@@ -36,27 +37,34 @@
 import com.android.wm.shell.bubbles.BubbleLogger
 import com.android.wm.shell.bubbles.BubbleOverflow
 import com.android.wm.shell.bubbles.BubblePositioner
+import com.android.wm.shell.bubbles.BubbleTaskView
 import com.android.wm.shell.bubbles.DeviceConfig
 import com.android.wm.shell.bubbles.FakeBubbleExpandedViewManager
 import com.android.wm.shell.bubbles.FakeBubbleFactory
-import com.android.wm.shell.bubbles.FakeBubbleTaskViewFactory
+import com.android.wm.shell.taskview.TaskView
+import com.android.wm.shell.taskview.TaskViewTaskController
 import com.google.common.truth.Truth.assertThat
 import java.util.concurrent.Semaphore
 import java.util.concurrent.TimeUnit
 import org.junit.After
 import org.junit.Before
-import org.junit.ClassRule
+import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.mockito.kotlin.any
+import org.mockito.kotlin.clearInvocations
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
 
 /** Tests for [BubbleBarAnimationHelper] */
 @SmallTest
 @RunWith(AndroidJUnit4::class)
 class BubbleBarAnimationHelperTest {
 
-    companion object {
-        @JvmField @ClassRule val animatorTestRule: AnimatorTestRule = AnimatorTestRule()
+    @get:Rule val animatorTestRule: AnimatorTestRule = AnimatorTestRule(this)
 
+    companion object {
         const val SCREEN_WIDTH = 2000
         const val SCREEN_HEIGHT = 1000
     }
@@ -148,6 +156,26 @@
     }
 
     @Test
+    fun animateSwitch_bubbleToBubble_updateTaskBounds() {
+        val fromBubble = createBubble("from").initialize(container)
+        val toBubbleTaskController = mock<TaskViewTaskController>()
+        val toBubble = createBubble("to", toBubbleTaskController).initialize(container)
+
+        getInstrumentation().runOnMainSync {
+            animationHelper.animateSwitch(fromBubble, toBubble) {}
+            // Start the animation, but don't finish
+            animatorTestRule.advanceTimeBy(100)
+        }
+        getInstrumentation().waitForIdleSync()
+        // Clear invocations to ensure that bounds update happens after animation ends
+        clearInvocations(toBubbleTaskController)
+        getInstrumentation().runOnMainSync { animatorTestRule.advanceTimeBy(900) }
+        getInstrumentation().waitForIdleSync()
+
+        verify(toBubbleTaskController).setWindowBounds(any())
+    }
+
+    @Test
     fun animateSwitch_bubbleToOverflow_oldHiddenNewShown() {
         val fromBubble = createBubble(key = "from").initialize(container)
         val overflow = createOverflow().initialize(container)
@@ -193,13 +221,43 @@
         assertThat(toBubble.bubbleBarExpandedView?.isSurfaceZOrderedOnTop).isFalse()
     }
 
-    private fun createBubble(key: String): Bubble {
+    @Test
+    fun animateToRestPosition_updateTaskBounds() {
+        val taskController = mock<TaskViewTaskController>()
+        val bubble = createBubble("key", taskController).initialize(container)
+
+        getInstrumentation().runOnMainSync {
+            animationHelper.animateExpansion(bubble) {}
+            animatorTestRule.advanceTimeBy(1000)
+        }
+        getInstrumentation().waitForIdleSync()
+        getInstrumentation().runOnMainSync {
+            animationHelper.animateToRestPosition()
+            animatorTestRule.advanceTimeBy(100)
+        }
+        // Clear invocations to ensure that bounds update happens after animation ends
+        clearInvocations(taskController)
+        getInstrumentation().runOnMainSync { animatorTestRule.advanceTimeBy(900) }
+        getInstrumentation().waitForIdleSync()
+
+        verify(taskController).setWindowBounds(any())
+    }
+
+    private fun createBubble(
+        key: String,
+        taskViewTaskController: TaskViewTaskController = mock<TaskViewTaskController>(),
+    ): Bubble {
+        val taskView = TaskView(context, taskViewTaskController)
+        val taskInfo = mock<ActivityManager.RunningTaskInfo>()
+        whenever(taskViewTaskController.taskInfo).thenReturn(taskInfo)
+        val bubbleTaskView = BubbleTaskView(taskView, mainExecutor)
+
         val bubbleBarExpandedView =
             FakeBubbleFactory.createExpandedView(
                 context,
                 bubblePositioner,
                 expandedViewManager,
-                FakeBubbleTaskViewFactory(context, mainExecutor).create(),
+                bubbleTaskView,
                 mainExecutor,
                 bgExecutor,
                 bubbleLogger,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java
index 3e8a9b6..3188e5b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java
@@ -463,6 +463,7 @@
                 super.onAnimationEnd(animation);
                 bbev.resetPivot();
                 bbev.setDragging(false);
+                updateExpandedView(bbev);
             }
         });
         startNewAnimator(animatorSet);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
index c74bf53..9ebb7f5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
@@ -643,7 +643,9 @@
                         t.setPosition(animatingLeash, x, endY);
                         t.setAlpha(animatingLeash, 1.f);
                     }
-                    dispatchEndPositioning(mDisplayId, mCancelled, t);
+                    if (!android.view.inputmethod.Flags.refactorInsetsController()) {
+                        dispatchEndPositioning(mDisplayId, mCancelled, t);
+                    }
                     if (mAnimationDirection == DIRECTION_HIDE && !mCancelled) {
                         ImeTracker.forLogging().onProgress(mStatsToken,
                                 ImeTracker.PHASE_WM_ANIMATION_RUNNING);
@@ -659,6 +661,14 @@
                         ImeTracker.forLogging().onCancelled(mStatsToken,
                                 ImeTracker.PHASE_WM_ANIMATION_RUNNING);
                     }
+                    if (android.view.inputmethod.Flags.refactorInsetsController()) {
+                        // In split screen, we also set {@link
+                        // WindowContainer#mExcludeInsetsTypes} but this should only happen after
+                        // the IME client visibility was set. Otherwise the insets will we
+                        // dispatched too early, and we get a flicker. Thus, only dispatching it
+                        // after reporting that the IME is hidden to system server.
+                        dispatchEndPositioning(mDisplayId, mCancelled, t);
+                    }
                     if (DEBUG_IME_VISIBILITY) {
                         EventLog.writeEvent(IMF_IME_REMOTE_ANIM_END,
                                 mStatsToken != null ? mStatsToken.getTag() : ImeTracker.TOKEN_NONE,
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/src/com/android/settingslib/widget/SelectorWithWidgetPreference.java b/packages/SettingsLib/SelectorWithWidgetPreference/src/com/android/settingslib/widget/SelectorWithWidgetPreference.java
index 03a2101..218983a 100644
--- a/packages/SettingsLib/SelectorWithWidgetPreference/src/com/android/settingslib/widget/SelectorWithWidgetPreference.java
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/src/com/android/settingslib/widget/SelectorWithWidgetPreference.java
@@ -31,7 +31,6 @@
 import androidx.preference.PreferenceViewHolder;
 
 import com.android.settingslib.widget.preference.selector.R;
-import com.android.settingslib.widget.selectorwithwidgetpreference.flags.Flags;
 
 /**
  * Selector preference (checkbox or radio button) with an optional additional widget.
@@ -180,10 +179,8 @@
                     : getContext().getString(R.string.settings_label));
         }
 
-        if (Flags.allowSetTitleMaxLines()) {
-            TextView title = (TextView) holder.findViewById(android.R.id.title);
-            title.setMaxLines(mTitleMaxLines);
-        }
+        TextView title = (TextView) holder.findViewById(android.R.id.title);
+        title.setMaxLines(mTitleMaxLines);
     }
 
     /**
@@ -244,16 +241,12 @@
         setLayoutResource(R.layout.preference_selector_with_widget);
         setIconSpaceReserved(false);
 
-        if (Flags.allowSetTitleMaxLines()) {
-            final TypedArray a =
-                    context.obtainStyledAttributes(
-                            attrs, R.styleable.SelectorWithWidgetPreference, defStyleAttr,
-                            defStyleRes);
-            mTitleMaxLines =
-                    a.getInt(R.styleable.SelectorWithWidgetPreference_titleMaxLines,
-                            DEFAULT_MAX_LINES);
-            a.recycle();
-        }
+        final TypedArray a =
+                context.obtainStyledAttributes(
+                        attrs, R.styleable.SelectorWithWidgetPreference, defStyleAttr, defStyleRes);
+        mTitleMaxLines =
+                a.getInt(R.styleable.SelectorWithWidgetPreference_titleMaxLines, DEFAULT_MAX_LINES);
+        a.recycle();
     }
 
     @VisibleForTesting(otherwise = VisibleForTesting.NONE)
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/SelectorWithWidgetPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/SelectorWithWidgetPreferenceTest.java
index 2b8b3b7..c939c77 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/SelectorWithWidgetPreferenceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/SelectorWithWidgetPreferenceTest.java
@@ -21,9 +21,6 @@
 import static org.junit.Assert.assertEquals;
 
 import android.app.Application;
-import android.platform.test.annotations.DisableFlags;
-import android.platform.test.annotations.EnableFlags;
-import android.platform.test.flag.junit.SetFlagsRule;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -33,10 +30,8 @@
 import androidx.test.core.app.ApplicationProvider;
 
 import com.android.settingslib.widget.preference.selector.R;
-import com.android.settingslib.widget.selectorwithwidgetpreference.flags.Flags;
 
 import org.junit.Before;
-import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.robolectric.Robolectric;
@@ -45,7 +40,6 @@
 @RunWith(RobolectricTestRunner.class)
 public class SelectorWithWidgetPreferenceTest {
 
-    @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
     private Application mContext;
     private SelectorWithWidgetPreference mPreference;
 
@@ -128,26 +122,6 @@
     }
 
     @Test
-    @DisableFlags(Flags.FLAG_ALLOW_SET_TITLE_MAX_LINES)
-    public void onBindViewHolder_titleMaxLinesSet_flagOff_titleMaxLinesMatchesDefault() {
-        final int titleMaxLines = 5;
-        AttributeSet attributeSet = Robolectric.buildAttributeSet()
-                .addAttribute(R.attr.titleMaxLines, String.valueOf(titleMaxLines))
-                .build();
-        mPreference = new SelectorWithWidgetPreference(mContext, attributeSet);
-        View view = LayoutInflater.from(mContext)
-                .inflate(mPreference.getLayoutResource(), null /* root */);
-        PreferenceViewHolder preferenceViewHolder =
-                PreferenceViewHolder.createInstanceForTests(view);
-
-        mPreference.onBindViewHolder(preferenceViewHolder);
-
-        TextView title = (TextView) preferenceViewHolder.findViewById(android.R.id.title);
-        assertThat(title.getMaxLines()).isEqualTo(SelectorWithWidgetPreference.DEFAULT_MAX_LINES);
-    }
-
-    @Test
-    @EnableFlags(Flags.FLAG_ALLOW_SET_TITLE_MAX_LINES)
     public void onBindViewHolder_noTitleMaxLinesSet_titleMaxLinesMatchesDefault() {
         AttributeSet attributeSet = Robolectric.buildAttributeSet().build();
         mPreference = new SelectorWithWidgetPreference(mContext, attributeSet);
@@ -163,7 +137,6 @@
     }
 
     @Test
-    @EnableFlags(Flags.FLAG_ALLOW_SET_TITLE_MAX_LINES)
     public void onBindViewHolder_titleMaxLinesSet_titleMaxLinesUpdated() {
         final int titleMaxLines = 5;
         AttributeSet attributeSet = Robolectric.buildAttributeSet()
diff --git a/packages/SystemUI/animation/lib/src/com/android/systemui/animation/OriginRemoteTransition.java b/packages/SystemUI/animation/lib/src/com/android/systemui/animation/OriginRemoteTransition.java
index ca2b957..7d27a56 100644
--- a/packages/SystemUI/animation/lib/src/com/android/systemui/animation/OriginRemoteTransition.java
+++ b/packages/SystemUI/animation/lib/src/com/android/systemui/animation/OriginRemoteTransition.java
@@ -195,7 +195,10 @@
         // Create the origin leash and add to the transition root leash.
         mOriginLeash =
                 new SurfaceControl.Builder().setName("OriginTransition-origin-leash").build();
-        mStartTransaction
+
+        // Create temporary transaction to build
+        final SurfaceControl.Transaction tmpTransaction = new SurfaceControl.Transaction();
+        tmpTransaction
                 .reparent(mOriginLeash, rootLeash)
                 .show(mOriginLeash)
                 .setCornerRadius(mOriginLeash, windowRadius)
@@ -208,14 +211,14 @@
             int mode = change.getMode();
             SurfaceControl leash = change.getLeash();
             // Reparent leash to the transition root.
-            mStartTransaction.reparent(leash, rootLeash);
+            tmpTransaction.reparent(leash, rootLeash);
             if (TransitionUtil.isOpeningMode(mode)) {
                 openingSurfaces.add(change.getLeash());
                 // For opening surfaces, ending bounds are base bound. Apply corner radius if
                 // it's full screen.
                 Rect bounds = change.getEndAbsBounds();
                 if (displayBounds.equals(bounds)) {
-                    mStartTransaction
+                    tmpTransaction
                             .setCornerRadius(leash, windowRadius)
                             .setWindowCrop(leash, bounds.width(), bounds.height());
                 }
@@ -226,28 +229,53 @@
                 // it's full screen.
                 Rect bounds = change.getStartAbsBounds();
                 if (displayBounds.equals(bounds)) {
-                    mStartTransaction
+                    tmpTransaction
                             .setCornerRadius(leash, windowRadius)
                             .setWindowCrop(leash, bounds.width(), bounds.height());
                 }
             }
         }
 
+        if (openingSurfaces.isEmpty() && closingSurfaces.isEmpty()) {
+            logD("prepareUIs: no opening/closing surfaces available, nothing to prepare.");
+            return false;
+        }
+
         // Set relative order:
         // ----  App1  ----
         // ---- origin ----
         // ----  App2  ----
+
         if (mIsEntry) {
-            mStartTransaction
-                    .setRelativeLayer(mOriginLeash, closingSurfaces.get(0), 1)
-                    .setRelativeLayer(
-                            openingSurfaces.get(openingSurfaces.size() - 1), mOriginLeash, 1);
+            if (!closingSurfaces.isEmpty()) {
+                tmpTransaction
+                        .setRelativeLayer(mOriginLeash, closingSurfaces.get(0), 1);
+            } else {
+                logW("Missing closing surface is entry transition");
+            }
+            if (!openingSurfaces.isEmpty()) {
+                tmpTransaction
+                        .setRelativeLayer(
+                                openingSurfaces.get(openingSurfaces.size() - 1), mOriginLeash, 1);
+            } else {
+                logW("Missing opening surface is entry transition");
+            }
+
         } else {
-            mStartTransaction
-                    .setRelativeLayer(mOriginLeash, openingSurfaces.get(0), 1)
-                    .setRelativeLayer(
-                            closingSurfaces.get(closingSurfaces.size() - 1), mOriginLeash, 1);
+            if (!openingSurfaces.isEmpty()) {
+                tmpTransaction
+                        .setRelativeLayer(mOriginLeash, openingSurfaces.get(0), 1);
+            } else {
+                logW("Missing opening surface is exit transition");
+            }
+            if (!closingSurfaces.isEmpty()) {
+                tmpTransaction.setRelativeLayer(
+                        closingSurfaces.get(closingSurfaces.size() - 1), mOriginLeash, 1);
+            } else {
+                logW("Missing closing surface is exit transition");
+            }
         }
+        mStartTransaction.merge(tmpTransaction);
 
         // Attach origin UIComponent to origin leash.
         mOriginTransaction = mOrigin.newTransaction();
@@ -300,6 +328,7 @@
     }
 
     private void cancel() {
+        logD("cancel()");
         if (mAnimator != null) {
             mAnimator.cancel();
         }
@@ -311,6 +340,10 @@
         }
     }
 
+    private static void logW(String msg) {
+        Log.w(TAG, msg);
+    }
+
     private static void logE(String msg) {
         Log.e(TAG, msg);
     }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
index 5dbedc7..bf3360f 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
@@ -931,7 +931,9 @@
                         Modifier.requiredSize(dpSize)
                             .thenIf(!isItemDragging) {
                                 Modifier.animateItem(
-                                    placementSpec = spring(stiffness = Spring.StiffnessMediumLow)
+                                    placementSpec = spring(stiffness = Spring.StiffnessMediumLow),
+                                    // See b/376495198 - not supported with AndroidView
+                                    fadeOutSpec = null,
                                 )
                             }
                             .thenIf(isItemDragging) { Modifier.zIndex(1f) },
@@ -980,11 +982,14 @@
                     size = size,
                     selected = false,
                     modifier =
-                        Modifier.requiredSize(dpSize).animateItem().thenIf(
-                            communalResponsiveGrid()
-                        ) {
-                            Modifier.graphicsLayer { alpha = itemAlpha?.value ?: 1f }
-                        },
+                        Modifier.requiredSize(dpSize)
+                            .animateItem(
+                                // See b/376495198 - not supported with AndroidView
+                                fadeOutSpec = null
+                            )
+                            .thenIf(communalResponsiveGrid()) {
+                                Modifier.graphicsLayer { alpha = itemAlpha?.value ?: 1f }
+                            },
                     index = index,
                     contentListState = contentListState,
                     interactionHandler = interactionHandler,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeOverlay.kt b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeOverlay.kt
index 2af5ffa..5790c4a 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeOverlay.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeOverlay.kt
@@ -19,6 +19,7 @@
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.layout.layoutId
 import com.android.compose.animation.scene.ContentScope
@@ -84,7 +85,11 @@
                 viewModel.notificationsPlaceholderViewModelFactory.create()
             }
 
-        OverlayShade(modifier = modifier, onScrimClicked = viewModel::onScrimClicked) {
+        OverlayShade(
+            panelAlignment = Alignment.TopStart,
+            modifier = modifier,
+            onScrimClicked = viewModel::onScrimClicked,
+        ) {
             Column {
                 if (viewModel.showHeader) {
                     val burnIn = rememberBurnIn(clockInteractor)
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt
index b1a1945..f6c5f58 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt
@@ -99,7 +99,11 @@
         val viewModel =
             rememberViewModel("QuickSettingsShadeOverlay") { contentViewModelFactory.create() }
 
-        OverlayShade(modifier = modifier, onScrimClicked = viewModel::onScrimClicked) {
+        OverlayShade(
+            panelAlignment = Alignment.TopEnd,
+            modifier = modifier,
+            onScrimClicked = viewModel::onScrimClicked,
+        ) {
             Column {
                 ExpandedShadeHeader(
                     viewModelFactory = viewModel.shadeHeaderViewModelFactory,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt
index f821e42..cfbe667 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt
@@ -55,16 +55,17 @@
 import androidx.compose.ui.res.dimensionResource
 import androidx.compose.ui.unit.Velocity
 import androidx.compose.ui.unit.dp
+import com.android.compose.animation.scene.ContentScope
 import com.android.compose.animation.scene.ElementKey
 import com.android.compose.animation.scene.LowestZIndexContentPicker
-import com.android.compose.animation.scene.SceneScope
 import com.android.compose.animation.scene.effect.rememberOffsetOverscrollEffect
 import com.android.compose.windowsizeclass.LocalWindowSizeClass
 import com.android.systemui.res.R
 
 /** Renders a lightweight shade UI container, as an overlay. */
 @Composable
-fun SceneScope.OverlayShade(
+fun ContentScope.OverlayShade(
+    panelAlignment: Alignment,
     onScrimClicked: () -> Unit,
     modifier: Modifier = Modifier,
     content: @Composable () -> Unit,
@@ -87,7 +88,7 @@
     ) {
         Scrim(onClicked = onScrimClicked)
 
-        Box(modifier = Modifier.fillMaxSize().panelPadding(), contentAlignment = Alignment.TopEnd) {
+        Box(modifier = Modifier.fillMaxSize().panelPadding(), contentAlignment = panelAlignment) {
             Panel(
                 modifier =
                     Modifier.element(OverlayShade.Elements.Panel)
@@ -100,7 +101,7 @@
 }
 
 @Composable
-private fun SceneScope.Scrim(onClicked: () -> Unit, modifier: Modifier = Modifier) {
+private fun ContentScope.Scrim(onClicked: () -> Unit, modifier: Modifier = Modifier) {
     Spacer(
         modifier =
             modifier
@@ -112,7 +113,7 @@
 }
 
 @Composable
-private fun SceneScope.Panel(modifier: Modifier = Modifier, content: @Composable () -> Unit) {
+private fun ContentScope.Panel(modifier: Modifier = Modifier, content: @Composable () -> Unit) {
     Box(modifier = modifier.clip(OverlayShade.Shapes.RoundedCornerPanel)) {
         Spacer(
             modifier =
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
index f48fd3c..6bdd86e 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
@@ -241,7 +241,7 @@
             shadeTestUtil.setSplitShade(true)
 
             val horizontalPosition = checkNotNull(dimens).horizontalPosition
-            assertIs<HorizontalPosition.FloatAtEnd>(horizontalPosition)
+            assertIs<HorizontalPosition.FloatAtStart>(horizontalPosition)
             assertThat(horizontalPosition.width).isEqualTo(200)
         }
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/SystemUIBottomSheetDialogTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/SystemUIBottomSheetDialogTest.kt
index b560c59..1ee8005 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/SystemUIBottomSheetDialogTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/SystemUIBottomSheetDialogTest.kt
@@ -20,7 +20,9 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.kosmos.runTest
 import com.android.systemui.kosmos.testScope
+import com.android.systemui.kosmos.useUnconfinedTestDispatcher
 import com.android.systemui.statusbar.policy.ConfigurationController
 import com.android.systemui.testKosmos
 import com.android.systemui.util.mockito.any
@@ -31,7 +33,6 @@
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.flowOf
-import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
 import org.junit.Before
 import org.junit.runner.RunWith
@@ -43,7 +44,7 @@
 @RunWithLooper(setAsMainLooper = true)
 class SystemUIBottomSheetDialogTest : SysuiTestCase() {
 
-    private val kosmos = testKosmos()
+    private val kosmos = testKosmos().useUnconfinedTestDispatcher()
     private val configurationController = mock<ConfigurationController>()
     private val config = mock<Configuration>()
     private val delegate = mock<DialogDelegate<Dialog>>()
@@ -67,21 +68,17 @@
 
     @Test
     fun onStart_registersConfigCallback() {
-        kosmos.testScope.runTest {
+        kosmos.runTest {
             dialog.show()
-            runCurrent()
-
             verify(configurationController).addCallback(any())
         }
     }
 
     @Test
     fun onStop_unregisterConfigCallback() {
-        kosmos.testScope.runTest {
+        kosmos.runTest {
             dialog.show()
-            runCurrent()
             dialog.dismiss()
-            runCurrent()
 
             verify(configurationController).removeCallback(any())
         }
@@ -89,14 +86,12 @@
 
     @Test
     fun onConfigurationChanged_calledInDelegate() {
-        kosmos.testScope.runTest {
+        kosmos.runTest {
             dialog.show()
-            runCurrent()
             val captor = argumentCaptor<ConfigurationController.ConfigurationListener>()
             verify(configurationController).addCallback(capture(captor))
 
             captor.value.onConfigChanged(config)
-            runCurrent()
 
             verify(delegate).onConfigurationChanged(any(), any())
         }
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
index 9ae106c..014c0db 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
@@ -267,6 +267,7 @@
     }
 
     @Provides
+    @Nullable
     @Singleton
     static VirtualDeviceManager provideVirtualDeviceManager(Context context) {
         return context.getSystemService(VirtualDeviceManager.class);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/SharedNotificationContainer.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/SharedNotificationContainer.kt
index 42acd7bc..705845f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/SharedNotificationContainer.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/SharedNotificationContainer.kt
@@ -75,7 +75,7 @@
         constraintSet.apply {
             if (SceneContainerFlag.isEnabled) {
                 when (horizontalPosition) {
-                    is HorizontalPosition.FloatAtEnd ->
+                    is HorizontalPosition.FloatAtStart ->
                         constrainWidth(nsslId, horizontalPosition.width)
                     is HorizontalPosition.MiddleToEdge ->
                         setGuidelinePercent(R.id.nssl_guideline, horizontalPosition.ratio)
@@ -83,13 +83,13 @@
                 }
             }
 
+            connect(nsslId, START, startConstraintId, START, marginStart)
             if (
                 !SceneContainerFlag.isEnabled ||
-                    horizontalPosition !is HorizontalPosition.FloatAtEnd
+                    horizontalPosition !is HorizontalPosition.FloatAtStart
             ) {
-                connect(nsslId, START, startConstraintId, START, marginStart)
+                connect(nsslId, END, PARENT_ID, END, marginEnd)
             }
-            connect(nsslId, END, PARENT_ID, END, marginEnd)
             connect(nsslId, BOTTOM, PARENT_ID, BOTTOM, marginBottom)
             connect(nsslId, TOP, PARENT_ID, TOP, marginTop)
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
index b81c71e..fc8c70f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
@@ -247,7 +247,7 @@
                                 Split -> HorizontalPosition.MiddleToEdge(ratio = 0.5f)
                                 Dual ->
                                     if (isShadeLayoutWide) {
-                                        HorizontalPosition.FloatAtEnd(
+                                        HorizontalPosition.FloatAtStart(
                                             width = getDimensionPixelSize(R.dimen.shade_panel_width)
                                         )
                                     } else {
@@ -830,10 +830,10 @@
         data class MiddleToEdge(val ratio: Float = 0.5f) : HorizontalPosition
 
         /**
-         * The container has a fixed [width] and is aligned to the end of the screen. In this
-         * layout, the start edge of the container is floating, i.e. unconstrained.
+         * The container has a fixed [width] and is aligned to the start of the screen. In this
+         * layout, the end edge of the container is floating, i.e. unconstrained.
          */
-        data class FloatAtEnd(val width: Int) : HorizontalPosition
+        data class FloatAtStart(val width: Int) : HorizontalPosition
     }
 
     /**
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeSettings.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeSettings.kt
index a357275..f31697e8 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeSettings.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeSettings.kt
@@ -70,6 +70,14 @@
         }
     }
 
+    fun getContentObservers(uri: Uri, userHandle: Int): List<ContentObserver> {
+        if (userHandle == UserHandle.USER_ALL) {
+            return contentObserversAllUsers[uri.toString()] ?: listOf()
+        } else {
+            return contentObservers[SettingsKey(userHandle, uri.toString())] ?: listOf()
+        }
+    }
+
     override fun getContentResolver(): ContentResolver {
         throw UnsupportedOperationException("FakeSettings.getContentResolver is not implemented")
     }
diff --git a/tests/Input/src/com/android/test/input/KeyCharacterMapTest.kt b/tests/Input/src/com/android/test/input/KeyCharacterMapTest.kt
index 2818379..860d9f6 100644
--- a/tests/Input/src/com/android/test/input/KeyCharacterMapTest.kt
+++ b/tests/Input/src/com/android/test/input/KeyCharacterMapTest.kt
@@ -16,10 +16,17 @@
 
 package com.android.test.input
 
+import android.platform.test.annotations.EnableFlags
+import android.platform.test.flag.junit.SetFlagsRule
+
 import android.view.KeyCharacterMap
 import android.view.KeyEvent
 
+import com.android.hardware.input.Flags
+
 import org.junit.Assert.assertEquals
+import org.junit.Assert.assertNull
+import org.junit.Rule
 import org.junit.Test
 
 /**
@@ -30,26 +37,38 @@
  *
  */
 class KeyCharacterMapTest {
+    @get:Rule
+    val setFlagsRule = SetFlagsRule()
+
     @Test
+    @EnableFlags(Flags.FLAG_REMOVE_FALLBACK_MODIFIERS)
     fun testGetFallback() {
         // Based off of VIRTUAL kcm fallbacks.
         val keyCharacterMap = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD)
 
         // One modifier fallback.
-        assertEquals(
-            keyCharacterMap.getFallbackAction(KeyEvent.KEYCODE_SPACE,
-                KeyEvent.META_CTRL_ON).keyCode,
-            KeyEvent.KEYCODE_LANGUAGE_SWITCH)
+        val oneModifierFallback = keyCharacterMap.getFallbackAction(KeyEvent.KEYCODE_SPACE,
+            KeyEvent.META_CTRL_ON)
+        assertEquals(KeyEvent.KEYCODE_LANGUAGE_SWITCH, oneModifierFallback.keyCode)
+        assertEquals(0, oneModifierFallback.metaState)
 
         // Multiple modifier fallback.
-        assertEquals(
-            keyCharacterMap.getFallbackAction(KeyEvent.KEYCODE_DEL,
-                KeyEvent.META_CTRL_ON or KeyEvent.META_ALT_ON).keyCode,
-            KeyEvent.KEYCODE_BACK)
+        val twoModifierFallback = keyCharacterMap.getFallbackAction(KeyEvent.KEYCODE_DEL,
+            KeyEvent.META_CTRL_ON or KeyEvent.META_ALT_ON)
+        assertEquals(KeyEvent.KEYCODE_BACK, twoModifierFallback.keyCode)
+        assertEquals(0, twoModifierFallback.metaState)
 
         // No default button, fallback only.
-        assertEquals(
-            keyCharacterMap.getFallbackAction(KeyEvent.KEYCODE_BUTTON_A, 0).keyCode,
-            KeyEvent.KEYCODE_DPAD_CENTER)
+        val keyOnlyFallback =
+            keyCharacterMap.getFallbackAction(KeyEvent.KEYCODE_BUTTON_A, 0)
+        assertEquals(KeyEvent.KEYCODE_DPAD_CENTER, keyOnlyFallback.keyCode)
+        assertEquals(0, keyOnlyFallback.metaState)
+
+        // A key event that is not an exact match for a fallback. Expect a null return.
+        // E.g. Ctrl + Space -> LanguageSwitch
+        //      Ctrl + Alt + Space -> Ctrl + Alt + Space (No fallback).
+        val noMatchFallback = keyCharacterMap.getFallbackAction(KeyEvent.KEYCODE_SPACE,
+            KeyEvent.META_CTRL_ON or KeyEvent.META_ALT_ON)
+        assertNull(noMatchFallback)
     }
 }