adding the new Material U App Shortcut Popup design

Bug: 247880037
Test: tested manually
Change-Id: I66c291df54dfc2a76fc974082a19091deb167f73
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
index 30d6eb4..115b99e 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
@@ -15,6 +15,7 @@
  */
 package com.android.launcher3.taskbar;
 
+import static com.android.launcher3.config.FeatureFlags.ENABLE_MATERIAL_U_POPUP;
 import static com.android.launcher3.util.SplitConfigurationOptions.getLogEventForPosition;
 
 import android.content.Intent;
@@ -56,6 +57,7 @@
 
 import java.io.PrintWriter;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Objects;
 import java.util.function.Predicate;
 import java.util.stream.Collectors;
@@ -152,9 +154,28 @@
             return null;
         }
 
-        final PopupContainerWithArrow<BaseTaskbarContext> container =
-                (PopupContainerWithArrow<BaseTaskbarContext>) context.getLayoutInflater().inflate(
-                        R.layout.popup_container, context.getDragLayer(), false);
+        PopupContainerWithArrow<BaseTaskbarContext> container;
+        int deepShortcutCount = mPopupDataProvider.getShortcutCountForItem(item);
+        // TODO(b/198438631): add support for INSTALL shortcut factory
+        List<SystemShortcut> systemShortcuts = getSystemShortcuts()
+                .map(s -> s.getShortcut(context, item, icon))
+                .filter(Objects::nonNull)
+                .collect(Collectors.toList());
+
+        if (ENABLE_MATERIAL_U_POPUP.get()) {
+            container = (PopupContainerWithArrow) context.getLayoutInflater().inflate(
+                    R.layout.popup_container_material_u, context.getDragLayer(), false);
+            container.populateAndShowRowsMaterialU(icon, deepShortcutCount, systemShortcuts);
+        } else {
+            container = (PopupContainerWithArrow) context.getLayoutInflater().inflate(
+                    R.layout.popup_container, context.getDragLayer(), false);
+            container.populateAndShow(
+                    icon,
+                    deepShortcutCount,
+                    mPopupDataProvider.getNotificationKeysForItem(item),
+                    systemShortcuts);
+        }
+
         container.addOnAttachStateChangeListener(
                 new PopupLiveUpdateHandler<BaseTaskbarContext>(context, container) {
                     @Override
@@ -165,15 +186,6 @@
         // TODO (b/198438631): configure for taskbar/context
         container.setPopupItemDragHandler(new TaskbarPopupItemDragHandler());
         mControllers.taskbarDragController.addDragListener(container);
-
-        container.populateAndShow(icon,
-                mPopupDataProvider.getShortcutCountForItem(item),
-                mPopupDataProvider.getNotificationKeysForItem(item),
-                // TODO (b/198438631): add support for INSTALL shortcut factory
-                getSystemShortcuts()
-                        .map(s -> s.getShortcut(context, item, icon))
-                        .filter(Objects::nonNull)
-                        .collect(Collectors.toList()));
         container.requestFocus();
 
         // Make focusable to receive back events
diff --git a/res/drawable/popup_background_material_u.xml b/res/drawable/popup_background_material_u.xml
new file mode 100644
index 0000000..4d40ba8
--- /dev/null
+++ b/res/drawable/popup_background_material_u.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 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">
+    <solid android:color="?attr/popupColorPrimary"/>
+    <corners android:radius="@dimen/dialogCornerRadius"/>
+</shape>
\ No newline at end of file
diff --git a/res/layout/deep_shortcut_container.xml b/res/layout/deep_shortcut_container.xml
new file mode 100644
index 0000000..b6c3f56
--- /dev/null
+++ b/res/layout/deep_shortcut_container.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 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.
+-->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/deep_shortcuts_container"
+    android:background="@drawable/popup_background_material_u"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:tag="@string/popup_container_iterate_children"
+    android:elevation="@dimen/deep_shortcuts_elevation"
+    android:orientation="vertical"/>
\ No newline at end of file
diff --git a/res/layout/deep_shortcut_material_u.xml b/res/layout/deep_shortcut_material_u.xml
new file mode 100644
index 0000000..fc019e9
--- /dev/null
+++ b/res/layout/deep_shortcut_material_u.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 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.
+-->
+<com.android.launcher3.shortcuts.DeepShortcutView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:launcher="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/deep_shortcut_material"
+    android:layout_width="@dimen/bg_popup_item_width"
+    android:layout_height="@dimen/bg_popup_item_height"
+    android:elevation="@dimen/deep_shortcuts_elevation"
+    android:background="@drawable/middle_item_primary"
+    android:theme="@style/PopupItem" >
+
+    <com.android.launcher3.shortcuts.DeepShortcutTextView
+        style="@style/BaseIcon"
+        android:id="@+id/bubble_text"
+        android:background="?android:attr/selectableItemBackground"
+        android:gravity="start|center_vertical"
+        android:textAlignment="viewStart"
+        android:paddingStart="@dimen/deep_shortcuts_text_padding_start"
+        android:paddingEnd="@dimen/popup_padding_end"
+        android:drawablePadding="@dimen/deep_shortcut_drawable_padding"
+        android:singleLine="true"
+        android:ellipsize="end"
+        android:textSize="14sp"
+        android:textColor="?android:attr/textColorPrimary"
+        launcher:layoutHorizontal="true"
+        launcher:iconDisplay="shortcut_popup"
+        launcher:iconSizeOverride="@dimen/deep_shortcut_icon_size" />
+
+    <View
+        android:id="@+id/icon"
+        android:layout_width="@dimen/deep_shortcut_icon_size"
+        android:layout_height="@dimen/deep_shortcut_icon_size"
+        android:layout_marginStart="@dimen/popup_padding_start"
+        android:layout_gravity="start|center_vertical"
+        android:background="@drawable/ic_deepshortcut_placeholder"/>
+</com.android.launcher3.shortcuts.DeepShortcutView>
\ No newline at end of file
diff --git a/res/layout/popup_container_material_u.xml b/res/layout/popup_container_material_u.xml
new file mode 100644
index 0000000..d3036b6
--- /dev/null
+++ b/res/layout/popup_container_material_u.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 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.
+-->
+<com.android.launcher3.popup.PopupContainerWithArrow
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/popup_container"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:orientation="vertical"/>
\ No newline at end of file
diff --git a/res/layout/system_shortcut.xml b/res/layout/system_shortcut.xml
index 21d532e..cbd7fa4 100644
--- a/res/layout/system_shortcut.xml
+++ b/res/layout/system_shortcut.xml
@@ -18,6 +18,7 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="@dimen/bg_popup_item_width"
     android:layout_height="wrap_content"
+    android:id="@+id/system_shortcut"
     android:minHeight="@dimen/bg_popup_item_height"
     android:elevation="@dimen/deep_shortcuts_elevation"
     android:background="@drawable/middle_item_primary"
diff --git a/res/layout/system_shortcut_icons.xml b/res/layout/system_shortcut_icons_container.xml
similarity index 89%
rename from res/layout/system_shortcut_icons.xml
rename to res/layout/system_shortcut_icons_container.xml
index 775a45f..ee104d9 100644
--- a/res/layout/system_shortcut_icons.xml
+++ b/res/layout/system_shortcut_icons_container.xml
@@ -26,7 +26,7 @@
     android:clipToPadding="true">
 
     <Space android:layout_width="0dp"
-           android:layout_height="match_parent"
-           android:layout_weight="1"
-           android:id="@+id/separator"/>
+        android:layout_height="match_parent"
+        android:layout_weight="1"
+        android:id="@+id/separator"/>
 </LinearLayout>
diff --git a/res/layout/system_shortcut_icons.xml b/res/layout/system_shortcut_icons_container_material_u.xml
similarity index 73%
copy from res/layout/system_shortcut_icons.xml
copy to res/layout/system_shortcut_icons_container_material_u.xml
index 775a45f..afd11e6 100644
--- a/res/layout/system_shortcut_icons.xml
+++ b/res/layout/system_shortcut_icons_container_material_u.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
+<!-- Copyright (C) 2023 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.
@@ -17,16 +17,16 @@
 <LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/system_shortcut_icons"
+    android:tag="@string/popup_container_iterate_children"
     android:layout_width="match_parent"
     android:layout_height="@dimen/system_shortcut_header_height"
     android:orientation="horizontal"
     android:gravity="end|center_vertical"
-    android:background="@drawable/single_item_primary"
-    android:elevation="@dimen/deep_shortcuts_elevation"
-    android:clipToPadding="true">
+    android:background="@drawable/popup_background_material_u"
+    android:elevation="@dimen/deep_shortcuts_elevation">
 
     <Space android:layout_width="0dp"
-           android:layout_height="match_parent"
-           android:layout_weight="1"
-           android:id="@+id/separator"/>
+        android:layout_height="match_parent"
+        android:layout_weight="1"
+        android:id="@+id/separator"/>
 </LinearLayout>
diff --git a/res/layout/system_shortcut_rows_container_material_u.xml b/res/layout/system_shortcut_rows_container_material_u.xml
new file mode 100644
index 0000000..006e280
--- /dev/null
+++ b/res/layout/system_shortcut_rows_container_material_u.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 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.
+-->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/system_shortcuts_container"
+    android:background="@drawable/popup_background_material_u"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:tag="@string/popup_container_iterate_children"
+    android:elevation="@dimen/deep_shortcuts_elevation"
+    android:orientation="vertical"/>
diff --git a/res/layout/system_shortcut_icons.xml b/res/layout/widget_shortcut_container_material_u.xml
similarity index 71%
copy from res/layout/system_shortcut_icons.xml
copy to res/layout/widget_shortcut_container_material_u.xml
index 775a45f..aab34e3 100644
--- a/res/layout/system_shortcut_icons.xml
+++ b/res/layout/widget_shortcut_container_material_u.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
+<!-- Copyright (C) 2023 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.
@@ -16,17 +16,12 @@
 
 <LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/system_shortcut_icons"
+    android:id="@+id/widget_shortcut_container"
+    android:background="@drawable/popup_background_material_u"
     android:layout_width="match_parent"
     android:layout_height="@dimen/system_shortcut_header_height"
     android:orientation="horizontal"
     android:gravity="end|center_vertical"
-    android:background="@drawable/single_item_primary"
     android:elevation="@dimen/deep_shortcuts_elevation"
-    android:clipToPadding="true">
-
-    <Space android:layout_width="0dp"
-           android:layout_height="match_parent"
-           android:layout_weight="1"
-           android:id="@+id/separator"/>
-</LinearLayout>
+    android:tag="@string/popup_container_iterate_children"
+    android:clipToPadding="true"/>
\ No newline at end of file
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 9d2aa06..d292017 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -349,7 +349,7 @@
     <dimen name="developer_options_filter_margins">10dp</dimen>
 
     <!-- Theming related -->
-    <dimen name="default_dialog_corner_radius">8dp</dimen>
+    <dimen name="default_dialog_corner_radius">26dp</dimen>
     <dimen name="dialogCornerRadius">@dimen/default_dialog_corner_radius</dimen>
 
     <!-- Onboarding bottomsheet related -->
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 41632f7..8097fd7 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -3211,7 +3211,7 @@
     }
 
     @Override
-    public boolean shouldUseColorExtractionForPopup() {
+    public boolean canUseMultipleShadesForPopup() {
         return getTopOpenViewWithType(this, TYPE_FOLDER) == null
                 && getStateManager().getState() != LauncherState.ALL_APPS;
     }
diff --git a/src/com/android/launcher3/popup/ArrowPopup.java b/src/com/android/launcher3/popup/ArrowPopup.java
index 9a745ab..c23ea8a 100644
--- a/src/com/android/launcher3/popup/ArrowPopup.java
+++ b/src/com/android/launcher3/popup/ArrowPopup.java
@@ -21,6 +21,7 @@
 import static com.android.launcher3.anim.Interpolators.ACCELERATED_EASE;
 import static com.android.launcher3.anim.Interpolators.DECELERATED_EASE;
 import static com.android.launcher3.anim.Interpolators.LINEAR;
+import static com.android.launcher3.config.FeatureFlags.ENABLE_MATERIAL_U_POPUP;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -116,7 +117,7 @@
 
     private final String mIterateChildrenTag;
 
-    private final int[] mColorIds;
+    protected final int[] mColorIds;
 
     public ArrowPopup(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
@@ -125,8 +126,8 @@
         mActivityContext = ActivityContext.lookupContext(context);
         mIsRtl = Utilities.isRtl(getResources());
 
-        int backgroundColor = Themes.getAttrColor(context, R.attr.popupColorPrimary);
-        mArrowColor = backgroundColor;
+        int popupPrimaryColor = Themes.getAttrColor(context, R.attr.popupColorPrimary);
+        mArrowColor = popupPrimaryColor;
         mElevation = getResources().getDimension(R.dimen.deep_shortcuts_elevation);
 
         // Initialize arrow view
@@ -143,18 +144,18 @@
 
         int smallerRadius = resources.getDimensionPixelSize(R.dimen.popup_smaller_radius);
         mRoundedTop = new GradientDrawable();
-        mRoundedTop.setColor(backgroundColor);
+        mRoundedTop.setColor(popupPrimaryColor);
         mRoundedTop.setCornerRadii(new float[] { mOutlineRadius, mOutlineRadius, mOutlineRadius,
                 mOutlineRadius, smallerRadius, smallerRadius, smallerRadius, smallerRadius});
 
         mRoundedBottom = new GradientDrawable();
-        mRoundedBottom.setColor(backgroundColor);
+        mRoundedBottom.setColor(popupPrimaryColor);
         mRoundedBottom.setCornerRadii(new float[] { smallerRadius, smallerRadius, smallerRadius,
                 smallerRadius, mOutlineRadius, mOutlineRadius, mOutlineRadius, mOutlineRadius});
 
         mIterateChildrenTag = getContext().getString(R.string.popup_container_iterate_children);
 
-        if (mActivityContext.shouldUseColorExtractionForPopup()) {
+        if (!ENABLE_MATERIAL_U_POPUP.get() && mActivityContext.canUseMultipleShadesForPopup()) {
             mColorIds = new int[]{R.color.popup_shade_first, R.color.popup_shade_second,
                     R.color.popup_shade_third};
         } else {
@@ -241,15 +242,23 @@
                 mlp.bottomMargin = 0;
 
                 if (colors != null) {
-                    backgroundColor = colors[numVisibleChild % colors.length];
+                    if (!ENABLE_MATERIAL_U_POPUP.get()) {
+                        backgroundColor = colors[numVisibleChild % colors.length];
+                    }
+
+                    if (ENABLE_MATERIAL_U_POPUP.get() && isShortcutContainer(view)) {
+                        setChildColor(view, colors[0], colorAnimator);
+                        mArrowColor = colors[0];
+                    }
                 }
 
                 // Arrow color matches the first child or the last child.
-                if (mIsAboveIcon || (numVisibleChild == 0 && viewGroup == this)) {
+                if (!ENABLE_MATERIAL_U_POPUP.get()
+                        && (mIsAboveIcon || (numVisibleChild == 0 && viewGroup == this))) {
                     mArrowColor = backgroundColor;
                 }
 
-                if (view instanceof ViewGroup && mIterateChildrenTag.equals(view.getTag())) {
+                if (view instanceof ViewGroup && isShortcutContainer(view)) {
                     assignMarginsAndBackgrounds((ViewGroup) view, backgroundColor);
                     numVisibleChild++;
                     continue;
@@ -287,6 +296,13 @@
     }
 
     /**
+     * Returns {@code true} if view is a layout container of shortcuts
+     */
+    boolean isShortcutContainer(View view) {
+        return mIterateChildrenTag.equals(view.getTag());
+    }
+
+    /**
      * Sets the background color of the child.
      */
     protected void setChildColor(View view, int color, AnimatorSet animatorSetOut) {
@@ -308,7 +324,7 @@
      */
     protected void reorderAndShow(int viewsToFlip) {
         setupForDisplay();
-        boolean reverseOrder = mIsAboveIcon;
+        boolean reverseOrder = !ENABLE_MATERIAL_U_POPUP.get() && mIsAboveIcon;
         if (reverseOrder) {
             reverseOrder(viewsToFlip);
         }
@@ -634,7 +650,7 @@
         for (int i = group.getChildCount() - 1; i >= 0; --i) {
             View view = group.getChildAt(i);
             if (view.getVisibility() == VISIBLE && view instanceof ViewGroup) {
-                if (mIterateChildrenTag.equals(view.getTag())) {
+                if (isShortcutContainer(view)) {
                     fadeInChildViews((ViewGroup) view, alphaValues, startDelay, duration, out);
                     continue;
                 }
diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
index 4da588e..8fef5c6 100644
--- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java
+++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
@@ -17,12 +17,16 @@
 package com.android.launcher3.popup;
 
 import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_SHORTCUTS;
+import static com.android.launcher3.Utilities.ATLEAST_P;
 import static com.android.launcher3.Utilities.squaredHypot;
 import static com.android.launcher3.Utilities.squaredTouchSlop;
+import static com.android.launcher3.config.FeatureFlags.ENABLE_MATERIAL_U_POPUP;
 import static com.android.launcher3.popup.PopupPopulator.MAX_SHORTCUTS;
 import static com.android.launcher3.popup.PopupPopulator.MAX_SHORTCUTS_IF_NOTIFICATIONS;
 import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
 
+import static java.util.Collections.emptyList;
+
 import android.animation.AnimatorSet;
 import android.animation.LayoutTransition;
 import android.annotation.TargetApi;
@@ -39,6 +43,8 @@
 import android.view.ViewGroup;
 import android.widget.ImageView;
 
+import androidx.annotation.LayoutRes;
+
 import com.android.launcher3.AbstractFloatingView;
 import com.android.launcher3.BaseDraggingActivity;
 import com.android.launcher3.BubbleTextView;
@@ -82,20 +88,20 @@
 public class PopupContainerWithArrow<T extends Context & ActivityContext>
         extends ArrowPopup<T> implements DragSource, DragController.DragListener {
 
-    private final List<DeepShortcutView> mShortcuts = new ArrayList<>();
+    private final List<DeepShortcutView> mDeepShortcuts = new ArrayList<>();
     private final PointF mInterceptTouchDown = new PointF();
 
     private final int mStartDragThreshold;
 
+    private static final int SHORTCUT_COLLAPSE_THRESHOLD = 6;
+
     private BubbleTextView mOriginalIcon;
     private int mNumNotifications;
     private NotificationContainer mNotificationContainer;
     private int mContainerWidth;
 
     private ViewGroup mWidgetContainer;
-
     private ViewGroup mDeepShortcutContainer;
-
     private ViewGroup mSystemShortcutContainer;
 
     protected PopupItemDragHandler mPopupItemDragHandler;
@@ -211,19 +217,27 @@
             return null;
         }
 
-        final PopupContainerWithArrow<Launcher> container =
-                (PopupContainerWithArrow) launcher.getLayoutInflater().inflate(
-                        R.layout.popup_container, launcher.getDragLayer(), false);
-        container.configureForLauncher(launcher);
-
+        PopupContainerWithArrow<Launcher> container;
         PopupDataProvider popupDataProvider = launcher.getPopupDataProvider();
-        container.populateAndShow(icon,
-                popupDataProvider.getShortcutCountForItem(item),
-                popupDataProvider.getNotificationKeysForItem(item),
-                launcher.getSupportedShortcuts()
-                        .map(s -> s.getShortcut(launcher, item, icon))
-                        .filter(Objects::nonNull)
-                        .collect(Collectors.toList()));
+        int deepShortcutCount = popupDataProvider.getShortcutCountForItem(item);
+        List<SystemShortcut> systemShortcuts = launcher.getSupportedShortcuts()
+                .map(s -> s.getShortcut(launcher, item, icon))
+                .filter(Objects::nonNull)
+                .collect(Collectors.toList());
+        if (ENABLE_MATERIAL_U_POPUP.get()) {
+            container = (PopupContainerWithArrow) launcher.getLayoutInflater().inflate(
+                    R.layout.popup_container_material_u, launcher.getDragLayer(), false);
+            container.populateAndShowRowsMaterialU(icon, deepShortcutCount, systemShortcuts);
+        } else {
+            container = (PopupContainerWithArrow) launcher.getLayoutInflater().inflate(
+                    R.layout.popup_container, launcher.getDragLayer(), false);
+            container.populateAndShow(
+                    icon,
+                    deepShortcutCount,
+                    popupDataProvider.getNotificationKeysForItem(item),
+                    systemShortcuts);
+        }
+        container.configureForLauncher(launcher);
         launcher.refreshAndBindWidgetsForPackageUser(PackageUserKey.fromItemInfo(item));
         container.requestFocus();
         return container;
@@ -246,7 +260,7 @@
             initializeSystemShortcut(R.layout.system_shortcut, this, shortcuts.get(0));
             return;
         }
-        mSystemShortcutContainer = inflateAndAdd(R.layout.system_shortcut_icons, this);
+        mSystemShortcutContainer = inflateAndAdd(R.layout.system_shortcut_icons_container, this);
         for (SystemShortcut shortcut : shortcuts) {
             initializeSystemShortcut(
                     R.layout.system_shortcut_icon_only, mSystemShortcutContainer,
@@ -281,17 +295,7 @@
             mDeepShortcutContainer = findViewById(R.id.deep_shortcuts_container);
         }
         if (hasDeepShortcuts) {
-            // Remove the widget shortcut fom the list
-            List<SystemShortcut> systemShortcuts = shortcuts
-                    .stream()
-                    .filter(shortcut -> !(shortcut instanceof SystemShortcut.Widgets))
-                    .collect(Collectors.toList());
-            Optional<SystemShortcut.Widgets> widgetShortcutOpt = shortcuts
-                    .stream()
-                    .filter(shortcut -> shortcut instanceof SystemShortcut.Widgets)
-                    .map(SystemShortcut.Widgets.class::cast)
-                    .findFirst();
-
+            List<SystemShortcut> systemShortcuts = getNonWidgetSystemShortcuts(shortcuts);
             // if there are deep shortcuts, we might want to increase the width of shortcuts to fit
             // horizontally laid out system shortcuts.
             mContainerWidth = Math.max(mContainerWidth,
@@ -304,10 +308,10 @@
             for (int i = shortcutCount; i > 0; i--) {
                 DeepShortcutView v = inflateAndAdd(R.layout.deep_shortcut, mDeepShortcutContainer);
                 v.getLayoutParams().width = mContainerWidth;
-                mShortcuts.add(v);
+                mDeepShortcuts.add(v);
             }
             updateHiddenShortcuts();
-
+            Optional<SystemShortcut.Widgets> widgetShortcutOpt = getWidgetShortcut(shortcuts);
             if (widgetShortcutOpt.isPresent()) {
                 if (mWidgetContainer == null) {
                     mWidgetContainer = inflateAndAdd(R.layout.widget_shortcut_container,
@@ -327,21 +331,151 @@
         }
 
         reorderAndShow(viewsToFlip);
+        showPopupContainer((ItemInfo) originalIcon.getTag(), notificationKeys);
+    }
 
-        ItemInfo originalItemInfo = (ItemInfo) originalIcon.getTag();
-        if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
-            setAccessibilityPaneTitle(getTitleForAccessibility());
+    /**
+     * Populate and show shortcuts for the Launcher U app shortcut design.
+     * Will inflate the container and shortcut View instances for the popup container.
+     * @param originalIcon App icon that the popup is shown for
+     * @param deepShortcutCount Number of DeepShortcutView instances to add to container
+     * @param systemShortcuts List of SystemShortcuts to add to container
+     */
+    public void populateAndShowRowsMaterialU(final BubbleTextView originalIcon,
+            int deepShortcutCount, List<SystemShortcut> systemShortcuts) {
+
+        mOriginalIcon = originalIcon;
+        mContainerWidth = getResources().getDimensionPixelSize(R.dimen.bg_popup_item_width);
+
+        if (deepShortcutCount > 0) {
+            addAllShortcutsMaterialU(deepShortcutCount, systemShortcuts);
+        } else if (!systemShortcuts.isEmpty()) {
+            addSystemShortcutsMaterialU(systemShortcuts,
+                    R.layout.system_shortcut_rows_container_material_u,
+                    R.layout.system_shortcut);
         }
 
-        mOriginalIcon.setForceHideDot(true);
+        // no reversing needed for U design
+        reorderAndShow(0);
+        showPopupContainer((ItemInfo) originalIcon.getTag(), /* notificationKeys= */ emptyList());
+    }
 
+    /**
+     * Animates and loads shortcuts on background thread for this popup container
+     */
+    private void showPopupContainer(ItemInfo originalItemInfo,
+            List<NotificationKeyData> notificationKeys) {
+
+        if (ATLEAST_P) {
+            setAccessibilityPaneTitle(getTitleForAccessibility());
+        }
+        mOriginalIcon.setForceHideDot(true);
         // All views are added. Animate layout from now on.
         setLayoutTransition(new LayoutTransition());
-
         // Load the shortcuts on a background thread and update the container as it animates.
         MODEL_EXECUTOR.getHandler().postAtFrontOfQueue(PopupPopulator.createUpdateRunnable(
                 mActivityContext, originalItemInfo, new Handler(Looper.getMainLooper()),
-                this, mShortcuts, notificationKeys));
+                this, mDeepShortcuts, notificationKeys));
+    }
+
+    /**
+     * Adds any Deep Shortcuts, System Shortcuts and the Widget Shortcut to their respective
+     * containers
+     * @param deepShortcutCount number of DeepShortcutView instances
+     * @param systemShortcuts List of SystemShortcuts
+     */
+    private void addAllShortcutsMaterialU(int deepShortcutCount,
+            List<SystemShortcut> systemShortcuts) {
+
+        if (deepShortcutCount + systemShortcuts.size() <= SHORTCUT_COLLAPSE_THRESHOLD) {
+            // add all system shortcuts including widgets shortcut to same container
+            addSystemShortcutsMaterialU(systemShortcuts,
+                    R.layout.system_shortcut_rows_container_material_u,
+                    R.layout.system_shortcut);
+            addDeepShortcutsMaterialU(deepShortcutCount);
+            return;
+        }
+
+        List<SystemShortcut> nonWidgetSystemShortcuts =
+                getNonWidgetSystemShortcuts(systemShortcuts);
+        // If total shortcuts over threshold, collapse system shortcuts to single row
+        addSystemShortcutsMaterialU(nonWidgetSystemShortcuts,
+                R.layout.system_shortcut_icons_container_material_u,
+                R.layout.system_shortcut_icon_only);
+        // May need to recalculate row width
+        mContainerWidth = Math.max(mContainerWidth,
+                nonWidgetSystemShortcuts.size() * getResources()
+                        .getDimensionPixelSize(R.dimen.system_shortcut_header_icon_touch_size));
+        // Add widget shortcut to separate container
+        Optional<SystemShortcut.Widgets> widgetShortcutOpt = getWidgetShortcut(systemShortcuts);
+        if (widgetShortcutOpt.isPresent()) {
+            mWidgetContainer = inflateAndAdd(R.layout.widget_shortcut_container_material_u,
+                    this);
+            initializeWidgetShortcut(mWidgetContainer, widgetShortcutOpt.get());
+        }
+        addDeepShortcutsMaterialU(deepShortcutCount);
+    }
+
+    /**
+     * Finds the first instance of the Widgets Shortcut from the SystemShortcut List
+     * @param systemShortcuts List of SystemShortcut instances to search
+     * @return Optional Widgets SystemShortcut
+     */
+    private static Optional<SystemShortcut.Widgets> getWidgetShortcut(
+            List<SystemShortcut> systemShortcuts) {
+        return systemShortcuts
+                .stream()
+                .filter(shortcut -> shortcut instanceof SystemShortcut.Widgets)
+                .map(SystemShortcut.Widgets.class::cast)
+                .findFirst();
+    }
+
+    /**
+     * Returns list of [systemShortcuts] without the Widgets shortcut instance if found
+     * @param systemShortcuts list of SystemShortcuts to filter from
+     * @return systemShortcuts without the Widgets Shortcut
+     */
+    private static List<SystemShortcut> getNonWidgetSystemShortcuts(
+            List<SystemShortcut> systemShortcuts) {
+
+        return systemShortcuts
+                .stream()
+                .filter(shortcut -> !(shortcut instanceof SystemShortcut.Widgets))
+                .collect(Collectors.toList());
+    }
+
+    /**
+     * Inflates the given systemShortcutContainerLayout as a container, and populates with
+     * the systemShortcuts as views using the systemShortcutLayout
+     * @param systemShortcuts List of SystemShortcut to inflate as Views
+     * @param systemShortcutContainerLayout Layout Resource for the Container of shortcut Views
+     * @param systemShortcutLayout Layout Resource for the individual shortcut Views
+     */
+    private void addSystemShortcutsMaterialU(List<SystemShortcut> systemShortcuts,
+            @LayoutRes int systemShortcutContainerLayout, @LayoutRes int systemShortcutLayout) {
+
+        if (systemShortcuts.size() == 0) {
+            return;
+        }
+        mSystemShortcutContainer = inflateAndAdd(systemShortcutContainerLayout, this);
+        for (SystemShortcut shortcut : systemShortcuts) {
+            initializeSystemShortcut(systemShortcutLayout, mSystemShortcutContainer, shortcut);
+        }
+    }
+
+    /**
+     * Inflates and adds [deepShortcutCount] number of DeepShortcutView for the  to a new container
+     * @param deepShortcutCount number of DeepShortcutView instances to add
+     */
+    private void addDeepShortcutsMaterialU(int deepShortcutCount) {
+        mDeepShortcutContainer = inflateAndAdd(R.layout.deep_shortcut_container, this);
+        for (int i = deepShortcutCount; i > 0; i--) {
+            DeepShortcutView v = inflateAndAdd(R.layout.deep_shortcut_material_u,
+                    mDeepShortcutContainer);
+            v.getLayoutParams().width = mContainerWidth;
+            mDeepShortcuts.add(v);
+        }
+        updateHiddenShortcuts();
     }
 
     protected NotificationContainer getNotificationContainer() {
@@ -391,9 +525,9 @@
         int allowedCount = mNotificationContainer != null
                 ? MAX_SHORTCUTS_IF_NOTIFICATIONS : MAX_SHORTCUTS;
 
-        int total = mShortcuts.size();
+        int total = mDeepShortcuts.size();
         for (int i = 0; i < total; i++) {
-            DeepShortcutView view = mShortcuts.get(i);
+            DeepShortcutView view = mDeepShortcuts.get(i);
             view.setVisibility(i >= allowedCount ? GONE : VISIBLE);
         }
     }
diff --git a/src/com/android/launcher3/secondarydisplay/SecondaryDragLayer.java b/src/com/android/launcher3/secondarydisplay/SecondaryDragLayer.java
index c8455b8..2ffe34f 100644
--- a/src/com/android/launcher3/secondarydisplay/SecondaryDragLayer.java
+++ b/src/com/android/launcher3/secondarydisplay/SecondaryDragLayer.java
@@ -18,6 +18,7 @@
 import static android.view.View.MeasureSpec.EXACTLY;
 import static android.view.View.MeasureSpec.makeMeasureSpec;
 
+import static com.android.launcher3.config.FeatureFlags.ENABLE_MATERIAL_U_POPUP;
 import static com.android.launcher3.popup.SystemShortcut.APP_INFO;
 
 import android.content.Context;
@@ -203,14 +204,22 @@
             systemShortcuts.add(mPinnedAppsAdapter.getSystemShortcut(item, v));
         }
         systemShortcuts.add(APP_INFO.getShortcut(mActivity, item, v));
-
-        final PopupContainerWithArrow container =
-                (PopupContainerWithArrow) mActivity.getLayoutInflater().inflate(
-                        R.layout.popup_container, mActivity.getDragLayer(), false);
-
-        container.populateAndShow((BubbleTextView) v,
-                popupDataProvider.getShortcutCountForItem(item),
-                Collections.emptyList(), systemShortcuts);
+        int deepShortcutCount = popupDataProvider.getShortcutCountForItem(item);
+        final PopupContainerWithArrow<SecondaryDisplayLauncher> container;
+        if (ENABLE_MATERIAL_U_POPUP.get()) {
+            container = (PopupContainerWithArrow) mActivity.getLayoutInflater().inflate(
+                    R.layout.popup_container_material_u, mActivity.getDragLayer(), false);
+            container.populateAndShowRowsMaterialU((BubbleTextView) v, deepShortcutCount,
+                    systemShortcuts);
+        } else {
+            container = (PopupContainerWithArrow) mActivity.getLayoutInflater().inflate(
+                    R.layout.popup_container, mActivity.getDragLayer(), false);
+            container.populateAndShow(
+                    (BubbleTextView) v,
+                    deepShortcutCount,
+                    Collections.emptyList(),
+                    systemShortcuts);
+        }
         container.requestFocus();
 
         if (!FeatureFlags.SECONDARY_DRAG_N_DROP_TO_PIN.get() || !mActivity.isAppDrawerShown()) {
diff --git a/src/com/android/launcher3/views/ActivityContext.java b/src/com/android/launcher3/views/ActivityContext.java
index 2ab4601..f7837f5 100644
--- a/src/com/android/launcher3/views/ActivityContext.java
+++ b/src/com/android/launcher3/views/ActivityContext.java
@@ -199,9 +199,9 @@
     }
 
     /**
-     * Returns {@code true} if popups should use color extraction.
+     * Returns {@code true} if popups can use a range of color shades instead of a singular color.
      */
-    default boolean shouldUseColorExtractionForPopup() {
+    default boolean canUseMultipleShadesForPopup() {
         return true;
     }
 
diff --git a/src/com/android/launcher3/views/OptionsPopupView.java b/src/com/android/launcher3/views/OptionsPopupView.java
index 5b57e22..315cbad 100644
--- a/src/com/android/launcher3/views/OptionsPopupView.java
+++ b/src/com/android/launcher3/views/OptionsPopupView.java
@@ -15,12 +15,16 @@
  */
 package com.android.launcher3.views;
 
+import static androidx.core.content.ContextCompat.getColorStateList;
+
+import static com.android.launcher3.config.FeatureFlags.ENABLE_MATERIAL_U_POPUP;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.IGNORE;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SETTINGS_BUTTON_TAP_OR_LONGPRESS;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_WIDGETSTRAY_BUTTON_TAP_OR_LONGPRESS;
 
 import android.content.Context;
 import android.content.Intent;
+import android.graphics.Color;
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.graphics.drawable.Drawable;
@@ -31,6 +35,7 @@
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.view.View.OnLongClickListener;
+import android.view.ViewGroup;
 import android.widget.Toast;
 
 import androidx.annotation.Nullable;
@@ -139,6 +144,16 @@
         mTargetRect.roundOut(outPos);
     }
 
+    @Override
+    public void assignMarginsAndBackgrounds(ViewGroup viewGroup) {
+        if (ENABLE_MATERIAL_U_POPUP.get()) {
+            assignMarginsAndBackgrounds(viewGroup,
+                    getColorStateList(getContext(), mColorIds[0]).getDefaultColor());
+        } else {
+            assignMarginsAndBackgrounds(viewGroup, Color.TRANSPARENT);
+        }
+    }
+
     public static OptionsPopupView show(ActivityContext launcher, RectF targetRect,
             List<OptionItem> items, boolean shouldAddArrow) {
         return show(launcher, targetRect, items, shouldAddArrow, 0 /* width */);