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

Commit fbc5b186 authored by Winson Chung's avatar Winson Chung
Browse files

Refactored section names to only draw when there is space.

- This CL removes all space for section names in both phones
  and tablets.  And when there are no section names, the layout
  will automatically fully merge the sections.

Bug: 20222023
Change-Id: Ic7c751d86f095e5cbd690bfd4f94bb5b00ff8ae4
parent c332934e
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -55,7 +55,7 @@
    <!-- Notes: container_bounds_inset - quantum_panel_outer_padding -->
    <dimen name="container_bounds_minus_quantum_panel_padding_inset">4dp</dimen>

    <dimen name="all_apps_grid_view_start_margin">56dp</dimen>
    <dimen name="all_apps_grid_view_start_margin">0dp</dimen>
    <dimen name="all_apps_grid_section_y_offset">8dp</dimen>
    <dimen name="all_apps_grid_section_text_size">24sp</dimen>
    <dimen name="all_apps_search_bar_height">48dp</dimen>
@@ -65,7 +65,7 @@
    <dimen name="all_apps_prediction_bar_top_bottom_padding">16dp</dimen>

    <dimen name="all_apps_fast_scroll_bar_width">4dp</dimen>
    <dimen name="all_apps_fast_scroll_scrubber_touch_inset">-16dp</dimen>
    <dimen name="all_apps_fast_scroll_scrubber_touch_inset">-24dp</dimen>
    <dimen name="all_apps_fast_scroll_popup_size">72dp</dimen>
    <dimen name="all_apps_fast_scroll_text_size">48dp</dimen>

+28 −1
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package com.android.launcher3;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.res.Resources;
@@ -315,12 +317,37 @@ public class BaseRecyclerView extends RecyclerView
    /**
     * Animates the visibility of the fast scroller popup.
     */
    private void animateFastScrollerVisibility(boolean visible) {
    private void animateFastScrollerVisibility(final boolean visible) {
        ObjectAnimator anim = ObjectAnimator.ofFloat(this, "fastScrollerAlpha", visible ? 1f : 0f);
        anim.setDuration(visible ? 200 : 150);
        anim.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationStart(Animator animation) {
                if (visible) {
                    onFastScrollingStart();
                }
            }

            @Override
            public void onAnimationEnd(Animator animation) {
                if (!visible) {
                    onFastScrollingEnd();
                }
            }
        });
        anim.start();
    }

    /**
     * To be overridden by subclasses.
     */
    protected void onFastScrollingStart() {}

    /**
     * To be overridden by subclasses.
     */
    protected void onFastScrollingEnd() {}

    /**
     * Invalidates the fast scroller popup.
     */
+76 −8
Original line number Diff line number Diff line
@@ -58,11 +58,70 @@ import com.android.launcher3.Utilities;
import com.android.launcher3.Workspace;
import com.android.launcher3.util.Thunk;

import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder;
import java.util.ArrayList;
import java.util.List;



/**
 * A merge algorithm that merges every section indiscriminately.
 */
final class FullMergeAlgorithm implements AlphabeticalAppsList.MergeAlgorithm {

    @Override
    public boolean continueMerging(AlphabeticalAppsList.SectionInfo section,
           AlphabeticalAppsList.SectionInfo withSection,
           int sectionAppCount, int numAppsPerRow, int mergeCount) {
        // Merge EVERYTHING
        return true;
    }
}

/**
 * The logic we use to merge multiple sections.  We only merge sections when their final row
 * contains less than a certain number of icons, and stop at a specified max number of merges.
 * In addition, we will try and not merge sections that identify apps from different scripts.
 */
final class SimpleSectionMergeAlgorithm implements AlphabeticalAppsList.MergeAlgorithm {

    private int mMinAppsPerRow;
    private int mMinRowsInMergedSection;
    private int mMaxAllowableMerges;
    private CharsetEncoder mAsciiEncoder;

    public SimpleSectionMergeAlgorithm(int minAppsPerRow, int minRowsInMergedSection, int maxNumMerges) {
        mMinAppsPerRow = minAppsPerRow;
        mMinRowsInMergedSection = minRowsInMergedSection;
        mMaxAllowableMerges = maxNumMerges;
        mAsciiEncoder = Charset.forName("US-ASCII").newEncoder();
    }

    @Override
    public boolean continueMerging(AlphabeticalAppsList.SectionInfo section,
           AlphabeticalAppsList.SectionInfo withSection,
           int sectionAppCount, int numAppsPerRow, int mergeCount) {
        // Continue merging if the number of hanging apps on the final row is less than some
        // fixed number (ragged), the merged rows has yet to exceed some minimum row count,
        // and while the number of merged sections is less than some fixed number of merges
        int rows = sectionAppCount / numAppsPerRow;
        int cols = sectionAppCount % numAppsPerRow;

        // Ensure that we do not merge across scripts, currently we only allow for english and
        // native scripts so we can test if both can just be ascii encoded
        boolean isCrossScript = false;
        if (section.firstAppItem != null && withSection.firstAppItem != null) {
            isCrossScript = mAsciiEncoder.canEncode(section.firstAppItem.sectionName) !=
                    mAsciiEncoder.canEncode(withSection.firstAppItem.sectionName);
        }
        return (0 < cols && cols < mMinAppsPerRow) &&
                rows < mMinRowsInMergedSection &&
                mergeCount < mMaxAllowableMerges &&
                !isCrossScript;
    }
}

/**
 * The all apps view container.
 */
@@ -72,7 +131,8 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
        View.OnLongClickListener, ViewTreeObserver.OnPreDrawListener,
        AllAppsSearchBarController.Callbacks, Stats.LaunchSourceProvider {

    public static final boolean GRID_MERGE_SECTIONS = true;
    private static final int MIN_ROWS_IN_MERGED_SECTION_PHONE = 3;
    private static final int MAX_NUM_MERGES_PHONE = 2;

    @Thunk Launcher mLauncher;
    @Thunk AlphabeticalAppsList mApps;
@@ -90,6 +150,7 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
    private ViewGroup mSearchBarContainerView;
    private View mSearchBarView;

    private int mSectionNamesMargin;
    private int mNumAppsPerRow;
    private int mNumPredictedAppsPerRow;
    // This coordinate is relative to this container view
@@ -127,7 +188,7 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
                Utilities.calculateTextHeight(grid.allAppsIconTextSizePx) +
                2 * res.getDimensionPixelSize(R.dimen.all_apps_icon_top_bottom_padding) +
                2 * res.getDimensionPixelSize(R.dimen.all_apps_prediction_bar_top_bottom_padding));

        mSectionNamesMargin = res.getDimensionPixelSize(R.dimen.all_apps_grid_view_start_margin);
        mApps = new AlphabeticalAppsList(context);
        mApps.setAdapterChangedCallback(this);
        mAdapter = new AllAppsGridAdapter(context, mApps, this, this, mLauncher, this);
@@ -342,9 +403,18 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
                mNumPredictedAppsPerRow != grid.allAppsNumPredictiveCols) {
            mNumAppsPerRow = grid.allAppsNumCols;
            mNumPredictedAppsPerRow = grid.allAppsNumPredictiveCols;

            // If there is a start margin to draw section names, determine how we are going to merge
            // app sections
            boolean mergeSectionsFully = mSectionNamesMargin == 0 || !grid.isPhone;
            AlphabeticalAppsList.MergeAlgorithm mergeAlgorithm = mergeSectionsFully ?
                    new FullMergeAlgorithm() :
                    new SimpleSectionMergeAlgorithm((int) Math.ceil(mNumAppsPerRow / 2f),
                            MIN_ROWS_IN_MERGED_SECTION_PHONE, MAX_NUM_MERGES_PHONE);

            mAppsRecyclerView.setNumAppsPerRow(mNumAppsPerRow, mNumPredictedAppsPerRow);
            mAdapter.setNumAppsPerRow(mNumAppsPerRow);
            mApps.setNumAppsPerRow(mNumAppsPerRow, mNumPredictedAppsPerRow);
            mApps.setNumAppsPerRow(mNumAppsPerRow, mNumPredictedAppsPerRow, mergeAlgorithm);
        }

        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
@@ -376,14 +446,12 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc

        // Pad the recycler view by the background padding plus the start margin (for the section
        // names)
        DeviceProfile grid = mLauncher.getDeviceProfile();
        int startMargin = grid.isPhone ? getResources().getDimensionPixelSize(
                R.dimen.all_apps_grid_view_start_margin) : mAppsRecyclerView.getScrollbarWidth();
        int startInset = Math.max(mSectionNamesMargin, mAppsRecyclerView.getScrollbarWidth());
        if (isRtl) {
            mAppsRecyclerView.setPadding(padding.left + mAppsRecyclerView.getScrollbarWidth(), 0,
                    padding.right + startMargin, 0);
                    padding.right + startInset, 0);
        } else {
            mAppsRecyclerView.setPadding(padding.left + startMargin, 0,
            mAppsRecyclerView.setPadding(padding.left + startInset, 0,
                    padding.right + mAppsRecyclerView.getScrollbarWidth(), 0);
        }

+10 −16
Original line number Diff line number Diff line
@@ -21,7 +21,6 @@ import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
@@ -32,7 +31,6 @@ import android.view.ViewGroup;
import android.widget.TextView;
import com.android.launcher3.AppInfo;
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
@@ -114,11 +112,6 @@ class AllAppsGridAdapter extends RecyclerView.Adapter<AllAppsGridAdapter.ViewHol

        private HashMap<String, PointF> mCachedSectionBounds = new HashMap<>();
        private Rect mTmpBounds = new Rect();
        private Launcher mLauncher;

        public GridItemDecoration(Context context) {
            mLauncher = (Launcher) context;
        }

        @Override
        public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
@@ -129,13 +122,13 @@ class AllAppsGridAdapter extends RecyclerView.Adapter<AllAppsGridAdapter.ViewHol
            if (DEBUG_SECTION_MARGIN) {
                Paint p = new Paint();
                p.setColor(0x33ff0000);
                c.drawRect(mBackgroundPadding.left, 0, mBackgroundPadding.left + mStartMargin,
                c.drawRect(mBackgroundPadding.left, 0, mBackgroundPadding.left + mSectionNamesMargin,
                        parent.getMeasuredHeight(), p);
            }

            DeviceProfile grid = mLauncher.getDeviceProfile();
            List<AlphabeticalAppsList.AdapterItem> items = mApps.getAdapterItems();
            boolean hasDrawnPredictedAppsDivider = false;
            boolean showSectionNames = mSectionNamesMargin > 0;
            int childCount = parent.getChildCount();
            int lastSectionTop = 0;
            int lastSectionHeight = 0;
@@ -154,7 +147,7 @@ class AllAppsGridAdapter extends RecyclerView.Adapter<AllAppsGridAdapter.ViewHol
                            mPredictedAppsDividerPaint);
                    hasDrawnPredictedAppsDivider = true;

                } else if (grid.isPhone && shouldDrawItemSection(holder, i, items)) {
                } else if (showSectionNames && shouldDrawItemSection(holder, i, items)) {
                    // At this point, we only draw sections for each section break;
                    int viewTopOffset = (2 * child.getPaddingTop());
                    int pos = holder.getPosition();
@@ -179,9 +172,10 @@ class AllAppsGridAdapter extends RecyclerView.Adapter<AllAppsGridAdapter.ViewHol

                        // Calculate where to draw the section
                        int sectionBaseline = (int) (viewTopOffset + sectionBounds.y);
                        int x = mIsRtl ? parent.getWidth() - mBackgroundPadding.left - mStartMargin :
                        int x = mIsRtl ?
                                parent.getWidth() - mBackgroundPadding.left - mSectionNamesMargin :
                                        mBackgroundPadding.left;
                        x += (int) ((mStartMargin - sectionBounds.x) / 2f);
                        x += (int) ((mSectionNamesMargin - sectionBounds.x) / 2f);
                        int y = child.getTop() + sectionBaseline;

                        // Determine whether this is the last row with apps in that section, if
@@ -309,7 +303,7 @@ class AllAppsGridAdapter extends RecyclerView.Adapter<AllAppsGridAdapter.ViewHol
    private String mEmptySearchText;

    // Section drawing
    @Thunk int mStartMargin;
    @Thunk int mSectionNamesMargin;
    @Thunk int mSectionHeaderOffset;
    @Thunk Paint mSectionTextPaint;
    @Thunk Paint mPredictedAppsDividerPaint;
@@ -324,12 +318,12 @@ class AllAppsGridAdapter extends RecyclerView.Adapter<AllAppsGridAdapter.ViewHol
        mGridSizer = new GridSpanSizer();
        mGridLayoutMgr = new GridLayoutManager(context, 1, GridLayoutManager.VERTICAL, false);
        mGridLayoutMgr.setSpanSizeLookup(mGridSizer);
        mItemDecoration = new GridItemDecoration(context);
        mItemDecoration = new GridItemDecoration();
        mLayoutInflater = LayoutInflater.from(context);
        mTouchListener = touchListener;
        mIconClickListener = iconClickListener;
        mIconLongClickListener = iconLongClickListener;
        mStartMargin = res.getDimensionPixelSize(R.dimen.all_apps_grid_view_start_margin);
        mSectionNamesMargin = res.getDimensionPixelSize(R.dimen.all_apps_grid_view_start_margin);
        mSectionHeaderOffset = res.getDimensionPixelSize(R.dimen.all_apps_grid_section_y_offset);

        mSectionTextPaint = new Paint();
+10 −2
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@ public class AllAppsRecyclerView extends BaseRecyclerView
    private int mNumAppsPerRow;
    private int mNumPredictedAppsPerRow;
    private int mPredictionBarHeight;
    private int mLastFastscrollPosition = -1;

    private Launcher mLauncher;

@@ -131,6 +132,11 @@ public class AllAppsRecyclerView extends BaseRecyclerView
        }
    }

    @Override
    protected void onFastScrollingEnd() {
        mLastFastscrollPosition = -1;
    }

    /**
     * Maps the touch (from 0..1) to the adapter position that should be visible.
     */
@@ -174,12 +180,14 @@ public class AllAppsRecyclerView extends BaseRecyclerView

        // Scroll to the view at the position, anchored at the top of the screen. We call the scroll
        // method on the LayoutManager directly since it is not exposed by RecyclerView.
        if (mLastFastscrollPosition != lastScrollSection.appItem.position) {
            mLastFastscrollPosition = lastScrollSection.appItem.position;
            layoutManager.scrollToPositionWithOffset(lastScrollSection.appItem.position, 0);
        }

        return lastScrollSection.sectionName;
    }


    /**
     * Returns the row index for a app index in the list.
     */
Loading