Merge "Rename keylayout for SnakeByte iDroid:con to match by name" into sc-dev
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 67d29b5..646fbd3 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -3587,13 +3587,21 @@
     -->
     <integer name="config_respectsActivityMinWidthHeightMultiWindow">0</integer>
 
-    <!-- This value is only used when the device checks activity min width/height to determine if it
+    <!-- This value is only used when the device checks activity min height to determine if it
          can be shown in multi windowing modes.
-         If the activity min width/height is greater than this percentage of the display smallest
-         width, it will not be allowed to be shown in multi windowing modes.
+         If the activity min height is greater than this percentage of the display height in
+         portrait, it will not be allowed to be shown in multi windowing modes.
          The value should be between [0 - 1].
     -->
-    <item name="config_minPercentageMultiWindowSupportWidth" format="float" type="dimen">0.3</item>
+    <item name="config_minPercentageMultiWindowSupportHeight" format="float" type="dimen">0.3</item>
+
+    <!-- This value is only used when the device checks activity min width to determine if it
+         can be shown in multi windowing modes.
+         If the activity min width is greater than this percentage of the display width in
+         landscape, it will not be allowed to be shown in multi windowing modes.
+         The value should be between [0 - 1].
+    -->
+    <item name="config_minPercentageMultiWindowSupportWidth" format="float" type="dimen">0.5</item>
 
     <!-- If the display smallest screen width is greater or equal to this value, we will treat it
          as a large screen device, which will have some multi window features enabled by default.
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 9976f36..c05adfd 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -395,6 +395,7 @@
   <java-symbol type="bool" name="config_supportsMultiDisplay" />
   <java-symbol type="integer" name="config_supportsNonResizableMultiWindow" />
   <java-symbol type="integer" name="config_respectsActivityMinWidthHeightMultiWindow" />
+  <java-symbol type="dimen" name="config_minPercentageMultiWindowSupportHeight" />
   <java-symbol type="dimen" name="config_minPercentageMultiWindowSupportWidth" />
   <java-symbol type="integer" name="config_largeScreenSmallestScreenWidthDp" />
   <java-symbol type="bool" name="config_useLegacySplit" />
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 04291e3..12eb50e 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -428,6 +428,8 @@
         <!-- Permissions required for CTS test - TVInputManagerTest -->
         <permission name="android.permission.ACCESS_TUNED_INFO" />
         <permission name="android.permission.TV_INPUT_HARDWARE" />
+        <permission name="com.android.providers.tv.permission.ACCESS_WATCHED_PROGRAMS" />
+        <permission name="com.android.providers.tv.permission.WRITE_EPG_DATA"/>
         <!-- Permission required for CTS test - PrivilegedLocationPermissionTest -->
         <permission name="android.permission.LOCATION_HARDWARE" />
         <!-- Permissions required for GTS test - GtsDialerAudioTestCases -->
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizer.java
index 53dd391..75a1dde 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizer.java
@@ -19,8 +19,8 @@
 import static android.view.Display.DEFAULT_DISPLAY;
 
 import android.content.Context;
+import android.content.res.Configuration;
 import android.graphics.Insets;
-import android.graphics.Point;
 import android.graphics.Rect;
 import android.util.ArrayMap;
 import android.util.Log;
@@ -40,13 +40,12 @@
 import androidx.annotation.VisibleForTesting;
 
 import com.android.internal.R;
-import com.android.wm.shell.common.DisplayChangeController;
 import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.DisplayLayout;
 import com.android.wm.shell.common.ShellExecutor;
 
 import java.io.PrintWriter;
 import java.util.List;
-import java.util.concurrent.Executor;
 
 /**
  * Manages the display areas of hide display cutout feature.
@@ -76,19 +75,29 @@
     @VisibleForTesting
     int mRotation;
 
-    /**
-     * Handles rotation based on OnDisplayChangingListener callback.
-     */
-    private final DisplayChangeController.OnDisplayChangingListener mRotationController =
-            (display, fromRotation, toRotation, wct) -> {
-                mRotation = toRotation;
-                updateBoundsAndOffsets(true /* enable */);
-                final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
-                applyAllBoundsAndOffsets(wct, t);
-                // Only apply t here since the server will do the wct.apply when the method
-                // finishes.
-                t.apply();
-            };
+    private final DisplayController.OnDisplaysChangedListener mListener =
+            new DisplayController.OnDisplaysChangedListener() {
+                @Override
+                public void onDisplayConfigurationChanged(int displayId, Configuration newConfig) {
+                    if (displayId != DEFAULT_DISPLAY) {
+                        return;
+                    }
+                    DisplayLayout displayLayout =
+                            mDisplayController.getDisplayLayout(DEFAULT_DISPLAY);
+                    if (displayLayout == null) {
+                        return;
+                    }
+                    final boolean rotationChanged = mRotation != displayLayout.rotation();
+                    mRotation = displayLayout.rotation();
+                    if (rotationChanged || isDisplayBoundsChanged()) {
+                        updateBoundsAndOffsets(true /* enabled */);
+                        final WindowContainerTransaction wct = new WindowContainerTransaction();
+                        final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+                        applyAllBoundsAndOffsets(wct, t);
+                        applyTransaction(wct, t);
+                    }
+                }
+    };
 
     HideDisplayCutoutOrganizer(Context context, DisplayController displayController,
             ShellExecutor mainExecutor) {
@@ -154,10 +163,10 @@
      * Enables hide display cutout.
      */
     void enableHideDisplayCutout() {
-        mDisplayController.addDisplayChangingController(mRotationController);
-        final Display display = mDisplayController.getDisplay(DEFAULT_DISPLAY);
-        if (display != null) {
-            mRotation = display.getRotation();
+        mDisplayController.addDisplayWindowListener(mListener);
+        final DisplayLayout displayLayout = mDisplayController.getDisplayLayout(DEFAULT_DISPLAY);
+        if (displayLayout != null) {
+            mRotation = displayLayout.rotation();
         }
         final List<DisplayAreaAppearedInfo> displayAreaInfos =
                 registerOrganizer(DisplayAreaOrganizer.FEATURE_HIDE_DISPLAY_CUTOUT);
@@ -174,7 +183,7 @@
      */
     void disableHideDisplayCutout() {
         updateBoundsAndOffsets(false /* enabled */);
-        mDisplayController.removeDisplayChangingController(mRotationController);
+        mDisplayController.removeDisplayWindowListener(mListener);
         unregisterOrganizer();
     }
 
@@ -193,23 +202,35 @@
 
     @VisibleForTesting
     Rect getDisplayBoundsOfNaturalOrientation() {
-        Point realSize = new Point(0, 0);
-        final Display display = mDisplayController.getDisplay(DEFAULT_DISPLAY);
-        if (display != null) {
-            display.getRealSize(realSize);
+        final DisplayLayout displayLayout = mDisplayController.getDisplayLayout(DEFAULT_DISPLAY);
+        if (displayLayout == null) {
+            return new Rect();
         }
         final boolean isDisplaySizeFlipped = isDisplaySizeFlipped();
         return new Rect(
                 0,
                 0,
-                isDisplaySizeFlipped ? realSize.y : realSize.x,
-                isDisplaySizeFlipped ? realSize.x : realSize.y);
+                isDisplaySizeFlipped ? displayLayout.height() : displayLayout.width(),
+                isDisplaySizeFlipped ? displayLayout.width() : displayLayout.height());
     }
 
     private boolean isDisplaySizeFlipped() {
         return mRotation == Surface.ROTATION_90 || mRotation == Surface.ROTATION_270;
     }
 
+    private boolean isDisplayBoundsChanged() {
+        final DisplayLayout displayLayout = mDisplayController.getDisplayLayout(DEFAULT_DISPLAY);
+        if (displayLayout == null) {
+            return false;
+        }
+        final boolean isDisplaySizeFlipped = isDisplaySizeFlipped();
+        final int width = isDisplaySizeFlipped ? displayLayout.height() : displayLayout.width();
+        final int height = isDisplaySizeFlipped ? displayLayout.width() : displayLayout.height();
+        return mDefaultDisplayBounds.isEmpty()
+                || mDefaultDisplayBounds.width() != width
+                || mDefaultDisplayBounds.height() != height;
+    }
+
     /**
      * Updates bounds and offsets according to current state.
      *
@@ -237,7 +258,6 @@
                         mCurrentDisplayBounds.right);
             }
             mCurrentDisplayBounds.inset(mCurrentCutoutInsets);
-
             // Replace the top bound with the max(status bar height, cutout height) if there is
             // cutout on the top side.
             mStatusBarHeight = getStatusBarHeight();
@@ -256,7 +276,7 @@
     }
 
     private void initDefaultValuesIfNeeded() {
-        if (!mDefaultDisplayBounds.isEmpty()) {
+        if (!isDisplayBoundsChanged()) {
             return;
         }
         mDefaultDisplayBounds.set(getDisplayBoundsOfNaturalOrientation());
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
index bf75372..1cc7ed3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
@@ -500,6 +500,11 @@
 
     @VisibleForTesting
     void onActivatedActionChanged() {
+        if (!isShortcutEnabled()) {
+            Slog.w(TAG, "Shortcut not enabled, skip onActivatedActionChanged()");
+            return;
+        }
+
         if (!isOneHandedEnabled()) {
             final boolean success = mOneHandedSettingsUtil.setOneHandedModeEnabled(
                     mContext.getContentResolver(), 1 /* Enabled for shortcut */, mUserId);
@@ -614,6 +619,11 @@
     }
 
     @VisibleForTesting
+    boolean isShortcutEnabled() {
+        return mOneHandedSettingsUtil.getShortcutEnabled(mContext.getContentResolver(), mUserId);
+    }
+
+    @VisibleForTesting
     boolean isSwipeToNotificationEnabled() {
         return mIsSwipeToNotificationEnabled;
     }
@@ -623,8 +633,11 @@
             mMainExecutor.execute(() -> stopOneHanded());
         }
 
-        // Reset and align shortcut one_handed_mode_activated status with current mState
-        notifyShortcutState(mState.getState());
+        // If setting is pull screen, notify shortcut one_handed_mode_activated to reset
+        // and align status with current mState when function enabled.
+        if (isOneHandedEnabled() && !isSwipeToNotificationEnabled()) {
+            notifyShortcutState(mState.getState());
+        }
 
         mTouchHandler.onOneHandedEnabled(mIsOneHandedEnabled);
 
@@ -723,6 +736,8 @@
         pw.println(mLockedDisabled);
         pw.print(innerPrefix + "mUserId=");
         pw.println(mUserId);
+        pw.print(innerPrefix + "isShortcutEnabled=");
+        pw.println(isShortcutEnabled());
 
         if (mBackgroundPanelOrganizer != null) {
             mBackgroundPanelOrganizer.dump(pw);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java
index da53b35..3baa69f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java
@@ -16,6 +16,8 @@
 
 package com.android.wm.shell.onehanded;
 
+import static com.android.internal.accessibility.AccessibilityShortcutController.ONE_HANDED_COMPONENT_NAME;
+
 import android.annotation.IntDef;
 import android.content.ContentResolver;
 import android.database.ContentObserver;
@@ -34,6 +36,9 @@
 public final class OneHandedSettingsUtil {
     private static final String TAG = "OneHandedSettingsUtil";
 
+    private static final String ONE_HANDED_MODE_TARGET_NAME =
+            ONE_HANDED_COMPONENT_NAME.getShortClassName();
+
     @IntDef(prefix = {"ONE_HANDED_TIMEOUT_"}, value = {
             ONE_HANDED_TIMEOUT_NEVER,
             ONE_HANDED_TIMEOUT_SHORT_IN_SECONDS,
@@ -158,6 +163,17 @@
     }
 
     /**
+     * Queries one-handed mode shortcut enabled in settings or not.
+     *
+     * @return true if user enabled one-handed shortcut in settings, false otherwise.
+     */
+    public boolean getShortcutEnabled(ContentResolver resolver, int userId) {
+        final String targets = Settings.Secure.getStringForUser(resolver,
+                Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, userId);
+        return targets != null ? targets.contains(ONE_HANDED_MODE_TARGET_NAME) : false;
+    }
+
+    /**
      * Sets tutorial shown counts.
      *
      * @return true if the value was set, false on database errors.
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizerTest.java
index 9637570..3c124ba 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizerTest.java
@@ -50,6 +50,7 @@
 
 import com.android.internal.R;
 import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.DisplayLayout;
 import com.android.wm.shell.common.ShellExecutor;
 
 import org.junit.Before;
@@ -82,6 +83,8 @@
     @Mock
     private Display mDisplay;
     @Mock
+    private DisplayLayout mDisplayLayout;
+    @Mock
     private IWindowContainerToken mMockRealToken;
     private WindowContainerToken mToken;
 
@@ -95,6 +98,7 @@
         MockitoAnnotations.initMocks(this);
 
         when(mMockDisplayController.getDisplay(anyInt())).thenReturn(mDisplay);
+        when(mMockDisplayController.getDisplayLayout(anyInt())).thenReturn(mDisplayLayout);
 
         HideDisplayCutoutOrganizer organizer = new HideDisplayCutoutOrganizer(
                 mContext, mMockDisplayController, mMockMainExecutor);
@@ -152,7 +156,7 @@
                 .getDisplayCutoutInsetsOfNaturalOrientation();
         mContext.getOrCreateTestableResources().addOverride(
                 R.dimen.status_bar_height_portrait, mFakeStatusBarHeightPortrait);
-        doReturn(Surface.ROTATION_0).when(mDisplay).getRotation();
+        doReturn(Surface.ROTATION_0).when(mDisplayLayout).rotation();
         mOrganizer.enableHideDisplayCutout();
 
         verify(mOrganizer).registerOrganizer(DisplayAreaOrganizer.FEATURE_HIDE_DISPLAY_CUTOUT);
@@ -171,7 +175,7 @@
                 .getDisplayCutoutInsetsOfNaturalOrientation();
         mContext.getOrCreateTestableResources().addOverride(
                 R.dimen.status_bar_height_landscape, mFakeStatusBarHeightLandscape);
-        doReturn(Surface.ROTATION_90).when(mDisplay).getRotation();
+        doReturn(Surface.ROTATION_90).when(mDisplayLayout).rotation();
         mOrganizer.enableHideDisplayCutout();
 
         verify(mOrganizer).registerOrganizer(DisplayAreaOrganizer.FEATURE_HIDE_DISPLAY_CUTOUT);
@@ -190,7 +194,7 @@
                 .getDisplayCutoutInsetsOfNaturalOrientation();
         mContext.getOrCreateTestableResources().addOverride(
                 R.dimen.status_bar_height_landscape, mFakeStatusBarHeightLandscape);
-        doReturn(Surface.ROTATION_270).when(mDisplay).getRotation();
+        doReturn(Surface.ROTATION_270).when(mDisplayLayout).rotation();
         mOrganizer.enableHideDisplayCutout();
 
         verify(mOrganizer).registerOrganizer(DisplayAreaOrganizer.FEATURE_HIDE_DISPLAY_CUTOUT);
@@ -219,4 +223,22 @@
         assertThat(mOrganizer.mOffsetX).isEqualTo(0);
         assertThat(mOrganizer.mOffsetY).isEqualTo(0);
     }
+
+    @Test
+    public void testDisplaySizeChange() {
+        doReturn(100).when(mDisplayLayout).width();
+        doReturn(200).when(mDisplayLayout).height();
+        doReturn(mFakeDefaultCutoutInsets).when(mOrganizer)
+                .getDisplayCutoutInsetsOfNaturalOrientation();
+        mContext.getOrCreateTestableResources().addOverride(
+                R.dimen.status_bar_height_portrait, mFakeStatusBarHeightPortrait);
+        doReturn(Surface.ROTATION_0).when(mDisplayLayout).rotation();
+        mOrganizer.enableHideDisplayCutout();
+        assertThat(mOrganizer.mCurrentDisplayBounds).isEqualTo(new Rect(0, 15, 100, 200));
+
+        doReturn(200).when(mDisplayLayout).width();
+        doReturn(400).when(mDisplayLayout).height();
+        mOrganizer.updateBoundsAndOffsets(true);
+        assertThat(mOrganizer.mCurrentDisplayBounds).isEqualTo(new Rect(0, 15, 200, 400));
+    }
 }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java
index 9509003..be786fb 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java
@@ -118,6 +118,7 @@
                 mDefaultTapAppToExitEnabled);
         when(mMockSettingsUitl.getSettingsSwipeToNotificationEnabled(any(), anyInt())).thenReturn(
                 mDefaultSwipeToNotificationEnabled);
+        when(mMockSettingsUitl.getShortcutEnabled(any(), anyInt())).thenReturn(false);
 
         when(mMockDisplayAreaOrganizer.getLastDisplayBounds()).thenReturn(
                 new Rect(0, 0, mDisplayLayout.width(), mDisplayLayout.height()));
@@ -341,6 +342,7 @@
         when(mSpiedTransitionState.getState()).thenReturn(STATE_ACTIVE);
         when(mSpiedTransitionState.isTransitioning()).thenReturn(false);
         when(mMockSettingsUitl.getOneHandedModeActivated(any(), anyInt())).thenReturn(true);
+        when(mSpiedOneHandedController.isShortcutEnabled()).thenReturn(true);
         mSpiedOneHandedController.onActivatedActionChanged();
 
         verify(mSpiedOneHandedController, never()).startOneHanded();
@@ -352,6 +354,7 @@
         when(mSpiedTransitionState.getState()).thenReturn(STATE_NONE);
         when(mSpiedTransitionState.isTransitioning()).thenReturn(false);
         when(mMockSettingsUitl.getOneHandedModeActivated(any(), anyInt())).thenReturn(false);
+        when(mSpiedOneHandedController.isShortcutEnabled()).thenReturn(true);
         mSpiedOneHandedController.onActivatedActionChanged();
 
         verify(mSpiedOneHandedController, never()).startOneHanded();
@@ -363,6 +366,7 @@
         when(mSpiedTransitionState.getState()).thenReturn(STATE_NONE);
         when(mSpiedTransitionState.isTransitioning()).thenReturn(false);
         when(mMockSettingsUitl.getOneHandedModeActivated(any(), anyInt())).thenReturn(true);
+        when(mSpiedOneHandedController.isShortcutEnabled()).thenReturn(true);
         mSpiedOneHandedController.onActivatedActionChanged();
 
         verify(mSpiedOneHandedController).startOneHanded();
@@ -374,6 +378,7 @@
         when(mSpiedTransitionState.getState()).thenReturn(STATE_ENTERING);
         when(mSpiedTransitionState.isTransitioning()).thenReturn(true);
         when(mMockSettingsUitl.getOneHandedModeActivated(any(), anyInt())).thenReturn(true);
+        when(mSpiedOneHandedController.isShortcutEnabled()).thenReturn(true);
         mSpiedOneHandedController.onActivatedActionChanged();
 
         verify(mSpiedTransitionState, never()).setState(STATE_EXITING);
@@ -384,6 +389,7 @@
         when(mSpiedTransitionState.getState()).thenReturn(STATE_EXITING);
         when(mSpiedTransitionState.isTransitioning()).thenReturn(true);
         when(mMockSettingsUitl.getOneHandedModeActivated(any(), anyInt())).thenReturn(true);
+        when(mSpiedOneHandedController.isShortcutEnabled()).thenReturn(true);
         mSpiedOneHandedController.onActivatedActionChanged();
 
         verify(mSpiedTransitionState, never()).setState(STATE_ENTERING);
@@ -392,6 +398,7 @@
     @Test
     public void testOneHandedDisabled_shortcutTrigger_thenAutoEnabled() {
         when(mSpiedOneHandedController.isOneHandedEnabled()).thenReturn(false);
+        when(mSpiedOneHandedController.isShortcutEnabled()).thenReturn(true);
         when(mSpiedTransitionState.getState()).thenReturn(STATE_NONE);
         when(mSpiedTransitionState.isTransitioning()).thenReturn(false);
         when(mMockSettingsUitl.getOneHandedModeActivated(any(), anyInt())).thenReturn(false);
@@ -417,6 +424,7 @@
         when(mSpiedOneHandedController.isOneHandedEnabled()).thenReturn(true);
         when(mSpiedTransitionState.getState()).thenReturn(STATE_NONE);
         when(mSpiedTransitionState.isTransitioning()).thenReturn(false);
+        when(mSpiedOneHandedController.isShortcutEnabled()).thenReturn(true);
         when(mSpiedOneHandedController.isSwipeToNotificationEnabled()).thenReturn(true);
         mSpiedOneHandedController.registerEventCallback(mMockEventCallback);
         mSpiedOneHandedController.onActivatedActionChanged();
@@ -425,11 +433,11 @@
     }
 
     @Test
-    public void testNotifyShortcutState_whenUpdateOneHandedEnabled() {
-        when(mSpiedOneHandedController.isOneHandedEnabled()).thenReturn(false);
+    public void testNotifyShortcutState_whenSetOneHandedEnabled() {
+        when(mSpiedOneHandedController.isOneHandedEnabled()).thenReturn(true);
         when(mSpiedTransitionState.getState()).thenReturn(STATE_NONE);
         when(mSpiedTransitionState.isTransitioning()).thenReturn(false);
-        when(mSpiedOneHandedController.isSwipeToNotificationEnabled()).thenReturn(true);
+        when(mSpiedOneHandedController.isSwipeToNotificationEnabled()).thenReturn(false);
         mSpiedOneHandedController.registerEventCallback(mMockEventCallback);
         mSpiedOneHandedController.setOneHandedEnabled(true);
 
@@ -448,4 +456,31 @@
         // Verify no NPE crash and mMockShellMainExecutor never be execute.
         verify(mMockShellMainExecutor, never()).execute(any());
     }
+
+    @Test
+    public void testShortcutEnable_ableToAutoEnableOneHandedMode() {
+        when(mSpiedOneHandedController.isOneHandedEnabled()).thenReturn(false);
+        when(mSpiedTransitionState.getState()).thenReturn(STATE_NONE);
+        when(mSpiedTransitionState.isTransitioning()).thenReturn(false);
+        when(mSpiedOneHandedController.isShortcutEnabled()).thenReturn(true);
+        when(mSpiedOneHandedController.isSwipeToNotificationEnabled()).thenReturn(false);
+        when(mMockSettingsUitl.setOneHandedModeEnabled(any(), anyInt(), anyInt())).thenReturn(
+                false /* To avoid test runner create Toast */);
+        mSpiedOneHandedController.onActivatedActionChanged();
+
+        verify(mSpiedOneHandedController).notifyUserConfigChanged(anyBoolean());
+    }
+
+    @Test
+    public void testShortcutDisable_shouldNotAutoEnableOneHandedMode() {
+        when(mSpiedOneHandedController.isOneHandedEnabled()).thenReturn(false);
+        when(mSpiedTransitionState.getState()).thenReturn(STATE_NONE);
+        when(mSpiedTransitionState.isTransitioning()).thenReturn(false);
+        when(mSpiedOneHandedController.isSwipeToNotificationEnabled()).thenReturn(false);
+        when(mMockSettingsUitl.setOneHandedModeEnabled(any(), anyInt(), anyInt())).thenReturn(true);
+        mSpiedOneHandedController.onActivatedActionChanged();
+
+        verify(mMockSettingsUitl, never()).setOneHandedModeEnabled(any(), anyInt(), anyInt());
+        verify(mSpiedOneHandedController, never()).notifyUserConfigChanged(anyBoolean());
+    }
 }
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseFragment.java b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseFragment.java
index faa73ff..e702668 100644
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseFragment.java
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseFragment.java
@@ -42,6 +42,8 @@
     private static final String KEY_IS_TOOLBAR_COLLAPSED = "is_toolbar_collapsed";
 
     @Nullable
+    private CoordinatorLayout mCoordinatorLayout;
+    @Nullable
     private CollapsingToolbarLayout mCollapsingToolbarLayout;
     @Nullable
     private AppBarLayout mAppBarLayout;
@@ -57,9 +59,12 @@
             @Nullable Bundle savedInstanceState) {
         final View view = inflater.inflate(R.layout.collapsing_toolbar_base_layout, container,
                 false);
+        mCoordinatorLayout = view.findViewById(R.id.content_parent);
         mCollapsingToolbarLayout = view.findViewById(R.id.collapsing_toolbar);
         mAppBarLayout = view.findViewById(R.id.app_bar);
-        mAppBarLayout.addOnOffsetChangedListener(this);
+        if (mAppBarLayout != null) {
+            mAppBarLayout.addOnOffsetChangedListener(this);
+        }
         if (savedInstanceState != null) {
             mIsToolbarCollapsed = savedInstanceState.getBoolean(KEY_IS_TOOLBAR_COLLAPSED);
         }
@@ -95,6 +100,14 @@
     }
 
     /**
+     * Return an instance of CoordinatorLayout.
+     */
+    @Nullable
+    public CoordinatorLayout getCoordinatorLayout() {
+        return mCoordinatorLayout;
+    }
+
+    /**
      * Return an instance of app bar.
      */
     @Nullable
diff --git a/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_thumb_disabled.xml b/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_thumb_disabled.xml
deleted file mode 100644
index b41762f..0000000
--- a/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_thumb_disabled.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  Copyright (C) 2021 The Android Open Source Project
-
-  Licensed under the Apache License, Version 2.0 (the "License");
-  you may not use this file except in compliance with the License.
-  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License.
-  -->
-
-<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
-    <item
-        android:top="@dimen/settingslib_switch_thumb_margin"
-        android:left="@dimen/settingslib_switch_thumb_margin"
-        android:right="@dimen/settingslib_switch_thumb_margin"
-        android:bottom="@dimen/settingslib_switch_thumb_margin">
-        <shape android:shape="oval">
-            <size
-                android:height="@dimen/settingslib_switch_thumb_size"
-                android:width="@dimen/settingslib_switch_thumb_size"/>
-            <solid
-                android:color="@color/settingslib_thumb_off_color"
-                android:alpha="?android:attr/disabledAlpha"/>
-        </shape>
-    </item>
-</layer-list>
diff --git a/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_thumb_off.xml b/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_thumb_off.xml
deleted file mode 100644
index 8b69ad1..0000000
--- a/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_thumb_off.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  Copyright (C) 2020 The Android Open Source Project
-
-  Licensed under the Apache License, Version 2.0 (the "License");
-  you may not use this file except in compliance with the License.
-  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License.
-  -->
-
-<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
-    <item
-        android:top="@dimen/settingslib_switch_thumb_margin"
-        android:left="@dimen/settingslib_switch_thumb_margin"
-        android:right="@dimen/settingslib_switch_thumb_margin"
-        android:bottom="@dimen/settingslib_switch_thumb_margin">
-        <shape android:shape="oval">
-            <size
-                android:height="@dimen/settingslib_switch_thumb_size"
-                android:width="@dimen/settingslib_switch_thumb_size"/>
-            <solid android:color="@color/settingslib_thumb_off_color"/>
-        </shape>
-    </item>
-</layer-list>
diff --git a/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_thumb_on.xml b/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_thumb_on.xml
deleted file mode 100644
index 0f27fc2..0000000
--- a/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_thumb_on.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  Copyright (C) 2020 The Android Open Source Project
-
-  Licensed under the Apache License, Version 2.0 (the "License");
-  you may not use this file except in compliance with the License.
-  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License.
-  -->
-
-<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
-    <item
-        android:top="@dimen/settingslib_switch_thumb_margin"
-        android:left="@dimen/settingslib_switch_thumb_margin"
-        android:right="@dimen/settingslib_switch_thumb_margin"
-        android:bottom="@dimen/settingslib_switch_thumb_margin">
-        <shape android:shape="oval">
-            <size
-                android:height="@dimen/settingslib_switch_thumb_size"
-                android:width="@dimen/settingslib_switch_thumb_size"/>
-            <solid android:color="@color/settingslib_state_on_color"/>
-        </shape>
-    </item>
-</layer-list>
diff --git a/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_thumb_selector.xml b/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_thumb_selector.xml
deleted file mode 100644
index 06bb779..0000000
--- a/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_thumb_selector.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  Copyright (C) 2020 The Android Open Source Project
-
-  Licensed under the Apache License, Version 2.0 (the "License");
-  you may not use this file except in compliance with the License.
-  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License.
-  -->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:drawable="@drawable/settingslib_thumb_on" android:state_checked="true"/>
-    <item android:drawable="@drawable/settingslib_thumb_off" android:state_checked="false"/>
-    <item android:drawable="@drawable/settingslib_thumb_disabled" android:state_enabled="false"/>
-</selector>
diff --git a/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_track_disabled_background.xml b/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_track_disabled_background.xml
deleted file mode 100644
index 15dfcb7..0000000
--- a/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_track_disabled_background.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  Copyright (C) 2021 The Android Open Source Project
-
-  Licensed under the Apache License, Version 2.0 (the "License");
-  you may not use this file except in compliance with the License.
-  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License.
-  -->
-
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
-    android:shape="rectangle"
-    android:width="@dimen/settingslib_switch_track_width"
-    android:height="@dimen/settingslib_switch_track_height">
-    <solid
-        android:color="@color/settingslib_track_off_color"
-        android:alpha="?android:attr/disabledAlpha"/>
-    <corners android:radius="@dimen/settingslib_switch_track_radius"/>
-</shape>
diff --git a/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_track_off_background.xml b/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_track_off_background.xml
deleted file mode 100644
index 4d79a6e..0000000
--- a/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_track_off_background.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  Copyright (C) 2020 The Android Open Source Project
-
-  Licensed under the Apache License, Version 2.0 (the "License");
-  you may not use this file except in compliance with the License.
-  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License.
-  -->
-
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
-    android:shape="rectangle"
-    android:width="@dimen/settingslib_switch_track_width"
-    android:height="@dimen/settingslib_switch_track_height">
-    <solid android:color="@color/settingslib_track_off_color"/>
-    <corners android:radius="@dimen/settingslib_switch_track_radius"/>
-</shape>
diff --git a/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_track_on_background.xml b/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_track_on_background.xml
deleted file mode 100644
index c12d012..0000000
--- a/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_track_on_background.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  Copyright (C) 2020 The Android Open Source Project
-
-  Licensed under the Apache License, Version 2.0 (the "License");
-  you may not use this file except in compliance with the License.
-  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License.
-  -->
-
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
-    android:shape="rectangle"
-    android:width="@dimen/settingslib_switch_track_width"
-    android:height="@dimen/settingslib_switch_track_height">
-    <solid android:color="@color/settingslib_track_on_color"/>
-    <corners android:radius="@dimen/settingslib_switch_track_radius"/>
-</shape>
diff --git a/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_track_selector.xml b/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_track_selector.xml
deleted file mode 100644
index a38c3b4..0000000
--- a/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_track_selector.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  Copyright (C) 2020 The Android Open Source Project
-
-  Licensed under the Apache License, Version 2.0 (the "License");
-  you may not use this file except in compliance with the License.
-  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License.
-  -->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:drawable="@drawable/settingslib_track_on_background" android:state_checked="true"/>
-    <item android:drawable="@drawable/settingslib_track_off_background" android:state_checked="false"/>
-    <item android:drawable="@drawable/settingslib_track_disabled_background" android:state_enabled="false"/>
-</selector>
diff --git a/packages/SettingsLib/MainSwitchPreference/res/layout-v31/settingslib_main_switch_bar.xml b/packages/SettingsLib/MainSwitchPreference/res/layout-v31/settingslib_main_switch_bar.xml
index f9e9eab..2518a6d 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/layout-v31/settingslib_main_switch_bar.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/layout-v31/settingslib_main_switch_bar.xml
@@ -60,9 +60,7 @@
             android:layout_gravity="center_vertical"
             android:focusable="false"
             android:clickable="false"
-            android:track="@drawable/settingslib_track_selector"
-            android:thumb="@drawable/settingslib_thumb_selector"
-            android:theme="@style/MainSwitch.Settingslib"/>
+            android:theme="@style/Switch.SettingsLib"/>
     </LinearLayout>
 
 </LinearLayout>
diff --git a/packages/SettingsLib/MainSwitchPreference/res/values/dimens.xml b/packages/SettingsLib/MainSwitchPreference/res/values/dimens.xml
index a1cbcf72..a386adb 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/values/dimens.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/values/dimens.xml
@@ -41,21 +41,6 @@
     <!-- Radius of switch bar -->
     <dimen name="settingslib_switch_bar_radius">28dp</dimen>
 
-    <!-- Margin of switch thumb -->
-    <dimen name="settingslib_switch_thumb_margin">4dp</dimen>
-
-    <!-- Size of switch thumb -->
-    <dimen name="settingslib_switch_thumb_size">20dp</dimen>
-
-    <!-- Width of switch track -->
-    <dimen name="settingslib_switch_track_width">52dp</dimen>
-
-    <!-- Height of switch track -->
-    <dimen name="settingslib_switch_track_height">28dp</dimen>
-
-    <!-- Radius of switch track -->
-    <dimen name="settingslib_switch_track_radius">35dp</dimen>
-
     <!-- SwitchBar sub settings margin start / end -->
     <dimen name="settingslib_switchbar_subsettings_margin_start">72dp</dimen>
     <dimen name="settingslib_switchbar_subsettings_margin_end">16dp</dimen>
diff --git a/packages/SettingsLib/MainSwitchPreference/res/values/styles.xml b/packages/SettingsLib/MainSwitchPreference/res/values/styles.xml
index 472025a..3924e30 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/values/styles.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/values/styles.xml
@@ -23,9 +23,6 @@
         <item name="android:textColor">@android:color/black</item>
     </style>
 
-    <style name="MainSwitch.Settingslib" parent="@android:style/Widget.Material.CompoundButton.Switch">
-        <item name="android:switchMinWidth">@dimen/settingslib_min_switch_width</item>
-    </style>
 
     <style name="SwitchBar.Switch.Settingslib" parent="@android:style/Widget.Material.CompoundButton.Switch">
         <item name="android:trackTint">@color/settingslib_switchbar_switch_track_tint</item>
diff --git a/packages/SettingsLib/src/com/android/settingslib/notification/ConversationIconFactory.java b/packages/SettingsLib/src/com/android/settingslib/notification/ConversationIconFactory.java
index 549bc8a..ebdfbea 100644
--- a/packages/SettingsLib/src/com/android/settingslib/notification/ConversationIconFactory.java
+++ b/packages/SettingsLib/src/com/android/settingslib/notification/ConversationIconFactory.java
@@ -33,6 +33,7 @@
 
 import com.android.launcher3.icons.BaseIconFactory;
 import com.android.settingslib.R;
+import com.android.settingslib.Utils;
 
 /**
  * Factory for creating normalized conversation icons.
@@ -99,7 +100,7 @@
         try {
             final ApplicationInfo appInfo = mPackageManager.getApplicationInfoAsUser(
                     packageName, PackageManager.GET_META_DATA, userId);
-            badge = mIconDrawableFactory.getBadgedIcon(appInfo, userId);
+            badge = Utils.getBadgedIcon(mContext, appInfo);
         } catch (PackageManager.NameNotFoundException e) {
             badge = mPackageManager.getDefaultActivityIcon();
         }
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index f7123c1..491f0d9 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -436,6 +436,8 @@
     <!-- Permissions required for CTS test - TVInputManagerTest -->
     <uses-permission android:name="android.permission.ACCESS_TUNED_INFO" />
     <uses-permission android:name="android.permission.TV_INPUT_HARDWARE" />
+    <uses-permission android:name="com.android.providers.tv.permission.ACCESS_WATCHED_PROGRAMS" />
+    <uses-permission android:name="com.android.providers.tv.permission.WRITE_EPG_DATA"/>
 
     <!-- Permission needed for CTS test - PrivilegedLocationPermissionTest -->
     <uses-permission android:name="android.permission.LOCATION_HARDWARE" />
diff --git a/packages/SystemUI/res/layout/people_space_activity_no_conversations.xml b/packages/SystemUI/res/layout/people_space_activity_no_conversations.xml
index 2a4a21f..e87bf61 100644
--- a/packages/SystemUI/res/layout/people_space_activity_no_conversations.xml
+++ b/packages/SystemUI/res/layout/people_space_activity_no_conversations.xml
@@ -48,13 +48,13 @@
 
     <Button
         style="?android:attr/buttonBarButtonStyle"
-        android:id="@+id/okay_button"
+        android:id="@+id/got_it_button"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_gravity="center"
         android:background="@drawable/rounded_bg_full_large_radius"
         android:onClick="dismissActivity"
-        android:text="@string/okay"
+        android:text="@string/got_it"
         android:textColor="?android:attr/textColorPrimary"
         android:layout_marginBottom="60dp"
         android:layout_alignParentBottom="true" />
@@ -62,7 +62,7 @@
     <LinearLayout
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_above="@id/okay_button"
+        android:layout_above="@id/got_it_button"
         android:layout_below="@id/select_conversation"
         android:layout_centerInParent="true"
         android:clipToOutline="true">
@@ -72,7 +72,7 @@
             android:layout_height="100dp"
             android:layout_gravity="center"
             android:background="@drawable/rounded_bg_full_large_radius"
-            android:layout_above="@id/okay_button">
+            android:layout_above="@id/got_it_button">
             <include layout="@layout/people_space_placeholder_layout" />
         </LinearLayout>
     </LinearLayout>
diff --git a/packages/SystemUI/res/layout/people_space_initial_layout.xml b/packages/SystemUI/res/layout/people_space_initial_layout.xml
index c57ec34..9892041 100644
--- a/packages/SystemUI/res/layout/people_space_initial_layout.xml
+++ b/packages/SystemUI/res/layout/people_space_initial_layout.xml
@@ -22,7 +22,8 @@
 
     <LinearLayout
         android:background="@drawable/people_space_tile_view_card"
-        android:id="@+id/item"
+        android:clipToOutline="true"
+        android:id="@android:id/background"
         android:orientation="horizontal"
         android:gravity="center"
         android:layout_gravity="top"
diff --git a/packages/SystemUI/res/layout/people_space_placeholder_layout.xml b/packages/SystemUI/res/layout/people_space_placeholder_layout.xml
index 5f1aa22..c728bee 100644
--- a/packages/SystemUI/res/layout/people_space_placeholder_layout.xml
+++ b/packages/SystemUI/res/layout/people_space_placeholder_layout.xml
@@ -22,7 +22,8 @@
 
     <LinearLayout
         android:background="@drawable/people_space_tile_view_card"
-        android:id="@+id/item"
+        android:clipToOutline="true"
+        android:id="@android:id/background"
         android:orientation="horizontal"
         android:gravity="center"
         android:layout_gravity="center"
diff --git a/packages/SystemUI/res/layout/people_space_widget_item.xml b/packages/SystemUI/res/layout/people_space_widget_item.xml
index 17d0c56..492d3ab 100644
--- a/packages/SystemUI/res/layout/people_space_widget_item.xml
+++ b/packages/SystemUI/res/layout/people_space_widget_item.xml
@@ -21,7 +21,8 @@
     android:orientation="vertical">
     <LinearLayout
         android:background="@drawable/people_space_tile_view_card"
-        android:id="@+id/item"
+        android:clipToOutline="true"
+        android:id="@android:id/background"
         android:orientation="vertical"
         android:padding="4dp"
         android:layout_marginBottom="2dp"
diff --git a/packages/SystemUI/res/layout/people_tile_empty_layout.xml b/packages/SystemUI/res/layout/people_tile_empty_layout.xml
index 8e9ebc6..f115002 100644
--- a/packages/SystemUI/res/layout/people_tile_empty_layout.xml
+++ b/packages/SystemUI/res/layout/people_tile_empty_layout.xml
@@ -14,9 +14,10 @@
   ~ limitations under the License.
   -->
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/item"
+    android:id="@android:id/background"
     android:theme="@android:style/Theme.DeviceDefault.DayNight"
     android:background="@drawable/people_tile_empty_background"
+    android:clipToOutline="true"
     android:layout_width="match_parent"
     android:layout_height="match_parent">
 
diff --git a/packages/SystemUI/res/layout/people_tile_large_empty.xml b/packages/SystemUI/res/layout/people_tile_large_empty.xml
index d4a8e15..f2a3922 100644
--- a/packages/SystemUI/res/layout/people_tile_large_empty.xml
+++ b/packages/SystemUI/res/layout/people_tile_large_empty.xml
@@ -14,8 +14,9 @@
   ~ limitations under the License.
   -->
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/item"
+    android:id="@android:id/background"
     android:background="@drawable/people_space_tile_view_card"
+    android:clipToOutline="true"
     android:theme="@android:style/Theme.DeviceDefault.DayNight"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
diff --git a/packages/SystemUI/res/layout/people_tile_large_with_content.xml b/packages/SystemUI/res/layout/people_tile_large_with_content.xml
index 3f78fe7..6da17bc 100644
--- a/packages/SystemUI/res/layout/people_tile_large_with_content.xml
+++ b/packages/SystemUI/res/layout/people_tile_large_with_content.xml
@@ -126,6 +126,7 @@
                 android:layout_width="match_parent"
                 android:layout_height="match_parent"
                 android:background="@drawable/people_space_content_background"
+                android:clipToOutline="true"
                 android:gravity="center"
                 android:scaleType="centerCrop" />
 
diff --git a/packages/SystemUI/res/layout/people_tile_large_with_notification_content.xml b/packages/SystemUI/res/layout/people_tile_large_with_notification_content.xml
index 60ff68e..c18a59a 100644
--- a/packages/SystemUI/res/layout/people_tile_large_with_notification_content.xml
+++ b/packages/SystemUI/res/layout/people_tile_large_with_notification_content.xml
@@ -15,7 +15,7 @@
   -->
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:background="@drawable/people_space_tile_view_card"
-    android:id="@+id/item"
+    android:id="@android:id/background"
     android:clipToOutline="true"
     android:theme="@android:style/Theme.DeviceDefault.DayNight"
     android:layout_gravity="center"
diff --git a/packages/SystemUI/res/layout/people_tile_large_with_status_content.xml b/packages/SystemUI/res/layout/people_tile_large_with_status_content.xml
index cbc6ea8..508a255 100644
--- a/packages/SystemUI/res/layout/people_tile_large_with_status_content.xml
+++ b/packages/SystemUI/res/layout/people_tile_large_with_status_content.xml
@@ -15,7 +15,7 @@
   -->
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:background="@drawable/people_space_tile_view_card"
-    android:id="@+id/item"
+    android:id="@android:id/background"
     android:clipToOutline="true"
     android:theme="@android:style/Theme.DeviceDefault.DayNight"
     android:layout_gravity="center"
diff --git a/packages/SystemUI/res/layout/people_tile_medium_empty.xml b/packages/SystemUI/res/layout/people_tile_medium_empty.xml
index ebb61c9..4a18683 100644
--- a/packages/SystemUI/res/layout/people_tile_medium_empty.xml
+++ b/packages/SystemUI/res/layout/people_tile_medium_empty.xml
@@ -21,7 +21,8 @@
     android:orientation="vertical">
     <LinearLayout
         android:background="@drawable/people_space_tile_view_card"
-        android:id="@+id/item"
+        android:clipToOutline="true"
+        android:id="@android:id/background"
         android:gravity="center"
         android:paddingHorizontal="16dp"
         android:orientation="horizontal"
diff --git a/packages/SystemUI/res/layout/people_tile_medium_with_content.xml b/packages/SystemUI/res/layout/people_tile_medium_with_content.xml
index 0a5bf1d..9314685 100644
--- a/packages/SystemUI/res/layout/people_tile_medium_with_content.xml
+++ b/packages/SystemUI/res/layout/people_tile_medium_with_content.xml
@@ -18,8 +18,9 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
     android:theme="@android:style/Theme.DeviceDefault.DayNight"
-    android:id="@+id/item"
+    android:id="@android:id/background"
     android:background="@drawable/people_space_tile_view_card"
+    android:clipToOutline="true"
     android:layout_gravity="center"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
@@ -83,6 +84,7 @@
                         android:id="@+id/image"
                         android:gravity="center"
                         android:background="@drawable/people_space_content_background"
+                        android:clipToOutline="true"
                         android:layout_width="match_parent"
                         android:layout_height="match_parent"
                         android:scaleType="centerCrop" />
diff --git a/packages/SystemUI/res/layout/people_tile_small.xml b/packages/SystemUI/res/layout/people_tile_small.xml
index 553b8a43..44e68e5 100644
--- a/packages/SystemUI/res/layout/people_tile_small.xml
+++ b/packages/SystemUI/res/layout/people_tile_small.xml
@@ -20,11 +20,12 @@
     android:layout_height="match_parent">
 
     <LinearLayout
-        android:id="@+id/item"
+        android:id="@android:id/background"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:layout_gravity="center"
         android:background="@drawable/people_space_tile_view_card"
+        android:clipToOutline="true"
         android:orientation="vertical"
         android:paddingHorizontal="4dp"
         android:paddingTop="6dp"
diff --git a/packages/SystemUI/res/layout/people_tile_suppressed_layout.xml b/packages/SystemUI/res/layout/people_tile_suppressed_layout.xml
index b151c60..4820a35 100644
--- a/packages/SystemUI/res/layout/people_tile_suppressed_layout.xml
+++ b/packages/SystemUI/res/layout/people_tile_suppressed_layout.xml
@@ -14,9 +14,10 @@
   ~ limitations under the License.
   -->
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/item"
+    android:id="@android:id/background"
     android:theme="@android:style/Theme.DeviceDefault.DayNight"
     android:background="@drawable/people_tile_suppressed_background"
+    android:clipToOutline="true"
     android:layout_width="match_parent"
     android:layout_height="match_parent">
 
diff --git a/packages/SystemUI/res/layout/people_tile_with_suppression_detail_content_horizontal.xml b/packages/SystemUI/res/layout/people_tile_with_suppression_detail_content_horizontal.xml
index b53c88b..f7e12eb 100644
--- a/packages/SystemUI/res/layout/people_tile_with_suppression_detail_content_horizontal.xml
+++ b/packages/SystemUI/res/layout/people_tile_with_suppression_detail_content_horizontal.xml
@@ -14,10 +14,11 @@
 ~ limitations under the License.
 -->
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:theme="@android:style/Theme.DeviceDefault.DayNight"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:gravity="center"
-    android:id="@+id/item"
+    android:id="@android:id/background"
     android:background="@drawable/people_tile_suppressed_background"
     android:clipToOutline="true"
     android:padding="8dp"
diff --git a/packages/SystemUI/res/layout/people_tile_with_suppression_detail_content_vertical.xml b/packages/SystemUI/res/layout/people_tile_with_suppression_detail_content_vertical.xml
index c79cdad..c488d890 100644
--- a/packages/SystemUI/res/layout/people_tile_with_suppression_detail_content_vertical.xml
+++ b/packages/SystemUI/res/layout/people_tile_with_suppression_detail_content_vertical.xml
@@ -15,10 +15,11 @@
 -->
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:tools="http://schemas.android.com/tools"
+    android:theme="@android:style/Theme.DeviceDefault.DayNight"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:gravity="center"
-    android:id="@+id/item"
+    android:id="@android:id/background"
     android:background="@drawable/people_tile_suppressed_background"
     android:clipToOutline="true"
     android:padding="8dp"
diff --git a/packages/SystemUI/res/layout/people_tile_work_profile_quiet_layout.xml b/packages/SystemUI/res/layout/people_tile_work_profile_quiet_layout.xml
index 25ab5a6..1ccfb07 100644
--- a/packages/SystemUI/res/layout/people_tile_work_profile_quiet_layout.xml
+++ b/packages/SystemUI/res/layout/people_tile_work_profile_quiet_layout.xml
@@ -15,9 +15,10 @@
   -->
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
-    android:id="@+id/item"
+    android:id="@android:id/background"
     android:theme="@android:style/Theme.DeviceDefault.DayNight"
     android:background="@drawable/people_tile_suppressed_background"
+    android:clipToOutline="true"
     android:layout_width="match_parent"
     android:layout_height="match_parent">
 
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 36717c7..bc1c67c 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2889,7 +2889,7 @@
     <!--Text explaining to tap a conversation to select it show in their Conversation widget [CHAR LIMIT=180] -->
     <string name="select_conversation_text">Tap a conversation to add it to your Home screen</string>
     <!--Text explaining there are no existing conversations to show in their Conversation widget [CHAR LIMIT=100] -->
-    <string name="no_conversations_text">Check back here once you get some messages</string>
+    <string name="no_conversations_text">Your recent conversations will show up here</string>
     <!--Text header for priority conversation tiles available to be added to the home screen [CHAR LIMIT=100] -->
     <string name="priority_conversations">Priority conversations</string>
     <!--Text header for recent conversation tiles available to be added to the home screen [CHAR LIMIT=100] -->
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
index 3957a60..8c6a3ca 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
@@ -204,7 +204,7 @@
                 isSsReactivated: Boolean
             ) {
                 if (addOrUpdatePlayer(key, oldKey, data)) {
-                    MediaPlayerData.getMediaPlayer(key, null)?.let {
+                    MediaPlayerData.getMediaPlayer(key)?.let {
                         logSmartspaceCardReported(759, // SMARTSPACE_CARD_RECEIVED
                                 it.mInstanceId,
                                 /* isRecommendationCard */ false,
@@ -241,7 +241,7 @@
                 if (DEBUG) Log.d(TAG, "Loading Smartspace media update")
                 if (data.isActive) {
                     addSmartspaceMediaRecommendations(key, data, shouldPrioritize)
-                    MediaPlayerData.getMediaPlayer(key, null)?.let {
+                    MediaPlayerData.getMediaPlayer(key)?.let {
                         logSmartspaceCardReported(759, // SMARTSPACE_CARD_RECEIVED
                                 it.mInstanceId,
                                 /* isRecommendationCard */ true,
@@ -344,7 +344,8 @@
     // Returns true if new player is added
     private fun addOrUpdatePlayer(key: String, oldKey: String?, data: MediaData): Boolean {
         val dataCopy = data.copy(backgroundColor = bgColor)
-        val existingPlayer = MediaPlayerData.getMediaPlayer(key, oldKey)
+        MediaPlayerData.moveIfExists(oldKey, key)
+        val existingPlayer = MediaPlayerData.getMediaPlayer(key)
         val curVisibleMediaKey = MediaPlayerData.playerKeys()
             .elementAtOrNull(mediaCarouselScrollHandler.visibleMediaIndex)
         if (existingPlayer == null) {
@@ -386,7 +387,7 @@
         shouldPrioritize: Boolean
     ) {
         if (DEBUG) Log.d(TAG, "Updating smartspace target in carousel")
-        if (MediaPlayerData.getMediaPlayer(key, null) != null) {
+        if (MediaPlayerData.getMediaPlayer(key) != null) {
             Log.w(TAG, "Skip adding smartspace target in carousel")
             return
         }
@@ -795,13 +796,18 @@
         smartspaceMediaData = data
     }
 
-    fun getMediaPlayer(key: String, oldKey: String?): MediaControlPanel? {
-        // If the key was changed, update entry
-        oldKey?.let {
-            if (it != key) {
-                mediaData.remove(it)?.let { sortKey -> mediaData.put(key, sortKey) }
-            }
+    fun moveIfExists(oldKey: String?, newKey: String) {
+        if (oldKey == null || oldKey == newKey) {
+            return
         }
+
+        mediaData.remove(oldKey)?.let {
+            removeMediaPlayer(newKey)
+            mediaData.put(newKey, it)
+        }
+    }
+
+    fun getMediaPlayer(key: String): MediaControlPanel? {
         return mediaData.get(key)?.let { mediaPlayers.get(it) }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
index 1d6d1f2..391dff63 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
@@ -142,6 +142,9 @@
                 mDivider.setVisibility(View.GONE);
                 mAddIcon.setVisibility(View.GONE);
             }
+            if (mCurrentActivePosition == position) {
+                mCurrentActivePosition = -1;
+            }
             if (mController.isTransferring()) {
                 if (device.getState() == MediaDeviceState.STATE_CONNECTING
                         && !mController.hasAdjustVolumeUserRestriction()) {
@@ -214,6 +217,7 @@
                 return;
             }
 
+            mCurrentActivePosition = -1;
             playSwitchingAnim(mConnectedItem, view);
             mController.connectDevice(device);
             device.setState(MediaDeviceState.STATE_CONNECTING);
diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java
index d9e2648..93a3f81 100644
--- a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java
@@ -89,7 +89,7 @@
 
             // The Tile preview has colorBackground as its background. Change it so it's different
             // than the activity's background.
-            LinearLayout item = findViewById(R.id.item);
+            LinearLayout item = findViewById(android.R.id.background);
             GradientDrawable shape = (GradientDrawable) item.getBackground();
             final TypedArray ta = mContext.getTheme().obtainStyledAttributes(
                     new int[]{com.android.internal.R.attr.colorSurface});
diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java b/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java
index 4a8775f..a388853 100644
--- a/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java
@@ -453,7 +453,6 @@
                 views.setViewVisibility(R.id.availability, View.GONE);
             }
 
-            views.setBoolean(R.id.image, "setClipToOutline", true);
             views.setImageViewBitmap(R.id.person_icon,
                     getPersonIconBitmap(mContext, mTile, maxAvatarSize));
             return views;
@@ -481,7 +480,7 @@
                         PeopleSpaceWidgetProvider.EXTRA_NOTIFICATION_KEY,
                         mTile.getNotificationKey());
             }
-            views.setOnClickPendingIntent(R.id.item, PendingIntent.getActivity(
+            views.setOnClickPendingIntent(android.R.id.background, PendingIntent.getActivity(
                     mContext,
                     mAppWidgetId,
                     activityIntent,
@@ -504,7 +503,7 @@
         int outerPadding = mLayoutSize == LAYOUT_LARGE ? 16 : 8;
         int outerPaddingPx = dpToPx(outerPadding);
         views.setViewPadding(
-                R.id.item,
+                android.R.id.background,
                 outerPaddingPx,
                 outerPaddingPx,
                 outerPaddingPx,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaPlayerDataTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaPlayerDataTest.kt
index ef8d322..ba4fc0a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaPlayerDataTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaPlayerDataTest.kt
@@ -22,14 +22,24 @@
 import com.google.common.truth.Truth.assertThat
 import org.junit.Before
 import org.junit.Ignore
+import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.mockito.Mock
 import org.mockito.Mockito.mock
+import org.mockito.junit.MockitoJUnit
 
 @SmallTest
 @RunWith(AndroidTestingRunner::class)
 public class MediaPlayerDataTest : SysuiTestCase() {
 
+    @Mock
+    private lateinit var playerIsPlaying: MediaControlPanel
+
+    @JvmField
+    @Rule
+    val mockito = MockitoJUnit.rule()
+
     companion object {
         val LOCAL = true
         val RESUMPTION = true
@@ -44,7 +54,6 @@
 
     @Test
     fun addPlayingThenRemote() {
-        val playerIsPlaying = mock(MediaControlPanel::class.java)
         val dataIsPlaying = createMediaData("app1", PLAYING, LOCAL, !RESUMPTION)
 
         val playerIsRemote = mock(MediaControlPanel::class.java)
@@ -83,7 +92,6 @@
 
     @Test
     fun fullOrderTest() {
-        val playerIsPlaying = mock(MediaControlPanel::class.java)
         val dataIsPlaying = createMediaData("app1", PLAYING, LOCAL, !RESUMPTION)
 
         val playerIsPlayingAndRemote = mock(MediaControlPanel::class.java)
@@ -115,6 +123,26 @@
             playerUndetermined).inOrder()
     }
 
+    @Test
+    fun testMoveMediaKeysAround() {
+        val keyA = "a"
+        val keyB = "b"
+
+        val data = createMediaData("app1", PLAYING, LOCAL, !RESUMPTION)
+
+        MediaPlayerData.addMediaPlayer(keyA, data, playerIsPlaying)
+        MediaPlayerData.addMediaPlayer(keyB, data, playerIsPlaying)
+
+        assertThat(MediaPlayerData.players()).hasSize(2)
+
+        MediaPlayerData.moveIfExists(keyA, keyB)
+
+        assertThat(MediaPlayerData.players()).hasSize(1)
+
+        assertThat(MediaPlayerData.getMediaPlayer(keyA)).isNull()
+        assertThat(MediaPlayerData.getMediaPlayer(keyB)).isNotNull()
+    }
+
     private fun createMediaData(
         app: String,
         isPlaying: Boolean?,
diff --git a/services/core/java/com/android/server/media/metrics/MediaMetricsManagerService.java b/services/core/java/com/android/server/media/metrics/MediaMetricsManagerService.java
index 2cc2ebf..981e759 100644
--- a/services/core/java/com/android/server/media/metrics/MediaMetricsManagerService.java
+++ b/services/core/java/com/android/server/media/metrics/MediaMetricsManagerService.java
@@ -17,6 +17,7 @@
 package com.android.server.media.metrics;
 
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.media.metrics.IMediaMetricsManager;
 import android.media.metrics.NetworkEvent;
 import android.media.metrics.PlaybackErrorEvent;
@@ -24,19 +25,60 @@
 import android.media.metrics.PlaybackStateEvent;
 import android.media.metrics.TrackChangeEvent;
 import android.os.Binder;
+import android.provider.DeviceConfig;
+import android.provider.DeviceConfig.Properties;
 import android.util.Base64;
+import android.util.Slog;
 import android.util.StatsEvent;
 import android.util.StatsLog;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.server.SystemService;
 
 import java.security.SecureRandom;
+import java.util.Arrays;
+import java.util.List;
 
 /**
  * System service manages media metrics.
  */
 public final class MediaMetricsManagerService extends SystemService {
+    private static final String TAG = "MediaMetricsManagerService";
+
+    private static final String MEDIA_METRICS_MODE = "media_metrics_mode";
+    private static final String PLAYER_METRICS_PER_APP_ATTRIBUTION_ALLOWLIST =
+            "player_metrics_per_app_attribution_allowlist";
+    private static final String PLAYER_METRICS_APP_ALLOWLIST = "player_metrics_app_allowlist";
+
+    private static final String PLAYER_METRICS_PER_APP_ATTRIBUTION_BLOCKLIST =
+            "player_metrics_per_app_attribution_blocklist";
+    private static final String PLAYER_METRICS_APP_BLOCKLIST = "player_metrics_app_blocklist";
+
+    private static final int MEDIA_METRICS_MODE_OFF = 0;
+    private static final int MEDIA_METRICS_MODE_ON = 1;
+    private static final int MEDIA_METRICS_MODE_BLOCKLIST = 2;
+    private static final int MEDIA_METRICS_MODE_ALLOWLIST = 3;
+
+    // Cascading logging levels. The higher value, the more constrains (less logging data).
+    // The unused values between 2 consecutive levels are reserved for potential extra levels.
+    private static final int LOGGING_LEVEL_EVERYTHING = 0;
+    private static final int LOGGING_LEVEL_NO_UID = 1000;
+    private static final int LOGGING_LEVEL_BLOCKED = 99999;
+
+    private static final String FAILED_TO_GET = "failed_to_get";
     private final SecureRandom mSecureRandom;
+    @GuardedBy("mLock")
+    private Integer mMode = null;
+    @GuardedBy("mLock")
+    private List<String> mAllowlist = null;
+    @GuardedBy("mLock")
+    private List<String> mNoUidAllowlist = null;
+    @GuardedBy("mLock")
+    private List<String> mBlockList = null;
+    @GuardedBy("mLock")
+    private List<String> mNoUidBlocklist = null;
+    private final Object mLock = new Object();
+    private final Context mContext;
 
     /**
      * Initializes the playback metrics manager service.
@@ -45,20 +87,73 @@
      */
     public MediaMetricsManagerService(Context context) {
         super(context);
+        mContext = context;
         mSecureRandom = new SecureRandom();
     }
 
     @Override
     public void onStart() {
         publishBinderService(Context.MEDIA_METRICS_SERVICE, new BinderService());
+        DeviceConfig.addOnPropertiesChangedListener(
+                DeviceConfig.NAMESPACE_MEDIA,
+                mContext.getMainExecutor(),
+                this::updateConfigs);
+    }
+
+    private void updateConfigs(Properties properties) {
+        synchronized (mLock) {
+            mMode = properties.getInt(
+                    MEDIA_METRICS_MODE,
+                    MEDIA_METRICS_MODE_BLOCKLIST);
+            List<String> newList = getListLocked(PLAYER_METRICS_APP_ALLOWLIST);
+            if (newList != null || mMode != MEDIA_METRICS_MODE_ALLOWLIST) {
+                // don't overwrite the list if the mode IS MEDIA_METRICS_MODE_ALLOWLIST
+                // but failed to get
+                mAllowlist = newList;
+            }
+            newList = getListLocked(PLAYER_METRICS_PER_APP_ATTRIBUTION_ALLOWLIST);
+            if (newList != null || mMode != MEDIA_METRICS_MODE_ALLOWLIST) {
+                mNoUidAllowlist = newList;
+            }
+            newList = getListLocked(PLAYER_METRICS_APP_BLOCKLIST);
+            if (newList != null || mMode != MEDIA_METRICS_MODE_BLOCKLIST) {
+                mBlockList = newList;
+            }
+            newList = getListLocked(PLAYER_METRICS_PER_APP_ATTRIBUTION_BLOCKLIST);
+            if (newList != null || mMode != MEDIA_METRICS_MODE_BLOCKLIST) {
+                mNoUidBlocklist = newList;
+            }
+        }
+    }
+
+    @GuardedBy("mLock")
+    private List<String> getListLocked(String listName) {
+        final long identity = Binder.clearCallingIdentity();
+        String listString = FAILED_TO_GET;
+        try {
+            listString = DeviceConfig.getString(
+                    DeviceConfig.NAMESPACE_MEDIA, listName, FAILED_TO_GET);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+        if (listString.equals(FAILED_TO_GET)) {
+            Slog.d(TAG, "failed to get " + listName + " from DeviceConfig");
+            return null;
+        }
+        String[] pkgArr = listString.split(",");
+        return Arrays.asList(pkgArr);
     }
 
     private final class BinderService extends IMediaMetricsManager.Stub {
         @Override
         public void reportPlaybackMetrics(String sessionId, PlaybackMetrics metrics, int userId) {
+            int level = loggingLevel();
+            if (level == LOGGING_LEVEL_BLOCKED) {
+                return;
+            }
             StatsEvent statsEvent = StatsEvent.newBuilder()
                     .setAtomId(320)
-                    .writeInt(Binder.getCallingUid())
+                    .writeInt(level == LOGGING_LEVEL_EVERYTHING ? Binder.getCallingUid() : 0)
                     .writeString(sessionId)
                     .writeLong(metrics.getMediaDurationMillis())
                     .writeInt(metrics.getStreamSource())
@@ -85,6 +180,10 @@
         @Override
         public void reportPlaybackStateEvent(
                 String sessionId, PlaybackStateEvent event, int userId) {
+            int level = loggingLevel();
+            if (level == LOGGING_LEVEL_BLOCKED) {
+                return;
+            }
             StatsEvent statsEvent = StatsEvent.newBuilder()
                     .setAtomId(322)
                     .writeString(sessionId)
@@ -116,6 +215,10 @@
         @Override
         public void reportPlaybackErrorEvent(
                 String sessionId, PlaybackErrorEvent event, int userId) {
+            int level = loggingLevel();
+            if (level == LOGGING_LEVEL_BLOCKED) {
+                return;
+            }
             StatsEvent statsEvent = StatsEvent.newBuilder()
                     .setAtomId(323)
                     .writeString(sessionId)
@@ -130,6 +233,10 @@
 
         public void reportNetworkEvent(
                 String sessionId, NetworkEvent event, int userId) {
+            int level = loggingLevel();
+            if (level == LOGGING_LEVEL_BLOCKED) {
+                return;
+            }
             StatsEvent statsEvent = StatsEvent.newBuilder()
                     .setAtomId(321)
                     .writeString(sessionId)
@@ -143,6 +250,10 @@
         @Override
         public void reportTrackChangeEvent(
                 String sessionId, TrackChangeEvent event, int userId) {
+            int level = loggingLevel();
+            if (level == LOGGING_LEVEL_BLOCKED) {
+                return;
+            }
             StatsEvent statsEvent = StatsEvent.newBuilder()
                     .setAtomId(324)
                     .writeString(sessionId)
@@ -165,5 +276,140 @@
                     .build();
             StatsLog.write(statsEvent);
         }
+
+        private int loggingLevel() {
+            synchronized (mLock) {
+                int uid = Binder.getCallingUid();
+
+                if (mMode == null) {
+                    final long identity = Binder.clearCallingIdentity();
+                    try {
+                        mMode = DeviceConfig.getInt(
+                            DeviceConfig.NAMESPACE_MEDIA,
+                            MEDIA_METRICS_MODE,
+                            MEDIA_METRICS_MODE_BLOCKLIST);
+                    } finally {
+                        Binder.restoreCallingIdentity(identity);
+                    }
+                }
+
+                if (mMode == MEDIA_METRICS_MODE_ON) {
+                    return LOGGING_LEVEL_EVERYTHING;
+                }
+                if (mMode == MEDIA_METRICS_MODE_OFF) {
+                    return LOGGING_LEVEL_BLOCKED;
+                }
+
+                PackageManager pm = getContext().getPackageManager();
+                String[] packages = pm.getPackagesForUid(uid);
+                if (packages == null || packages.length == 0) {
+                    // The valid application UID range is from
+                    // android.os.Process.FIRST_APPLICATION_UID to
+                    // android.os.Process.LAST_APPLICATION_UID.
+                    // UIDs outside this range will not have a package.
+                    Slog.d(TAG, "empty package from uid " + uid);
+                    // block the data if the mode is MEDIA_METRICS_MODE_ALLOWLIST
+                    return mMode == MEDIA_METRICS_MODE_BLOCKLIST
+                            ? LOGGING_LEVEL_NO_UID : LOGGING_LEVEL_BLOCKED;
+                }
+                if (mMode == MEDIA_METRICS_MODE_BLOCKLIST) {
+                    if (mBlockList == null) {
+                        mBlockList = getListLocked(PLAYER_METRICS_APP_BLOCKLIST);
+                        if (mBlockList == null) {
+                            // failed to get the blocklist. Block it.
+                            return LOGGING_LEVEL_BLOCKED;
+                        }
+                    }
+                    Integer level = loggingLevelInternal(
+                            packages, mBlockList, PLAYER_METRICS_APP_BLOCKLIST);
+                    if (level != null) {
+                        return level;
+                    }
+                    if (mNoUidBlocklist == null) {
+                        mNoUidBlocklist =
+                                getListLocked(PLAYER_METRICS_PER_APP_ATTRIBUTION_BLOCKLIST);
+                        if (mNoUidBlocklist == null) {
+                            // failed to get the blocklist. Block it.
+                            return LOGGING_LEVEL_BLOCKED;
+                        }
+                    }
+                    level = loggingLevelInternal(
+                            packages,
+                            mNoUidBlocklist,
+                            PLAYER_METRICS_PER_APP_ATTRIBUTION_BLOCKLIST);
+                    if (level != null) {
+                        return level;
+                    }
+                    // Not detected in any blocklist. Log everything.
+                    return LOGGING_LEVEL_EVERYTHING;
+                }
+                if (mMode == MEDIA_METRICS_MODE_ALLOWLIST) {
+                    if (mNoUidAllowlist == null) {
+                        mNoUidAllowlist =
+                                getListLocked(PLAYER_METRICS_PER_APP_ATTRIBUTION_ALLOWLIST);
+                        if (mNoUidAllowlist == null) {
+                            // failed to get the allowlist. Block it.
+                            return LOGGING_LEVEL_BLOCKED;
+                        }
+                    }
+                    Integer level = loggingLevelInternal(
+                            packages,
+                            mNoUidAllowlist,
+                            PLAYER_METRICS_PER_APP_ATTRIBUTION_ALLOWLIST);
+                    if (level != null) {
+                        return level;
+                    }
+                    if (mAllowlist == null) {
+                        mAllowlist = getListLocked(PLAYER_METRICS_APP_ALLOWLIST);
+                        if (mAllowlist == null) {
+                            // failed to get the allowlist. Block it.
+                            return LOGGING_LEVEL_BLOCKED;
+                        }
+                    }
+                    level = loggingLevelInternal(
+                            packages, mAllowlist, PLAYER_METRICS_APP_ALLOWLIST);
+                    if (level != null) {
+                        return level;
+                    }
+                    // Not detected in any allowlist. Block.
+                    return LOGGING_LEVEL_BLOCKED;
+                }
+            }
+            // Blocked by default.
+            return LOGGING_LEVEL_BLOCKED;
+        }
+
+        private Integer loggingLevelInternal(
+                String[] packages, List<String> cached, String listName) {
+            if (inList(packages, cached)) {
+                return listNameToLoggingLevel(listName);
+            }
+            return null;
+        }
+
+        private boolean inList(String[] packages, List<String> arr) {
+            for (String p : packages) {
+                for (String element : arr) {
+                    if (p.equals(element)) {
+                        return true;
+                    }
+                }
+            }
+            return false;
+        }
+
+        private int listNameToLoggingLevel(String listName) {
+            switch (listName) {
+                case PLAYER_METRICS_APP_BLOCKLIST:
+                    return LOGGING_LEVEL_BLOCKED;
+                case PLAYER_METRICS_APP_ALLOWLIST:
+                    return LOGGING_LEVEL_EVERYTHING;
+                case PLAYER_METRICS_PER_APP_ATTRIBUTION_ALLOWLIST:
+                case PLAYER_METRICS_PER_APP_ATTRIBUTION_BLOCKLIST:
+                    return LOGGING_LEVEL_NO_UID;
+                default:
+                    return LOGGING_LEVEL_BLOCKED;
+            }
+        }
     }
 }
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
index f6217bc..0f6a718 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
@@ -609,13 +609,27 @@
             return;
         }
 
+        // If the launched activity is started from an existing active transition, it will be put
+        // into the transition info.
         if (info != null && info.canCoalesce(launchedActivity)) {
-            // If we are already in an existing transition on the same display, only update the
-            // activity name, but not the other attributes.
+            if (DEBUG_METRICS) Slog.i(TAG, "notifyActivityLaunched consecutive launch");
 
-            if (DEBUG_METRICS) Slog.i(TAG, "notifyActivityLaunched update launched activity");
+            final boolean crossPackage =
+                    !info.mLastLaunchedActivity.packageName.equals(launchedActivity.packageName);
+            // The trace name uses package name so different packages should be separated.
+            if (crossPackage) {
+                stopLaunchTrace(info);
+            }
+
+            mLastTransitionInfo.remove(info.mLastLaunchedActivity);
             // Coalesce multiple (trampoline) activities from a single sequence together.
             info.setLatestLaunchedActivity(launchedActivity);
+            // Update the latest one so it can be found when reporting fully-drawn.
+            mLastTransitionInfo.put(launchedActivity, info);
+
+            if (crossPackage) {
+                startLaunchTrace(info);
+            }
             return;
         }
 
@@ -638,12 +652,24 @@
             launchObserverNotifyIntentFailed();
         }
         if (launchedActivity.mDisplayContent.isSleeping()) {
-            // It is unknown whether the activity can be drawn or not, e.g. ut depends on the
+            // It is unknown whether the activity can be drawn or not, e.g. it depends on the
             // keyguard states and the attributes or flags set by the activity. If the activity
             // keeps invisible in the grace period, the tracker will be cancelled so it won't get
             // a very long launch time that takes unlocking as the end of launch.
             scheduleCheckActivityToBeDrawn(launchedActivity, UNKNOWN_VISIBILITY_CHECK_DELAY_MS);
         }
+
+        // If the previous transitions are no longer visible, abort them to avoid counting the
+        // launch time when resuming from back stack. E.g. launch 2 independent tasks in a short
+        // time, the transition info of the first task should not keep active until it becomes
+        // visible such as after the top task is finished.
+        for (int i = mTransitionInfoList.size() - 2; i >= 0; i--) {
+            final TransitionInfo prevInfo = mTransitionInfoList.get(i);
+            prevInfo.updatePendingDraw();
+            if (prevInfo.allDrawn()) {
+                abort(prevInfo, "nothing will be drawn");
+            }
+        }
     }
 
     /**
@@ -864,6 +890,7 @@
         final Boolean isHibernating =
                 mLastHibernationStates.remove(info.mLastLaunchedActivity.packageName);
         if (abort) {
+            mLastTransitionInfo.remove(info.mLastLaunchedActivity);
             mSupervisor.stopWaitingForActivityVisible(info.mLastLaunchedActivity);
             launchObserverNotifyActivityLaunchCancelled(info);
         } else {
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index db89208..569c11b 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -580,19 +580,28 @@
      *     windowing modes.
      *  0: If it is a small screen (smallest width < {@link #mLargeScreenSmallestScreenWidthDp}),
      *     the device compares the activity min width/height with the min multi windowing modes
-     *     dimensions {@link #mMinPercentageMultiWindowSupportWidth} the device supports to
+     *     dimensions {@link #mMinPercentageMultiWindowSupportHeight} the device supports to
      *     determine whether the activity can be shown in multi windowing modes
      *  1: The device always compare the activity min width/height with the min multi windowing
-     *     modes dimensions {@link #mMinPercentageMultiWindowSupportWidth} the device supports to
+     *     modes dimensions {@link #mMinPercentageMultiWindowSupportHeight} the device supports to
      *     determine whether it can be shown in multi windowing modes.
      */
     int mRespectsActivityMinWidthHeightMultiWindow;
 
     /**
-     * This value is only used when the device checks activity min width/height to determine if it
+     * This value is only used when the device checks activity min height to determine if it
      * can be shown in multi windowing modes.
-     * If the activity min width/height is greater than this percentage of the display smallest
-     * width, it will not be allowed to be shown in multi windowing modes.
+     * If the activity min height is greater than this percentage of the display height in portrait,
+     * it will not be allowed to be shown in multi windowing modes.
+     * The value should be between [0 - 1].
+     */
+    float mMinPercentageMultiWindowSupportHeight;
+
+    /**
+     * This value is only used when the device checks activity min width to determine if it
+     * can be shown in multi windowing modes.
+     * If the activity min width is greater than this percentage of the display width in landscape,
+     * it will not be allowed to be shown in multi windowing modes.
      * The value should be between [0 - 1].
      */
     float mMinPercentageMultiWindowSupportWidth;
@@ -840,6 +849,8 @@
                 com.android.internal.R.integer.config_supportsNonResizableMultiWindow);
         final int respectsActivityMinWidthHeightMultiWindow = mContext.getResources().getInteger(
                 com.android.internal.R.integer.config_respectsActivityMinWidthHeightMultiWindow);
+        final float minPercentageMultiWindowSupportHeight = mContext.getResources().getFloat(
+                com.android.internal.R.dimen.config_minPercentageMultiWindowSupportHeight);
         final float minPercentageMultiWindowSupportWidth = mContext.getResources().getFloat(
                 com.android.internal.R.dimen.config_minPercentageMultiWindowSupportWidth);
         final int largeScreenSmallestScreenWidthDp = mContext.getResources().getInteger(
@@ -860,6 +871,7 @@
             mDevEnableNonResizableMultiWindow = devEnableNonResizableMultiWindow;
             mSupportsNonResizableMultiWindow = supportsNonResizableMultiWindow;
             mRespectsActivityMinWidthHeightMultiWindow = respectsActivityMinWidthHeightMultiWindow;
+            mMinPercentageMultiWindowSupportHeight = minPercentageMultiWindowSupportHeight;
             mMinPercentageMultiWindowSupportWidth = minPercentageMultiWindowSupportWidth;
             mLargeScreenSmallestScreenWidthDp = largeScreenSmallestScreenWidthDp;
             final boolean multiWindowFormEnabled = freeformWindowManagement
diff --git a/services/core/java/com/android/server/wm/NonAppWindowAnimationAdapter.java b/services/core/java/com/android/server/wm/NonAppWindowAnimationAdapter.java
index b1e12b6..d230936 100644
--- a/services/core/java/com/android/server/wm/NonAppWindowAnimationAdapter.java
+++ b/services/core/java/com/android/server/wm/NonAppWindowAnimationAdapter.java
@@ -99,8 +99,10 @@
 
         final WindowManagerPolicy policy = service.mPolicy;
         service.mRoot.forAllWindows(nonAppWindow -> {
+            // Animation on the IME window is controlled via Insets.
             if (nonAppWindow.mActivityRecord == null && policy.canBeHiddenByKeyguardLw(nonAppWindow)
-                    && nonAppWindow.wouldBeVisibleIfPolicyIgnored() && !nonAppWindow.isVisible()) {
+                    && nonAppWindow.wouldBeVisibleIfPolicyIgnored() && !nonAppWindow.isVisible()
+                    && nonAppWindow != service.mRoot.getCurrentInputMethodWindow()) {
                 final NonAppWindowAnimationAdapter nonAppAdapter = new NonAppWindowAnimationAdapter(
                         nonAppWindow, durationHint, statusBarTransitionDelay);
                 adaptersOut.add(nonAppAdapter);
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index 90d40f3..d450dbf 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -31,6 +31,7 @@
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
 
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STATES;
@@ -44,6 +45,7 @@
 import android.annotation.Nullable;
 import android.app.ActivityOptions;
 import android.app.WindowConfiguration;
+import android.content.res.Configuration;
 import android.os.UserHandle;
 import android.util.IntArray;
 import android.util.Slog;
@@ -1705,10 +1707,18 @@
             return true;
         }
         // Check if the request min width/height is supported in multi window.
-        final int maxSupportMinDimensions = (int) (mAtmService.mMinPercentageMultiWindowSupportWidth
-                * getConfiguration().smallestScreenWidthDp
-                * mDisplayContent.getDisplayMetrics().density);
-        return minWidth <= maxSupportMinDimensions && minHeight <= maxSupportMinDimensions;
+        final Configuration config = getConfiguration();
+        final int orientation = config.orientation;
+        if (orientation == ORIENTATION_LANDSCAPE) {
+            final int maxSupportMinWidth = (int) (mAtmService.mMinPercentageMultiWindowSupportWidth
+                    * config.screenWidthDp * mDisplayContent.getDisplayMetrics().density);
+            return minWidth <= maxSupportMinWidth;
+        } else {
+            final int maxSupportMinHeight =
+                    (int) (mAtmService.mMinPercentageMultiWindowSupportHeight
+                            * config.screenHeightDp * mDisplayContent.getDisplayMetrics().density);
+            return minHeight <= maxSupportMinHeight;
+        }
     }
 
     /**
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
index 38466eb..32a4774 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
@@ -270,9 +270,16 @@
 
     @Test
     public void testOnReportFullyDrawn() {
+        // Create an invisible event that should be cancelled after the next event starts.
+        onActivityLaunched(mTrampolineActivity);
+        mTrampolineActivity.mVisibleRequested = false;
+
         mActivityOptions = ActivityOptions.makeBasic();
         mActivityOptions.setSourceInfo(SourceInfo.TYPE_LAUNCHER, SystemClock.uptimeMillis() - 10);
-        onActivityLaunched(mTopActivity);
+        onIntentStarted(mTopActivity.intent);
+        notifyActivityLaunched(START_SUCCESS, mTopActivity);
+        verifyAsync(mLaunchObserver).onActivityLaunched(eqProto(mTopActivity), anyInt());
+        verifyAsync(mLaunchObserver).onActivityLaunchCancelled(eqProto(mTrampolineActivity));
 
         // The activity reports fully drawn before windows drawn, then the fully drawn event will
         // be pending (see {@link WindowingModeTransitionInfo#pendingFullyDrawn}).
@@ -287,6 +294,10 @@
         verifyAsync(mLaunchObserver).onReportFullyDrawn(eqProto(mTopActivity), anyLong());
         verifyOnActivityLaunchFinished(mTopActivity);
         verifyNoMoreInteractions(mLaunchObserver);
+
+        final ActivityMetricsLogger.TransitionInfoSnapshot fullyDrawnInfo = mActivityMetricsLogger
+                .logAppTransitionReportedDrawn(mTopActivity, false /* restoredFromBundle */);
+        assertWithMessage("Invisible event must be dropped").that(fullyDrawnInfo).isNull();
     }
 
     private void onActivityLaunchedTrampoline() {
@@ -480,6 +491,7 @@
     @Test
     public void testConsecutiveLaunchWithDifferentWindowingMode() {
         mTopActivity.setWindowingMode(WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW);
+        mTrampolineActivity.mVisibleRequested = true;
         onActivityLaunched(mTrampolineActivity);
         mActivityMetricsLogger.notifyActivityLaunching(mTopActivity.intent,
                 mTrampolineActivity /* caller */, mTrampolineActivity.getUid());
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
index 2558259..741f33f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
@@ -18,6 +18,8 @@
 
 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
+import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
+import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
@@ -407,16 +409,16 @@
     }
 
     @Test
-    public void testSupportsMultiWindow_activityMinWidthHeight_smallerThanSupport() {
+    public void testSupportsMultiWindow_landscape_checkActivityMinWidth() {
         // This is smaller than the min dimensions device support in multi window,
         // the activity will be supported in multi window
         final float density = mContext.getResources().getDisplayMetrics().density;
-        final int supportedDimensions = (int) ((mAtm.mLargeScreenSmallestScreenWidthDp - 1)
+        final int supportedWidth = (int) (mAtm.mLargeScreenSmallestScreenWidthDp
                 * mAtm.mMinPercentageMultiWindowSupportWidth * density);
         final ActivityInfo.WindowLayout windowLayout =
                 new ActivityInfo.WindowLayout(0, 0, 0, 0, 0,
-                        /* minWidth= */supportedDimensions,
-                        /* minHeight= */supportedDimensions);
+                        /* minWidth= */ supportedWidth,
+                        /* minHeight= */ 0);
         final ActivityRecord activity = new ActivityBuilder(mAtm)
                 .setCreateTask(true)
                 .setWindowLayout(windowLayout)
@@ -425,15 +427,48 @@
         final Task task = activity.getTask();
         final TaskDisplayArea tda = task.getDisplayArea();
         tda.getConfiguration().smallestScreenWidthDp = mAtm.mLargeScreenSmallestScreenWidthDp - 1;
+        tda.getConfiguration().screenWidthDp = mAtm.mLargeScreenSmallestScreenWidthDp - 1;
+        tda.getConfiguration().orientation = ORIENTATION_LANDSCAPE;
 
-        // Always check the activity min width/height.
-        mAtm.mSupportsNonResizableMultiWindow = 1;
+        assertFalse(activity.supportsMultiWindow());
+        assertFalse(task.supportsMultiWindow());
+
+        tda.getConfiguration().screenWidthDp = (int) Math.ceil(
+                mAtm.mLargeScreenSmallestScreenWidthDp
+                        / mAtm.mMinPercentageMultiWindowSupportWidth);
 
         assertTrue(activity.supportsMultiWindow());
         assertTrue(task.supportsMultiWindow());
+    }
 
-        // The default config is relying on the screen size. Check for small screen
-        mAtm.mSupportsNonResizableMultiWindow = 0;
+    @Test
+    public void testSupportsMultiWindow_portrait_checkActivityMinHeight() {
+        // This is smaller than the min dimensions device support in multi window,
+        // the activity will be supported in multi window
+        final float density = mContext.getResources().getDisplayMetrics().density;
+        final int supportedHeight = (int) (mAtm.mLargeScreenSmallestScreenWidthDp
+                * mAtm.mMinPercentageMultiWindowSupportHeight * density);
+        final ActivityInfo.WindowLayout windowLayout =
+                new ActivityInfo.WindowLayout(0, 0, 0, 0, 0,
+                        /* minWidth= */ 0,
+                        /* minHeight= */ supportedHeight);
+        final ActivityRecord activity = new ActivityBuilder(mAtm)
+                .setCreateTask(true)
+                .setWindowLayout(windowLayout)
+                .setResizeMode(RESIZE_MODE_RESIZEABLE)
+                .build();
+        final Task task = activity.getTask();
+        final TaskDisplayArea tda = task.getDisplayArea();
+        tda.getConfiguration().smallestScreenWidthDp = mAtm.mLargeScreenSmallestScreenWidthDp - 1;
+        tda.getConfiguration().screenHeightDp = mAtm.mLargeScreenSmallestScreenWidthDp - 1;
+        tda.getConfiguration().orientation = ORIENTATION_PORTRAIT;
+
+        assertFalse(activity.supportsMultiWindow());
+        assertFalse(task.supportsMultiWindow());
+
+        tda.getConfiguration().screenHeightDp = (int) Math.ceil(
+                mAtm.mLargeScreenSmallestScreenWidthDp
+                        / mAtm.mMinPercentageMultiWindowSupportHeight);
 
         assertTrue(activity.supportsMultiWindow());
         assertTrue(task.supportsMultiWindow());
diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
index 42ef086..a8e1753 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -484,7 +484,8 @@
             mSupportsFreeformWindowManagement = true;
             mSupportsPictureInPicture = true;
             mDevEnableNonResizableMultiWindow = false;
-            mMinPercentageMultiWindowSupportWidth = 0.3f;
+            mMinPercentageMultiWindowSupportHeight = 0.3f;
+            mMinPercentageMultiWindowSupportWidth = 0.5f;
             mLargeScreenSmallestScreenWidthDp = 600;
             mSupportsNonResizableMultiWindow = 0;
             mRespectsActivityMinWidthHeightMultiWindow = 0;