Merge "Stop showing first run launcher cling." into ub-launcher3-calgary
diff --git a/res/drawable/all_apps_search_bg.xml b/res/drawable/all_apps_search_bg.xml
index b0ed9b5..cf63d41 100644
--- a/res/drawable/all_apps_search_bg.xml
+++ b/res/drawable/all_apps_search_bg.xml
@@ -15,14 +15,6 @@
      limitations under the License.
 -->
 <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
-    <item>
-        <shape android:shape="rectangle">
-            <solid android:color="@color/quantum_panel_bg_color" />
-            <corners
-                android:topLeftRadius="2dp"
-                android:topRightRadius="2dp" />
-        </shape>
-    </item>
     <item
         android:top="@dimen/all_apps_search_bar_bg_overflow"
         android:left="@dimen/all_apps_search_bar_bg_overflow"
@@ -33,7 +25,7 @@
             <solid android:color="@android:color/transparent" />
             <stroke
                 android:width="@dimen/all_apps_search_bar_divider_width"
-                android:color="#1E000000"/>
+                android:color="?android:attr/colorAccent"/>
         </shape>
     </item>
 </layer-list>
\ No newline at end of file
diff --git a/res/drawable/all_apps_search_hint.xml b/res/drawable/all_apps_search_hint.xml
new file mode 100644
index 0000000..b2ff7a4
--- /dev/null
+++ b/res/drawable/all_apps_search_hint.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2016 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.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="@android:color/transparent" android:state_focused="true" />
+    <item android:color="?android:attr/colorAccent"/>
+</selector>
\ No newline at end of file
diff --git a/res/drawable/ic_allapps_search.xml b/res/drawable/ic_allapps_search.xml
new file mode 100644
index 0000000..2aeb947
--- /dev/null
+++ b/res/drawable/ic_allapps_search.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+     Copyright (C) 2016 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportHeight="24.0"
+    android:viewportWidth="24.0">
+    <path
+        android:fillColor="?android:attr/colorAccent"
+        android:pathData="M15.5,14h-0.79l-0.28,-0.27C15.41,12.59 16,11.11 16,9.5 16,5.91 13.09,3 9.5,3S3,5.91 3,9.5 5.91,16 9.5,16c1.61,0 3.09,-0.59 4.23,-1.57l0.27,0.28v0.79l5,4.99L20.49,19l-4.99,-5zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z" />
+</vector>
diff --git a/res/drawable/quantum_panel_shape_dark.xml b/res/drawable/quantum_panel_shape_dark.xml
index c3821c4..b299eb8 100644
--- a/res/drawable/quantum_panel_shape_dark.xml
+++ b/res/drawable/quantum_panel_shape_dark.xml
@@ -16,7 +16,7 @@
 -->
 <shape xmlns:android="http://schemas.android.com/apk/res/android"
        android:shape="rectangle">
-    <solid android:color="@color/quantum_panel_bg_color_dark" />
+    <solid android:color="?attr/colorSecondary" />
     <corners
         android:radius="2dp" />
-</shape>
\ No newline at end of file
+</shape>
diff --git a/res/drawable/widgets_row_divider.xml b/res/drawable/widgets_row_divider.xml
index bb5b6b5..2c3c7a2 100644
--- a/res/drawable/widgets_row_divider.xml
+++ b/res/drawable/widgets_row_divider.xml
@@ -15,5 +15,5 @@
 -->
 <shape xmlns:android="http://schemas.android.com/apk/res/android" >
     <size android:width="@dimen/widget_row_divider" />
-    <solid android:color="@color/quantum_panel_bg_color_dark" />
+    <solid android:color="?attr/colorSecondary" />
 </shape>
diff --git a/res/layout/all_apps.xml b/res/layout/all_apps.xml
index 1b843ed..a0b73f0 100644
--- a/res/layout/all_apps.xml
+++ b/res/layout/all_apps.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
+<!-- Copyright (C) 2016 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.
@@ -16,15 +16,14 @@
 <!-- The top and bottom paddings are defined in this container, but since we want
      the list view to span the full width (for touch interception purposes), we
      will bake the left/right padding into that view's background itself. -->
-<com.android.launcher3.allapps.AllAppsContainerView
-    xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.launcher3.allapps.AllAppsContainerView xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:launcher="http://schemas.android.com/apk/res-auto"
     android:id="@+id/apps_view"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:paddingTop="@dimen/container_bounds_inset"
-    android:paddingBottom="@dimen/container_bounds_inset"
     android:orientation="vertical"
+    android:paddingBottom="@dimen/container_bounds_inset"
+    android:paddingTop="@dimen/container_bounds_inset"
     launcher:revealBackground="@drawable/quantum_panel_shape">
 
     <View
@@ -32,60 +31,70 @@
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:layout_gravity="center"
-        android:focusable="false"
         android:elevation="2dp"
+        android:focusable="false"
         android:visibility="invisible" />
 
 
     <com.android.launcher3.allapps.AllAppsRecyclerViewContainerView
+        android:id="@+id/main_content"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:id="@+id/main_content"
-        android:saveEnabled="false"
-        android:visibility="gone"
         android:layout_gravity="center"
+        android:elevation="15dp"
         android:focusable="true"
         android:focusableInTouchMode="true"
-        android:elevation="15dp" >
+        android:saveEnabled="false"
+        android:visibility="gone">
 
         <!-- DO NOT CHANGE THE ID -->
         <com.android.launcher3.allapps.AllAppsRecyclerView
             android:id="@+id/apps_list_view"
-            android:theme="@style/CustomOverscroll.Light"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
             android:layout_gravity="center_horizontal|top"
-            android:clipToPadding="false"
-            android:focusable="true"
             android:layout_marginTop="@dimen/all_apps_search_bar_height"
-            android:descendantFocusability="afterDescendants" />
+            android:clipToPadding="false"
+            android:descendantFocusability="afterDescendants"
+            android:focusable="true"
+            android:theme="@style/CustomOverscroll.Light" />
 
         <LinearLayout
             android:id="@+id/search_container"
             android:layout_width="match_parent"
-            android:saveEnabled="false"
             android:layout_height="@dimen/all_apps_search_bar_height"
-            android:layout_gravity="start|top"
+            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:background="@drawable/all_apps_search_bg" >
+            android:saveEnabled="false">
+
+            <ImageView
+                android:id="@+id/search_icon"
+                android:layout_width="wrap_content"
+                android:layout_height="match_parent"
+                android:scaleType="fitCenter"
+                android:layout_marginTop="@dimen/all_apps_search_bar_icon_margin_top"
+                android:paddingEnd="@dimen/all_apps_search_bar_icon_margin_right"
+                android:src="@drawable/ic_allapps_search" />
 
             <com.android.launcher3.ExtendedEditText
                 android:id="@+id/search_box_input"
-                android:layout_width="match_parent"
+                android:layout_width="wrap_content"
                 android:layout_height="match_parent"
                 android:background="@android:color/transparent"
                 android:focusableInTouchMode="true"
-                android:gravity="fill_horizontal|center_vertical"
+                android:gravity="start|center_vertical"
                 android:hint="@string/all_apps_search_bar_hint"
-                android:inputType="text|textNoSuggestions|textCapWords"
                 android:imeOptions="actionSearch|flagNoExtractUi"
+                android:inputType="text|textNoSuggestions|textCapWords"
                 android:maxLines="1"
                 android:scrollHorizontally="true"
-                android:layout_marginLeft="@dimen/container_fastscroll_thumb_max_width"
-                android:layout_marginRight="@dimen/container_fastscroll_thumb_max_width"
                 android:singleLine="true"
                 android:textColor="#4c4c4c"
-                android:textColorHint="#9c9c9c"
+                android:textColorHint="@drawable/all_apps_search_hint"
                 android:textSize="16sp" />
         </LinearLayout>
 
diff --git a/res/layout/widgets_list_row_view.xml b/res/layout/widgets_list_row_view.xml
index c0219b9..4687b38 100644
--- a/res/layout/widgets_list_row_view.xml
+++ b/res/layout/widgets_list_row_view.xml
@@ -30,7 +30,7 @@
         android:id="@+id/section"
         android:layout_width="match_parent"
         android:layout_height="@dimen/widget_section_height"
-        android:background="@color/quantum_panel_bg_color_dark"
+        android:background="?attr/colorSecondary"
         android:drawablePadding="@dimen/widget_section_horizontal_padding"
         android:ellipsize="end"
         android:focusable="true"
diff --git a/res/layout/widgets_view.xml b/res/layout/widgets_view.xml
index e9bbd37..74f7ca1 100644
--- a/res/layout/widgets_view.xml
+++ b/res/layout/widgets_view.xml
@@ -26,7 +26,7 @@
     android:paddingBottom="@dimen/container_bounds_inset"
     android:descendantFocusability="afterDescendants"
     launcher:revealBackground="@drawable/quantum_panel_shape_dark"
-    android:theme="@android:style/Theme.DeviceDefault.Settings">
+    android:theme="@style/WidgetContainerTheme">
 
     <View
         android:id="@+id/reveal_view"
diff --git a/res/values-v25/styles.xml b/res/values-v25/styles.xml
new file mode 100644
index 0000000..ed670a9
--- /dev/null
+++ b/res/values-v25/styles.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+* Copyright (C) 2016 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.
+*/
+-->
+<resources>
+    <!-- Theme for the widget container. -->
+    <style name="WidgetContainerTheme" parent="@android:style/Theme.DeviceDefault.Settings">
+        <item name="colorSecondary">?android:attr/colorSecondary</item>
+    </style>
+</resources>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index ca28ad3..21a05c0 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -82,4 +82,7 @@
     <declare-styleable name="ButtonDropTarget">
         <attr name="hideParentOnDisable" format="boolean" />
     </declare-styleable>
+
+    <!-- Fallback attr for pre-API 25 support -->
+    <attr name="colorSecondary" format="reference|color" />
 </resources>
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 44e77e2..1af449c 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -34,7 +34,6 @@
 
     <color name="quantum_panel_text_color">#FF666666</color>
     <color name="quantum_panel_bg_color">#FFF5F5F5</color>
-    <color name="quantum_panel_bg_color_dark">#FF374248</color>
 
     <color name="outline_color">#FFFFFFFF</color>
 
@@ -44,4 +43,7 @@
     <!-- Widgets view -->
     <color name="widgets_view_section_text_color">#FFFFFF</color>
     <color name="widgets_view_item_text_color">#C4C4C4</color>
+
+    <!-- Used as a fallback since colorSecondary doesn't exist pre-API 25 -->
+    <color name="fallback_secondary_color">#FF37474F</color>
 </resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index c7dd375..c8a05b7 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -64,6 +64,8 @@
     <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_height">60dp</dimen>
+    <dimen name="all_apps_search_bar_icon_margin_right">4dp</dimen>
+    <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 -->
@@ -76,7 +78,7 @@
     <dimen name="all_apps_background_canvas_height">475dp</dimen>
 
     <!-- Search bar in All Apps -->
-    <dimen name="all_apps_header_max_elevation">4dp</dimen>
+    <dimen name="all_apps_header_max_elevation">3dp</dimen>
     <dimen name="all_apps_header_scroll_to_elevation">16dp</dimen>
     <dimen name="all_apps_header_shadow_height">6dp</dimen>
 
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 4e5fcff..11760f4 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -47,7 +47,7 @@
 
     <!-- All Apps -->
     <!-- Search bar text in the apps view. [CHAR_LIMIT=50] -->
-    <string name="all_apps_search_bar_hint">Search Apps&#8230;</string>
+    <string name="all_apps_search_bar_hint">Search Apps</string>
     <!-- Loading apps text. [CHAR_LIMIT=50] -->
     <string name="all_apps_loading_message">Loading Apps&#8230;</string>
     <!-- No-search-results text. [CHAR_LIMIT=50] -->
diff --git a/res/values/styles.xml b/res/values/styles.xml
index a1ba0b0..3e827a6 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -30,12 +30,19 @@
 
     <style name="Theme" parent="@style/LauncherTheme"></style>
 
+    <!-- Theme for the widget container. Overridden on API 25. -->
+    <style name="WidgetContainerTheme" parent="@android:style/Theme.DeviceDefault.Settings">
+        <item name="colorSecondary">@color/fallback_secondary_color</item>
+    </style>
+
     <!-- Overscroll effect -->
+    <style name="CustomOverscroll" />
+
     <style name="CustomOverscroll.Light" parent="@android:style/Theme.DeviceDefault.Light">
         <item name="android:colorEdgeEffect">@color/folder_edge_effect_color</item>
     </style>
 
-    <style name="CustomOverscroll.Dark" parent="@android:style/Theme.DeviceDefault">
+    <style name="CustomOverscroll.Dark">
         <item name="android:colorEdgeEffect">@color/workspace_edge_effect_color</item>
     </style>
 
diff --git a/src/com/android/launcher3/BaseContainerView.java b/src/com/android/launcher3/BaseContainerView.java
index 45d0b52..f9c2407 100644
--- a/src/com/android/launcher3/BaseContainerView.java
+++ b/src/com/android/launcher3/BaseContainerView.java
@@ -18,6 +18,8 @@
 
 import android.content.Context;
 import android.content.res.TypedArray;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.InsetDrawable;
 import android.util.AttributeSet;
@@ -60,12 +62,17 @@
             mHorizontalPadding = DeviceProfile.getContainerPadding(context, width);
         }
 
-        TypedArray a = context.obtainStyledAttributes(attrs,
-                R.styleable.BaseContainerView, defStyleAttr, 0);
-        mRevealDrawable = new InsetDrawable(
-                a.getDrawable(R.styleable.BaseContainerView_revealBackground),
-                mHorizontalPadding, 0, mHorizontalPadding, 0);
-        a.recycle();
+        if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP && this instanceof AllAppsContainerView) {
+            mRevealDrawable = new InsetDrawable(new ColorDrawable(Color.WHITE), mHorizontalPadding,
+                    0, mHorizontalPadding, 0);
+        } else {
+            TypedArray a = context.obtainStyledAttributes(attrs,
+                    R.styleable.BaseContainerView, defStyleAttr, 0);
+            mRevealDrawable = new InsetDrawable(
+                    a.getDrawable(R.styleable.BaseContainerView_revealBackground),
+                    mHorizontalPadding, 0, mHorizontalPadding, 0);
+            a.recycle();
+        }
     }
 
     @Override
diff --git a/src/com/android/launcher3/BaseRecyclerViewFastScrollPopup.java b/src/com/android/launcher3/BaseRecyclerViewFastScrollPopup.java
index da7fa41..37584fe 100644
--- a/src/com/android/launcher3/BaseRecyclerViewFastScrollPopup.java
+++ b/src/com/android/launcher3/BaseRecyclerViewFastScrollPopup.java
@@ -32,9 +32,9 @@
 
     private static final float FAST_SCROLL_OVERLAY_Y_OFFSET_FACTOR = 1.5f;
 
-    private static final int SHADOW_INSET = 6;
+    private static final int SHADOW_INSET = 5;
     private static final int SHADOW_SHIFT_Y = 4;
-    private static final float SHADOW_ALPHA_MULTIPLIER = 0.6f;
+    private static final float SHADOW_ALPHA_MULTIPLIER = 0.5f;
 
     private Resources mRes;
     private BaseRecyclerView mRv;
diff --git a/src/com/android/launcher3/IconCache.java b/src/com/android/launcher3/IconCache.java
index ac9a8aa..1fea6b4 100644
--- a/src/com/android/launcher3/IconCache.java
+++ b/src/com/android/launcher3/IconCache.java
@@ -26,6 +26,7 @@
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Resources;
+import android.content.res.TypedArray;
 import android.database.Cursor;
 import android.database.sqlite.SQLiteDatabase;
 import android.database.sqlite.SQLiteException;
@@ -126,7 +127,9 @@
         mWorkerHandler = new Handler(LauncherModel.getWorkerLooper());
 
         mActivityBgColor = context.getResources().getColor(R.color.quantum_panel_bg_color);
-        mPackageBgColor = context.getResources().getColor(R.color.quantum_panel_bg_color_dark);
+        TypedArray ta = context.obtainStyledAttributes(new int[]{R.attr.colorSecondary});
+        mPackageBgColor = ta.getColor(0, 0);
+        ta.recycle();
         mLowResOptions = new BitmapFactory.Options();
         // Always prefer RGB_565 config for low res. If the bitmap has transparency, it will
         // automatically be loaded as ALPHA_8888.
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index f143847..2ecf176 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -1369,7 +1369,9 @@
         mDragController.addDropTarget(mWorkspace);
         mDropTargetBar.setup(mDragController);
 
-        mAllAppsController.setupViews(mAppsView, mHotseat, mWorkspace);
+        if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP) {
+            mAllAppsController.setupViews(mAppsView, mHotseat, mWorkspace);
+        }
 
         if (TestingUtils.MEMORY_DUMP_ENABLED) {
             TestingUtils.addWeightWatcher(this);
diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
index ab4cd8d..2fcd73d 100644
--- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
+++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
@@ -273,7 +273,8 @@
         // Update the workspace state
         float finalBackgroundAlpha = (states.stateIsSpringLoaded || states.stateIsOverview) ?
                 1.0f : 0f;
-        float finalHotseatAlpha = (states.stateIsNormal || states.stateIsSpringLoaded) ? 1f : 0f;
+        float finalHotseatAlpha = (states.stateIsNormal || states.stateIsSpringLoaded ||
+                (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP && states.stateIsNormalHidden)) ? 1f : 0f;
         float finalOverviewPanelAlpha = states.stateIsOverview ? 1f : 0f;
 
         float finalWorkspaceTranslationY = 0;
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index c3da491..868408f 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -25,11 +25,14 @@
 import android.text.SpannableStringBuilder;
 import android.text.method.TextKeyListener;
 import android.util.AttributeSet;
+import android.view.Gravity;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewConfiguration;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.ImageView;
 import android.widget.LinearLayout;
 
 import com.android.launcher3.AppInfo;
@@ -58,7 +61,6 @@
 import java.util.List;
 
 
-
 /**
  * A merge algorithm that merges every section indiscriminately.
  */
@@ -66,8 +68,8 @@
 
     @Override
     public boolean continueMerging(AlphabeticalAppsList.SectionInfo section,
-           AlphabeticalAppsList.SectionInfo withSection,
-           int sectionAppCount, int numAppsPerRow, int mergeCount) {
+            AlphabeticalAppsList.SectionInfo withSection,
+            int sectionAppCount, int numAppsPerRow, int mergeCount) {
         // Don't merge the predicted apps
         if (section.firstAppItem.viewType != AllAppsGridAdapter.ICON_VIEW_TYPE) {
             return false;
@@ -98,8 +100,8 @@
 
     @Override
     public boolean continueMerging(AlphabeticalAppsList.SectionInfo section,
-           AlphabeticalAppsList.SectionInfo withSection,
-           int sectionAppCount, int numAppsPerRow, int mergeCount) {
+            AlphabeticalAppsList.SectionInfo withSection,
+            int sectionAppCount, int numAppsPerRow, int mergeCount) {
         // Don't merge the predicted apps
         if (section.firstAppItem.viewType != AllAppsGridAdapter.ICON_VIEW_TYPE) {
             return false;
@@ -148,6 +150,7 @@
 
     private View mSearchContainer;
     private ExtendedEditText mSearchInput;
+    private ImageView mSearchIcon;
     private HeaderElevationController mElevationController;
 
     private SpannableStringBuilder mSearchQueryBuilder = null;
@@ -232,6 +235,7 @@
             mSearchBarController.setVisibility(View.INVISIBLE);
         }
     }
+
     /**
      * Sets the search bar that shows above the a-z list.
      */
@@ -261,8 +265,8 @@
         Utilities.mapCoordInSelfToDescendent(mAppsRecyclerView, this, point);
 
         // if the MotionEvent is inside the thumb, container should not be pulled down.
-        if (mAppsRecyclerView.getScrollBar().isNearThumb(point[0], point[1])){
-             return false;
+        if (mAppsRecyclerView.getScrollBar().isNearThumb(point[0], point[1])) {
+            return false;
         }
         // If scroller is at the very top, then it's okay for the container to be pulled down.
         if (Float.compare(0f, mAppsRecyclerView.getScrollBar().getThumbOffset().y) == 0) {
@@ -270,6 +274,7 @@
         }
         return false;
     }
+
     /**
      * Focuses the search field and begins an app search.
      */
@@ -305,6 +310,42 @@
 
         mSearchContainer = findViewById(R.id.search_container);
         mSearchInput = (ExtendedEditText) findViewById(R.id.search_box_input);
+        mSearchIcon = (ImageView) findViewById(R.id.search_icon);
+
+        final LinearLayout.LayoutParams searchParams =
+                (LinearLayout.LayoutParams) mSearchInput.getLayoutParams();
+        mSearchInput.setOnFocusChangeListener(new OnFocusChangeListener() {
+            @Override
+            public void onFocusChange(View view, boolean focused) {
+                if (focused) {
+                    searchParams.width = LayoutParams.MATCH_PARENT;
+                    mSearchInput.setLayoutParams(searchParams);
+                    mSearchInput.setGravity(Gravity.FILL_HORIZONTAL | Gravity.CENTER_VERTICAL);
+                    mSearchIcon.setVisibility(View.GONE);
+                } else {
+                    searchParams.width = LayoutParams.WRAP_CONTENT;
+                    mSearchInput.setLayoutParams(searchParams);
+                    mSearchInput.setGravity(Gravity.START | Gravity.CENTER_VERTICAL);
+                    mSearchIcon.setVisibility(View.VISIBLE);
+                }
+            }
+        });
+
+        final OnClickListener searchFocusListener = new OnClickListener() {
+            @Override
+            public void onClick(View view) {
+                if (!mSearchInput.isFocused()) {
+                    mSearchInput.requestFocus();
+                    final InputMethodManager imm =
+                            (InputMethodManager)getContext().getSystemService(
+                                    Context.INPUT_METHOD_SERVICE);
+                    imm.showSoftInput(mSearchInput, 0);
+                }
+            }
+        };
+        mSearchInput.setOnClickListener(searchFocusListener);
+        mSearchContainer.setOnClickListener(searchFocusListener);
+
         mElevationController = Utilities.ATLEAST_LOLLIPOP
                 ? new HeaderElevationController.ControllerVL(mSearchContainer)
                 : new HeaderElevationController.ControllerV16(mSearchContainer);
@@ -379,7 +420,11 @@
                 if (mNumAppsPerRow > 0) {
                     int iconSize = availableWidth / mNumAppsPerRow;
                     int iconSpacing = (iconSize - grid.allAppsIconSizePx) / 2;
-                    mSearchInput.setPaddingRelative(iconSpacing, 0, iconSpacing, 0);
+                    final int thumbMaxWidth =
+                            getResources().getDimensionPixelSize(
+                                    R.dimen.container_fastscroll_thumb_max_width);
+                    mSearchContainer.setPaddingRelative(
+                            iconSpacing + thumbMaxWidth, 0, iconSpacing + thumbMaxWidth, 0);
                 }
             }
             super.onMeasure(widthMeasureSpec, heightMeasureSpec);
@@ -452,7 +497,6 @@
         lp.leftMargin = bgPadding.left;
         lp.rightMargin = bgPadding.right;
 
-
         // Clip the view to the left and right edge of the background to
         // to prevent shadows from rendering beyond the edges
         final Rect newClipBounds = new Rect(
@@ -472,7 +516,7 @@
                 MarginLayoutParams mlp = (MarginLayoutParams) mAppsRecyclerView.getLayoutParams();
 
                 Rect insets = mLauncher.getDragLayer().getInsets();
-                getContentView().setPadding(0,0,0, insets.bottom);
+                getContentView().setPadding(0, 0, 0, insets.bottom);
                 int height = insets.top + grid.hotseatCellHeightPx;
 
                 mlp.topMargin = height;
@@ -482,10 +526,10 @@
                         (LinearLayout.LayoutParams) mSearchInput.getLayoutParams();
                 llp.topMargin = insets.top;
                 mSearchInput.setLayoutParams(llp);
+                mSearchIcon.setLayoutParams(llp);
 
                 lp.height = height;
             }
-            mSearchContainer.getBackground().setAlpha(0);
         }
         mSearchContainer.setLayoutParams(lp);
     }
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index 8a14a66..3ae8cd8 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -11,7 +11,6 @@
 import android.view.animation.DecelerateInterpolator;
 import android.view.animation.Interpolator;
 
-import com.android.launcher3.CellLayout;
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Hotseat;
 import com.android.launcher3.Launcher;
@@ -100,31 +99,34 @@
             } else {
                 // Now figure out which direction scroll events the controller will start
                 // calling the callbacks.
-                int conditionsToReportScroll = 0;
+                int directionsToDetectScroll = 0;
+                boolean ignoreSlopWhenSettling = false;
 
-                if (mDetector.isRestingState()) {
+                if (mDetector.isIdleState()) {
                     if (mLauncher.isAllAppsVisible()) {
-                        conditionsToReportScroll |= VerticalPullDetector.THRESHOLD_DOWN;
+                        directionsToDetectScroll |= VerticalPullDetector.DIRECTION_DOWN;
                     } else {
-                        conditionsToReportScroll |= VerticalPullDetector.THRESHOLD_UP;
+                        directionsToDetectScroll |= VerticalPullDetector.DIRECTION_UP;
                     }
                 } else {
                     if (isInDisallowRecatchBottomZone()) {
-                        conditionsToReportScroll |= VerticalPullDetector.THRESHOLD_UP;
+                        directionsToDetectScroll |= VerticalPullDetector.DIRECTION_UP;
                     } else if (isInDisallowRecatchTopZone()) {
-                        conditionsToReportScroll |= VerticalPullDetector.THRESHOLD_DOWN;
+                        directionsToDetectScroll |= VerticalPullDetector.DIRECTION_DOWN;
                     } else {
-                        conditionsToReportScroll |= VerticalPullDetector.THRESHOLD_ONLY;
+                        directionsToDetectScroll |= VerticalPullDetector.DIRECTION_BOTH;
+                        ignoreSlopWhenSettling = true;
                     }
                 }
-                mDetector.setDetectableScrollConditions(conditionsToReportScroll);
+                mDetector.setDetectableScrollConditions(directionsToDetectScroll,
+                        ignoreSlopWhenSettling);
             }
         }
         if (mNoIntercept) {
             return false;
         }
         mDetector.onTouchEvent(ev);
-        if (mDetector.isScrollingState() && (isInDisallowRecatchBottomZone() || isInDisallowRecatchTopZone())) {
+        if (mDetector.isSettlingState() && (isInDisallowRecatchBottomZone() || isInDisallowRecatchTopZone())) {
             return false;
         }
         return mDetector.shouldIntercept();
@@ -132,7 +134,7 @@
 
     private boolean shouldPossiblyIntercept(MotionEvent ev) {
         DeviceProfile grid = mLauncher.getDeviceProfile();
-        if (mDetector.isRestingState()) {
+        if (mDetector.isIdleState()) {
             if (grid.isVerticalBarLayout()) {
                 if (ev.getY() > mLauncher.getDeviceProfile().heightPx - mBezelSwipeUpHeight) {
                     return true;
@@ -164,7 +166,7 @@
     }
 
     @Override
-    public void onScrollStart(boolean start) {
+    public void onDragStart(boolean start) {
         cancelAnimation();
         mCurrentAnimation = LauncherAnimUtils.createAnimatorSet();
         mShiftStart = mAppsView.getTranslationY();
@@ -172,7 +174,7 @@
     }
 
     @Override
-    public boolean onScroll(float displacement, float velocity) {
+    public boolean onDrag(float displacement, float velocity) {
         if (mAppsView == null) {
             return false;   // early termination.
         }
@@ -182,7 +184,7 @@
     }
 
     @Override
-    public void onScrollEnd(float velocity, boolean fling) {
+    public void onDragEnd(float velocity, boolean fling) {
         if (mAppsView == null) {
             return; // early termination.
         }
@@ -229,7 +231,7 @@
      */
     public void preparePull(boolean start) {
         if (start) {
-            // Initialize values that should not change until #onScrollEnd
+            // Initialize values that should not change until #onDragEnd
             mStatusBarHeight = mLauncher.getDragLayer().getInsets().top;
             mHotseat.setVisibility(View.VISIBLE);
             mHotseat.bringToFront();
@@ -321,7 +323,7 @@
         if (animationOut == null){
             return;
         }
-        if (mDetector.isRestingState()) {
+        if (mDetector.isIdleState()) {
             preparePull(true);
             mAnimationDuration = duration;
             mShiftStart = mAppsView.getTranslationY();
@@ -361,7 +363,7 @@
         if (animationOut == null){
             return;
         }
-        if(mDetector.isRestingState()) {
+        if(mDetector.isIdleState()) {
             preparePull(true);
             mAnimationDuration = duration;
             mShiftStart = mAppsView.getTranslationY();
@@ -408,6 +410,7 @@
         mAppsView.setVisibility(View.INVISIBLE);
         mHotseat.setBackgroundTransparent(false /* transparent */);
         mHotseat.setVisibility(View.VISIBLE);
+        mAppsView.reset();
         setProgress(mShiftRange);
     }
 
diff --git a/src/com/android/launcher3/allapps/VerticalPullDetector.java b/src/com/android/launcher3/allapps/VerticalPullDetector.java
index b54cb00..b058ad2 100644
--- a/src/com/android/launcher3/allapps/VerticalPullDetector.java
+++ b/src/com/android/launcher3/allapps/VerticalPullDetector.java
@@ -18,10 +18,10 @@
 
     private float mTouchSlop;
 
-    private int mScrollDirections;
-    public static final int THRESHOLD_UP = 1 << 0;
-    public static final int THRESHOLD_DOWN = 1 << 1;
-    public static final int THRESHOLD_ONLY = THRESHOLD_DOWN | THRESHOLD_UP;
+    private int mScrollConditions;
+    public static final int DIRECTION_UP = 1 << 0;
+    public static final int DIRECTION_DOWN = 1 << 1;
+    public static final int DIRECTION_BOTH = DIRECTION_DOWN | DIRECTION_UP;
 
 
     /**
@@ -36,42 +36,54 @@
     public static final float SCROLL_VELOCITY_DAMPENING_RC = 1000f / (2f * (float) Math.PI * 10);
 
     /* Scroll state, this is set to true during dragging and animation. */
-    private State mState = State.NONE;
+    private ScrollState mState = ScrollState.IDLE;
 
-    enum State {
-        NONE,
-        CATCH,          // onScrollStart
-        DRAG,           // onScrollStart, onScroll
-        SCROLLING       // onScrollEnd
+    enum ScrollState {
+        IDLE,
+        DRAGGING,      // onDragStart, onDrag
+        SETTLING       // onDragEnd
     };
 
-    //------------------- State transition diagram -----------------------------------
+    //------------------- ScrollState transition diagram -----------------------------------
     //
-    // NONE -> (mDisplacement > mTouchSlop) -> DRAG
-    // DRAG -> (MotionEvent#ACTION_UP, MotionEvent#ACTION_CANCEL) -> SCROLLING
-    // SCROLLING -> (MotionEvent#ACTION_DOWN) && (mDisplacement > mTouchSlop) -> CATCH
-    // SCROLLING -> (View settled) -> NONE
+    // IDLE ->      (mDisplacement > mTouchSlop) -> DRAGGING
+    // DRAGGING -> (MotionEvent#ACTION_UP, MotionEvent#ACTION_CANCEL) -> SETTLING
+    // SETTLING -> (MotionEvent#ACTION_DOWN) -> DRAGGING
+    // SETTLING -> (View settled) -> IDLE
 
-    private void setState(State newState) {
+    private void setState(ScrollState newState) {
         if (DBG) {
             Log.d(TAG, "setState:" + mState + "->" + newState);
         }
+        // onDragStart and onDragEnd is reported ONLY on state transition
+        if (newState == ScrollState.DRAGGING) {
+            initializeDragging();
+            if (mState == ScrollState.IDLE) {
+                reportDragStart(false /* recatch */);
+            } else if (mState == ScrollState.SETTLING) {
+                reportDragStart(true /* recatch */);
+            }
+        }
+        if (newState == ScrollState.SETTLING) {
+            reportDragEnd();
+        }
+
         mState = newState;
     }
 
     public boolean shouldIntercept() {
-        return mState == State.DRAG || mState == State.SCROLLING || mState == State.CATCH;
+        return mState == ScrollState.DRAGGING || mState == ScrollState.SETTLING;
     }
 
     /**
      * There's no touch and there's no animation.
      */
-    public boolean isRestingState() {
-        return mState == State.NONE;
+    public boolean isIdleState() {
+        return mState == ScrollState.IDLE;
     }
 
-    public boolean isScrollingState() {
-        return mState == State.SCROLLING;
+    public boolean isSettlingState() {
+        return mState == ScrollState.SETTLING;
     }
 
     private float mDownX;
@@ -87,6 +99,7 @@
     private float mDisplacementX;
 
     private float mSubtractDisplacement;
+    private boolean mIgnoreSlopWhenSettling;
 
     /* Client of this gesture detector can register a callback. */
     Listener mListener;
@@ -96,17 +109,18 @@
     }
 
     interface Listener{
-        void onScrollStart(boolean start);
-        boolean onScroll(float displacement, float velocity);
-        void onScrollEnd(float velocity, boolean fling);
+        void onDragStart(boolean start);
+        boolean onDrag(float displacement, float velocity);
+        void onDragEnd(float velocity, boolean fling);
     }
 
     public VerticalPullDetector(Context context) {
         mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
     }
 
-    public void setDetectableScrollConditions(int scrollDirectionFlags) {
-        mScrollDirections = scrollDirectionFlags;
+    public void setDetectableScrollConditions(int scrollDirectionFlags, boolean ignoreSlop) {
+        mScrollConditions = scrollDirectionFlags;
+        mIgnoreSlopWhenSettling = ignoreSlop;
     }
 
     private boolean shouldScrollStart() {
@@ -122,8 +136,8 @@
             return false;
         }
         // Check if the client is interested in scroll in current direction.
-        if (((mScrollDirections & THRESHOLD_DOWN) > 0 && mDisplacementY > 0) ||
-            ((mScrollDirections & THRESHOLD_UP) > 0 && mDisplacementY < 0)) {
+        if (((mScrollConditions & DIRECTION_DOWN) > 0 && mDisplacementY > 0) ||
+            ((mScrollConditions & DIRECTION_UP) > 0 && mDisplacementY < 0)) {
             return true;
         }
         return false;
@@ -136,12 +150,11 @@
                 mDownX = ev.getX();
                 mDownY = ev.getY();
                 mLastDisplacement = 0;
+                mDisplacementY = 0;
                 mVelocity = 0;
 
-                // handle state and listener calls.
-                if (mState == State.SCROLLING && shouldScrollStart()){
-                    reportScrollStart(true /* recatch */);
-                    setState(State.CATCH);
+                if (mState == ScrollState.SETTLING && mIgnoreSlopWhenSettling) {
+                    setState(ScrollState.DRAGGING);
                 }
                 break;
             case MotionEvent.ACTION_MOVE:
@@ -150,22 +163,18 @@
                 mVelocity = computeVelocity(ev, mVelocity);
 
                 // handle state and listener calls.
-                if (shouldScrollStart() && mState != State.DRAG) {
-                    if (mState == State.NONE) {
-                        reportScrollStart(false /* recatch */);
-                    }
-                    setState(State.DRAG);
+                if (mState != ScrollState.DRAGGING && shouldScrollStart()) {
+                    setState(ScrollState.DRAGGING);
                 }
-                if (mState == State.DRAG) {
-                    reportScroll();
+                if (mState == ScrollState.DRAGGING) {
+                    reportDragging();
                 }
                 break;
             case MotionEvent.ACTION_CANCEL:
             case MotionEvent.ACTION_UP:
                 // These are synthetic events and there is no need to update internal values.
-                if (mState == State.DRAG || mState == State.CATCH) {
-                    reportScrollEnd();
-                    setState(State.SCROLLING);
+                if (mState == ScrollState.DRAGGING) {
+                    setState(ScrollState.SETTLING);
                 }
                 break;
             default:
@@ -182,41 +191,47 @@
     }
 
     public void finishedScrolling() {
-        setState(State.NONE);
+        setState(ScrollState.IDLE);
     }
 
-    private boolean reportScrollStart(boolean recatch) {
-        mListener.onScrollStart(!recatch);
+    private boolean reportDragStart(boolean recatch) {
+        mListener.onDragStart(!recatch);
+        if (DBG) {
+            Log.d(TAG, "onDragStart recatch:" + recatch);
+        }
+        return true;
+    }
+
+    private void initializeDragging() {
+        if (mState == ScrollState.SETTLING && mIgnoreSlopWhenSettling) {
+            mSubtractDisplacement = 0;
+        }
         if (mDisplacementY > 0) {
             mSubtractDisplacement = mTouchSlop;
         } else {
             mSubtractDisplacement = -mTouchSlop;
         }
-        if (DBG) {
-            Log.d(TAG, "onScrollStart recatch:" + recatch);
-        }
-        return true;
     }
 
-    private boolean reportScroll() {
+    private boolean reportDragging() {
         float delta = mDisplacementY - mLastDisplacement;
         if (delta != 0) {
             if (DBG) {
-                Log.d(TAG, String.format("onScroll disp=%.1f, velocity=%.1f",
+                Log.d(TAG, String.format("onDrag disp=%.1f, velocity=%.1f",
                         mDisplacementY, mVelocity));
             }
 
-            return mListener.onScroll(mDisplacementY - mSubtractDisplacement, mVelocity);
+            return mListener.onDrag(mDisplacementY - mSubtractDisplacement, mVelocity);
         }
         return true;
     }
 
-    private void reportScrollEnd() {
+    private void reportDragEnd() {
         if (DBG) {
             Log.d(TAG, String.format("onScrolEnd disp=%.1f, velocity=%.1f",
                     mDisplacementY, mVelocity));
         }
-        mListener.onScrollEnd(mVelocity, Math.abs(mVelocity) > RELEASE_VELOCITY_PX_MS);
+        mListener.onDragEnd(mVelocity, Math.abs(mVelocity) > RELEASE_VELOCITY_PX_MS);
 
     }
     /**