Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1076f176 authored by Shamali P's avatar Shamali P
Browse files

Limit the recommendations space in two pane picker

- This makes the suggestion section non-overwhelming
- Currently it shows too many suggestions for user to find any value
- Limiting the height also allows pagination to feel smooth when showing
in categories

Bug: 318410881
Flag: ACONFIG com.android.launcher3.enable_categorized_widget_recommendations DEVELOPMENT
Test: Manual
Change-Id: Iab1f9a15bdd46ee1560734e30551bfb7c8a74a82
parent 927dd27e
Loading
Loading
Loading
Loading
+68 −32
Original line number Diff line number Diff line
@@ -36,12 +36,8 @@ public final class WidgetsListHeaderEntry extends WidgetsListBaseEntry {
            (context, entry) -> entry.mWidgets.stream()
                    .map(item -> item.label).sorted().collect(Collectors.joining(", "));

    private static final BiFunction<Context, WidgetsListHeaderEntry, String> SUBTITLE_DEFAULT =
            (context, entry) -> {
                List<WidgetItem> items = entry.mWidgets;
                int wc = (int) items.stream().filter(item -> item.widgetInfo != null).count();
                int sc = Math.max(0, items.size() - wc);

    @Nullable
    private static String buildWidgetsCountString(Context context, int wc, int sc) {
        Resources resources = context.getResources();
        if (wc == 0 && sc == 0) {
            return null;
@@ -63,14 +59,26 @@ public final class WidgetsListHeaderEntry extends WidgetsListBaseEntry {
                    R.string.shortcuts_count, sc);
        }
        return subtitle;
            };
    }

    private final boolean mIsWidgetListShown;
    /** Selected widgets displayed */
    private final int mVisibleWidgetsCount;
    private final boolean mIsSearchEntry;

    private WidgetsListHeaderEntry(PackageItemInfo pkgItem, String titleSectionName,
            List<WidgetItem> items, int visibleWidgetsCount,
            boolean isSearchEntry, boolean isWidgetListShown) {
        super(pkgItem, titleSectionName, items);
        mVisibleWidgetsCount = visibleWidgetsCount;
        mIsSearchEntry = isSearchEntry;
        mIsWidgetListShown = isWidgetListShown;
    }

    private WidgetsListHeaderEntry(PackageItemInfo pkgItem, String titleSectionName,
            List<WidgetItem> items, boolean isSearchEntry, boolean isWidgetListShown) {
        super(pkgItem, titleSectionName, items);
        mVisibleWidgetsCount = (int) items.stream().filter(w -> w.widgetInfo != null).count();
        mIsSearchEntry = isSearchEntry;
        mIsWidgetListShown = isWidgetListShown;
    }
@@ -91,8 +99,13 @@ public final class WidgetsListHeaderEntry extends WidgetsListBaseEntry {

    @Nullable
    public String getSubtitle(Context context) {
        return mIsSearchEntry
                ? SUBTITLE_SEARCH.apply(context, this) : SUBTITLE_DEFAULT.apply(context, this);
        if (mIsSearchEntry) {
            return SUBTITLE_SEARCH.apply(context, this);
        } else {
            int shortcutsCount = Math.max(0,
                    (int) mWidgets.stream().filter(WidgetItem::isShortcut).count());
            return buildWidgetsCountString(context, mVisibleWidgetsCount, shortcutsCount);
        }
    }

    @Override
@@ -102,6 +115,7 @@ public final class WidgetsListHeaderEntry extends WidgetsListBaseEntry {
        return mWidgets.equals(otherEntry.mWidgets) && mPkgItem.equals(otherEntry.mPkgItem)
                && mTitleSectionName.equals(otherEntry.mTitleSectionName)
                && mIsWidgetListShown == otherEntry.mIsWidgetListShown
                && mVisibleWidgetsCount == otherEntry.mVisibleWidgetsCount
                && mIsSearchEntry == otherEntry.mIsSearchEntry;
    }

@@ -112,6 +126,7 @@ public final class WidgetsListHeaderEntry extends WidgetsListBaseEntry {
                mPkgItem,
                mTitleSectionName,
                mWidgets,
                mVisibleWidgetsCount,
                mIsSearchEntry,
                /* isWidgetListShown= */ true);
    }
@@ -122,7 +137,28 @@ public final class WidgetsListHeaderEntry extends WidgetsListBaseEntry {
                pkgItem,
                titleSectionName,
                items,
                /* forSearch */ false,
                /* isSearchEntry= */ false,
                /* isWidgetListShown= */ false);
    }

    /**
     * Creates a widget list holder for an header ("app" / "suggestions") which has widgets or/and
     * shortcuts.
     *
     * @param pkgItem             package item info for the header section
     * @param titleSectionName    title string for the header
     * @param items               all items for the given header
     * @param visibleWidgetsCount widgets count when only selected widgets are shown due to
     *                            limited space.
     */
    public static WidgetsListHeaderEntry create(PackageItemInfo pkgItem, String titleSectionName,
            List<WidgetItem> items, int visibleWidgetsCount) {
        return new WidgetsListHeaderEntry(
                pkgItem,
                titleSectionName,
                items,
                visibleWidgetsCount,
                /* isSearchEntry= */ false,
                /* isWidgetListShown= */ false);
    }

@@ -132,7 +168,7 @@ public final class WidgetsListHeaderEntry extends WidgetsListBaseEntry {
                pkgItem,
                titleSectionName,
                items,
                /* forSearch */ true,
                /* isSearchEntry */ true,
                /* isWidgetListShown= */ false);
    }
}
+28 −29
Original line number Diff line number Diff line
@@ -93,18 +93,19 @@ public final class WidgetRecommendationsView extends PagedView<PageIndicatorDots
     * @param availableWidth     width in px that the recommendations should display in
     * @param cellPadding        padding in px that should be applied to each widget in the
     *                           recommendations
     * @return {@code false} if no recommendations could fit in the available space.
     * @return number of recommendations that could fit in the available space.
     */
    public boolean setRecommendations(
    public int setRecommendations(
            List<WidgetItem> recommendedWidgets, DeviceProfile deviceProfile,
            final @Px float availableHeight, final @Px int availableWidth,
            final @Px int cellPadding) {
        this.mAvailableHeight = availableHeight;
        removeAllViews();
        clear();

        maybeDisplayInTable(recommendedWidgets, deviceProfile, availableWidth, cellPadding);
        int displayedWidgets = maybeDisplayInTable(recommendedWidgets, deviceProfile,
                availableWidth, cellPadding);
        updateTitleAndIndicator();
        return getChildCount() > 0;
        return displayedWidgets;
    }

    /**
@@ -118,9 +119,9 @@ public final class WidgetRecommendationsView extends PagedView<PageIndicatorDots
     * @param availableWidth  width in px that the recommendations should display in
     * @param cellPadding     padding in px that should be applied to each widget in the
     *                        recommendations
     * @return {@code false} if no recommendations could fit in the available space.
     * @return number of recommendations that could fit in the available space.
     */
    public boolean setRecommendations(
    public int setRecommendations(
            Map<WidgetRecommendationCategory, List<WidgetItem>> recommendations,
            DeviceProfile deviceProfile,
            final @Px float availableHeight, final @Px int availableWidth,
@@ -128,19 +129,23 @@ public final class WidgetRecommendationsView extends PagedView<PageIndicatorDots
        this.mAvailableHeight = availableHeight;
        Context context = getContext();
        mPageIndicator.setPauseScroll(true, deviceProfile.isTwoPanels);
        removeAllViews();
        clear();

        int displayedCategories = 0;
        int totalDisplayedWidgets = 0;

        // Render top MAX_CATEGORIES in separate tables. Each table becomes a page.
        for (Map.Entry<WidgetRecommendationCategory, List<WidgetItem>> entry :
                new TreeMap<>(recommendations).entrySet()) {
            // If none of the recommendations for the category could fit in the mAvailableHeight, we
            // don't want to add that category; and we look for the next one.
            if (maybeDisplayInTable(entry.getValue(), deviceProfile, availableWidth, cellPadding)) {
            int displayedCount = maybeDisplayInTable(entry.getValue(), deviceProfile,
                    availableWidth, cellPadding);
            if (displayedCount > 0) {
                mCategoryTitles.add(
                        context.getResources().getString(entry.getKey().categoryTitleRes));
                displayedCategories++;
                totalDisplayedWidgets += displayedCount;
            }

            if (displayedCategories == MAX_CATEGORIES) {
@@ -150,7 +155,12 @@ public final class WidgetRecommendationsView extends PagedView<PageIndicatorDots

        updateTitleAndIndicator();
        mPageIndicator.setPauseScroll(false, deviceProfile.isTwoPanels);
        return getChildCount() > 0;
        return totalDisplayedWidgets;
    }

    private void clear() {
        mCategoryTitles.clear();
        removeAllViews();
    }

    /** Displays the page title and paging indicator if there are multiple pages. */
@@ -199,22 +209,9 @@ public final class WidgetRecommendationsView extends PagedView<PageIndicatorDots
            for (int i = 0; i < getChildCount(); i++) {
                View child = getChildAt(i);
                measureChild(child, widthMeasureSpec, heightMeasureSpec);
                if (mAvailableHeight == Float.MAX_VALUE) {
                    // When we are not limited by height, use currentPage's height. This is the case
                    // when the paged layout is placed in a scrollable container. We cannot use
                    // height
                    // of tallest child in such case, as it will display a scrollbar even for
                    // smaller
                    // pages that don't have more content.
                    if (i == mCurrentPage) {
                        int parentHeight = MeasureSpec.getSize(heightMeasureSpec);
                        desiredHeight = Math.max(parentHeight, child.getMeasuredHeight());
                    }
                } else {
                    // Use height of tallest child when we are limited to a certain height.
                // Use height of tallest child as we have limited height.
                desiredHeight = Math.max(desiredHeight, child.getMeasuredHeight());
            }
            }

            int finalHeight = resolveSizeAndState(desiredHeight, heightMeasureSpec, 0);
            setMeasuredDimension(finalWidth, finalHeight);
@@ -228,12 +225,14 @@ public final class WidgetRecommendationsView extends PagedView<PageIndicatorDots
     * fits.
     * <p>Returns false if none of the recommendations could fit.</p>
     */
    private boolean maybeDisplayInTable(List<WidgetItem> recommendedWidgets,
    private int maybeDisplayInTable(List<WidgetItem> recommendedWidgets,
            DeviceProfile deviceProfile,
            final @Px int availableWidth, final @Px int cellPadding) {
        Context context = getContext();
        LayoutInflater inflater = LayoutInflater.from(context);

        // Since we are limited by space, we don't sort recommendations - to show most relevant
        // (if possible).
        List<ArrayList<WidgetItem>> rows = groupWidgetItemsUsingRowPxWithoutReordering(
                recommendedWidgets,
                context,
@@ -249,13 +248,13 @@ public final class WidgetRecommendationsView extends PagedView<PageIndicatorDots
        recommendationsTable.setWidgetCellOnClickListener(mWidgetCellOnClickListener);
        recommendationsTable.setWidgetCellLongClickListener(mWidgetCellOnLongClickListener);

        boolean displayedAtLeastOne = recommendationsTable.setRecommendedWidgets(rows,
        int displayedCount = recommendationsTable.setRecommendedWidgets(rows,
                deviceProfile, mAvailableHeight);
        if (displayedAtLeastOne) {
        if (displayedCount > 0) {
            addView(recommendationsTable);
        }

        return displayedAtLeastOne;
        return displayedCount;
    }

    /** Returns location of a widget cell for displaying the "touch and hold" education tip. */
+7 −5
Original line number Diff line number Diff line
@@ -107,7 +107,8 @@ public class WidgetsFullSheet extends BaseWidgetSheet
            entry -> mCurrentUser.equals(entry.mPkgItem.user);
    private final Predicate<WidgetsListBaseEntry> mWorkWidgetsFilter;
    protected final boolean mHasWorkProfile;
    protected boolean mHasRecommendedWidgets;
    // Number of recommendations displayed
    protected int mRecommendedWidgetsCount;
    protected final SparseArray<AdapterHolder> mAdapters = new SparseArray();
    @Nullable private ArrowTipView mLatestEducationalTip;
    private final OnLayoutChangeListener mLayoutChangeListenerToShowTips =
@@ -581,7 +582,7 @@ public class WidgetsFullSheet extends BaseWidgetSheet
        }

        if (enableCategorizedWidgetSuggestions()) {
            mHasRecommendedWidgets = mWidgetRecommendationsView.setRecommendations(
            mRecommendedWidgetsCount = mWidgetRecommendationsView.setRecommendations(
                    mActivityContext.getPopupDataProvider().getCategorizedRecommendedWidgets(),
                    mDeviceProfile,
                    /* availableHeight= */ getMaxAvailableHeightForRecommendations(),
@@ -589,7 +590,7 @@ public class WidgetsFullSheet extends BaseWidgetSheet
                    /* cellPadding= */ mWidgetCellHorizontalPadding
            );
        } else {
            mHasRecommendedWidgets = mWidgetRecommendationsView.setRecommendations(
            mRecommendedWidgetsCount = mWidgetRecommendationsView.setRecommendations(
                    mActivityContext.getPopupDataProvider().getRecommendedWidgets(),
                    mDeviceProfile,
                    /* availableHeight= */ getMaxAvailableHeightForRecommendations(),
@@ -597,7 +598,8 @@ public class WidgetsFullSheet extends BaseWidgetSheet
                    /* cellPadding= */ mWidgetCellHorizontalPadding
            );
        }
        mWidgetRecommendationsContainer.setVisibility(mHasRecommendedWidgets ? VISIBLE : GONE);
        mWidgetRecommendationsContainer.setVisibility(
                mRecommendedWidgetsCount > 0 ? VISIBLE : GONE);
    }

    @Px
@@ -790,7 +792,7 @@ public class WidgetsFullSheet extends BaseWidgetSheet
    }

    /** private the height, in pixel, + the vertical margins of a given view. */
    private static int measureHeightWithVerticalMargins(View view) {
    protected static int measureHeightWithVerticalMargins(View view) {
        if (view.getVisibility() != VISIBLE) {
            return 0;
        }
+6 −5
Original line number Diff line number Diff line
@@ -167,7 +167,7 @@ public class WidgetsTwoPaneSheet extends WidgetsFullSheet {
    @Override
    public void onWidgetsBound() {
        super.onWidgetsBound();
        if (!mHasRecommendedWidgets && mSelectedHeader == null) {
        if (mRecommendedWidgetsCount == 0 && mSelectedHeader == null) {
            mAdapters.get(mActivePage).mWidgetsListAdapter.selectFirstHeaderEntry();
            mAdapters.get(mActivePage).mWidgetsRecyclerView.scrollToTop();
        }
@@ -177,7 +177,7 @@ public class WidgetsTwoPaneSheet extends WidgetsFullSheet {
    public void onRecommendedWidgetsBound() {
        super.onRecommendedWidgetsBound();

        if (mSuggestedWidgetsContainer == null && mHasRecommendedWidgets) {
        if (mSuggestedWidgetsContainer == null && mRecommendedWidgetsCount > 0) {
            setupSuggestedWidgets(LayoutInflater.from(getContext()));
            mSuggestedWidgetsHeader.callOnClick();
        }
@@ -209,8 +209,9 @@ public class WidgetsTwoPaneSheet extends WidgetsFullSheet {
        packageItemInfo.title = suggestionsHeaderTitle;
        WidgetsListHeaderEntry widgetsListHeaderEntry = WidgetsListHeaderEntry.create(
                        packageItemInfo,
                        suggestionsHeaderTitle,
                        mActivityContext.getPopupDataProvider().getRecommendedWidgets())
                        /*titleSectionName=*/ suggestionsHeaderTitle,
                        /*items=*/ mActivityContext.getPopupDataProvider().getRecommendedWidgets(),
                        /*visibleWidgetsCount=*/ mRecommendedWidgetsCount)
                .withWidgetListShown();

        mSuggestedWidgetsHeader.applyFromItemInfoWithIcon(widgetsListHeaderEntry);
@@ -233,7 +234,7 @@ public class WidgetsTwoPaneSheet extends WidgetsFullSheet {
    @Override
    @Px
    protected float getMaxTableHeight(@Px float noWidgetsViewHeight) {
        return Float.MAX_VALUE;
        return mContent.getMeasuredHeight() - measureHeightWithVerticalMargins(mHeaderTitle);
    }

    @Override