Merge "Small refactoring to apps list." into ub-launcher3-burnaby
diff --git a/src/com/android/launcher3/AlphabeticalAppsList.java b/src/com/android/launcher3/AlphabeticalAppsList.java
index 9ab9d12..8d1db63 100644
--- a/src/com/android/launcher3/AlphabeticalAppsList.java
+++ b/src/com/android/launcher3/AlphabeticalAppsList.java
@@ -81,24 +81,65 @@
     /**
      * 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 @@
     /**
      * 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 @@
      * 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);
-            if (lastSectionInfo == null || !lastSectionInfo.sectionName.equals(sectionName)) {
-                lastSectionInfo = new SectionInfo();
-                lastSectionInfo.sectionName = sectionName;
-                mSectionedFilteredApps.add(SECTION_BREAK_INFO);
-                mSections.add(lastSectionInfo);
+        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(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 b942ea4..63e7fe4 100644
--- a/src/com/android/launcher3/AppsContainerRecyclerView.java
+++ b/src/com/android/launcher3/AppsContainerRecyclerView.java
@@ -228,12 +228,12 @@
      * 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 @@
      */
     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 @@
         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 06fe93c..2de45cb 100644
--- a/src/com/android/launcher3/AppsContainerView.java
+++ b/src/com/android/launcher3/AppsContainerView.java
@@ -21,7 +21,6 @@
 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 @@
             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 @@
     @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;
             }
-            return true;
+
+            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 false;
     }
diff --git a/src/com/android/launcher3/AppsGridAdapter.java b/src/com/android/launcher3/AppsGridAdapter.java
index 5895cbf..96d9716 100644
--- a/src/com/android/launcher3/AppsGridAdapter.java
+++ b/src/com/android/launcher3/AppsGridAdapter.java
@@ -12,9 +12,10 @@
 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 @@
                 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 @@
 
         @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 @@
                     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 @@
     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 @@
             // 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 e1f4d35..ffd3092 100644
--- a/src/com/android/launcher3/AppsListAdapter.java
+++ b/src/com/android/launcher3/AppsListAdapter.java
@@ -9,7 +9,6 @@
 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 @@
     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 @@
 
                 // 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 @@
             // 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 50549ca..ae6ebba 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -389,11 +389,6 @@
     }
 
     @Override
-    protected boolean onSetAlpha(int alpha) {
-        return true;
-    }
-
-    @Override
     public void cancelLongPress() {
         super.cancelLongPress();