Removing the section break UI support

This was an exploration for an alternative UI in all apps, where we
show section headers before every section. This was never released.

Change-Id: I2d36f1d078cc9a6f3ba6f0ec9655412182c9b016
This commit is contained in:
Sunny Goyal 2016-10-13 09:31:24 -07:00
parent 7630369904
commit 2a65020da1
11 changed files with 28 additions and 489 deletions

View File

@ -53,6 +53,7 @@
android:clipToPadding="false"
android:descendantFocusability="afterDescendants"
android:focusable="true"
android:paddingEnd="@dimen/container_fastscroll_thumb_max_width"
android:theme="@style/CustomOverscroll.Light" />
<!-- Fast scroller popup -->

View File

@ -16,8 +16,6 @@
<resources>
<!-- All Apps -->
<dimen name="all_apps_grid_view_start_margin">0dp</dimen>
<dimen name="all_apps_grid_section_text_size">26sp</dimen>
<dimen name="all_apps_background_canvas_width">850dp</dimen>
<dimen name="all_apps_background_canvas_height">525dp</dimen>

View File

@ -62,9 +62,6 @@
<!-- All Apps -->
<dimen name="all_apps_button_scale_down">0dp</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_field_height">48dp</dimen>
<dimen name="all_apps_search_bar_height">60dp</dimen>
<dimen name="all_apps_search_bar_icon_margin_right">4dp</dimen>

View File

@ -172,13 +172,6 @@ public abstract class BaseRecyclerView extends RecyclerView
return mBackgroundPadding;
}
/**
* Returns the scroll bar width when the user is scrolling.
*/
public int getMaxScrollbarWidth() {
return mScrollbar.getThumbMaxWidth();
}
/**
* Returns the visible height of the recycler view:
* VisibleHeight = View height - top padding - bottom padding

View File

@ -177,10 +177,6 @@ public class BaseRecyclerViewFastScrollBar {
return mThumbHeight;
}
public int getThumbMaxWidth() {
return mMaxWidth;
}
public boolean isDraggingThumb() {
return mIsDragging;
}

View File

@ -16,7 +16,6 @@
package com.android.launcher3.allapps;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Rect;
import android.support.v7.widget.RecyclerView;
import android.text.Selection;
@ -56,78 +55,9 @@ import com.android.launcher3.shortcuts.DeepShortcutsContainer;
import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
import com.android.launcher3.util.ComponentKey;
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) {
// Don't merge the predicted apps
if (section.firstAppItem.viewType != AllAppsGridAdapter.VIEW_TYPE_ICON) {
return false;
}
// Otherwise, merge every other section
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) {
// Don't merge the predicted apps
if (section.firstAppItem.viewType != AllAppsGridAdapter.VIEW_TYPE_ICON) {
return false;
}
// 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.
*/
@ -135,14 +65,10 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
LauncherTransitionable, View.OnLongClickListener, AllAppsSearchBarController.Callbacks,
Insettable {
private static final int MIN_ROWS_IN_MERGED_SECTION_PHONE = 3;
private static final int MAX_NUM_MERGES_PHONE = 2;
private final Launcher mLauncher;
private final AlphabeticalAppsList mApps;
private final AllAppsGridAdapter mAdapter;
private final RecyclerView.LayoutManager mLayoutManager;
private final RecyclerView.ItemDecoration mItemDecoration;
private AllAppsRecyclerView mAppsRecyclerView;
private AllAppsSearchBarController mSearchBarController;
@ -153,7 +79,6 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
private SpannableStringBuilder mSearchQueryBuilder = null;
private int mSectionNamesMargin;
private int mNumAppsPerRow;
private int mNumPredictedAppsPerRow;
@ -167,15 +92,12 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
public AllAppsContainerView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
Resources res = context.getResources();
mLauncher = Launcher.getLauncher(context);
mSectionNamesMargin = res.getDimensionPixelSize(R.dimen.all_apps_grid_view_start_margin);
mApps = new AlphabeticalAppsList(context);
mAdapter = new AllAppsGridAdapter(mLauncher, mApps, mLauncher, this);
mApps.setAdapter(mAdapter);
mLayoutManager = mAdapter.getLayoutManager();
mItemDecoration = mAdapter.getItemDecoration();
mSearchQueryBuilder = new SpannableStringBuilder();
Selection.setSelection(mSearchQueryBuilder, 0);
}
@ -337,10 +259,6 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
mAppsRecyclerView.addOnScrollListener(mElevationController);
mAppsRecyclerView.setElevationController(mElevationController);
if (mItemDecoration != null) {
mAppsRecyclerView.addItemDecoration(mItemDecoration);
}
FocusedItemDecorator focusedItemDecorator = new FocusedItemDecorator(mAppsRecyclerView);
mAppsRecyclerView.addItemDecoration(focusedItemDecorator);
mAppsRecyclerView.preMeasureViews(mAdapter);
@ -351,14 +269,6 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
getContentView().setVisibility(View.VISIBLE);
getContentView().setBackground(null);
}
int maxScrollBarWidth = mAppsRecyclerView.getMaxScrollbarWidth();
int startInset = Math.max(mSectionNamesMargin, maxScrollBarWidth);
if (Utilities.isRtl(getResources())) {
mAppsRecyclerView.setPadding(maxScrollBarWidth, 0, startInset, 0);
} else {
mAppsRecyclerView.setPadding(startInset, 0, maxScrollBarWidth, 0);
}
}
@Override
@ -381,7 +291,7 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
mAppsRecyclerView.setNumAppsPerRow(grid, mNumAppsPerRow);
mAdapter.setNumAppsPerRow(mNumAppsPerRow);
mApps.setNumAppsPerRow(mNumAppsPerRow, mNumPredictedAppsPerRow, new FullMergeAlgorithm());
mApps.setNumAppsPerRow(mNumAppsPerRow, mNumPredictedAppsPerRow);
}
if (!grid.isVerticalBarLayout()) {
MarginLayoutParams searchContainerLp =
@ -396,25 +306,15 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
// --- remove START when {@code FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP} is enabled. ---
// Update the number of items in the grid before we measure the view
// TODO: mSectionNamesMargin is currently 0, but also account for it,
// if it's enabled in the future.
grid.updateAppsViewNumCols();
if (mNumAppsPerRow != grid.allAppsNumCols ||
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(grid, mNumAppsPerRow);
mAdapter.setNumAppsPerRow(mNumAppsPerRow);
mApps.setNumAppsPerRow(mNumAppsPerRow, mNumPredictedAppsPerRow, mergeAlgorithm);
mApps.setNumAppsPerRow(mNumAppsPerRow, mNumPredictedAppsPerRow);
}
// --- remove END when {@code FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP} is enabled. ---

View File

@ -29,7 +29,6 @@ public class AllAppsFastScrollHelper implements AllAppsGridAdapter.BindViewCallb
private static final int INITIAL_TOUCH_SETTLING_DURATION = 100;
private static final int REPEAT_TOUCH_SETTLING_DURATION = 200;
private static final float FAST_SCROLL_TOUCH_VELOCITY_BARRIER = 1900f;
private AllAppsRecyclerView mRv;
private AlphabeticalAppsList mApps;
@ -187,9 +186,9 @@ public class AllAppsFastScrollHelper implements AllAppsGridAdapter.BindViewCallb
public void onBindView(AllAppsGridAdapter.ViewHolder holder) {
// Update newly bound views to the current fast scroll state if we are fast scrolling
if (mCurrentFastScrollSection != null || mTargetFastScrollSection != null) {
if (holder.mContent instanceof BaseRecyclerViewFastScrollBar.FastScrollFocusableView) {
if (holder.itemView instanceof BaseRecyclerViewFastScrollBar.FastScrollFocusableView) {
BaseRecyclerViewFastScrollBar.FastScrollFocusableView v =
(BaseRecyclerViewFastScrollBar.FastScrollFocusableView) holder.mContent;
(BaseRecyclerViewFastScrollBar.FastScrollFocusableView) holder.itemView;
updateViewFastScrollFocusState(v, holder.getPosition(), false /* animated */);
mTrackedFastScrollViews.add(v);
}

View File

@ -18,10 +18,7 @@ package com.android.launcher3.allapps;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
import android.support.v4.view.accessibility.AccessibilityEventCompat;
import android.support.v4.view.accessibility.AccessibilityRecordCompat;
@ -41,10 +38,6 @@ 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;
import java.util.HashMap;
import java.util.List;
/**
* The grid view adapter of all the apps.
@ -52,10 +45,7 @@ import java.util.List;
public class AllAppsGridAdapter extends RecyclerView.Adapter<AllAppsGridAdapter.ViewHolder> {
public static final String TAG = "AppsGridAdapter";
private static final boolean DEBUG = false;
// A section break in the grid
public static final int VIEW_TYPE_SECTION_BREAK = 1 << 0;
// A normal icon
public static final int VIEW_TYPE_ICON = 1 << 1;
// A prediction icon
@ -78,25 +68,22 @@ public class AllAppsGridAdapter extends RecyclerView.Adapter<AllAppsGridAdapter.
// Common view type masks
public static final int VIEW_TYPE_MASK_DIVIDER = VIEW_TYPE_SEARCH_DIVIDER
| VIEW_TYPE_SEARCH_MARKET_DIVIDER
| VIEW_TYPE_PREDICTION_DIVIDER
| VIEW_TYPE_SECTION_BREAK;
| VIEW_TYPE_PREDICTION_DIVIDER;
public static final int VIEW_TYPE_MASK_ICON = VIEW_TYPE_ICON
| VIEW_TYPE_PREDICTION_ICON;
public interface BindViewCallback {
public void onBindView(ViewHolder holder);
void onBindView(ViewHolder holder);
}
/**
* ViewHolder for each icon.
*/
public static class ViewHolder extends RecyclerView.ViewHolder {
public View mContent;
public ViewHolder(View v) {
super(v);
mContent = v;
}
}
@ -158,189 +145,14 @@ public class AllAppsGridAdapter extends RecyclerView.Adapter<AllAppsGridAdapter.
}
}
/**
* Helper class to draw the section headers
*/
public class GridItemDecoration extends RecyclerView.ItemDecoration {
private static final boolean DEBUG_SECTION_MARGIN = false;
private static final boolean FADE_OUT_SECTIONS = false;
private HashMap<String, PointF> mCachedSectionBounds = new HashMap<>();
private Rect mTmpBounds = new Rect();
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
if (mApps.hasFilter() || mAppsPerRow == 0) {
return;
}
if (DEBUG_SECTION_MARGIN) {
Paint p = new Paint();
p.setColor(0x33ff0000);
c.drawRect(mBackgroundPadding.left, 0, mBackgroundPadding.left + mSectionNamesMargin,
parent.getMeasuredHeight(), p);
}
List<AlphabeticalAppsList.AdapterItem> items = mApps.getAdapterItems();
boolean showSectionNames = mSectionNamesMargin > 0;
int childCount = parent.getChildCount();
int lastSectionTop = 0;
int lastSectionHeight = 0;
for (int i = 0; i < childCount; i++) {
View child = parent.getChildAt(i);
ViewHolder holder = (ViewHolder) parent.getChildViewHolder(child);
if (!isValidHolderAndChild(holder, child, items)) {
continue;
}
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();
AlphabeticalAppsList.AdapterItem item = items.get(pos);
AlphabeticalAppsList.SectionInfo sectionInfo = item.sectionInfo;
// Draw all the sections for this index
String lastSectionName = item.sectionName;
for (int j = item.sectionAppIndex; j < sectionInfo.numApps; j++, pos++) {
AlphabeticalAppsList.AdapterItem nextItem = items.get(pos);
String sectionName = nextItem.sectionName;
if (nextItem.sectionInfo != sectionInfo) {
break;
}
if (j > item.sectionAppIndex && sectionName.equals(lastSectionName)) {
continue;
}
// Find the section name bounds
PointF sectionBounds = getAndCacheSectionBounds(sectionName);
// Calculate where to draw the section
int sectionBaseline = (int) (viewTopOffset + sectionBounds.y);
int x = mIsRtl ?
parent.getWidth() - mBackgroundPadding.left - mSectionNamesMargin :
mBackgroundPadding.left;
x += (int) ((mSectionNamesMargin - sectionBounds.x) / 2f);
int y = child.getTop() + sectionBaseline;
// Determine whether this is the last row with apps in that section, if
// so, then fix the section to the row allowing it to scroll past the
// baseline, otherwise, bound it to the baseline so it's in the viewport
int appIndexInSection = items.get(pos).sectionAppIndex;
int nextRowPos = Math.min(items.size() - 1,
pos + mAppsPerRow - (appIndexInSection % mAppsPerRow));
AlphabeticalAppsList.AdapterItem nextRowItem = items.get(nextRowPos);
boolean fixedToRow = !sectionName.equals(nextRowItem.sectionName);
if (!fixedToRow) {
y = Math.max(sectionBaseline, y);
}
// In addition, if it overlaps with the last section that was drawn, then
// offset it so that it does not overlap
if (lastSectionHeight > 0 && y <= (lastSectionTop + lastSectionHeight)) {
y += lastSectionTop - y + lastSectionHeight;
}
// Draw the section header
if (FADE_OUT_SECTIONS) {
int alpha = 255;
if (fixedToRow) {
alpha = Math.min(255,
(int) (255 * (Math.max(0, y) / (float) sectionBaseline)));
}
mSectionTextPaint.setAlpha(alpha);
}
c.drawText(sectionName, x, y, mSectionTextPaint);
lastSectionTop = y;
lastSectionHeight = (int) (sectionBounds.y + mSectionHeaderOffset);
lastSectionName = sectionName;
}
i += (sectionInfo.numApps - item.sectionAppIndex);
}
}
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
RecyclerView.State state) {
// Do nothing
}
/**
* Given a section name, return the bounds of the given section name.
*/
private PointF getAndCacheSectionBounds(String sectionName) {
PointF bounds = mCachedSectionBounds.get(sectionName);
if (bounds == null) {
mSectionTextPaint.getTextBounds(sectionName, 0, sectionName.length(), mTmpBounds);
bounds = new PointF(mSectionTextPaint.measureText(sectionName), mTmpBounds.height());
mCachedSectionBounds.put(sectionName, bounds);
}
return bounds;
}
/**
* Returns whether we consider this a valid view holder for us to draw a divider or section for.
*/
private boolean isValidHolderAndChild(ViewHolder holder, View child,
List<AlphabeticalAppsList.AdapterItem> items) {
// Ensure item is not already removed
GridLayoutManager.LayoutParams lp = (GridLayoutManager.LayoutParams)
child.getLayoutParams();
if (lp.isItemRemoved()) {
return false;
}
// Ensure we have a valid holder
if (holder == null) {
return false;
}
// Ensure we have a holder position
int pos = holder.getPosition();
if (pos < 0 || pos >= items.size()) {
return false;
}
return true;
}
/**
* Returns whether to draw the section for the given child.
*/
private boolean shouldDrawItemSection(ViewHolder holder, int childIndex,
List<AlphabeticalAppsList.AdapterItem> items) {
int pos = holder.getPosition();
AlphabeticalAppsList.AdapterItem item = items.get(pos);
// Ensure it's an icon
if (item.viewType != AllAppsGridAdapter.VIEW_TYPE_ICON) {
return false;
}
// Draw the section header for the first item in each section
return (childIndex == 0) ||
(items.get(pos - 1).viewType == AllAppsGridAdapter.VIEW_TYPE_SECTION_BREAK);
}
}
private final Launcher mLauncher;
private final LayoutInflater mLayoutInflater;
private final AlphabeticalAppsList mApps;
private final GridLayoutManager mGridLayoutMgr;
private final GridSpanSizer mGridSizer;
private final GridItemDecoration mItemDecoration;
private final View.OnClickListener mIconClickListener;
private final View.OnLongClickListener mIconLongClickListener;
private final Rect mBackgroundPadding = new Rect();
private final boolean mIsRtl;
// Section drawing
@Deprecated
private final int mSectionNamesMargin;
@Deprecated
private final int mSectionHeaderOffset;
private final Paint mSectionTextPaint;
private int mAppsPerRow;
private BindViewCallback mBindViewCallback;
@ -361,18 +173,9 @@ public class AllAppsGridAdapter extends RecyclerView.Adapter<AllAppsGridAdapter.
mGridSizer = new GridSpanSizer();
mGridLayoutMgr = new AppsGridLayoutManager(launcher);
mGridLayoutMgr.setSpanSizeLookup(mGridSizer);
mItemDecoration = new GridItemDecoration();
mLayoutInflater = LayoutInflater.from(launcher);
mIconClickListener = iconClickListener;
mIconLongClickListener = iconLongClickListener;
mSectionNamesMargin = res.getDimensionPixelSize(R.dimen.all_apps_grid_view_start_margin);
mSectionHeaderOffset = res.getDimensionPixelSize(R.dimen.all_apps_grid_section_y_offset);
mIsRtl = Utilities.isRtl(res);
mSectionTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mSectionTextPaint.setTextSize(res.getDimensionPixelSize(
R.dimen.all_apps_grid_section_text_size));
mSectionTextPaint.setColor(Utilities.getColorAccent(launcher));
}
public static boolean isDividerViewType(int viewType) {
@ -420,14 +223,6 @@ public class AllAppsGridAdapter extends RecyclerView.Adapter<AllAppsGridAdapter.
mBindViewCallback = cb;
}
/**
* Notifies the adapter of the background padding so that it can draw things correctly in the
* item decorator.
*/
public void updateBackgroundPadding(Rect padding) {
mBackgroundPadding.set(padding);
}
/**
* Returns the grid layout manager.
*/
@ -435,19 +230,9 @@ public class AllAppsGridAdapter extends RecyclerView.Adapter<AllAppsGridAdapter.
return mGridLayoutMgr;
}
/**
* Returns the item decoration for the recycler view.
*/
public RecyclerView.ItemDecoration getItemDecoration() {
// We don't draw any headers when we are uncomfortably dense
return mItemDecoration;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
switch (viewType) {
case VIEW_TYPE_SECTION_BREAK:
return new ViewHolder(new View(parent.getContext()));
case VIEW_TYPE_ICON:
/* falls through */
case VIEW_TYPE_PREDICTION_ICON: {
@ -499,26 +284,26 @@ public class AllAppsGridAdapter extends RecyclerView.Adapter<AllAppsGridAdapter.
switch (holder.getItemViewType()) {
case VIEW_TYPE_ICON: {
AppInfo info = mApps.getAdapterItems().get(position).appInfo;
BubbleTextView icon = (BubbleTextView) holder.mContent;
BubbleTextView icon = (BubbleTextView) holder.itemView;
icon.applyFromApplicationInfo(info);
icon.setAccessibilityDelegate(mLauncher.getAccessibilityDelegate());
break;
}
case VIEW_TYPE_PREDICTION_ICON: {
AppInfo info = mApps.getAdapterItems().get(position).appInfo;
BubbleTextView icon = (BubbleTextView) holder.mContent;
BubbleTextView icon = (BubbleTextView) holder.itemView;
icon.applyFromApplicationInfo(info);
icon.setAccessibilityDelegate(mLauncher.getAccessibilityDelegate());
break;
}
case VIEW_TYPE_EMPTY_SEARCH:
TextView emptyViewText = (TextView) holder.mContent;
TextView emptyViewText = (TextView) holder.itemView;
emptyViewText.setText(mEmptySearchMessage);
emptyViewText.setGravity(mApps.hasNoFilteredResults() ? Gravity.CENTER :
Gravity.START | Gravity.CENTER_VERTICAL);
break;
case VIEW_TYPE_SEARCH_MARKET:
TextView searchView = (TextView) holder.mContent;
TextView searchView = (TextView) holder.itemView;
if (mMarketSearchIntent != null) {
searchView.setVisibility(View.VISIBLE);
} else {

View File

@ -101,7 +101,6 @@ public class AllAppsRecyclerView extends BaseRecyclerView {
pool.setMaxRecycledViews(AllAppsGridAdapter.VIEW_TYPE_ICON, approxRows * mNumAppsPerRow);
pool.setMaxRecycledViews(AllAppsGridAdapter.VIEW_TYPE_PREDICTION_ICON, mNumAppsPerRow);
pool.setMaxRecycledViews(AllAppsGridAdapter.VIEW_TYPE_PREDICTION_DIVIDER, 1);
pool.setMaxRecycledViews(AllAppsGridAdapter.VIEW_TYPE_SECTION_BREAK, approxRows);
}
/**
@ -116,21 +115,21 @@ public class AllAppsRecyclerView extends BaseRecyclerView {
// Icons
BubbleTextView icon = (BubbleTextView) adapter.onCreateViewHolder(this,
AllAppsGridAdapter.VIEW_TYPE_ICON).mContent;
AllAppsGridAdapter.VIEW_TYPE_ICON).itemView;
int iconHeight = icon.getLayoutParams().height;
mViewHeights.put(AllAppsGridAdapter.VIEW_TYPE_ICON, iconHeight);
mViewHeights.put(AllAppsGridAdapter.VIEW_TYPE_PREDICTION_ICON, iconHeight);
// Search divider
View searchDivider = adapter.onCreateViewHolder(this,
AllAppsGridAdapter.VIEW_TYPE_SEARCH_DIVIDER).mContent;
AllAppsGridAdapter.VIEW_TYPE_SEARCH_DIVIDER).itemView;
searchDivider.measure(widthMeasureSpec, heightMeasureSpec);
int searchDividerHeight = searchDivider.getMeasuredHeight();
mViewHeights.put(AllAppsGridAdapter.VIEW_TYPE_SEARCH_DIVIDER, searchDividerHeight);
// Generic dividers
View divider = adapter.onCreateViewHolder(this,
AllAppsGridAdapter.VIEW_TYPE_PREDICTION_DIVIDER).mContent;
AllAppsGridAdapter.VIEW_TYPE_PREDICTION_DIVIDER).itemView;
divider.measure(widthMeasureSpec, heightMeasureSpec);
int dividerHeight = divider.getMeasuredHeight();
mViewHeights.put(AllAppsGridAdapter.VIEW_TYPE_PREDICTION_DIVIDER, dividerHeight);
@ -138,18 +137,15 @@ public class AllAppsRecyclerView extends BaseRecyclerView {
// Search views
View emptySearch = adapter.onCreateViewHolder(this,
AllAppsGridAdapter.VIEW_TYPE_EMPTY_SEARCH).mContent;
AllAppsGridAdapter.VIEW_TYPE_EMPTY_SEARCH).itemView;
emptySearch.measure(widthMeasureSpec, heightMeasureSpec);
mViewHeights.put(AllAppsGridAdapter.VIEW_TYPE_EMPTY_SEARCH,
emptySearch.getMeasuredHeight());
View searchMarket = adapter.onCreateViewHolder(this,
AllAppsGridAdapter.VIEW_TYPE_SEARCH_MARKET).mContent;
AllAppsGridAdapter.VIEW_TYPE_SEARCH_MARKET).itemView;
searchMarket.measure(widthMeasureSpec, heightMeasureSpec);
mViewHeights.put(AllAppsGridAdapter.VIEW_TYPE_SEARCH_MARKET,
searchMarket.getMeasuredHeight());
// Section breaks
mViewHeights.put(AllAppsGridAdapter.VIEW_TYPE_SECTION_BREAK, 0);
}
/**

View File

@ -48,18 +48,6 @@ public class AlphabeticalAppsList {
private final int mFastScrollDistributionMode = FAST_SCROLL_FRACTION_DISTRIBUTE_BY_NUM_SECTIONS;
/**
* Info about a section in the alphabetic list
*/
public static class SectionInfo {
// The number of applications in this section
public int numApps;
// The section break AdapterItem for this section
public AdapterItem sectionBreakItem;
// The first app AdapterItem for this section
public AdapterItem firstAppItem;
}
/**
* Info about a fast scroller section, depending if sections are merged, the fast scroller
* sections will not be the same set as the section headers.
@ -87,16 +75,10 @@ public class AlphabeticalAppsList {
// The type of this item
public int viewType;
/** Section & App properties */
// The section for this item
public SectionInfo sectionInfo;
/** App-only properties */
// The section name of this app. Note that there can be multiple items with different
// sectionNames in the same section
public String sectionName = null;
// The index of this app in the section
public int sectionAppIndex = -1;
// The row that this item shows up on
public int rowIndex;
// The index of this app in the row
@ -106,30 +88,19 @@ public class AlphabeticalAppsList {
// The index of this app not including sections
public int appIndex = -1;
public static AdapterItem asSectionBreak(int pos, SectionInfo section) {
AdapterItem item = new AdapterItem();
item.viewType = AllAppsGridAdapter.VIEW_TYPE_SECTION_BREAK;
item.position = pos;
item.sectionInfo = section;
section.sectionBreakItem = item;
return item;
}
public static AdapterItem asPredictedApp(int pos, SectionInfo section, String sectionName,
int sectionAppIndex, AppInfo appInfo, int appIndex) {
AdapterItem item = asApp(pos, section, sectionName, sectionAppIndex, appInfo, appIndex);
public static AdapterItem asPredictedApp(int pos, String sectionName, AppInfo appInfo,
int appIndex) {
AdapterItem item = asApp(pos, sectionName, appInfo, appIndex);
item.viewType = AllAppsGridAdapter.VIEW_TYPE_PREDICTION_ICON;
return item;
}
public static AdapterItem asApp(int pos, SectionInfo section, String sectionName,
int sectionAppIndex, AppInfo appInfo, int appIndex) {
public static AdapterItem asApp(int pos, String sectionName, AppInfo appInfo,
int appIndex) {
AdapterItem item = new AdapterItem();
item.viewType = AllAppsGridAdapter.VIEW_TYPE_ICON;
item.position = pos;
item.sectionInfo = section;
item.sectionName = sectionName;
item.sectionAppIndex = sectionAppIndex;
item.appInfo = appInfo;
item.appIndex = appIndex;
return item;
@ -171,14 +142,6 @@ public class AlphabeticalAppsList {
}
}
/**
* Common interface for different merging strategies.
*/
public interface MergeAlgorithm {
boolean continueMerging(SectionInfo section, SectionInfo withSection,
int sectionAppCount, int numAppsPerRow, int mergeCount);
}
private Launcher mLauncher;
// The set of apps from the system not including predictions
@ -189,8 +152,6 @@ public class AlphabeticalAppsList {
private List<AppInfo> mFilteredApps = new ArrayList<>();
// The current set of adapter items
private List<AdapterItem> mAdapterItems = new ArrayList<>();
// The set of sections for the apps with the current filter
private List<SectionInfo> mSections = new ArrayList<>();
// The set of sections that we allow fast-scrolling to (includes non-merged sections)
private List<FastScrollSectionInfo> mFastScrollerSections = new ArrayList<>();
// The set of predicted app component names
@ -203,7 +164,6 @@ public class AlphabeticalAppsList {
private AllAppsGridAdapter mAdapter;
private AlphabeticIndexCompat mIndexer;
private AppNameComparator mAppNameComparator;
private MergeAlgorithm mMergeAlgorithm;
private int mNumAppsPerRow;
private int mNumPredictedAppsPerRow;
private int mNumAppRowsInAdapter;
@ -217,11 +177,9 @@ public class AlphabeticalAppsList {
/**
* Sets the number of apps per row.
*/
public void setNumAppsPerRow(int numAppsPerRow, int numPredictedAppsPerRow,
MergeAlgorithm mergeAlgorithm) {
public void setNumAppsPerRow(int numAppsPerRow, int numPredictedAppsPerRow) {
mNumAppsPerRow = numAppsPerRow;
mNumPredictedAppsPerRow = numPredictedAppsPerRow;
mMergeAlgorithm = mergeAlgorithm;
updateAdapterItems();
}
@ -240,13 +198,6 @@ public class AlphabeticalAppsList {
return mApps;
}
/**
* Returns sections of all the current filtered applications.
*/
public List<SectionInfo> getSections() {
return mSections;
}
/**
* Returns fast scroller sections of all the current filtered applications.
*/
@ -403,7 +354,6 @@ public class AlphabeticalAppsList {
* mCachedSectionNames to have been calculated for the set of all apps in mApps.
*/
private void updateAdapterItems() {
SectionInfo lastSectionInfo = null;
String lastSectionName = null;
FastScrollSectionInfo lastFastScrollerSectionInfo = null;
int position = 0;
@ -413,7 +363,6 @@ public class AlphabeticalAppsList {
mFilteredApps.clear();
mFastScrollerSections.clear();
mAdapterItems.clear();
mSections.clear();
if (DEBUG_PREDICTIONS) {
if (mPredictedAppComponents.isEmpty() && !mApps.isEmpty()) {
@ -451,19 +400,14 @@ public class AlphabeticalAppsList {
if (!mPredictedApps.isEmpty()) {
// Add a section for the predictions
lastSectionInfo = new SectionInfo();
lastFastScrollerSectionInfo = new FastScrollSectionInfo("");
AdapterItem sectionItem = AdapterItem.asSectionBreak(position++, lastSectionInfo);
mSections.add(lastSectionInfo);
mFastScrollerSections.add(lastFastScrollerSectionInfo);
mAdapterItems.add(sectionItem);
// Add the predicted app items
for (AppInfo info : mPredictedApps) {
AdapterItem appItem = AdapterItem.asPredictedApp(position++, lastSectionInfo,
"", lastSectionInfo.numApps++, info, appIndex++);
if (lastSectionInfo.firstAppItem == null) {
lastSectionInfo.firstAppItem = appItem;
AdapterItem appItem = AdapterItem.asPredictedApp(position++, "", info,
appIndex++);
if (lastFastScrollerSectionInfo.fastScrollToItem == null) {
lastFastScrollerSectionInfo.fastScrollToItem = appItem;
}
mAdapterItems.add(appItem);
@ -480,25 +424,15 @@ public class AlphabeticalAppsList {
String sectionName = getAndUpdateCachedSectionName(info.title);
// Create a new section if the section names do not match
if (lastSectionInfo == null || !sectionName.equals(lastSectionName)) {
if (!sectionName.equals(lastSectionName)) {
lastSectionName = sectionName;
lastSectionInfo = new SectionInfo();
lastFastScrollerSectionInfo = new FastScrollSectionInfo(sectionName);
mSections.add(lastSectionInfo);
mFastScrollerSections.add(lastFastScrollerSectionInfo);
// Create a new section item to break the flow of items in the list
if (!hasFilter()) {
AdapterItem sectionItem = AdapterItem.asSectionBreak(position++, lastSectionInfo);
mAdapterItems.add(sectionItem);
}
}
// Create an app item
AdapterItem appItem = AdapterItem.asApp(position++, lastSectionInfo, sectionName,
lastSectionInfo.numApps++, info, appIndex++);
if (lastSectionInfo.firstAppItem == null) {
lastSectionInfo.firstAppItem = appItem;
AdapterItem appItem = AdapterItem.asApp(position++, sectionName, info, appIndex++);
if (lastFastScrollerSectionInfo.fastScrollToItem == null) {
lastFastScrollerSectionInfo.fastScrollToItem = appItem;
}
mAdapterItems.add(appItem);
@ -515,9 +449,6 @@ public class AlphabeticalAppsList {
mAdapterItems.add(AdapterItem.asMarketSearch(position++));
}
// Merge multiple sections together as requested by the merge strategy for this device
mergeSections();
if (mNumAppsPerRow != 0) {
// Update the number of rows in the adapter after we do all the merging (otherwise, we
// would have to shift the values again)
@ -593,61 +524,6 @@ public class AlphabeticalAppsList {
return result;
}
/**
* Merges multiple sections to reduce visual raggedness.
*/
private void mergeSections() {
// Ignore merging until we have an algorithm and a valid row size
if (mMergeAlgorithm == null || mNumAppsPerRow == 0) {
return;
}
// Go through each section and try and merge some of the sections
if (!hasFilter()) {
int sectionAppCount = 0;
for (int i = 0; i < mSections.size() - 1; i++) {
SectionInfo section = mSections.get(i);
sectionAppCount = section.numApps;
int mergeCount = 1;
// Merge rows based on the current strategy
while (i < (mSections.size() - 1) &&
mMergeAlgorithm.continueMerging(section, mSections.get(i + 1),
sectionAppCount, mNumAppsPerRow, mergeCount)) {
SectionInfo nextSection = mSections.remove(i + 1);
// Remove the next section break
mAdapterItems.remove(nextSection.sectionBreakItem);
int pos = mAdapterItems.indexOf(section.firstAppItem);
// Point the section for these new apps to the merged section
int nextPos = pos + section.numApps;
for (int j = nextPos; j < (nextPos + nextSection.numApps); j++) {
AdapterItem item = mAdapterItems.get(j);
item.sectionInfo = section;
item.sectionAppIndex += section.numApps;
}
// Update the following adapter items of the removed section item
pos = mAdapterItems.indexOf(nextSection.firstAppItem);
for (int j = pos; j < mAdapterItems.size(); j++) {
AdapterItem item = mAdapterItems.get(j);
item.position--;
}
section.numApps += nextSection.numApps;
sectionAppCount += nextSection.numApps;
if (DEBUG) {
Log.d(TAG, "Merging: " + nextSection.firstAppItem.sectionName +
" to " + section.firstAppItem.sectionName +
" mergedNumRows: " + (sectionAppCount / mNumAppsPerRow));
}
mergeCount++;
}
}
}
}
/**
* Returns the cached section name for the given title, recomputing and updating the cache if
* the title has no cached section name.

View File

@ -27,12 +27,10 @@ import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.LinearLayout;
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.WidgetPreviewLoader;
import com.android.launcher3.model.PackageItemInfo;
import com.android.launcher3.model.WidgetItem;
import com.android.launcher3.model.WidgetsModel;