Consolidate all the dividers to provide same look and feel

Bug: 30017936
Change-Id: I072cb116dba1df555a63f3f67b730f7f9c3a235a
diff --git a/res/drawable/all_apps_search_bg.xml b/res/drawable/all_apps_search_bg.xml
deleted file mode 100644
index cf63d41..0000000
--- a/res/drawable/all_apps_search_bg.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
-    <item
-        android:top="@dimen/all_apps_search_bar_bg_overflow"
-        android:left="@dimen/all_apps_search_bar_bg_overflow"
-        android:right="@dimen/all_apps_search_bar_bg_overflow"
-        android:bottom="0dp">
-
-        <shape android:shape="rectangle">
-            <solid android:color="@android:color/transparent" />
-            <stroke
-                android:width="@dimen/all_apps_search_bar_divider_width"
-                android:color="?android:attr/colorAccent"/>
-        </shape>
-    </item>
-</layer-list>
\ No newline at end of file
diff --git a/res/drawable/horizontal_line.xml b/res/drawable/horizontal_line.xml
deleted file mode 100644
index 3f3f17e3..0000000
--- a/res/drawable/horizontal_line.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
-    android:shape="rectangle">
-    <size android:height="1dp" />
-    <solid android:color="#ddd" />
-</shape>
diff --git a/res/layout/all_apps.xml b/res/layout/all_apps.xml
index 8c2010f..d55fda7 100644
--- a/res/layout/all_apps.xml
+++ b/res/layout/all_apps.xml
@@ -66,7 +66,6 @@
             android:layout_gravity="center|top"
             android:paddingLeft="@dimen/container_fastscroll_thumb_max_width"
             android:paddingRight="@dimen/container_fastscroll_thumb_max_width"
-            android:background="@drawable/all_apps_search_bg"
             android:gravity="center|bottom"
             android:orientation="horizontal"
             android:saveEnabled="false">
diff --git a/res/layout/all_apps_divider.xml b/res/layout/all_apps_divider.xml
new file mode 100644
index 0000000..b2ee7c1
--- /dev/null
+++ b/res/layout/all_apps_divider.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<View xmlns:android="http://schemas.android.com/apk/res/android"
+    android:importantForAccessibility="no"
+    android:layout_width="match_parent"
+    android:layout_height="@dimen/all_apps_divider_height"
+    android:layout_marginBottom="@dimen/all_apps_divider_margin_vertical"
+    android:layout_marginLeft="@dimen/container_fastscroll_thumb_max_width"
+    android:layout_marginRight="@dimen/container_fastscroll_thumb_max_width"
+    android:layout_marginTop="@dimen/all_apps_divider_margin_vertical"
+    android:background="@color/all_apps_divider_color"
+    android:focusable="false" />
\ No newline at end of file
diff --git a/res/layout/all_apps_prediction_bar_icon.xml b/res/layout/all_apps_prediction_bar_icon.xml
index 295b0b7..3836fed 100644
--- a/res/layout/all_apps_prediction_bar_icon.xml
+++ b/res/layout/all_apps_prediction_bar_icon.xml
@@ -21,8 +21,8 @@
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:layout_gravity="center"
-    android:paddingTop="@dimen/all_apps_prediction_icon_top_padding"
-    android:paddingBottom="@dimen/all_apps_prediction_icon_bottom_padding"
+    android:paddingTop="@dimen/all_apps_icon_top_bottom_padding"
+    android:paddingBottom="@dimen/all_apps_icon_top_bottom_padding"
     android:focusable="true"
     launcher:iconDisplay="all_apps" />
 
diff --git a/res/layout/all_apps_search_market.xml b/res/layout/all_apps_search_market.xml
index 741c96a..0199212 100644
--- a/res/layout/all_apps_search_market.xml
+++ b/res/layout/all_apps_search_market.xml
@@ -19,8 +19,8 @@
     android:layout_width="match_parent"
     android:layout_height="48dp"
     android:gravity="start|center_vertical"
-    android:paddingLeft="16dp"
-    android:paddingRight="16dp"
+    android:paddingLeft="@dimen/container_fastscroll_thumb_max_width"
+    android:paddingRight="@dimen/container_fastscroll_thumb_max_width"
     android:fontFamily="sans-serif-medium"
     android:textSize="14sp"
     android:textColor="?android:attr/colorAccent"
diff --git a/res/layout/all_apps_search_market_divider.xml b/res/layout/all_apps_search_market_divider.xml
deleted file mode 100644
index 3909781..0000000
--- a/res/layout/all_apps_search_market_divider.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<ImageView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:gravity="center"
-    android:paddingTop="16dp"
-    android:paddingBottom="8dp"
-    android:paddingLeft="16dp"
-    android:paddingRight="16dp"
-    android:focusable="false"
-    android:scaleType="matrix"
-    android:src="@drawable/horizontal_line" />
\ No newline at end of file
diff --git a/res/values/colors.xml b/res/values/colors.xml
index d411a4f..937b2f0 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -35,6 +35,7 @@
     <color name="quantum_panel_bg_color">#FFF5F5F5</color>
 
     <color name="outline_color">#FFFFFFFF</color>
+    <color name="all_apps_divider_color">#1E000000</color>
 
     <color name="spring_loaded_panel_color">#40FFFFFF</color>
     <color name="spring_loaded_highlighted_panel_border_color">#FFF</color>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index f3d0eaa..9abe3e6 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -58,7 +58,7 @@
     <dimen name="container_min_margin">8dp</dimen>
     <dimen name="container_max_width">0dp</dimen>
 
-<!-- All Apps -->
+    <!-- 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>
@@ -69,10 +69,7 @@
     <dimen name="all_apps_search_bar_icon_margin_top">1dp</dimen>
     <dimen name="all_apps_icon_top_bottom_padding">8dp</dimen>
     <dimen name="all_apps_icon_width_gap">24dp</dimen>
-    <!-- The top padding should account for the existing all_apps_list_top_bottom_padding -->
-    <dimen name="all_apps_prediction_icon_top_padding">8dp</dimen>
-    <dimen name="all_apps_prediction_icon_bottom_padding">18dp</dimen>
-    <dimen name="all_apps_list_top_bottom_padding">8dp</dimen>
+    <dimen name="all_apps_list_bottom_padding">8dp</dimen>
     <dimen name="all_apps_empty_search_message_top_offset">40dp</dimen>
     <dimen name="all_apps_empty_search_bg_top_offset">144dp</dimen>
     <dimen name="all_apps_background_canvas_width">700dp</dimen>
@@ -83,13 +80,8 @@
     <dimen name="all_apps_header_scroll_to_elevation">16dp</dimen>
     <dimen name="all_apps_header_shadow_height">6dp</dimen>
 
-    <!-- The overflow is used to create a bottom border, by drawing other three sides
-        outside the bounds. Ensure that:
-            all_apps_search_bar_bg_overflow < (-3 * all_apps_search_bar_divider_width)
-        -6dp is picked at random, any smaller value would do.
-    -->
-    <dimen name="all_apps_search_bar_bg_overflow">-6dp</dimen>
-    <dimen name="all_apps_search_bar_divider_width">1dp</dimen>
+    <dimen name="all_apps_divider_height">1dp</dimen>
+    <dimen name="all_apps_divider_margin_vertical">8dp</dimen>
 
     <dimen name="all_apps_bezel_swipe_height">24dp</dimen>
 <!-- Widget tray -->
diff --git a/src/com/android/launcher3/BaseRecyclerView.java b/src/com/android/launcher3/BaseRecyclerView.java
index f8ef1e1..4cb050e 100644
--- a/src/com/android/launcher3/BaseRecyclerView.java
+++ b/src/com/android/launcher3/BaseRecyclerView.java
@@ -264,7 +264,7 @@
         // Calculate the current scroll position, the scrollY of the recycler view accounts for the
         // view padding, while the scrollBarY is drawn right up to the background padding (ignoring
         // padding)
-        int scrollY = getScrollTop(scrollPosState);
+        int scrollY = Math.max(0, getScrollTop(scrollPosState));
         int scrollBarY = mBackgroundPadding.top +
                 (int) (((float) scrollY / availableScrollHeight) * availableScrollBarHeight);
 
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index 30cd607..717ce74 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -71,7 +71,7 @@
             AlphabeticalAppsList.SectionInfo withSection,
             int sectionAppCount, int numAppsPerRow, int mergeCount) {
         // Don't merge the predicted apps
-        if (section.firstAppItem.viewType != AllAppsGridAdapter.ICON_VIEW_TYPE) {
+        if (section.firstAppItem.viewType != AllAppsGridAdapter.VIEW_TYPE_ICON) {
             return false;
         }
         // Otherwise, merge every other section
@@ -103,7 +103,7 @@
             AlphabeticalAppsList.SectionInfo withSection,
             int sectionAppCount, int numAppsPerRow, int mergeCount) {
         // Don't merge the predicted apps
-        if (section.firstAppItem.viewType != AllAppsGridAdapter.ICON_VIEW_TYPE) {
+        if (section.firstAppItem.viewType != AllAppsGridAdapter.VIEW_TYPE_ICON) {
             return false;
         }
 
@@ -159,7 +159,7 @@
     private int mSectionNamesMargin;
     private int mNumAppsPerRow;
     private int mNumPredictedAppsPerRow;
-    private int mRecyclerViewTopBottomPadding;
+    private int mRecyclerViewBottomPadding;
     // This coordinate is relative to this container view
     private final Point mBoundsCheckLastTouchDownPos = new Point(-1, -1);
 
@@ -184,11 +184,11 @@
         mItemDecoration = mAdapter.getItemDecoration();
         DeviceProfile grid = mLauncher.getDeviceProfile();
         if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP && !grid.isVerticalBarLayout()) {
-            mRecyclerViewTopBottomPadding = 0;
+            mRecyclerViewBottomPadding = 0;
             setPadding(0, 0, 0, 0);
         } else {
-            mRecyclerViewTopBottomPadding =
-                    res.getDimensionPixelSize(R.dimen.all_apps_list_top_bottom_padding);
+            mRecyclerViewBottomPadding =
+                    res.getDimensionPixelSize(R.dimen.all_apps_list_bottom_padding);
         }
         mSearchQueryBuilder = new SpannableStringBuilder();
         Selection.setSelection(mSearchQueryBuilder, 0);
@@ -482,13 +482,12 @@
         // names)
         int maxScrollBarWidth = mAppsRecyclerView.getMaxScrollbarWidth();
         int startInset = Math.max(mSectionNamesMargin, maxScrollBarWidth);
-        int topBottomPadding = mRecyclerViewTopBottomPadding;
         if (Utilities.isRtl(getResources())) {
-            mAppsRecyclerView.setPadding(bgPadding.left + maxScrollBarWidth,
-                    topBottomPadding, bgPadding.right + startInset, topBottomPadding);
+            mAppsRecyclerView.setPadding(bgPadding.left + maxScrollBarWidth, 0, bgPadding.right
+                    + startInset, mRecyclerViewBottomPadding);
         } else {
-            mAppsRecyclerView.setPadding(bgPadding.left + startInset, topBottomPadding,
-                    bgPadding.right + maxScrollBarWidth, topBottomPadding);
+            mAppsRecyclerView.setPadding(bgPadding.left + startInset, 0, bgPadding.right +
+                    maxScrollBarWidth, mRecyclerViewBottomPadding);
         }
 
         MarginLayoutParams lp = (MarginLayoutParams) mSearchContainer.getLayoutParams();
diff --git a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
index d0b8abc..7d856c0 100644
--- a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
+++ b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
@@ -56,17 +56,34 @@
     private static final boolean DEBUG = false;
 
     // A section break in the grid
-    public static final int SECTION_BREAK_VIEW_TYPE = 0;
+    public static final int VIEW_TYPE_SECTION_BREAK = 1 << 0;
     // A normal icon
-    public static final int ICON_VIEW_TYPE = 1;
+    public static final int VIEW_TYPE_ICON = 1 << 1;
     // A prediction icon
-    public static final int PREDICTION_ICON_VIEW_TYPE = 2;
+    public static final int VIEW_TYPE_PREDICTION_ICON = 1 << 2;
     // The message shown when there are no filtered results
-    public static final int EMPTY_SEARCH_VIEW_TYPE = 3;
+    public static final int VIEW_TYPE_EMPTY_SEARCH = 1 << 3;
     // A divider that separates the apps list and the search market button
-    public static final int SEARCH_MARKET_DIVIDER_VIEW_TYPE = 4;
-    // The message to continue to a market search when there are no filtered results
-    public static final int SEARCH_MARKET_VIEW_TYPE = 5;
+    public static final int VIEW_TYPE_SEARCH_MARKET = 1 << 4;
+
+    // We use various dividers for various purposes.  They share enough attributes to reuse layouts,
+    // but differ in enough attributes to require different view types
+
+    // A divider that separates the apps list and the search market button
+    public static final int VIEW_TYPE_SEARCH_MARKET_DIVIDER = 1 << 5;
+    // The divider under the search field
+    public static final int VIEW_TYPE_SEARCH_DIVIDER = 1 << 6;
+    // The divider that separates prediction icons from the app list
+    public static final int VIEW_TYPE_PREDICTION_DIVIDER = 1 << 7;
+
+    // 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;
+    public static final int VIEW_TYPE_MASK_ICON = VIEW_TYPE_ICON
+            | VIEW_TYPE_PREDICTION_ICON;
+
 
     public interface BindViewCallback {
         public void onBindView(ViewHolder holder);
@@ -128,11 +145,9 @@
 
         @Override
         public int getSpanSize(int position) {
-            switch (mApps.getAdapterItems().get(position).viewType) {
-                case AllAppsGridAdapter.ICON_VIEW_TYPE:
-                case AllAppsGridAdapter.PREDICTION_ICON_VIEW_TYPE:
-                    return 1;
-                default:
+            if (isIconViewType(mApps.getAdapterItems().get(position).viewType)) {
+                return 1;
+            } else {
                     // Section breaks span the full width
                     return mAppsPerRow;
             }
@@ -164,7 +179,6 @@
             }
 
             List<AlphabeticalAppsList.AdapterItem> items = mApps.getAdapterItems();
-            boolean hasDrawnPredictedAppsDivider = false;
             boolean showSectionNames = mSectionNamesMargin > 0;
             int childCount = parent.getChildCount();
             int lastSectionTop = 0;
@@ -176,15 +190,7 @@
                     continue;
                 }
 
-                if (shouldDrawItemDivider(holder, items) && !hasDrawnPredictedAppsDivider) {
-                    // Draw the divider under the predicted apps
-                    int top = child.getTop() + child.getHeight() + mPredictionBarDividerOffset;
-                    c.drawLine(mBackgroundPadding.left, top,
-                            parent.getWidth() - mBackgroundPadding.right, top,
-                            mPredictedAppsDividerPaint);
-                    hasDrawnPredictedAppsDivider = true;
-
-                } else if (showSectionNames && shouldDrawItemSection(holder, i, items)) {
+                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();
@@ -210,7 +216,7 @@
                         int sectionBaseline = (int) (viewTopOffset + sectionBounds.y);
                         int x = mIsRtl ?
                                 parent.getWidth() - mBackgroundPadding.left - mSectionNamesMargin :
-                                        mBackgroundPadding.left;
+                                mBackgroundPadding.left;
                         x += (int) ((mSectionNamesMargin - sectionBounds.x) / 2f);
                         int y = child.getTop() + sectionBaseline;
 
@@ -295,15 +301,6 @@
         }
 
         /**
-         * Returns whether to draw the divider for a given child.
-         */
-        private boolean shouldDrawItemDivider(ViewHolder holder,
-                List<AlphabeticalAppsList.AdapterItem> items) {
-            int pos = holder.getPosition();
-            return items.get(pos).viewType == AllAppsGridAdapter.PREDICTION_ICON_VIEW_TYPE;
-        }
-
-        /**
          * Returns whether to draw the section for the given child.
          */
         private boolean shouldDrawItemSection(ViewHolder holder, int childIndex,
@@ -312,12 +309,12 @@
             AlphabeticalAppsList.AdapterItem item = items.get(pos);
 
             // Ensure it's an icon
-            if (item.viewType != AllAppsGridAdapter.ICON_VIEW_TYPE) {
+            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.SECTION_BREAK_VIEW_TYPE);
+                    (items.get(pos - 1).viewType == AllAppsGridAdapter.VIEW_TYPE_SECTION_BREAK);
         }
     }
 
@@ -337,9 +334,8 @@
     private final int mSectionNamesMargin;
     private final int mSectionHeaderOffset;
     private final Paint mSectionTextPaint;
-    private final Paint mPredictedAppsDividerPaint;
+    private int mAccentColor;
 
-    private final int mPredictionBarDividerOffset;
     private int mAppsPerRow;
 
     private BindViewCallback mBindViewCallback;
@@ -351,8 +347,8 @@
     // The intent to send off to the market app, updated each time the search query changes.
     private Intent mMarketSearchIntent;
 
-    public AllAppsGridAdapter(Launcher launcher, AlphabeticalAppsList apps,
-            View.OnClickListener iconClickListener, View.OnLongClickListener iconLongClickListener) {
+    public AllAppsGridAdapter(Launcher launcher, AlphabeticalAppsList apps, View.OnClickListener
+            iconClickListener, View.OnLongClickListener iconLongClickListener) {
         Resources res = launcher.getResources();
         mLauncher = launcher;
         mApps = apps;
@@ -368,17 +364,24 @@
         mSectionHeaderOffset = res.getDimensionPixelSize(R.dimen.all_apps_grid_section_y_offset);
         mIsRtl = Utilities.isRtl(res);
 
+        mAccentColor = Utilities.getColorAccent(launcher);
+
         mSectionTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
         mSectionTextPaint.setTextSize(res.getDimensionPixelSize(
                 R.dimen.all_apps_grid_section_text_size));
-        mSectionTextPaint.setColor(Utilities.getColorAccent(launcher));
+        mSectionTextPaint.setColor(mAccentColor);
+    }
 
-        mPredictedAppsDividerPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
-        mPredictedAppsDividerPaint.setStrokeWidth(Utilities.pxFromDp(1f, res.getDisplayMetrics()));
-        mPredictedAppsDividerPaint.setColor(0x1E000000);
-        mPredictionBarDividerOffset =
-                (-res.getDimensionPixelSize(R.dimen.all_apps_prediction_icon_bottom_padding) +
-                        res.getDimensionPixelSize(R.dimen.all_apps_icon_top_bottom_padding)) / 2;
+    public static boolean isDividerViewType(int viewType) {
+        return isViewType(viewType, VIEW_TYPE_MASK_DIVIDER);
+    }
+
+    public static boolean isIconViewType(int viewType) {
+        return isViewType(viewType, VIEW_TYPE_MASK_ICON);
+    }
+
+    public static boolean isViewType(int viewType, int viewTypeMask) {
+        return (viewType & viewTypeMask) != 0;
     }
 
     /**
@@ -440,12 +443,13 @@
     @Override
     public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
         switch (viewType) {
-            case SECTION_BREAK_VIEW_TYPE:
+            case VIEW_TYPE_SECTION_BREAK:
                 return new ViewHolder(new View(parent.getContext()));
-            case ICON_VIEW_TYPE:
-            case PREDICTION_ICON_VIEW_TYPE: {
+            case VIEW_TYPE_ICON:
+                /* falls through */
+            case VIEW_TYPE_PREDICTION_ICON: {
                 BubbleTextView icon = (BubbleTextView) mLayoutInflater.inflate(
-                        viewType == ICON_VIEW_TYPE ? R.layout.all_apps_icon :
+                        viewType == VIEW_TYPE_ICON ? R.layout.all_apps_icon :
                                 R.layout.all_apps_prediction_bar_icon, parent, false);
                 icon.setOnClickListener(mIconClickListener);
                 icon.setOnLongClickListener(mIconLongClickListener);
@@ -454,13 +458,10 @@
                 icon.setOnFocusChangeListener(mIconFocusListener);
                 return new ViewHolder(icon);
             }
-            case EMPTY_SEARCH_VIEW_TYPE:
+            case VIEW_TYPE_EMPTY_SEARCH:
                 return new ViewHolder(mLayoutInflater.inflate(R.layout.all_apps_empty_search,
                         parent, false));
-            case SEARCH_MARKET_DIVIDER_VIEW_TYPE:
-                return new ViewHolder(mLayoutInflater.inflate(R.layout.all_apps_search_market_divider,
-                        parent, false));
-            case SEARCH_MARKET_VIEW_TYPE:
+            case VIEW_TYPE_SEARCH_MARKET:
                 View searchMarketView = mLayoutInflater.inflate(R.layout.all_apps_search_market,
                         parent, false);
                 searchMarketView.setOnClickListener(new View.OnClickListener() {
@@ -470,6 +471,20 @@
                     }
                 });
                 return new ViewHolder(searchMarketView);
+            case VIEW_TYPE_SEARCH_DIVIDER:
+                final View searchDivider =
+                        mLayoutInflater.inflate(R.layout.all_apps_divider, parent, false);
+                searchDivider.setBackgroundColor(mAccentColor);
+                final GridLayoutManager.LayoutParams searchDividerParams =
+                        (GridLayoutManager.LayoutParams) searchDivider.getLayoutParams();
+                searchDividerParams.topMargin = 0;
+                searchDivider.setLayoutParams(searchDividerParams);
+                return new ViewHolder(searchDivider);
+            case VIEW_TYPE_PREDICTION_DIVIDER:
+                /* falls through */
+            case VIEW_TYPE_SEARCH_MARKET_DIVIDER:
+                return new ViewHolder(mLayoutInflater.inflate(
+                        R.layout.all_apps_divider, parent, false));
             default:
                 throw new RuntimeException("Unexpected view type");
         }
@@ -478,7 +493,7 @@
     @Override
     public void onBindViewHolder(ViewHolder holder, int position) {
         switch (holder.getItemViewType()) {
-            case ICON_VIEW_TYPE: {
+            case VIEW_TYPE_ICON: {
                 AppInfo info = mApps.getAdapterItems().get(position).appInfo;
                 BubbleTextView icon = (BubbleTextView) holder.mContent;
                 icon.applyFromApplicationInfo(info);
@@ -489,7 +504,7 @@
                 icon.setAccessibilityDelegate(mLauncher.getAccessibilityDelegate());
                 break;
             }
-            case PREDICTION_ICON_VIEW_TYPE: {
+            case VIEW_TYPE_PREDICTION_ICON: {
                 AppInfo info = mApps.getAdapterItems().get(position).appInfo;
                 BubbleTextView icon = (BubbleTextView) holder.mContent;
                 icon.applyFromApplicationInfo(info);
@@ -500,13 +515,13 @@
                 icon.setAccessibilityDelegate(mLauncher.getAccessibilityDelegate());
                 break;
             }
-            case EMPTY_SEARCH_VIEW_TYPE:
+            case VIEW_TYPE_EMPTY_SEARCH:
                 TextView emptyViewText = (TextView) holder.mContent;
                 emptyViewText.setText(mEmptySearchMessage);
                 emptyViewText.setGravity(mApps.hasNoFilteredResults() ? Gravity.CENTER :
                         Gravity.START | Gravity.CENTER_VERTICAL);
                 break;
-            case SEARCH_MARKET_VIEW_TYPE:
+            case VIEW_TYPE_SEARCH_MARKET:
                 TextView searchView = (TextView) holder.mContent;
                 if (mMarketSearchIntent != null) {
                     searchView.setVisibility(View.VISIBLE);
diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
index 8d5ade3..ac88113 100644
--- a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
@@ -98,12 +98,14 @@
 
         RecyclerView.RecycledViewPool pool = getRecycledViewPool();
         int approxRows = (int) Math.ceil(grid.availableHeightPx / grid.allAppsIconSizePx);
-        pool.setMaxRecycledViews(AllAppsGridAdapter.EMPTY_SEARCH_VIEW_TYPE, 1);
-        pool.setMaxRecycledViews(AllAppsGridAdapter.SEARCH_MARKET_DIVIDER_VIEW_TYPE, 1);
-        pool.setMaxRecycledViews(AllAppsGridAdapter.SEARCH_MARKET_VIEW_TYPE, 1);
-        pool.setMaxRecycledViews(AllAppsGridAdapter.ICON_VIEW_TYPE, approxRows * mNumAppsPerRow);
-        pool.setMaxRecycledViews(AllAppsGridAdapter.PREDICTION_ICON_VIEW_TYPE, mNumAppsPerRow);
-        pool.setMaxRecycledViews(AllAppsGridAdapter.SECTION_BREAK_VIEW_TYPE, approxRows);
+        pool.setMaxRecycledViews(AllAppsGridAdapter.VIEW_TYPE_EMPTY_SEARCH, 1);
+        pool.setMaxRecycledViews(AllAppsGridAdapter.VIEW_TYPE_SEARCH_DIVIDER, 1);
+        pool.setMaxRecycledViews(AllAppsGridAdapter.VIEW_TYPE_SEARCH_MARKET_DIVIDER, 1);
+        pool.setMaxRecycledViews(AllAppsGridAdapter.VIEW_TYPE_SEARCH_MARKET, 1);
+        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);
     }
 
     /**
@@ -176,7 +178,7 @@
                 if (position != NO_POSITION) {
                     List<AlphabeticalAppsList.AdapterItem> items = mApps.getAdapterItems();
                     AlphabeticalAppsList.AdapterItem item = items.get(position);
-                    if (item.viewType == AllAppsGridAdapter.PREDICTION_ICON_VIEW_TYPE) {
+                    if (item.viewType == AllAppsGridAdapter.VIEW_TYPE_PREDICTION_ICON) {
                         targetParent.containerType = LauncherLogProto.PREDICTION;
                         return;
                     }
@@ -265,7 +267,7 @@
 
         // Find the index and height of the first visible row (all rows have the same height)
         int rowCount = mApps.getNumAppRows();
-        getCurScrollState(mScrollPosState, -1);
+        getCurScrollState(mScrollPosState, AllAppsGridAdapter.VIEW_TYPE_MASK_ICON);
         if (mScrollPosState.rowIndex < 0) {
             mScrollbar.setThumbOffset(-1, -1);
             return;
@@ -352,7 +354,7 @@
             int position = getChildPosition(child);
             if (position != NO_POSITION) {
                 AlphabeticalAppsList.AdapterItem item = items.get(position);
-                if ((item.viewType & viewTypeMask) != 0) {
+                if (AllAppsGridAdapter.isViewType(item.viewType, viewTypeMask)) {
                     stateOut.rowIndex = item.rowIndex;
                     stateOut.rowTopOffset = getLayoutManager().getDecoratedTop(child);
                     stateOut.itemPos = position;
diff --git a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
index 9d2fe54..b70c165 100644
--- a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
+++ b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
@@ -108,7 +108,7 @@
 
         public static AdapterItem asSectionBreak(int pos, SectionInfo section) {
             AdapterItem item = new AdapterItem();
-            item.viewType = AllAppsGridAdapter.SECTION_BREAK_VIEW_TYPE;
+            item.viewType = AllAppsGridAdapter.VIEW_TYPE_SECTION_BREAK;
             item.position = pos;
             item.sectionInfo = section;
             section.sectionBreakItem = item;
@@ -118,14 +118,14 @@
         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);
-            item.viewType = AllAppsGridAdapter.PREDICTION_ICON_VIEW_TYPE;
+            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) {
             AdapterItem item = new AdapterItem();
-            item.viewType = AllAppsGridAdapter.ICON_VIEW_TYPE;
+            item.viewType = AllAppsGridAdapter.VIEW_TYPE_ICON;
             item.position = pos;
             item.sectionInfo = section;
             item.sectionName = sectionName;
@@ -137,21 +137,35 @@
 
         public static AdapterItem asEmptySearch(int pos) {
             AdapterItem item = new AdapterItem();
-            item.viewType = AllAppsGridAdapter.EMPTY_SEARCH_VIEW_TYPE;
+            item.viewType = AllAppsGridAdapter.VIEW_TYPE_EMPTY_SEARCH;
             item.position = pos;
             return item;
         }
 
-        public static AdapterItem asDivider(int pos) {
+        public static AdapterItem asPredictionDivider(int pos) {
             AdapterItem item = new AdapterItem();
-            item.viewType = AllAppsGridAdapter.SEARCH_MARKET_DIVIDER_VIEW_TYPE;
+            item.viewType = AllAppsGridAdapter.VIEW_TYPE_PREDICTION_DIVIDER;
+            item.position = pos;
+            return item;
+        }
+
+        public static AdapterItem asSearchDivder(int pos) {
+            AdapterItem item = new AdapterItem();
+            item.viewType = AllAppsGridAdapter.VIEW_TYPE_SEARCH_DIVIDER;
+            item.position = pos;
+            return item;
+        }
+
+        public static AdapterItem asMarketDivider(int pos) {
+            AdapterItem item = new AdapterItem();
+            item.viewType = AllAppsGridAdapter.VIEW_TYPE_SEARCH_MARKET_DIVIDER;
             item.position = pos;
             return item;
         }
 
         public static AdapterItem asMarketSearch(int pos) {
             AdapterItem item = new AdapterItem();
-            item.viewType = AllAppsGridAdapter.SEARCH_MARKET_VIEW_TYPE;
+            item.viewType = AllAppsGridAdapter.VIEW_TYPE_SEARCH_MARKET;
             item.position = pos;
             return item;
         }
@@ -414,6 +428,9 @@
             }
         }
 
+        // Add the search divider
+        mAdapterItems.add(AdapterItem.asSearchDivder(position++));
+
         // Process the predicted app components
         mPredictedApps.clear();
         if (mPredictedAppComponents != null && !mPredictedAppComponents.isEmpty() && !hasFilter()) {
@@ -452,6 +469,8 @@
                     mAdapterItems.add(appItem);
                     mFilteredApps.add(info);
                 }
+
+                mAdapterItems.add(AdapterItem.asPredictionDivider(position++));
             }
         }
 
@@ -491,7 +510,7 @@
             if (hasNoFilteredResults()) {
                 mAdapterItems.add(AdapterItem.asEmptySearch(position++));
             } else {
-                mAdapterItems.add(AdapterItem.asDivider(position++));
+                mAdapterItems.add(AdapterItem.asMarketDivider(position++));
             }
             mAdapterItems.add(AdapterItem.asMarketSearch(position++));
         }
@@ -507,10 +526,9 @@
             int rowIndex = -1;
             for (AdapterItem item : mAdapterItems) {
                 item.rowIndex = 0;
-                if (item.viewType == AllAppsGridAdapter.SECTION_BREAK_VIEW_TYPE) {
+                if (AllAppsGridAdapter.isDividerViewType(item.viewType)) {
                     numAppsInSection = 0;
-                } else if (item.viewType == AllAppsGridAdapter.ICON_VIEW_TYPE ||
-                        item.viewType == AllAppsGridAdapter.PREDICTION_ICON_VIEW_TYPE) {
+                } else if (AllAppsGridAdapter.isIconViewType(item.viewType)) {
                     if (numAppsInSection % mNumAppsPerRow == 0) {
                         numAppsInRow = 0;
                         rowIndex++;
@@ -529,8 +547,7 @@
                     float rowFraction = 1f / mNumAppRowsInAdapter;
                     for (FastScrollSectionInfo info : mFastScrollerSections) {
                         AdapterItem item = info.fastScrollToItem;
-                        if (item.viewType != AllAppsGridAdapter.ICON_VIEW_TYPE &&
-                                item.viewType != AllAppsGridAdapter.PREDICTION_ICON_VIEW_TYPE) {
+                        if (!AllAppsGridAdapter.isIconViewType(item.viewType)) {
                             info.touchFraction = 0f;
                             continue;
                         }
@@ -544,8 +561,7 @@
                     float cumulativeTouchFraction = 0f;
                     for (FastScrollSectionInfo info : mFastScrollerSections) {
                         AdapterItem item = info.fastScrollToItem;
-                        if (item.viewType != AllAppsGridAdapter.ICON_VIEW_TYPE &&
-                                item.viewType != AllAppsGridAdapter.PREDICTION_ICON_VIEW_TYPE) {
+                        if (!AllAppsGridAdapter.isIconViewType(item.viewType)) {
                             info.touchFraction = 0f;
                             continue;
                         }