Merge "Import translations. DO NOT MERGE ANYWHERE" into main
diff --git a/quickstep/res/layout/taskbar_edu_circle_to_search.xml b/quickstep/res/layout/taskbar_edu_search.xml
similarity index 79%
rename from quickstep/res/layout/taskbar_edu_circle_to_search.xml
rename to quickstep/res/layout/taskbar_edu_search.xml
index 6c95f25..ca84f35 100644
--- a/quickstep/res/layout/taskbar_edu_circle_to_search.xml
+++ b/quickstep/res/layout/taskbar_edu_search.xml
@@ -23,35 +23,35 @@
         style="@style/TextAppearance.TaskbarEduTooltip.Title"
         android:layout_width="0dp"
         android:layout_height="wrap_content"
-        android:text="@string/taskbar_edu_circle_to_search_title"
+        android:text="@string/taskbar_search_edu_title"
         app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintTop_toTopOf="parent"
-        app:layout_constraintBottom_toTopOf="@+id/circle_to_search_animation" />
+        app:layout_constraintBottom_toTopOf="@+id/search_edu_animation" />
 
     <com.airbnb.lottie.LottieAnimationView
-        android:id="@+id/circle_to_search_animation"
+        android:id="@+id/search_edu_animation"
         android:layout_width="@dimen/taskbar_edu_swipe_lottie_width"
         android:layout_height="@dimen/taskbar_edu_swipe_lottie_height"
         android:layout_marginTop="@dimen/taskbar_edu_tooltip_vertical_margin"
-        app:layout_constraintBottom_toTopOf="@id/circle_to_search_text"
+        app:layout_constraintBottom_toTopOf="@id/search_edu_text"
         app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintTop_toBottomOf="@id/title"
-        app:lottie_rawRes="@raw/taskbar_edu_circle_to_search"
+        app:lottie_rawRes="@raw/taskbar_edu_search"
         app:lottie_autoPlay="true"
         app:lottie_loop="true" />
 
     <TextView
-        android:id="@+id/circle_to_search_text"
+        android:id="@+id/search_edu_text"
         style="@style/TextAppearance.TaskbarEduTooltip.Subtext"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:gravity="center"
-        android:textSize="@dimen/taskbar_edu_circle_to_search_subtitle_text_size"
+        android:textSize="@dimen/taskbar_edu_search_subtitle_text_size"
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintTop_toBottomOf="@id/circle_to_search_animation"
+        app:layout_constraintTop_toBottomOf="@id/search_edu_animation"
         app:layout_constraintBottom_toBottomOf="parent" />
 
 </androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/quickstep/res/raw/taskbar_edu_circle_to_search.json b/quickstep/res/raw/taskbar_edu_search.json
similarity index 100%
rename from quickstep/res/raw/taskbar_edu_circle_to_search.json
rename to quickstep/res/raw/taskbar_edu_search.json
diff --git a/quickstep/res/values/config.xml b/quickstep/res/values/config.xml
index 28cdb99..b3502db 100644
--- a/quickstep/res/values/config.xml
+++ b/quickstep/res/values/config.xml
@@ -35,6 +35,7 @@
     <string name="taskbar_view_callbacks_factory_class" translatable="false">com.android.launcher3.taskbar.TaskbarViewCallbacksFactory</string>
     <string name="launcher_restore_event_logger_class" translatable="false">com.android.quickstep.LauncherRestoreEventLoggerImpl</string>
     <string name="plugin_manager_wrapper_class" translatable="false">com.android.launcher3.uioverrides.plugins.PluginManagerWrapperImpl</string>
+    <string name="taskbar_edu_tooltip_controller_class" translatable="false">com.android.launcher3.taskbar.TaskbarEduTooltipController</string>
 
     <string name="nav_handle_long_press_handler_class" translatable="false"></string>
     <string name="assist_utils_class" translatable="false"></string>
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 9ca8060..dbf075c 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -403,7 +403,7 @@
     <dimen name="taskbar_edu_features_tooltip_width_with_one_feature">412dp</dimen>
     <dimen name="taskbar_edu_features_tooltip_width_with_two_features">428dp</dimen>
     <dimen name="taskbar_edu_features_tooltip_width_with_three_features">624dp</dimen>
-    <dimen name="taskbar_edu_circle_to_search_subtitle_text_size">12sp</dimen>
+    <dimen name="taskbar_edu_search_subtitle_text_size">12sp</dimen>
 
     <!--- Taskbar Pinning -->
     <dimen name="taskbar_pinning_popup_menu_width">300dp</dimen>
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
index fc3c0e3..278c66a 100644
--- a/quickstep/res/values/strings.xml
+++ b/quickstep/res/values/strings.xml
@@ -275,10 +275,10 @@
     <string name="taskbar_edu_pinning_title">Always show the Taskbar</string>
     <!-- Text in dialog that shows a user how to pin the Taskbar. [CHAR_LIMIT 150] -->
     <string name="taskbar_edu_pinning_standalone">To always show the Taskbar on the bottom of your screen, touch &amp; hold the divider</string>
-    <!-- Title in dialog that shows a user how to invoke the Circle to Search feature. [CHAR_LIMIT 150] -->
-    <string name="taskbar_edu_circle_to_search_title">Touch &amp; hold the action key to search what\'s on your screen</string>
+    <!-- Title in dialog that shows a user how to invoke the Search feature. [CHAR_LIMIT 150] -->
+    <string name="taskbar_search_edu_title">Touch &amp; hold the action key to search what\'s on your screen</string>
     <!-- Message showed to user to disclose privacy information they need to accept in order to access the app. [CHAR LIMIT=200]-->
-    <string name="taskbar_edu_circle_to_search_disclosure">This product uses the selected part of your screen to search. Google\'s <xliff:g example="https://policies.google.com/privacy/embedded" id="begin_privacy_link">&lt;a href=\"%1$s\"&gt;</xliff:g>Privacy Policy<xliff:g id="end_privacy_link">&lt;/a&gt;</xliff:g> and <xliff:g example="https://policies.google.com/terms" id="begin_tos_link">&lt;a href=\"%2$s\"&gt;</xliff:g>Terms of Service<xliff:g id="end_tos_link">&lt;/a&gt;</xliff:g> apply.</string>
+    <string name="taskbar_edu_search_disclosure">This product uses the selected part of your screen to search. Google\'s <xliff:g example="https://policies.google.com/privacy/embedded" id="begin_privacy_link">&lt;a href=\"%1$s\"&gt;</xliff:g>Privacy Policy<xliff:g id="end_privacy_link">&lt;/a&gt;</xliff:g> and <xliff:g example="https://policies.google.com/terms" id="begin_tos_link">&lt;a href=\"%2$s\"&gt;</xliff:g>Terms of Service<xliff:g id="end_tos_link">&lt;/a&gt;</xliff:g> apply.</string>
     <!-- Text on button to exit a tutorial [CHAR_LIMIT=16] -->
     <string name="taskbar_edu_close">Close</string>
     <!-- Text on button to finish a tutorial [CHAR_LIMIT=16] -->
diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
index 489102f..2c2311a 100644
--- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
@@ -16,7 +16,6 @@
 package com.android.launcher3.taskbar;
 
 import static com.android.launcher3.QuickstepTransitionManager.TRANSIENT_TASKBAR_TRANSITION_DURATION;
-import static com.android.launcher3.config.FeatureFlags.enableSplitContextually;
 import static com.android.launcher3.statemanager.BaseState.FLAG_NON_INTERACTIVE;
 import static com.android.launcher3.taskbar.TaskbarEduTooltipControllerKt.TOOLTIP_STEP_FEATURES;
 import static com.android.launcher3.taskbar.TaskbarLauncherStateController.FLAG_VISIBLE;
@@ -306,8 +305,8 @@
      */
     public void showEduOnAppLaunch() {
         if (!shouldShowEduOnAppLaunch()) {
-            // Called in case the edu finishes and circle to search edu is still pending
-            mControllers.taskbarEduTooltipController.maybeShowCircleToSearchEdu();
+            // Called in case the edu finishes and search edu is still pending
+            mControllers.taskbarEduTooltipController.maybeShowSearchEdu();
             return;
         }
 
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 679528b..1a94424 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -306,7 +306,7 @@
                 new TaskbarTranslationController(this),
                 new TaskbarSpringOnStashController(this),
                 createTaskbarRecentAppsController(isPcMode),
-                new TaskbarEduTooltipController(this),
+                TaskbarEduTooltipController.newInstance(this),
                 new KeyboardQuickSwitchController(),
                 new TaskbarPinningController(this),
                 bubbleControllersOptional);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltipController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltipController.kt
index e53f627..d43055d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltipController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltipController.kt
@@ -15,6 +15,7 @@
  */
 package com.android.launcher3.taskbar
 
+import android.content.Context
 import android.content.Intent
 import android.net.Uri
 import android.os.Bundle
@@ -42,8 +43,10 @@
 import com.android.launcher3.taskbar.TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_EDU_OPEN
 import com.android.launcher3.taskbar.TaskbarControllers.LoggableTaskbarController
 import com.android.launcher3.util.DisplayController
-import com.android.launcher3.util.OnboardingPrefs.TASKBAR_CIRCLE_TO_SEARCH_EDU_SEEN
 import com.android.launcher3.util.OnboardingPrefs.TASKBAR_EDU_TOOLTIP_STEP
+import com.android.launcher3.util.OnboardingPrefs.TASKBAR_SEARCH_EDU_SEEN
+import com.android.launcher3.util.ResourceBasedOverride
+import com.android.launcher3.views.ActivityContext
 import com.android.launcher3.views.BaseDragLayer
 import com.android.quickstep.util.LottieAnimationColorUtils
 import java.io.PrintWriter
@@ -72,9 +75,11 @@
 annotation class TaskbarEduTooltipStep
 
 /** Controls stepping through the Taskbar tooltip EDU. */
-class TaskbarEduTooltipController(val activityContext: TaskbarActivityContext) :
-    LoggableTaskbarController {
+open class TaskbarEduTooltipController(context: Context) :
+    ResourceBasedOverride, LoggableTaskbarController {
 
+    protected val activityContext: TaskbarActivityContext = ActivityContext.lookupContext(context)
+    open val shouldShowSearchEdu = false
     private val isTooltipEnabled: Boolean
         get() = !Utilities.isRunningInTestHarness() && !activityContext.isPhoneMode
     private val isOpen: Boolean
@@ -83,13 +88,13 @@
         get() = isTooltipEnabled && tooltipStep <= TOOLTIP_STEP_FEATURES
     private lateinit var controllers: TaskbarControllers
 
-    // Keep track of whether the user has seen the Circle to Search Edu
-    private var userHasSeenCircleToSearchEdu: Boolean
+    // Keep track of whether the user has seen the Search Edu
+    private var userHasSeenSearchEdu: Boolean
         get() {
-            return TASKBAR_CIRCLE_TO_SEARCH_EDU_SEEN.get(activityContext)
+            return TASKBAR_SEARCH_EDU_SEEN.get(activityContext)
         }
         private set(seen) {
-            LauncherPrefs.get(activityContext).put(TASKBAR_CIRCLE_TO_SEARCH_EDU_SEEN, seen)
+            LauncherPrefs.get(activityContext).put(TASKBAR_SEARCH_EDU_SEEN, seen)
         }
 
     @TaskbarEduTooltipStep
@@ -105,8 +110,8 @@
 
     fun init(controllers: TaskbarControllers) {
         this.controllers = controllers
-        // We want to show the Circle To Search Edu right after pinning, so we post it here
-        activityContext.dragLayer.post { maybeShowCircleToSearchEdu() }
+        // We want to show the Search Edu right after pinning the taskbar, so we post it here
+        activityContext.dragLayer.post { maybeShowSearchEdu() }
     }
 
     /** Shows swipe EDU tooltip if it is the current [tooltipStep]. */
@@ -136,7 +141,7 @@
     fun maybeShowFeaturesEdu() {
         if (!isTooltipEnabled || tooltipStep > TOOLTIP_STEP_FEATURES) {
             maybeShowPinningEdu()
-            maybeShowCircleToSearchEdu()
+            maybeShowSearchEdu()
             return
         }
 
@@ -233,26 +238,26 @@
     }
 
     /**
-     * Shows standalone Circle To Search EDU tooltip if this EDU has not been seen.
+     * Shows standalone Search EDU tooltip if this EDU has not been seen.
      *
-     * We show this standalone edu for users to learn to how to trigger Circle To Search from the
-     * pinned taskbar
+     * We show this standalone edu for users to learn to how to trigger Search from the pinned
+     * taskbar
      */
-    fun maybeShowCircleToSearchEdu() {
+    fun maybeShowSearchEdu() {
         if (
             !enableTaskbarPinning() ||
                 !DisplayController.isPinnedTaskbar(activityContext) ||
                 !isTooltipEnabled ||
-                userHasSeenCircleToSearchEdu
+                !shouldShowSearchEdu ||
+                userHasSeenSearchEdu
         ) {
             return
         }
-        userHasSeenCircleToSearchEdu = true
-        inflateTooltip(R.layout.taskbar_edu_circle_to_search)
+        userHasSeenSearchEdu = true
+        inflateTooltip(R.layout.taskbar_edu_search)
         tooltip?.run {
-            requireViewById<LottieAnimationView>(R.id.circle_to_search_animation)
-                .supportLightTheme()
-            val eduSubtitle: TextView = requireViewById(R.id.circle_to_search_text)
+            requireViewById<LottieAnimationView>(R.id.search_edu_animation).supportLightTheme()
+            val eduSubtitle: TextView = requireViewById(R.id.search_edu_text)
             showDisclosureText(eduSubtitle)
             updateLayoutParams<BaseDragLayer.LayoutParams> {
                 if (DisplayController.isTransientTaskbar(activityContext)) {
@@ -285,7 +290,7 @@
      */
     private fun TaskbarEduTooltip.showDisclosureText(
         textView: TextView,
-        stringId: Int = R.string.taskbar_edu_circle_to_search_disclosure,
+        stringId: Int = R.string.taskbar_edu_search_disclosure,
     ) {
         val locale = resources.configuration.locales[0]
         val text =
@@ -395,6 +400,17 @@
         pw?.println("$prefix\tisOpen=$isOpen")
         pw?.println("$prefix\ttooltipStep=$tooltipStep")
     }
+
+    companion object {
+        @JvmStatic
+        fun newInstance(context: Context): TaskbarEduTooltipController {
+            return ResourceBasedOverride.Overrides.getObject(
+                TaskbarEduTooltipController::class.java,
+                context,
+                R.string.taskbar_edu_tooltip_controller_class
+            )
+        }
+    }
 }
 
 /**
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 445f082..5daafcf 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -2747,8 +2747,10 @@
             return Arrays.stream(runningTasks).anyMatch(
                     runningTask -> !taskView.containsTaskId(runningTask.key.id));
         } else {
-            // Ensure the TaskView only contains a single taskId, otherwise add a stub task.
-            return taskView.containsMultipleTasks();
+            // Ensure the TaskView only contains a single taskId, or is a DesktopTask,
+            // otherwise add a stub task.
+            // TODO(b/249371338): Figure out why DesktopTask only have a single runningTask.
+            return taskView.containsMultipleTasks() && !taskView.isDesktopTask();
         }
     }
 
diff --git a/res/layout/widget_cell_content.xml b/res/layout/widget_cell_content.xml
index 12453a5..8f786bf 100644
--- a/res/layout/widget_cell_content.xml
+++ b/res/layout/widget_cell_content.xml
@@ -78,7 +78,7 @@
                     android:gravity="center_horizontal"
                     android:textSize="@dimen/widget_cell_font_size"
                     android:textColor="?android:attr/textColorSecondary"
-                    android:maxLines="2"
+                    android:maxLines="3"
                     android:ellipsize="end"
                     android:fadingEdge="horizontal"
                     android:alpha="0.7" />
diff --git a/res/layout/widgets_bottom_sheet_content.xml b/res/layout/widgets_bottom_sheet_content.xml
index 065c2ed..0a1407e 100644
--- a/res/layout/widgets_bottom_sheet_content.xml
+++ b/res/layout/widgets_bottom_sheet_content.xml
@@ -25,11 +25,10 @@
             android:layout_width="@dimen/bottom_sheet_handle_width"
             android:layout_height="@dimen/bottom_sheet_handle_height"
             android:layout_gravity="center_horizontal"
-            android:layout_marginBottom="@dimen/bottom_sheet_handle_margin"
+            android:layout_marginBottom="@dimen/widgets_bottom_sheet_handle_margin"
             android:visibility="gone"
             android:background="@drawable/bg_rounded_corner_bottom_sheet_handle"/>
         <TextView
-            style="@style/TextHeadline"
             android:id="@+id/title"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
@@ -41,8 +40,13 @@
             android:id="@+id/widgets_table_scroll_view"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:fadeScrollbars="false"
-            android:layout_marginTop="16dp">
+            android:layout_marginTop="24dp"
+            android:layout_marginBottom="24dp"
+            android:layout_marginHorizontal="@dimen/widget_bottom_sheet_horizontal_margin"
+            android:background="@drawable/widgets_surface_background"
+            android:scrollbarThumbVertical="@drawable/widget_picker_preview_pane_scroll_thumb"
+            android:clipToOutline="true"
+            android:clipChildren="true">
             <include layout="@layout/widgets_table_container"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
diff --git a/res/values/config.xml b/res/values/config.xml
index 393a197..648a50c 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -76,6 +76,7 @@
     <string name="taskbar_model_callbacks_factory_class" translatable="false"></string>
     <string name="taskbar_view_callbacks_factory_class" translatable="false"></string>
     <string name="launcher_restore_event_logger_class" translatable="false"></string>
+    <string name="taskbar_edu_tooltip_controller_class" translatable="false"></string>
     <!--  Used for determining category of a widget presented in widget recommendations. -->
     <string name="widget_recommendation_category_provider_class" translatable="false"></string>
     <string name="api_wrapper_class" translatable="false"></string>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 5dd3569..f16c69b 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -209,6 +209,8 @@
     <dimen name="widget_list_left_pane_horizontal_margin">0dp</dimen>
     <dimen name="widget_list_horizontal_margin_two_pane">24dp</dimen>
     <dimen name="widget_picker_vertical_margin_right_pane">24dp</dimen>
+    <!-- Margin on sides of the widgets scrollview in widgets bottom sheet -->
+    <dimen name="widget_bottom_sheet_horizontal_margin">16dp</dimen>
 
     <dimen name="widget_preview_shadow_blur">0.5dp</dimen>
     <dimen name="widget_preview_key_shadow_distance">1dp</dimen>
@@ -476,6 +478,7 @@
     <dimen name="bottom_sheet_handle_width">32dp</dimen>
     <dimen name="bottom_sheet_handle_height">4dp</dimen>
     <dimen name="bottom_sheet_handle_margin">16dp</dimen>
+    <dimen name="widgets_bottom_sheet_handle_margin">24dp</dimen>
     <dimen name="bottom_sheet_handle_corner_radius">2dp</dimen>
 
     <!-- State transition -->
diff --git a/src/com/android/launcher3/util/OnboardingPrefs.kt b/src/com/android/launcher3/util/OnboardingPrefs.kt
index 370b4c8..ac6e97c 100644
--- a/src/com/android/launcher3/util/OnboardingPrefs.kt
+++ b/src/com/android/launcher3/util/OnboardingPrefs.kt
@@ -76,7 +76,5 @@
     @JvmField
     val HOTSEAT_LONGPRESS_TIP_SEEN = backedUpItem("launcher.hotseat_longpress_tip_seen", false)
 
-    @JvmField
-    val TASKBAR_CIRCLE_TO_SEARCH_EDU_SEEN =
-        backedUpItem("launcher.taskbar_circle_to_search_edu_seen", false)
+    @JvmField val TASKBAR_SEARCH_EDU_SEEN = backedUpItem("launcher.taskbar_search_edu_seen", false)
 }
diff --git a/src/com/android/launcher3/widget/WidgetsBottomSheet.java b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
index b14ec42..3be6c68 100644
--- a/src/com/android/launcher3/widget/WidgetsBottomSheet.java
+++ b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
@@ -21,7 +21,6 @@
 import android.content.Context;
 import android.graphics.Rect;
 import android.util.AttributeSet;
-import android.util.IntProperty;
 import android.util.Pair;
 import android.view.Gravity;
 import android.view.LayoutInflater;
@@ -50,22 +49,6 @@
  * Bottom sheet for the "Widgets" system shortcut in the long-press popup.
  */
 public class WidgetsBottomSheet extends BaseWidgetSheet {
-    private static final String TAG = "WidgetsBottomSheet";
-
-    private static final IntProperty<View> PADDING_BOTTOM =
-            new IntProperty<View>("paddingBottom") {
-                @Override
-                public void setValue(View view, int paddingBottom) {
-                    view.setPadding(view.getPaddingLeft(), view.getPaddingTop(),
-                            view.getPaddingRight(), paddingBottom);
-                }
-
-                @Override
-                public Integer get(View view) {
-                    return view.getPaddingBottom();
-                }
-            };
-
     private static final int DEFAULT_CLOSE_DURATION = 200;
     private static final long EDUCATION_TIP_DELAY_MS = 300;
 
@@ -119,9 +102,6 @@
         mContent = findViewById(R.id.widgets_bottom_sheet);
         setContentBackgroundWithParent(
                 getContext().getDrawable(R.drawable.bg_rounded_corner_bottom_sheet), mContent);
-        View scrollView = findViewById(R.id.widgets_table_scroll_view);
-        scrollView.setOutlineProvider(mViewOutlineProvider);
-        scrollView.setClipToOutline(true);
     }
 
     @Override
diff --git a/src/com/android/launcher3/widget/util/WidgetsTableUtils.java b/src/com/android/launcher3/widget/util/WidgetsTableUtils.java
index 5e0e203..edaf474 100644
--- a/src/com/android/launcher3/widget/util/WidgetsTableUtils.java
+++ b/src/com/android/launcher3/widget/util/WidgetsTableUtils.java
@@ -31,6 +31,7 @@
 
 /** An utility class which groups {@link WidgetItem}s into a table. */
 public final class WidgetsTableUtils {
+    private static final int MAX_ITEMS_IN_ROW = 3;
 
     /**
      * Groups widgets in the following order:
@@ -125,7 +126,8 @@
                 widgetItemsAtRow.add(widgetItem);
                 containerSizeForRow = containerSize;
                 currentRowWidth = containerWidth;
-            } else if ((currentRowWidth + containerWidth) <= rowPx
+            } else if (widgetItemsAtRow.size() < MAX_ITEMS_IN_ROW
+                    && (currentRowWidth + containerWidth) <= rowPx
                     && widgetItem.hasSameType(widgetItemsAtRow.get(numOfWidgetItems - 1))
                     && containerSize.equals(containerSizeForRow)) {
                 // Group items in the same row if