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 -->
<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>
<!-- 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>
}
/**
- * 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
*/
return mThumbHeight;
}
- public int getThumbMaxWidth() {
- return mMaxWidth;
- }
-
public boolean isDraggingThumb() {
return mIsDragging;
}
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;
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.
*/
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;
private SpannableStringBuilder mSearchQueryBuilder = null;
- private int mSectionNamesMargin;
private int mNumAppsPerRow;
private int mNumPredictedAppsPerRow;
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);
}
mAppsRecyclerView.addOnScrollListener(mElevationController);
mAppsRecyclerView.setElevationController(mElevationController);
- if (mItemDecoration != null) {
- mAppsRecyclerView.addItemDecoration(mItemDecoration);
- }
-
FocusedItemDecorator focusedItemDecorator = new FocusedItemDecorator(mAppsRecyclerView);
mAppsRecyclerView.addItemDecoration(focusedItemDecorator);
mAppsRecyclerView.preMeasureViews(mAdapter);
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
mAppsRecyclerView.setNumAppsPerRow(grid, mNumAppsPerRow);
mAdapter.setNumAppsPerRow(mNumAppsPerRow);
- mApps.setNumAppsPerRow(mNumAppsPerRow, mNumPredictedAppsPerRow, new FullMergeAlgorithm());
+ mApps.setNumAppsPerRow(mNumAppsPerRow, mNumPredictedAppsPerRow);
}
if (!grid.isVerticalBarLayout()) {
MarginLayoutParams searchContainerLp =
// --- 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. ---
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;
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);
}
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;
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.
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
// 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;
}
}
}
}
- /**
- * 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;
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) {
}
/**
- * 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.
*/
public GridLayoutManager getLayoutManager() {
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: {
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 {
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);
}
/**
// 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);
// 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);
}
/**
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.
*/
// 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
// 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;
}
}
- /**
- * 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
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
private AllAppsGridAdapter mAdapter;
private AlphabeticIndexCompat mIndexer;
private AppNameComparator mAppNameComparator;
- private MergeAlgorithm mMergeAlgorithm;
private int mNumAppsPerRow;
private int mNumPredictedAppsPerRow;
private int mNumAppRowsInAdapter;
/**
* 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();
}
}
/**
- * Returns sections of all the current filtered applications.
- */
- public List<SectionInfo> getSections() {
- return mSections;
- }
-
- /**
* Returns fast scroller sections of all the current filtered applications.
*/
public List<FastScrollSectionInfo> getFastScrollerSections() {
* 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;
mFilteredApps.clear();
mFastScrollerSections.clear();
mAdapterItems.clear();
- mSections.clear();
if (DEBUG_PREDICTIONS) {
if (mPredictedAppComponents.isEmpty() && !mApps.isEmpty()) {
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);
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);
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)
}
/**
- * 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.
*/
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;