diff options
author | Winson Chung <winsonc@google.com> | 2015-04-06 15:12:49 -0700 |
---|---|---|
committer | Winson Chung <winsonc@google.com> | 2015-04-06 15:12:49 -0700 |
commit | 9121fbffafe0b90a23768e5ebc5fffab2a2175c2 (patch) | |
tree | d380bc3984e66e89e44d6975627f9264ca0cf362 /src | |
parent | c517f4ce65cfbb3c52231262cf24847820213d29 (diff) | |
download | android_packages_apps_Trebuchet-9121fbffafe0b90a23768e5ebc5fffab2a2175c2.tar.gz android_packages_apps_Trebuchet-9121fbffafe0b90a23768e5ebc5fffab2a2175c2.tar.bz2 android_packages_apps_Trebuchet-9121fbffafe0b90a23768e5ebc5fffab2a2175c2.zip |
Small refactoring to apps list.
- Fixes issue with fading in app icons when items are added/removed
- Reduces number of expensive calls when drawing sections and the scrollbar
- Removes fake section AppInfos in the adapters
Diffstat (limited to 'src')
-rw-r--r-- | src/com/android/launcher3/AlphabeticalAppsList.java | 107 | ||||
-rw-r--r-- | src/com/android/launcher3/AppsContainerRecyclerView.java | 57 | ||||
-rw-r--r-- | src/com/android/launcher3/AppsContainerView.java | 27 | ||||
-rw-r--r-- | src/com/android/launcher3/AppsGridAdapter.java | 21 | ||||
-rw-r--r-- | src/com/android/launcher3/AppsListAdapter.java | 16 | ||||
-rw-r--r-- | src/com/android/launcher3/BubbleTextView.java | 5 |
6 files changed, 138 insertions, 95 deletions
diff --git a/src/com/android/launcher3/AlphabeticalAppsList.java b/src/com/android/launcher3/AlphabeticalAppsList.java index 9ab9d1295..8d1db632e 100644 --- a/src/com/android/launcher3/AlphabeticalAppsList.java +++ b/src/com/android/launcher3/AlphabeticalAppsList.java @@ -81,24 +81,65 @@ public class AlphabeticalAppsList { /** * Info about a section in the alphabetic list */ - public class SectionInfo { + public static class SectionInfo { + // The name of this section public String sectionName; + // The number of applications in this section public int numAppsInSection; + // The first app AdapterItem for this section + public AdapterItem firstAppItem; + + public SectionInfo(String name) { + sectionName = name; + } + } + + /** + * Info about a particular adapter item (can be either section or app) + */ + public static class AdapterItem { + // The index of this adapter item in the list + public int position; + // Whether or not the item at this adapter position is a section or not + public boolean isSectionHeader; + // The name of this section, or the section that this app is contained in + public String sectionName; + // The associated AppInfo, or null if this adapter item is a section + public AppInfo appInfo; + // The index of this app (not including sections), or -1 if this adapter item is a section + public int appIndex; + + public static AdapterItem asSection(int pos, String name) { + AdapterItem item = new AdapterItem(); + item.position = pos; + item.isSectionHeader = true; + item.sectionName = name; + item.appInfo = null; + item.appIndex = -1; + return item; + } + + public static AdapterItem asApp(int pos, String sectionName, AppInfo appInfo, int appIndex) { + AdapterItem item = new AdapterItem(); + item.position = pos; + item.isSectionHeader = false; + item.sectionName = sectionName; + item.appInfo = appInfo; + item.appIndex = appIndex; + return item; + } } /** * A filter interface to limit the set of applications in the apps list. */ public interface Filter { - public boolean retainApp(AppInfo info); + public boolean retainApp(AppInfo info, String sectionName); } - // Hack to force RecyclerView to break sections - public static final AppInfo SECTION_BREAK_INFO = null; - private List<AppInfo> mApps = new ArrayList<>(); private List<AppInfo> mFilteredApps = new ArrayList<>(); - private List<AppInfo> mSectionedFilteredApps = new ArrayList<>(); + private List<AdapterItem> mSectionedFilteredApps = new ArrayList<>(); private List<SectionInfo> mSections = new ArrayList<>(); private RecyclerView.Adapter mAdapter; private Filter mFilter; @@ -127,22 +168,15 @@ public class AlphabeticalAppsList { /** * Returns the current filtered list of applications broken down into their sections. */ - public List<AppInfo> getApps() { + public List<AdapterItem> getAdapterItems() { return mSectionedFilteredApps; } /** - * Returns the current filtered list of applications. + * Returns the number of applications in this list. */ - public List<AppInfo> getAppsWithoutSectionBreaks() { - return mFilteredApps; - } - - /** - * Returns the section name for the application. - */ - public String getSectionNameForApp(AppInfo info) { - return mIndexer.computeSectionName(info.title.toString().trim()); + public int getSize() { + return mFilteredApps.size(); } /** @@ -276,28 +310,39 @@ public class AlphabeticalAppsList { * Updates internals when the set of apps are updated. */ private void onAppsUpdated() { - // Recreate the filtered apps + // Recreate the filtered and sectioned apps (for convenience for the grid layout) mFilteredApps.clear(); - for (AppInfo info : mApps) { - if (mFilter == null || mFilter.retainApp(info)) { - mFilteredApps.add(info); - } - } - - // Section the apps (for convenience for the grid layout) mSections.clear(); mSectionedFilteredApps.clear(); SectionInfo lastSectionInfo = null; - for (AppInfo info : mFilteredApps) { - String sectionName = getSectionNameForApp(info); + int position = 0; + int appIndex = 0; + for (AppInfo info : mApps) { + String sectionName = mIndexer.computeSectionName(info.title.toString().trim()); + + // Check if we want to retain this app + if (mFilter != null && !mFilter.retainApp(info, sectionName)) { + continue; + } + + // Create a new section if necessary if (lastSectionInfo == null || !lastSectionInfo.sectionName.equals(sectionName)) { - lastSectionInfo = new SectionInfo(); - lastSectionInfo.sectionName = sectionName; - mSectionedFilteredApps.add(SECTION_BREAK_INFO); + lastSectionInfo = new SectionInfo(sectionName); mSections.add(lastSectionInfo); + + // Create a new section item + AdapterItem sectionItem = AdapterItem.asSection(position++, sectionName); + mSectionedFilteredApps.add(sectionItem); } + + // Create an app item + AdapterItem appItem = AdapterItem.asApp(position++, sectionName, info, appIndex++); lastSectionInfo.numAppsInSection++; - mSectionedFilteredApps.add(info); + if (lastSectionInfo.firstAppItem == null) { + lastSectionInfo.firstAppItem = appItem; + } + mSectionedFilteredApps.add(appItem); + mFilteredApps.add(info); } } } diff --git a/src/com/android/launcher3/AppsContainerRecyclerView.java b/src/com/android/launcher3/AppsContainerRecyclerView.java index b942ea451..63e7fe4ac 100644 --- a/src/com/android/launcher3/AppsContainerRecyclerView.java +++ b/src/com/android/launcher3/AppsContainerRecyclerView.java @@ -228,12 +228,12 @@ public class AppsContainerRecyclerView extends RecyclerView * Draws the fast scroller popup. */ private void drawFastScrollerPopup(Canvas canvas) { - int x; - int y; - boolean isRtl = (getResources().getConfiguration().getLayoutDirection() == - LAYOUT_DIRECTION_RTL); - if (mFastScrollAlpha > 0f) { + int x; + int y; + boolean isRtl = (getResources().getConfiguration().getLayoutDirection() == + LAYOUT_DIRECTION_RTL); + // Calculate the position for the fast scroller popup Rect bgBounds = mFastScrollerBg.getBounds(); if (isRtl) { @@ -288,52 +288,50 @@ public class AppsContainerRecyclerView extends RecyclerView */ private String scrollToPositionAtProgress(float progress) { List<AlphabeticalAppsList.SectionInfo> sections = mApps.getSections(); - // Get the total number of rows - int rowCount = getNumRows(); + if (sections.isEmpty()) { + return ""; + } // Find the position of the first application in the section that contains the row at the // current progress - int rowAtProgress = (int) (progress * rowCount); - int appIndex = 0; - rowCount = 0; - for (AlphabeticalAppsList.SectionInfo info : sections) { - int numRowsInSection = (int) Math.ceil((float) info.numAppsInSection / mNumAppsPerRow); - if (rowCount + numRowsInSection > rowAtProgress) { + int rowAtProgress = (int) (progress * getNumRows()); + int rowCount = 0; + AlphabeticalAppsList.SectionInfo lastSectionInfo = null; + for (AlphabeticalAppsList.SectionInfo section : sections) { + int numRowsInSection = (int) Math.ceil((float) section.numAppsInSection / mNumAppsPerRow); + if (rowCount + numRowsInSection >= rowAtProgress) { + lastSectionInfo = section; break; } rowCount += numRowsInSection; - appIndex += info.numAppsInSection; } - appIndex = Math.max(0, Math.min(mApps.getAppsWithoutSectionBreaks().size() - 1, appIndex)); - AppInfo appInfo = mApps.getAppsWithoutSectionBreaks().get(appIndex); - int sectionedAppIndex = mApps.getApps().indexOf(appInfo); + int position = mApps.getAdapterItems().indexOf(lastSectionInfo.firstAppItem); // Scroll the position into view, anchored at the top of the screen if possible. We call the // scroll method on the LayoutManager directly since it is not exposed by RecyclerView. LinearLayoutManager layoutManager = (LinearLayoutManager) getLayoutManager(); stopScroll(); - layoutManager.scrollToPositionWithOffset(sectionedAppIndex, 0); + layoutManager.scrollToPositionWithOffset(position, 0); // Return the section name of the row - return mApps.getSectionNameForApp(appInfo); + return mApps.getAdapterItems().get(position).sectionName; } /** * Returns the bounds for the scrollbar. */ private void updateVerticalScrollbarBounds() { - int x; - int y; - boolean isRtl = (getResources().getConfiguration().getLayoutDirection() == - LAYOUT_DIRECTION_RTL); - // Skip early if there are no items - if (mApps.getApps().isEmpty()) { + if (mApps.getAdapterItems().isEmpty()) { mVerticalScrollbarBounds.setEmpty(); return; } // Find the index and height of the first visible row (all rows have the same height) + int x; + int y; + boolean isRtl = (getResources().getConfiguration().getLayoutDirection() == + LAYOUT_DIRECTION_RTL); int rowIndex = -1; int rowTopOffset = -1; int rowHeight = -1; @@ -341,12 +339,11 @@ public class AppsContainerRecyclerView extends RecyclerView int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { View child = getChildAt(i); - int position = getChildPosition(child); + int position = getChildAdapterPosition(child); if (position != NO_POSITION) { - AppInfo info = mApps.getApps().get(position); - if (info != AlphabeticalAppsList.SECTION_BREAK_INFO) { - int appIndex = mApps.getAppsWithoutSectionBreaks().indexOf(info); - rowIndex = findRowForAppIndex(appIndex); + AlphabeticalAppsList.AdapterItem item = mApps.getAdapterItems().get(position); + if (!item.isSectionHeader) { + rowIndex = findRowForAppIndex(item.appIndex); rowTopOffset = getLayoutManager().getDecoratedTop(child); rowHeight = child.getHeight(); break; diff --git a/src/com/android/launcher3/AppsContainerView.java b/src/com/android/launcher3/AppsContainerView.java index 06fe93c1f..2de45cbcc 100644 --- a/src/com/android/launcher3/AppsContainerView.java +++ b/src/com/android/launcher3/AppsContainerView.java @@ -21,7 +21,6 @@ import android.graphics.Point; import android.graphics.Rect; import android.support.v7.widget.RecyclerView; import android.text.Editable; -import android.text.TextUtils; import android.text.TextWatcher; import android.util.AttributeSet; import android.view.KeyEvent; @@ -319,9 +318,8 @@ public class AppsContainerView extends FrameLayout implements DragSource, Insett final String filterText = s.toString().toLowerCase().replaceAll("\\s+", ""); mApps.setFilter(new AlphabeticalAppsList.Filter() { @Override - public boolean retainApp(AppInfo info) { + public boolean retainApp(AppInfo info, String sectionName) { String title = info.title.toString(); - String sectionName = mApps.getSectionNameForApp(info); return sectionName.toLowerCase().contains(filterText) || title.toLowerCase().replaceAll("\\s+", "").contains(filterText); } @@ -332,15 +330,22 @@ public class AppsContainerView extends FrameLayout implements DragSource, Insett @Override public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { if (ALLOW_SINGLE_APP_LAUNCH && actionId == EditorInfo.IME_ACTION_DONE) { - List<AppInfo> appsWithoutSections = mApps.getAppsWithoutSectionBreaks(); - List<AppInfo> apps = mApps.getApps(); - if (appsWithoutSections.size() == 1) { - mAppsListView.getChildAt(apps.indexOf(appsWithoutSections.get(0))).performClick(); - InputMethodManager imm = (InputMethodManager) - getContext().getSystemService(Context.INPUT_METHOD_SERVICE); - imm.hideSoftInputFromWindow(getWindowToken(), 0); + // Skip the quick-launch if there isn't exactly one item + if (mApps.getSize() != 1) { + return false; + } + + List<AlphabeticalAppsList.AdapterItem> items = mApps.getAdapterItems(); + for (int i = 0; i < items.size(); i++) { + AlphabeticalAppsList.AdapterItem item = items.get(i); + if (!item.isSectionHeader) { + mAppsListView.getChildAt(i).performClick(); + InputMethodManager imm = (InputMethodManager) + getContext().getSystemService(Context.INPUT_METHOD_SERVICE); + imm.hideSoftInputFromWindow(getWindowToken(), 0); + return true; + } } - return true; } return false; } diff --git a/src/com/android/launcher3/AppsGridAdapter.java b/src/com/android/launcher3/AppsGridAdapter.java index 5895cbf08..96d971669 100644 --- a/src/com/android/launcher3/AppsGridAdapter.java +++ b/src/com/android/launcher3/AppsGridAdapter.java @@ -12,9 +12,10 @@ import android.view.View; import android.view.ViewGroup; import android.widget.TextView; -import com.android.launcher3.compat.AlphabeticIndexCompat; import com.android.launcher3.util.Thunk; +import java.util.List; + /** * The grid view adapter of all the apps. @@ -54,8 +55,7 @@ class AppsGridAdapter extends RecyclerView.Adapter<AppsGridAdapter.ViewHolder> { return mAppsPerRow; } - AppInfo info = mApps.getApps().get(position); - if (info == AlphabeticalAppsList.SECTION_BREAK_INFO) { + if (mApps.getAdapterItems().get(position).isSectionHeader) { // Section break spans full width return mAppsPerRow; } else { @@ -71,6 +71,7 @@ class AppsGridAdapter extends RecyclerView.Adapter<AppsGridAdapter.ViewHolder> { @Override public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) { + List<AlphabeticalAppsList.AdapterItem> items = mApps.getAdapterItems(); for (int i = 0; i < parent.getChildCount(); i++) { View child = parent.getChildAt(i); ViewHolder holder = (ViewHolder) parent.getChildViewHolder(child); @@ -78,11 +79,11 @@ class AppsGridAdapter extends RecyclerView.Adapter<AppsGridAdapter.ViewHolder> { GridLayoutManager.LayoutParams lp = (GridLayoutManager.LayoutParams) child.getLayoutParams(); if (!holder.mIsSectionRow && !holder.mIsEmptyRow && !lp.isItemRemoved()) { - if (mApps.getApps().get(holder.getPosition() - 1) == - AlphabeticalAppsList.SECTION_BREAK_INFO) { + if (items.get(holder.getAdapterPosition() - 1).isSectionHeader) { // Draw at the parent - AppInfo info = mApps.getApps().get(holder.getPosition()); - String section = mApps.getSectionNameForApp(info); + AlphabeticalAppsList.AdapterItem item = + items.get(holder.getAdapterPosition()); + String section = item.sectionName; mSectionTextPaint.getTextBounds(section, 0, section.length(), mTmpBounds); if (mIsRtl) { @@ -212,7 +213,7 @@ class AppsGridAdapter extends RecyclerView.Adapter<AppsGridAdapter.ViewHolder> { public void onBindViewHolder(ViewHolder holder, int position) { switch (holder.getItemViewType()) { case ICON_VIEW_TYPE: - AppInfo info = mApps.getApps().get(position); + AppInfo info = mApps.getAdapterItems().get(position).appInfo; BubbleTextView icon = (BubbleTextView) holder.mContent; icon.applyFromApplicationInfo(info); break; @@ -229,14 +230,14 @@ class AppsGridAdapter extends RecyclerView.Adapter<AppsGridAdapter.ViewHolder> { // For the empty view return 1; } - return mApps.getApps().size(); + return mApps.getAdapterItems().size(); } @Override public int getItemViewType(int position) { if (mApps.hasNoFilteredResults()) { return EMPTY_VIEW_TYPE; - } else if (mApps.getApps().get(position) == AlphabeticalAppsList.SECTION_BREAK_INFO) { + } else if (mApps.getAdapterItems().get(position).isSectionHeader) { return SECTION_BREAK_VIEW_TYPE; } return ICON_VIEW_TYPE; diff --git a/src/com/android/launcher3/AppsListAdapter.java b/src/com/android/launcher3/AppsListAdapter.java index e1f4d3578..ffd309261 100644 --- a/src/com/android/launcher3/AppsListAdapter.java +++ b/src/com/android/launcher3/AppsListAdapter.java @@ -9,7 +9,6 @@ import android.view.View; import android.view.ViewGroup; import android.widget.LinearLayout; import android.widget.TextView; -import com.android.launcher3.compat.AlphabeticIndexCompat; /** * The linear list view adapter for all the apps. @@ -93,15 +92,16 @@ class AppsListAdapter extends RecyclerView.Adapter<AppsListAdapter.ViewHolder> { public void onBindViewHolder(ViewHolder holder, int position) { switch (holder.getItemViewType()) { case ICON_VIEW_TYPE: - AppInfo info = mApps.getApps().get(position); + AlphabeticalAppsList.AdapterItem item = mApps.getAdapterItems().get(position); ViewGroup content = (ViewGroup) holder.mContent; - String sectionDescription = mApps.getSectionNameForApp(info); + String sectionDescription = item.sectionName; // Bind the section header boolean showSectionHeader = true; if (position > 0) { - AppInfo prevInfo = mApps.getApps().get(position - 1); - showSectionHeader = (prevInfo == AlphabeticalAppsList.SECTION_BREAK_INFO); + AlphabeticalAppsList.AdapterItem prevItem = + mApps.getAdapterItems().get(position - 1); + showSectionHeader = prevItem.isSectionHeader; } TextView tv = (TextView) content.findViewById(R.id.section); if (showSectionHeader) { @@ -113,7 +113,7 @@ class AppsListAdapter extends RecyclerView.Adapter<AppsListAdapter.ViewHolder> { // Bind the icon BubbleTextView icon = (BubbleTextView) content.getChildAt(1); - icon.applyFromApplicationInfo(info); + icon.applyFromApplicationInfo(item.appInfo); break; case EMPTY_VIEW_TYPE: TextView emptyViewText = (TextView) holder.mContent.findViewById(R.id.empty_text); @@ -128,14 +128,14 @@ class AppsListAdapter extends RecyclerView.Adapter<AppsListAdapter.ViewHolder> { // For the empty view return 1; } - return mApps.getApps().size(); + return mApps.getAdapterItems().size(); } @Override public int getItemViewType(int position) { if (mApps.hasNoFilteredResults()) { return EMPTY_VIEW_TYPE; - } else if (mApps.getApps().get(position) == AlphabeticalAppsList.SECTION_BREAK_INFO) { + } else if (mApps.getAdapterItems().get(position).isSectionHeader) { return SECTION_BREAK_VIEW_TYPE; } return ICON_VIEW_TYPE; diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java index 50549cad0..ae6ebba34 100644 --- a/src/com/android/launcher3/BubbleTextView.java +++ b/src/com/android/launcher3/BubbleTextView.java @@ -389,11 +389,6 @@ public class BubbleTextView extends TextView { } @Override - protected boolean onSetAlpha(int alpha) { - return true; - } - - @Override public void cancelLongPress() { super.cancelLongPress(); |