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

Commit 53d1364e authored by Steven Ng's avatar Steven Ng
Browse files

Better estimate the height of widget recycler view

Test: Expand and collapse apps in the widgets picker. Then, observe
      the height of the fast scroller is correctly displayed.

Bug: 181629430
Change-Id: I9efcf902f8548fc5c8a398609758d43123228e5e
parent 976bd24f
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -19,7 +19,7 @@
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="?android:attr/selectableItemBackground"
    android:paddingVertical="20dp"
    android:paddingVertical="@dimen/widget_list_header_view_vertical_padding"
    android:orientation="horizontal">

    <ImageView
+2 −0
Original line number Diff line number Diff line
@@ -108,6 +108,8 @@
    <dimen name="widget_cell_vertical_padding">8dp</dimen>
    <dimen name="widget_cell_horizontal_padding">16dp</dimen>

    <dimen name="widget_list_header_view_vertical_padding">20dp</dimen>

    <dimen name="widget_preview_shadow_blur">0.5dp</dimen>
    <dimen name="widget_preview_key_shadow_distance">1dp</dimen>
    <dimen name="widget_preview_corner_radius">2dp</dimen>
+6 −4
Original line number Diff line number Diff line
@@ -385,14 +385,16 @@ public class WidgetsFullSheet extends BaseWidgetSheet

    @Override
    public int getHeaderViewHeight() {
        // No need to check work profile here because mInitialTabHeight is always 0 if there is no
        // work profile.
        return mInitialTabsHeight
                + measureHeightWithVerticalMargins(mSearchAndRecommendationViewHolder.mContainer);
        return measureHeightWithVerticalMargins(mSearchAndRecommendationViewHolder.mCollapseHandle)
                + measureHeightWithVerticalMargins(mSearchAndRecommendationViewHolder.mHeaderTitle)
                + measureHeightWithVerticalMargins(mSearchAndRecommendationViewHolder.mSearchBar);
    }

    /** private the height, in pixel, + the vertical margins of a given view. */
    private static int measureHeightWithVerticalMargins(View view) {
        if (view.getVisibility() != VISIBLE) {
            return 0;
        }
        MarginLayoutParams marginLayoutParams = (MarginLayoutParams) view.getLayoutParams();
        return view.getMeasuredHeight() + marginLayoutParams.bottomMargin
                + marginLayoutParams.topMargin;
+5 −0
Original line number Diff line number Diff line
@@ -122,6 +122,11 @@ public class WidgetsListAdapter extends Adapter<ViewHolder> implements OnHeaderC
        return mVisibleEntries.size();
    }

    /** Returns all items that will be drawn in a recycler view. */
    public List<WidgetsListBaseEntry> getItems() {
        return mVisibleEntries;
    }

    /** Gets the section name for {@link com.android.launcher3.views.RecyclerViewFastScroller}. */
    public String getSectionName(int pos) {
        return mVisibleEntries.get(pos).mTitleSectionName;
+57 −7
Original line number Diff line number Diff line
@@ -21,13 +21,19 @@ import android.graphics.Point;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.TableLayout;

import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.RecyclerView.OnItemTouchListener;

import com.android.launcher3.BaseRecyclerView;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.views.ActivityContext;
import com.android.launcher3.widget.model.WidgetsListBaseEntry;
import com.android.launcher3.widget.model.WidgetsListContentEntry;
import com.android.launcher3.widget.model.WidgetsListHeaderEntry;

/**
 * The widgets recycler view.
@@ -39,8 +45,10 @@ public class WidgetsRecyclerView extends BaseRecyclerView implements OnItemTouch
    private final int mScrollbarTop;

    private final Point mFastScrollerOffset = new Point();
    private final int mEstimatedWidgetListHeaderHeight;
    private boolean mTouchDownOnScroller;
    private HeaderViewDimensionsProvider mHeaderViewDimensionsProvider;
    private int mLastVisibleWidgetContentTableHeight = 0;

    public WidgetsRecyclerView(Context context) {
        this(context, null);
@@ -55,6 +63,12 @@ public class WidgetsRecyclerView extends BaseRecyclerView implements OnItemTouch
        super(context, attrs, defStyleAttr);
        mScrollbarTop = getResources().getDimensionPixelSize(R.dimen.dynamic_grid_edge_margin);
        addOnItemTouchListener(this);

        ActivityContext activity = ActivityContext.lookupContext(getContext());
        DeviceProfile grid = activity.getDeviceProfile();
        mEstimatedWidgetListHeaderHeight = grid.iconSizePx
                + 2 * context.getResources().getDimensionPixelSize(
                        R.dimen.widget_list_header_view_vertical_padding);
    }

    @Override
@@ -123,21 +137,32 @@ public class WidgetsRecyclerView extends BaseRecyclerView implements OnItemTouch

        View child = getChildAt(0);
        int rowIndex = getChildPosition(child);
        int y = (child.getMeasuredHeight() * rowIndex);
        for (int i = 0; i < getChildCount(); i++) {
            View view = getChildAt(i);
            if (view instanceof TableLayout) {
                // This assumes there is ever only one content shown in this recycler view.
                mLastVisibleWidgetContentTableHeight = view.getMeasuredHeight();
            }
        }

        int scrollPosition = getItemsHeight(rowIndex);
        int offset = getLayoutManager().getDecoratedTop(child);

        return getPaddingTop() + y - offset;
        return getPaddingTop() + scrollPosition - offset;
    }

    /**
     * Returns the available scroll height:
     *   AvailableScrollHeight = Total height of the all items - last page height
     * Returns the available scroll height, in pixel.
     *
     * <p>If the recycler view can't be scrolled, returns 0.
     */
    @Override
    protected int getAvailableScrollHeight() {
        View child = getChildAt(0);
        return child.getMeasuredHeight() * mAdapter.getItemCount() + getScrollBarTop()
                + getPaddingBottom() - mScrollbar.getHeight();
        // AvailableScrollHeight = Total height of the all items - first page height
        int firstPageHeight = getMeasuredHeight() - getPaddingTop() - getPaddingBottom();
        int totalHeightOfAllItems = getItemsHeight(/* untilIndex= */ mAdapter.getItemCount());
        int availableScrollHeight = totalHeightOfAllItems - firstPageHeight;
        return Math.max(0, availableScrollHeight);
    }

    private boolean isModelNotReady() {
@@ -180,6 +205,31 @@ public class WidgetsRecyclerView extends BaseRecyclerView implements OnItemTouch
        mHeaderViewDimensionsProvider = headerViewDimensionsProvider;
    }

    /**
     * Returns the sum of the height, in pixels, of this list adapter's items from index 0 until
     * {@code untilIndex}.
     *
     * <p>If the untilIndex is larger than the total number of items in this adapter, returns the
     * sum of all items' height.
     */
    private int getItemsHeight(int untilIndex) {
        if (untilIndex > mAdapter.getItems().size()) {
            untilIndex = mAdapter.getItems().size();
        }
        int totalItemsHeight = 0;
        for (int i = 0; i < untilIndex; i++) {
            WidgetsListBaseEntry entry = mAdapter.getItems().get(i);
            if (entry instanceof WidgetsListHeaderEntry) {
                totalItemsHeight += mEstimatedWidgetListHeaderHeight;
            } else if (entry instanceof WidgetsListContentEntry) {
                totalItemsHeight += mLastVisibleWidgetContentTableHeight;
            } else {
                throw new UnsupportedOperationException("Can't estimate height for " + entry);
            }
        }
        return totalItemsHeight;
    }

    /**
     * Provides dimensions of the header view that is shown at the top of a
     * {@link WidgetsRecyclerView}.