OSDN Git Service

Merging search bar with all apps
authorSunny Goyal <sunnygoyal@google.com>
Fri, 29 Jan 2016 21:14:14 +0000 (13:14 -0800)
committerSunny Goyal <sunnygoyal@google.com>
Mon, 8 Feb 2016 22:55:22 +0000 (14:55 -0800)
Change-Id: I78577124cd3c05d52669c3e52b0294d6eb1d194d

20 files changed:
res/drawable/all_apps_search_bg.xml
res/layout-land/launcher.xml
res/layout-port/launcher.xml
res/layout-sw720dp/launcher.xml
res/layout/all_apps.xml
res/layout/widgets_view.xml
res/values/attrs.xml
res/values/dimens.xml
res/values/strings.xml
src/com/android/launcher3/BaseContainerView.java
src/com/android/launcher3/Launcher.java
src/com/android/launcher3/LauncherStateTransitionAnimation.java
src/com/android/launcher3/SearchDropTargetBar.java
src/com/android/launcher3/Workspace.java
src/com/android/launcher3/allapps/AllAppsContainerView.java
src/com/android/launcher3/allapps/AllAppsRecyclerView.java
src/com/android/launcher3/allapps/AllAppsSearchBarController.java
src/com/android/launcher3/allapps/DefaultAppSearchController.java
src/com/android/launcher3/allapps/HeaderElevationController.java [new file with mode: 0644]
src/com/android/launcher3/widget/WidgetsContainerView.java

index a09f88f..5a2c9e8 100644 (file)
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<inset xmlns:android="http://schemas.android.com/apk/res/android"
-    android:drawable="@drawable/quantum_panel"
-    android:insetTop="@dimen/container_bounds_minus_quantum_panel_padding_inset"
-    android:insetBottom="@dimen/container_bounds_minus_quantum_panel_padding_inset" />
\ No newline at end of file
+<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"
+        android:right="@dimen/all_apps_search_bar_bg_overflow"
+        android:bottom="0dp">
+
+        <shape android:shape="rectangle">
+            <stroke
+                android:width="@dimen/all_apps_search_bar_divider_width"
+                android:color="#1E000000"/>
+        </shape>
+    </item>
+</layer-list>
\ No newline at end of file
index 6500ebc..1a951f1 100644 (file)
@@ -25,6 +25,8 @@
 
     <com.android.launcher3.DragLayer
         android:id="@+id/drag_layer"
+        android:clipChildren="false"
+        android:clipToPadding="false"
         android:layout_width="match_parent"
         android:layout_height="match_parent">
 
index d0772ee..8bf9d64 100644 (file)
@@ -26,6 +26,8 @@
 
     <com.android.launcher3.DragLayer
         android:id="@+id/drag_layer"
+        android:clipChildren="false"
+        android:clipToPadding="false"
         android:layout_width="match_parent"
         android:layout_height="match_parent">
 
index 802922e..2fc62c5 100644 (file)
@@ -25,6 +25,8 @@
 
     <com.android.launcher3.DragLayer
         android:id="@+id/drag_layer"
+        android:clipChildren="false"
+        android:clipToPadding="false"
         android:layout_width="match_parent"
         android:layout_height="match_parent">
 
index 1bf54ee..c2b1e6f 100644 (file)
      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"
+    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:orientation="vertical">
+    android:orientation="vertical"
+    launcher:revealBackground="@drawable/quantum_panel_shape">
 
-    <!-- Both android:focusable and android:focusableInTouchMode are needed for
-         the view to get focus change events. -->
-    <FrameLayout
-        android:id="@+id/search_box_container"
+    <View
+        android:id="@+id/reveal_view"
         android:layout_width="match_parent"
-        android:layout_height="wrap_content"
+        android:layout_height="match_parent"
+        android:layout_gravity="center"
+        android:focusable="false"
+        android:elevation="2dp"
+        android:visibility="invisible" />
+
+
+    <com.android.launcher3.allapps.AllAppsRecyclerViewContainerView
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:id="@+id/main_content"
+        android:visibility="gone"
+        android:layout_gravity="center"
         android:focusable="true"
         android:focusableInTouchMode="true"
-        android:visibility="gone" />
+        android:elevation="15dp" >
 
-    <FrameLayout
-        android:id="@+id/content"
-        android:layout_width="match_parent"
-        android:layout_height="0dp"
-        android:layout_weight="1">
-        <FrameLayout
-            android:id="@+id/all_apps_reveal"
+        <!-- DO NOT CHANGE THE ID -->
+        <com.android.launcher3.allapps.AllAppsRecyclerView
+            android:id="@+id/apps_list_view"
+            android:theme="@style/Theme.Light.CustomOverscroll"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
-            android:layout_gravity="center"
-            android:focusable="false"
-            android:elevation="2dp"
-            android:visibility="invisible" />
-        <include
-            layout="@layout/all_apps_container"
-            android:id="@+id/all_apps_container"
+            android:layout_gravity="center_horizontal|top"
+            android:clipToPadding="false"
+            android:focusable="true"
+            android:layout_marginTop="@dimen/all_apps_search_bar_height"
+            android:descendantFocusability="afterDescendants" />
+
+        <LinearLayout
+            android:id="@+id/search_container"
             android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:layout_gravity="center"
-            android:visibility="gone" />
-    </FrameLayout>
+            android:layout_height="@dimen/all_apps_search_bar_height"
+            android:layout_gravity="start|top"
+            android:orientation="horizontal"
+            android:background="@drawable/all_apps_search_bg" >
+
+            <com.android.launcher3.ExtendedEditText
+                android:id="@+id/search_box_input"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:background="@android:color/transparent"
+                android:focusableInTouchMode="true"
+                android:gravity="fill_horizontal|center_vertical"
+                android:hint="@string/all_apps_search_bar_hint"
+                android:inputType="text|textNoSuggestions|textCapWords"
+                android:imeOptions="actionSearch|flagNoExtractUi"
+                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:textSize="16sp" />
+        </LinearLayout>
+
+    </com.android.launcher3.allapps.AllAppsRecyclerViewContainerView>
 </com.android.launcher3.allapps.AllAppsContainerView>
\ No newline at end of file
index 755634f..e64f83a 100644 (file)
      will bake the left/right padding into that view's background itself. -->
 <com.android.launcher3.widget.WidgetsContainerView
     xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:launcher="http://schemas.android.com/apk/res-auto"
     android:id="@+id/widgets_view"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:orientation="vertical"
-    android:descendantFocusability="afterDescendants">
+    android:descendantFocusability="afterDescendants"
+    launcher:revealBackground="@drawable/quantum_panel_shape_dark">
 
-    <FrameLayout
-        android:id="@+id/content"
+    <View
+        android:id="@+id/reveal_view"
         android:layout_width="match_parent"
-        android:layout_height="match_parent">
-        <FrameLayout
-            android:id="@+id/widgets_reveal_view"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:layout_gravity="center"
-            android:focusable="false"
-            android:elevation="2dp"
-            android:visibility="invisible" />
+        android:layout_height="match_parent"
+        android:layout_gravity="center"
+        android:focusable="false"
+        android:elevation="2dp"
+        android:visibility="invisible" />
 
-        <!-- DO NOT CHANGE THE ID -->
-        <com.android.launcher3.widget.WidgetsRecyclerView
-            android:id="@+id/widgets_list_view"
-            android:theme="@style/Theme.Dark.CustomOverscroll"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:layout_gravity="center"
-            android:elevation="15dp"
-            android:visibility="gone" />
-    </FrameLayout>
+    <com.android.launcher3.widget.WidgetsRecyclerView
+        android:id="@+id/main_content"
+        android:theme="@style/Theme.Dark.CustomOverscroll"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_gravity="center"
+        android:elevation="15dp"
+        android:visibility="gone" />
 
 </com.android.launcher3.widget.WidgetsContainerView>
\ No newline at end of file
index 827332a..82f33d1 100644 (file)
         <attr name="pageIndicator" format="reference" />
     </declare-styleable>
 
+    <!-- BaseContainerView specific attributes. These attributes are used to customize
+         AllApps view and WidgetsView in xml. -->
+    <declare-styleable name="BaseContainerView">
+        <!-- Drawable to use for the reveal animation -->
+        <attr name="revealBackground" format="reference" />
+    </declare-styleable>
+
     <!-- XML attributes used by default_workspace.xml -->
     <declare-styleable name="Favorite">
         <attr name="className" format="string" />
index 076853e..a303dab 100644 (file)
@@ -77,7 +77,7 @@
     <dimen name="all_apps_grid_view_start_margin">0dp</dimen>
     <dimen name="all_apps_grid_section_y_offset">8dp</dimen>
     <dimen name="all_apps_grid_section_text_size">24sp</dimen>
-    <dimen name="all_apps_search_bar_height">48dp</dimen>
+    <dimen name="all_apps_search_bar_height">60dp</dimen>
     <dimen name="all_apps_search_bar_prediction_bar_padding">8dp</dimen>
     <dimen name="all_apps_icon_top_bottom_padding">8dp</dimen>
     <dimen name="all_apps_icon_width_gap">24dp</dimen>
     <dimen name="all_apps_background_canvas_width">700dp</dimen>
     <dimen name="all_apps_background_canvas_height">475dp</dimen>
 
-<!-- Widget tray -->
+    <!-- Search bar in All Apps -->
+    <dimen name="all_apps_header_max_elevation">4dp</dimen>
+    <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>
+
+    <!-- Widget tray -->
     <dimen name="widget_container_inset">8dp</dimen>
     <dimen name="widget_preview_label_vertical_padding">8dp</dimen>
     <dimen name="widget_preview_label_horizontal_padding">8dp</dimen>
index 6daa452..2838a22 100644 (file)
@@ -56,7 +56,7 @@
 
     <!-- All Apps -->
     <!-- Search bar text in the apps view. [CHAR_LIMIT=50] -->
-    <string name="all_apps_search_bar_hint">Search Apps</string>
+    <string name="all_apps_search_bar_hint">Search Apps&#8230;</string>
     <!-- Loading apps text. [CHAR_LIMIT=50] -->
     <string name="all_apps_loading_message">Loading Apps&#8230;</string>
     <!-- No-search-results text. [CHAR_LIMIT=50] -->
index c118240..8bb8c55 100644 (file)
 package com.android.launcher3;
 
 import android.content.Context;
+import android.content.res.TypedArray;
 import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.InsetDrawable;
 import android.util.AttributeSet;
 import android.util.Log;
-import android.widget.LinearLayout;
+import android.view.View;
+import android.widget.FrameLayout;
 
 /**
  * A base container view, which supports resizing.
  */
-public abstract class BaseContainerView extends LinearLayout implements Insettable {
+public abstract class BaseContainerView extends FrameLayout implements Insettable {
 
     private final static String TAG = "BaseContainerView";
 
     // The window insets
-    private Rect mInsets = new Rect();
+    private final Rect mInsets = new Rect();
     // The bounds of the search bar.  Only the left, top, right are used to inset the
     // search bar and the height is determined by the measurement of the layout
-    private Rect mFixedSearchBarBounds = new Rect();
-    // The computed bounds of the search bar
-    private Rect mSearchBarBounds = new Rect();
+    private final Rect mFixedSearchBarBounds = new Rect();
     // The computed bounds of the container
-    protected Rect mContentBounds = new Rect();
+    protected final Rect mContentBounds = new Rect();
     // The computed padding to apply to the container to achieve the container bounds
-    private Rect mContentPadding = new Rect();
+    private final Rect mContentPadding = new Rect();
     // The inset to apply to the edges and between the search bar and the container
-    private int mContainerBoundsInset;
-    private boolean mHasSearchBar;
+    private final int mContainerBoundsInset;
+
+    private final Drawable mRevealDrawable;
+
+    private View mRevealView;
+    private View mContent;
 
     public BaseContainerView(Context context) {
         this(context, null);
@@ -55,6 +61,19 @@ public abstract class BaseContainerView extends LinearLayout implements Insettab
     public BaseContainerView(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
         mContainerBoundsInset = getResources().getDimensionPixelSize(R.dimen.container_bounds_inset);
+
+        TypedArray a = context.obtainStyledAttributes(attrs,
+                R.styleable.BaseContainerView, defStyleAttr, 0);
+        mRevealDrawable = a.getDrawable(R.styleable.BaseContainerView_revealBackground);
+        a.recycle();
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+
+        mContent = findViewById(R.id.main_content);
+        mRevealView = findViewById(R.id.reveal_view);
     }
 
     @Override
@@ -63,10 +82,6 @@ public abstract class BaseContainerView extends LinearLayout implements Insettab
         updateBackgroundAndPaddings();
     }
 
-    protected void setHasSearchBar() {
-        mHasSearchBar = true;
-    }
-
     /**
      * Sets the search bar bounds for this container view to match.
      */
@@ -92,47 +107,48 @@ public abstract class BaseContainerView extends LinearLayout implements Insettab
      */
     protected void updateBackgroundAndPaddings() {
         Rect padding;
-        Rect searchBarBounds = new Rect();
-        if (!isValidSearchBarBounds(mFixedSearchBarBounds)) {
-            // Use the default bounds
-            padding = new Rect(mInsets.left + mContainerBoundsInset,
-                    (mHasSearchBar ? 0 : (mInsets.top + mContainerBoundsInset)),
-                    mInsets.right + mContainerBoundsInset,
-                    mInsets.bottom + mContainerBoundsInset);
-
-            // Special case -- we have the search bar, but no specific bounds, so just give it
-            // the inset bounds without a height.
-            searchBarBounds.set(mInsets.left + mContainerBoundsInset,
+        if (isValidSearchBarBounds(mFixedSearchBarBounds)) {
+            padding = new Rect(
+                    mFixedSearchBarBounds.left,
                     mInsets.top + mContainerBoundsInset,
-                    getMeasuredWidth() - (mInsets.right + mContainerBoundsInset), 0);
-        } else {
-            // Use the search bounds, if there is a search bar, the bounds will contain
-            // the offsets for the insets so we can ignore that
-            padding = new Rect(mFixedSearchBarBounds.left,
-                    (mHasSearchBar ? 0 : (mInsets.top + mContainerBoundsInset)),
                     getMeasuredWidth() - mFixedSearchBarBounds.right,
-                    mInsets.bottom + mContainerBoundsInset);
-
-            // Use the search bounds
-            searchBarBounds.set(mFixedSearchBarBounds);
+                    mInsets.bottom + mContainerBoundsInset
+            );
+        } else {
+            padding = new Rect(
+                    mInsets.left + mContainerBoundsInset,
+                    mInsets.top + mContainerBoundsInset,
+                    mInsets.right + mContainerBoundsInset,
+                    mInsets.bottom + mContainerBoundsInset
+            );
         }
 
-        // If either the computed container padding has changed, or the computed search bar bounds
-        // has changed, then notify the container
-        if (!padding.equals(mContentPadding) || !searchBarBounds.equals(mSearchBarBounds)) {
+        // The container padding changed, notify the container.
+        if (!padding.equals(mContentPadding)) {
             mContentPadding.set(padding);
             mContentBounds.set(padding.left, padding.top,
                     getMeasuredWidth() - padding.right,
                     getMeasuredHeight() - padding.bottom);
-            mSearchBarBounds.set(searchBarBounds);
-            onUpdateBackgroundAndPaddings(mSearchBarBounds, padding);
+            onUpdateBackgroundAndPaddings(padding);
         }
     }
 
-    /**
-     * To be implemented by container views to update themselves when the bounds changes.
-     */
-    protected abstract void onUpdateBackgroundAndPaddings(Rect searchBarBounds, Rect padding);
+    private void onUpdateBackgroundAndPaddings(Rect padding) {
+        // Apply the top-bottom padding to itself so that the launcher transition is
+        // clipped correctly
+        setPadding(0, padding.top, 0, padding.bottom);
+
+        InsetDrawable background = new InsetDrawable(mRevealDrawable,
+                padding.left, 0, padding.right, 0);
+        mRevealView.setBackground(background.getConstantState().newDrawable());
+        mContent.setBackground(background);
+
+        Rect bgPadding = new Rect();
+        background.getPadding(bgPadding);
+        onUpdateBgPadding(padding, bgPadding);
+    }
+
+    protected abstract void onUpdateBgPadding(Rect padding, Rect bgPadding);
 
     /**
      * Returns whether the search bar bounds we got are considered valid.
@@ -142,4 +158,12 @@ public abstract class BaseContainerView extends LinearLayout implements Insettab
                 searchBarBounds.right <= getMeasuredWidth() &&
                 searchBarBounds.bottom <= getMeasuredHeight();
     }
+
+    public final View getContentView() {
+        return mContent;
+    }
+
+    public final View getRevealView() {
+        return mRevealView;
+    }
 }
\ No newline at end of file
index 0599eb8..987698e 100644 (file)
@@ -97,6 +97,7 @@ import android.widget.Toast;
 import com.android.launcher3.DropTarget.DragObject;
 import com.android.launcher3.PagedView.PageSwitchListener;
 import com.android.launcher3.allapps.AllAppsContainerView;
+import com.android.launcher3.allapps.DefaultAppSearchController;
 import com.android.launcher3.compat.AppWidgetManagerCompat;
 import com.android.launcher3.compat.LauncherActivityInfoCompat;
 import com.android.launcher3.compat.LauncherAppsCompat;
@@ -1408,7 +1409,7 @@ public class Launcher extends Activity
         if (mLauncherCallbacks != null && mLauncherCallbacks.getAllAppsSearchBarController() != null) {
             mAppsView.setSearchBarController(mLauncherCallbacks.getAllAppsSearchBarController());
         } else {
-            mAppsView.setSearchBarController(mAppsView.newDefaultAppSearchController());
+            mAppsView.setSearchBarController(new DefaultAppSearchController());
         }
 
         // Setup the drag controller (drop targets have to be added in reverse order in priority)
index 83b12a9..30cae31 100644 (file)
@@ -80,13 +80,18 @@ import java.util.HashMap;
  */
 public class LauncherStateTransitionAnimation {
 
+    private static final float FINAL_REVEAL_ALPHA_FOR_WIDGETS = 0.3f;
+
     /**
      * Private callbacks made during transition setup.
      */
-    static abstract class PrivateTransitionCallbacks {
-        float getMaterialRevealViewFinalAlpha(View revealView) {
-            return 0;
+    private static class PrivateTransitionCallbacks {
+        private final float materialRevealViewFinalAlpha;
+
+        PrivateTransitionCallbacks(float revealAlpha) {
+            materialRevealViewFinalAlpha = revealAlpha;
         }
+
         float getMaterialRevealViewStartFinalRadius() {
             return 0;
         }
@@ -97,7 +102,7 @@ public class LauncherStateTransitionAnimation {
         void onTransitionComplete() {}
     }
 
-    public static final String TAG = "LauncherStateTransitionAnimation";
+    public static final String TAG = "LSTAnimation";
 
     // Flags to determine how to set the layers on views before the transition animation
     public static final int BUILD_LAYER = 0;
@@ -121,11 +126,7 @@ public class LauncherStateTransitionAnimation {
             final boolean animated, final boolean startSearchAfterTransition) {
         final AllAppsContainerView toView = mLauncher.getAppsView();
         final View buttonView = mLauncher.getAllAppsButton();
-        PrivateTransitionCallbacks cb = new PrivateTransitionCallbacks() {
-            @Override
-            public float getMaterialRevealViewFinalAlpha(View revealView) {
-                return 1f;
-            }
+        PrivateTransitionCallbacks cb = new PrivateTransitionCallbacks(1f) {
             @Override
             public float getMaterialRevealViewStartFinalRadius() {
                 int allAppsButtonSize = mLauncher.getDeviceProfile().allAppsButtonVisualSize;
@@ -152,8 +153,7 @@ public class LauncherStateTransitionAnimation {
         };
         // Only animate the search bar if animating from spring loaded mode back to all apps
         mCurrentAnimation = startAnimationToOverlay(fromWorkspaceState,
-                Workspace.State.NORMAL_HIDDEN, buttonView, toView, toView.getContentView(),
-                toView.getRevealView(), toView.getSearchBarView(), animated, cb);
+                Workspace.State.NORMAL_HIDDEN, buttonView, toView, animated, cb);
     }
 
     /**
@@ -164,15 +164,9 @@ public class LauncherStateTransitionAnimation {
         final WidgetsContainerView toView = mLauncher.getWidgetsView();
         final View buttonView = mLauncher.getWidgetsButton();
 
-        PrivateTransitionCallbacks cb = new PrivateTransitionCallbacks() {
-            @Override
-            public float getMaterialRevealViewFinalAlpha(View revealView) {
-                return 0.3f;
-            }
-        };
         mCurrentAnimation = startAnimationToOverlay(fromWorkspaceState,
-                Workspace.State.OVERVIEW_HIDDEN, buttonView, toView, toView.getContentView(),
-                toView.getRevealView(), null, animated, cb);
+                Workspace.State.OVERVIEW_HIDDEN, buttonView, toView, animated,
+                new PrivateTransitionCallbacks(FINAL_REVEAL_ALPHA_FOR_WIDGETS));
     }
 
     /**
@@ -200,16 +194,15 @@ public class LauncherStateTransitionAnimation {
      * Creates and starts a new animation to a particular overlay view.
      */
     @SuppressLint("NewApi")
-    private AnimatorSet startAnimationToOverlay(final Workspace.State fromWorkspaceState,
-            final Workspace.State toWorkspaceState, final View buttonView, final View toView,
-            final View contentView, final View revealView, final View overlaySearchBarView,
+    private AnimatorSet startAnimationToOverlay(
+            final Workspace.State fromWorkspaceState, final Workspace.State toWorkspaceState,
+            final View buttonView, final BaseContainerView toView,
             final boolean animated, final PrivateTransitionCallbacks pCb) {
         final AnimatorSet animation = LauncherAnimUtils.createAnimatorSet();
         final Resources res = mLauncher.getResources();
         final boolean material = Utilities.ATLEAST_LOLLIPOP;
         final int revealDuration = res.getInteger(R.integer.config_overlayRevealTime);
-        final int itemsAlphaStagger =
-                res.getInteger(R.integer.config_overlayItemsAlphaStagger);
+        final int itemsAlphaStagger = res.getInteger(R.integer.config_overlayItemsAlphaStagger);
 
         final View fromView = mLauncher.getWorkspace();
 
@@ -227,13 +220,17 @@ public class LauncherStateTransitionAnimation {
                 animated, layerViews);
 
         // Animate the search bar
-        startWorkspaceSearchBarAnimation(animation, fromWorkspaceState, toWorkspaceState,
-                animated ? revealDuration : 0, overlaySearchBarView);
+        startWorkspaceSearchBarAnimation(
+                toWorkspaceState, animated ? revealDuration : 0, animation);
 
         Animator updateTransitionStepAnim = dispatchOnLauncherTransitionStepAnim(fromView, toView);
 
+        final View contentView = toView.getContentView();
+
         if (animated && initialized) {
             // Setup the reveal view animation
+            final View revealView = toView.getRevealView();
+
             int width = revealView.getMeasuredWidth();
             int height = revealView.getMeasuredHeight();
             float revealRadius = (float) Math.hypot(width / 2, height / 2);
@@ -247,9 +244,9 @@ public class LauncherStateTransitionAnimation {
             final float revealViewToXDrift;
             final float revealViewToYDrift;
             if (material) {
-                int[] buttonViewToPanelDelta = Utilities.getCenterDeltaInScreenSpace(revealView,
-                        buttonView, null);
-                revealViewToAlpha = pCb.getMaterialRevealViewFinalAlpha(revealView);
+                int[] buttonViewToPanelDelta = Utilities.getCenterDeltaInScreenSpace(
+                        revealView, buttonView, null);
+                revealViewToAlpha = pCb.materialRevealViewFinalAlpha;
                 revealViewToYDrift = buttonViewToPanelDelta[1];
                 revealViewToXDrift = buttonViewToPanelDelta[0];
             } else {
@@ -274,15 +271,6 @@ public class LauncherStateTransitionAnimation {
             layerViews.put(revealView, BUILD_AND_SET_LAYER);
             animation.play(panelAlphaAndDrift);
 
-            if (overlaySearchBarView != null) {
-                overlaySearchBarView.setAlpha(0f);
-                ObjectAnimator searchBarAlpha = ObjectAnimator.ofFloat(overlaySearchBarView, "alpha", 0f, 1f);
-                searchBarAlpha.setDuration(revealDuration / 2);
-                searchBarAlpha.setInterpolator(new AccelerateInterpolator(1.5f));
-                layerViews.put(overlaySearchBarView, BUILD_AND_SET_LAYER);
-                animation.play(searchBarAlpha);
-            }
-
             // Setup the animation for the content view
             contentView.setVisibility(View.VISIBLE);
             contentView.setAlpha(0f);
@@ -430,12 +418,8 @@ public class LauncherStateTransitionAnimation {
             final Workspace.State toWorkspaceState, final int toWorkspacePage,
             final boolean animated, final Runnable onCompleteRunnable) {
         AllAppsContainerView appsView = mLauncher.getAppsView();
-        PrivateTransitionCallbacks cb = new PrivateTransitionCallbacks() {
-            @Override
-            float getMaterialRevealViewFinalAlpha(View revealView) {
-                // No alpha anim from all apps
-                return 1f;
-            }
+        // No alpha anim from all apps
+        PrivateTransitionCallbacks cb = new PrivateTransitionCallbacks(1f) {
             @Override
             float getMaterialRevealViewStartFinalRadius() {
                 int allAppsButtonSize = mLauncher.getDeviceProfile().allAppsButtonVisualSize;
@@ -463,9 +447,8 @@ public class LauncherStateTransitionAnimation {
         };
         // Only animate the search bar if animating to spring loaded mode from all apps
         mCurrentAnimation = startAnimationToWorkspaceFromOverlay(fromWorkspaceState, toWorkspaceState,
-                toWorkspacePage, mLauncher.getAllAppsButton(), appsView, appsView.getContentView(),
-                appsView.getRevealView(), appsView.getSearchBarView(), animated,
-                onCompleteRunnable, cb);
+                toWorkspacePage, mLauncher.getAllAppsButton(), appsView,
+                animated, onCompleteRunnable, cb);
     }
 
     /**
@@ -475,11 +458,8 @@ public class LauncherStateTransitionAnimation {
             final Workspace.State toWorkspaceState, final int toWorkspacePage,
             final boolean animated, final Runnable onCompleteRunnable) {
         final WidgetsContainerView widgetsView = mLauncher.getWidgetsView();
-        PrivateTransitionCallbacks cb = new PrivateTransitionCallbacks() {
-            @Override
-            float getMaterialRevealViewFinalAlpha(View revealView) {
-                return 0.3f;
-            }
+        PrivateTransitionCallbacks cb =
+                new PrivateTransitionCallbacks(FINAL_REVEAL_ALPHA_FOR_WIDGETS) {
             @Override
             public AnimatorListenerAdapter getMaterialRevealViewAnimatorListener(
                     final View revealView, final View widgetsButtonView) {
@@ -491,19 +471,20 @@ public class LauncherStateTransitionAnimation {
                 };
             }
         };
-        mCurrentAnimation = startAnimationToWorkspaceFromOverlay(fromWorkspaceState,
-                toWorkspaceState, toWorkspacePage, mLauncher.getWidgetsButton(), widgetsView,
-                widgetsView.getContentView(), widgetsView.getRevealView(), null, animated,
-                onCompleteRunnable, cb);
+        mCurrentAnimation = startAnimationToWorkspaceFromOverlay(
+                fromWorkspaceState, toWorkspaceState,
+                toWorkspacePage, mLauncher.getWidgetsButton(), widgetsView,
+                animated, onCompleteRunnable, cb);
     }
 
     /**
      * Creates and starts a new animation to the workspace.
      */
-    private AnimatorSet startAnimationToWorkspaceFromOverlay(final Workspace.State fromWorkspaceState,
-            final Workspace.State toWorkspaceState, final int toWorkspacePage, final View buttonView,
-            final View fromView, final View contentView, final View revealView,
-            final View overlaySearchBarView, final boolean animated, final Runnable onCompleteRunnable,
+    private AnimatorSet startAnimationToWorkspaceFromOverlay(
+            final Workspace.State fromWorkspaceState, final Workspace.State toWorkspaceState,
+            final int toWorkspacePage,
+            final View buttonView, final BaseContainerView fromView,
+            final boolean animated, final Runnable onCompleteRunnable,
             final PrivateTransitionCallbacks pCb) {
         final AnimatorSet animation = LauncherAnimUtils.createAnimatorSet();
         final Resources res = mLauncher.getResources();
@@ -528,8 +509,8 @@ public class LauncherStateTransitionAnimation {
                 toWorkspacePage, animated, layerViews);
 
         // Animate the search bar
-        startWorkspaceSearchBarAnimation(animation, fromWorkspaceState, toWorkspaceState,
-                animated ? revealDuration : 0, overlaySearchBarView);
+        startWorkspaceSearchBarAnimation(
+                toWorkspaceState, animated ? revealDuration : 0, animation);
 
         Animator updateTransitionStepAnim = dispatchOnLauncherTransitionStepAnim(fromView, toView);
 
@@ -540,6 +521,8 @@ public class LauncherStateTransitionAnimation {
             }
 
             animation.play(updateTransitionStepAnim);
+            final View revealView = fromView.getRevealView();
+            final View contentView = fromView.getContentView();
 
             // hideAppsCustomizeHelper is called in some cases when it is already hidden
             // don't perform all these no-op animations. In particularly, this was causing
@@ -588,7 +571,7 @@ public class LauncherStateTransitionAnimation {
 
                 // Setup animation for the reveal panel alpha
                 final float revealViewToAlpha = !material ? 0f :
-                        pCb.getMaterialRevealViewFinalAlpha(revealView);
+                        pCb.materialRevealViewFinalAlpha;
                 if (revealViewToAlpha != 1f) {
                     ObjectAnimator panelAlpha = ObjectAnimator.ofFloat(revealView, "alpha",
                             1f, revealViewToAlpha);
@@ -616,16 +599,6 @@ public class LauncherStateTransitionAnimation {
                 itemsAlpha.setInterpolator(decelerateInterpolator);
                 animation.play(itemsAlpha);
 
-                if (overlaySearchBarView != null) {
-                    overlaySearchBarView.setAlpha(1f);
-                    ObjectAnimator searchAlpha = ObjectAnimator.ofFloat(overlaySearchBarView, "alpha", 1f, 0f);
-                    searchAlpha.setDuration(revealDuration / 2);
-                    searchAlpha.setInterpolator(new AccelerateInterpolator(1.5f));
-                    searchAlpha.setStartDelay(material ? 0 : itemsAlphaStagger + SINGLE_FRAME_DELAY);
-                    layerViews.put(overlaySearchBarView, BUILD_AND_SET_LAYER);
-                    animation.play(searchAlpha);
-                }
-
                 if (material) {
                     // Animate the all apps button
                     float finalRadius = pCb.getMaterialRevealViewStartFinalRadius();
@@ -671,9 +644,6 @@ public class LauncherStateTransitionAnimation {
                         contentView.setTranslationY(0);
                         contentView.setAlpha(1);
                     }
-                    if (overlaySearchBarView != null) {
-                        overlaySearchBarView.setAlpha(1f);
-                    }
 
                     // This can hold unnecessary references to views.
                     cleanupAnimation();
@@ -729,36 +699,11 @@ public class LauncherStateTransitionAnimation {
     /**
      * Coordinates the workspace search bar animation along with the launcher state animation.
      */
-    private void startWorkspaceSearchBarAnimation(AnimatorSet animation,
-            final Workspace.State fromWorkspaceState, final Workspace.State toWorkspaceState, int duration,
-            View overlaySearchBar) {
+    private void startWorkspaceSearchBarAnimation(
+            final Workspace.State toWorkspaceState, int duration, AnimatorSet animation) {
         final SearchDropTargetBar.State toSearchBarState =
                 toWorkspaceState.getSearchDropTargetBarState();
-
-        if (overlaySearchBar != null) {
-            if (mLauncher.launcherCallbacksProvidesSearch()) {
-                if ((toWorkspaceState == Workspace.State.NORMAL) &&
-                        (fromWorkspaceState == Workspace.State.NORMAL_HIDDEN)) {
-                    // If we are transitioning from the overlay to the workspace, then show the
-                    // workspace search bar immediately and let the overlay search bar fade out on
-                    // top
-                    mLauncher.getSearchDropTargetBar().animateToState(toSearchBarState, 0);
-                    return;
-                } else if (fromWorkspaceState == Workspace.State.NORMAL) {
-                    // If we are transitioning from the workspace to the overlay, then keep the
-                    // workspace search bar visible until the overlay search bar fades in on top
-                    animation.addListener(new AnimatorListenerAdapter() {
-                        @Override
-                        public void onAnimationEnd(Animator animation) {
-                            mLauncher.getSearchDropTargetBar().animateToState(toSearchBarState, 0);
-                        }
-                    });
-                    return;
-                }
-            }
-        }
-        // Fallback to the default search bar animation otherwise
-        mLauncher.getSearchDropTargetBar().animateToState(toSearchBarState, duration);
+        mLauncher.getSearchDropTargetBar().animateToState(toSearchBarState, duration, animation);
     }
 
     /**
index aad6dbc..f7288a0 100644 (file)
@@ -18,12 +18,18 @@ package com.android.launcher3;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.TimeInterpolator;
 import android.content.Context;
 import android.graphics.Rect;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.view.View;
 import android.view.accessibility.AccessibilityManager;
+import android.view.animation.AccelerateDecelerateInterpolator;
 import android.view.animation.AccelerateInterpolator;
+import android.view.animation.DecelerateInterpolator;
 import android.widget.FrameLayout;
 
 import com.android.launcher3.util.Thunk;
@@ -34,35 +40,32 @@ import com.android.launcher3.util.Thunk;
  */
 public class SearchDropTargetBar extends FrameLayout implements DragController.DragListener {
 
+    private static final TimeInterpolator MOVE_DOWN_INTERPOLATOR = new DecelerateInterpolator(0.6f);
+    private static final TimeInterpolator MOVE_UP_INTERPOLATOR = new DecelerateInterpolator(1.5f);
+    private static final TimeInterpolator DEFAULT_INTERPOLATOR = new AccelerateInterpolator();
+
     /** The different states that the search bar space can be in. */
     public enum State {
-        INVISIBLE   (0f, 0f),
-        SEARCH_BAR  (1f, 0f),
-        DROP_TARGET (0f, 1f);
+        INVISIBLE             (0f, 0f, 0f),
+        INVISIBLE_TRANSLATED  (0f, 0f, -1f),
+        SEARCH_BAR            (1f, 0f, 0f),
+        DROP_TARGET           (0f, 1f, 0f);
 
         private final float mSearchBarAlpha;
         private final float mDropTargetBarAlpha;
+        private final float mTranslation;
 
-        State(float sbAlpha, float dtbAlpha) {
+        State(float sbAlpha, float dtbAlpha, float translation) {
             mSearchBarAlpha = sbAlpha;
             mDropTargetBarAlpha = dtbAlpha;
+            mTranslation = translation;
         }
 
-        float getSearchBarAlpha() {
-            return mSearchBarAlpha;
-        }
-
-        float getDropTargetBarAlpha() {
-            return mDropTargetBarAlpha;
-        }
     }
 
     private static int DEFAULT_DRAG_FADE_DURATION = 175;
 
-    private LauncherViewPropertyAnimator mDropTargetBarAnimator;
-    private LauncherViewPropertyAnimator mQSBSearchBarAnimator;
-    private static final AccelerateInterpolator sAccelerateInterpolator =
-            new AccelerateInterpolator();
+    private AnimatorSet mCurrentAnimation;
 
     private State mState = State.SEARCH_BAR;
     @Thunk View mQSB;
@@ -117,50 +120,10 @@ public class SearchDropTargetBar extends FrameLayout implements DragController.D
         // Create the various fade animations
         mDropTargetBar.setAlpha(0f);
         AlphaUpdateListener.updateVisibility(mDropTargetBar, mAccessibilityEnabled);
-
-        mDropTargetBarAnimator = new LauncherViewPropertyAnimator(mDropTargetBar);
-        mDropTargetBarAnimator.setInterpolator(sAccelerateInterpolator);
-        mDropTargetBarAnimator.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationStart(Animator animation) {
-                // Ensure that the view is visible for the animation
-                mDropTargetBar.setVisibility(View.VISIBLE);
-            }
-
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                if (mDropTargetBar != null) {
-                    AlphaUpdateListener.updateVisibility(mDropTargetBar, mAccessibilityEnabled);
-                }
-            }
-        });
     }
 
     public void setQsbSearchBar(View qsb) {
         mQSB = qsb;
-        if (mQSB != null) {
-            // Update the search ber animation
-            mQSBSearchBarAnimator = new LauncherViewPropertyAnimator(mQSB);
-            mQSBSearchBarAnimator.setInterpolator(sAccelerateInterpolator);
-            mQSBSearchBarAnimator.addListener(new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationStart(Animator animation) {
-                    // Ensure that the view is visible for the animation
-                    if (mQSB != null) {
-                        mQSB.setVisibility(View.VISIBLE);
-                    }
-                }
-
-                @Override
-                public void onAnimationEnd(Animator animation) {
-                    if (mQSB != null) {
-                        AlphaUpdateListener.updateVisibility(mQSB, mAccessibilityEnabled);
-                    }
-                }
-            });
-        } else {
-            mQSBSearchBarAnimator = null;
-        }
     }
 
     /**
@@ -168,6 +131,10 @@ public class SearchDropTargetBar extends FrameLayout implements DragController.D
      * the state is applied immediately.
      */
     public void animateToState(State newState, int duration) {
+        animateToState(newState, duration, null);
+    }
+
+    public void animateToState(State newState, int duration, AnimatorSet animation) {
         if (mState != newState) {
             mState = newState;
 
@@ -176,33 +143,66 @@ public class SearchDropTargetBar extends FrameLayout implements DragController.D
                     getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
             mAccessibilityEnabled = am.isEnabled();
 
-            animateViewAlpha(mQSBSearchBarAnimator, mQSB, newState.getSearchBarAlpha(),
-                    duration);
-            animateViewAlpha(mDropTargetBarAnimator, mDropTargetBar, newState.getDropTargetBarAlpha(),
-                    duration);
-        }
-    }
-
-    /**
-     * Convenience method to animate the alpha of a view using hardware layers.
-     */
-    private void animateViewAlpha(LauncherViewPropertyAnimator animator, View v, float alpha,
-            int duration) {
-        if (v == null) {
-            return;
-        }
+            if (mCurrentAnimation != null) {
+                mCurrentAnimation.cancel();
+                mCurrentAnimation = null;
+            }
+            mCurrentAnimation = null;
 
-        animator.cancel();
-        if (Float.compare(v.getAlpha(), alpha) != 0) {
             if (duration > 0) {
-                animator.alpha(alpha).withLayer().setDuration(duration).start();
+                mCurrentAnimation = new AnimatorSet();
+                mCurrentAnimation.setDuration(duration);
+
+                animateAlpha(mDropTargetBar, mState.mDropTargetBarAlpha, DEFAULT_INTERPOLATOR);
             } else {
-                v.setAlpha(alpha);
-                AlphaUpdateListener.updateVisibility(v, mAccessibilityEnabled);
+                mDropTargetBar.setAlpha(mState.mDropTargetBarAlpha);
+                AlphaUpdateListener.updateVisibility(mDropTargetBar, mAccessibilityEnabled);
+            }
+
+            if (mQSB != null) {
+                boolean isVertical = ((Launcher) getContext()).getDeviceProfile()
+                        .isVerticalBarLayout();
+                float translation = isVertical ? 0 : mState.mTranslation * getMeasuredHeight();
+
+                if (duration > 0) {
+                    int translationChange = Float.compare(mQSB.getTranslationY(), translation);
+
+                    animateAlpha(mQSB, mState.mSearchBarAlpha,
+                            translationChange == 0 ? DEFAULT_INTERPOLATOR
+                                    : (translationChange < 0 ? MOVE_DOWN_INTERPOLATOR
+                                    : MOVE_UP_INTERPOLATOR));
+
+                    if (translationChange != 0) {
+                        mCurrentAnimation.play(
+                                ObjectAnimator.ofFloat(mQSB, View.TRANSLATION_Y, translation));
+                    }
+                } else {
+                    mQSB.setTranslationY(translation);
+                    mQSB.setAlpha(mState.mSearchBarAlpha);
+                    AlphaUpdateListener.updateVisibility(mQSB, mAccessibilityEnabled);
+                }
+            }
+
+            // Start the final animation
+            if (duration > 0) {
+                if (animation != null) {
+                    animation.play(mCurrentAnimation);
+                } else {
+                    mCurrentAnimation.start();
+                }
             }
         }
     }
 
+    private void animateAlpha(View v, float alpha, TimeInterpolator interpolator) {
+        if (Float.compare(v.getAlpha(), alpha) != 0) {
+            ObjectAnimator anim = ObjectAnimator.ofFloat(v, View.ALPHA, alpha);
+            anim.setInterpolator(interpolator);
+            anim.addListener(new ViewVisiblilyUpdateHandler(v));
+            mCurrentAnimation.play(anim);
+        }
+    }
+
     /*
      * DragController.DragListener implementation
      */
@@ -255,4 +255,24 @@ public class SearchDropTargetBar extends FrameLayout implements DragController.D
         mDeleteDropTarget.enableAccessibleDrag(enable);
         mUninstallDropTarget.enableAccessibleDrag(enable);
     }
+
+    private class ViewVisiblilyUpdateHandler extends AnimatorListenerAdapter {
+        private final View mView;
+
+        ViewVisiblilyUpdateHandler(View v) {
+            mView = v;
+        }
+
+        @Override
+        public void onAnimationStart(Animator animation) {
+            // Ensure that the view is visible for the animation
+            mView.setVisibility(View.VISIBLE);
+        }
+
+        @Override
+        public void onAnimationEnd(Animator animation){
+            AlphaUpdateListener.updateVisibility(mView, mAccessibilityEnabled);
+        }
+
+    }
 }
index 56801ff..7b873d4 100644 (file)
@@ -181,7 +181,7 @@ public class Workspace extends PagedView
 
     enum State {
         NORMAL          (SearchDropTargetBar.State.SEARCH_BAR),
-        NORMAL_HIDDEN   (SearchDropTargetBar.State.INVISIBLE),
+        NORMAL_HIDDEN   (SearchDropTargetBar.State.INVISIBLE_TRANSLATED),
         SPRING_LOADED   (SearchDropTargetBar.State.DROP_TARGET),
         OVERVIEW        (SearchDropTargetBar.State.INVISIBLE),
         OVERVIEW_HIDDEN (SearchDropTargetBar.State.INVISIBLE);
index f9bb134..8f8858f 100644 (file)
@@ -17,11 +17,9 @@ package com.android.launcher3.allapps;
 
 import android.annotation.SuppressLint;
 import android.content.Context;
-import android.content.Intent;
 import android.content.res.Resources;
 import android.graphics.Point;
 import android.graphics.Rect;
-import android.graphics.drawable.InsetDrawable;
 import android.support.v7.widget.RecyclerView;
 import android.text.Selection;
 import android.text.SpannableStringBuilder;
@@ -32,8 +30,7 @@ import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewConfiguration;
-import android.view.ViewGroup;
-import android.widget.LinearLayout;
+
 import com.android.launcher3.AppInfo;
 import com.android.launcher3.BaseContainerView;
 import com.android.launcher3.BubbleTextView;
@@ -42,6 +39,7 @@ import com.android.launcher3.DeleteDropTarget;
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.DragSource;
 import com.android.launcher3.DropTarget;
+import com.android.launcher3.ExtendedEditText;
 import com.android.launcher3.Folder;
 import com.android.launcher3.ItemInfo;
 import com.android.launcher3.Launcher;
@@ -50,7 +48,6 @@ import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.Workspace;
 import com.android.launcher3.util.ComponentKey;
-import com.android.launcher3.util.Thunk;
 
 import java.nio.charset.Charset;
 import java.nio.charset.CharsetEncoder;
@@ -135,19 +132,19 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
     private static final int MIN_ROWS_IN_MERGED_SECTION_PHONE = 3;
     private static final int MAX_NUM_MERGES_PHONE = 2;
 
-    @Thunk Launcher mLauncher;
-    @Thunk AlphabeticalAppsList mApps;
-    private AllAppsGridAdapter mAdapter;
-    private RecyclerView.LayoutManager mLayoutManager;
-    private RecyclerView.ItemDecoration mItemDecoration;
-
-    @Thunk View mContent;
-    @Thunk View mContainerView;
-    @Thunk View mRevealView;
-    @Thunk AllAppsRecyclerView mAppsRecyclerView;
-    @Thunk AllAppsSearchBarController mSearchBarController;
-    private ViewGroup mSearchBarContainerView;
-    private View mSearchBarView;
+    private final Launcher mLauncher;
+    private final AlphabeticalAppsList mApps;
+    private final AllAppsGridAdapter mAdapter;
+    private final RecyclerView.LayoutManager mLayoutManager;
+    private final RecyclerView.ItemDecoration mItemDecoration;
+
+    private AllAppsRecyclerView mAppsRecyclerView;
+    private AllAppsSearchBarController mSearchBarController;
+
+    private View mSearchContainer;
+    private ExtendedEditText mSearchInput;
+    private HeaderElevationController mElevationController;
+
     private SpannableStringBuilder mSearchQueryBuilder = null;
 
     private int mSectionNamesMargin;
@@ -159,14 +156,6 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
     // This coordinate is relative to its parent
     private final Point mIconLastTouchPos = new Point();
 
-    private View.OnClickListener mSearchClickListener = new View.OnClickListener() {
-        @Override
-        public void onClick(View v) {
-            Intent searchIntent = (Intent) v.getTag();
-            mLauncher.startActivitySafely(v, searchIntent, null);
-        }
-    };
-
     public AllAppsContainerView(Context context) {
         this(context, null);
     }
@@ -236,14 +225,7 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
             throw new RuntimeException("Expected search bar controller to only be set once");
         }
         mSearchBarController = searchController;
-        mSearchBarController.initialize(mApps, this);
-
-        // Add the new search view to the layout
-        View searchBarView = searchController.getView(mSearchBarContainerView);
-        mSearchBarContainerView.addView(searchBarView);
-        mSearchBarContainerView.setVisibility(View.VISIBLE);
-        mSearchBarView = searchBarView;
-        setHasSearchBar();
+        mSearchBarController.initialize(mApps, mSearchInput, mAppsRecyclerView, this);
 
         updateBackgroundAndPaddings();
     }
@@ -256,34 +238,6 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
     }
 
     /**
-     * Returns the content view used for the launcher transitions.
-     */
-    public View getContentView() {
-        return mContainerView;
-    }
-
-    /**
-     * Returns the all apps search view.
-     */
-    public View getSearchBarView() {
-        return mSearchBarView;
-    }
-
-    /**
-     * Returns the reveal view used for the launcher transitions.
-     */
-    public View getRevealView() {
-        return mRevealView;
-    }
-
-    /**
-     * Returns an new instance of the default app search controller.
-     */
-    public AllAppsSearchBarController newDefaultAppSearchController() {
-        return new DefaultAppSearchController(getContext(), this, mAppsRecyclerView);
-    }
-
-    /**
      * Focuses the search field and begins an app search.
      */
     public void startAppsSearch() {
@@ -304,25 +258,24 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
-        boolean isRtl = Utilities.isRtl(getResources());
-        mAdapter.setRtl(isRtl);
-        mContent = findViewById(R.id.content);
+        mAdapter.setRtl(Utilities.isRtl(getResources()));
 
         // This is a focus listener that proxies focus from a view into the list view.  This is to
         // work around the search box from getting first focus and showing the cursor.
-        View.OnFocusChangeListener focusProxyListener = new View.OnFocusChangeListener() {
+        getContentView().setOnFocusChangeListener(new View.OnFocusChangeListener() {
             @Override
             public void onFocusChange(View v, boolean hasFocus) {
                 if (hasFocus) {
                     mAppsRecyclerView.requestFocus();
                 }
             }
-        };
-        mSearchBarContainerView = (ViewGroup) findViewById(R.id.search_box_container);
-        mSearchBarContainerView.setOnFocusChangeListener(focusProxyListener);
-        mContainerView = findViewById(R.id.all_apps_container);
-        mContainerView.setOnFocusChangeListener(focusProxyListener);
-        mRevealView = findViewById(R.id.all_apps_reveal);
+        });
+
+        mSearchContainer = findViewById(R.id.search_container);
+        mSearchInput = (ExtendedEditText) findViewById(R.id.search_box_input);
+        mElevationController = Utilities.ATLEAST_LOLLIPOP
+                ? new HeaderElevationController.ControllerVL(mSearchContainer)
+                : new HeaderElevationController.ControllerV16(mSearchContainer);
 
         // Load the all apps recycler view
         mAppsRecyclerView = (AllAppsRecyclerView) findViewById(R.id.apps_list_view);
@@ -330,22 +283,28 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
         mAppsRecyclerView.setLayoutManager(mLayoutManager);
         mAppsRecyclerView.setAdapter(mAdapter);
         mAppsRecyclerView.setHasFixedSize(true);
+        mAppsRecyclerView.addOnScrollListener(mElevationController);
+        mAppsRecyclerView.setElevationController(mElevationController);
+
         if (mItemDecoration != null) {
             mAppsRecyclerView.addItemDecoration(mItemDecoration);
         }
 
         // Precalculate the prediction icon and normal icon sizes
         LayoutInflater layoutInflater = LayoutInflater.from(getContext());
+        final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(
+                getResources().getDisplayMetrics().widthPixels, MeasureSpec.AT_MOST);
+        final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(
+                getResources().getDisplayMetrics().heightPixels, MeasureSpec.AT_MOST);
+
         BubbleTextView icon = (BubbleTextView) layoutInflater.inflate(
                 R.layout.all_apps_icon, this, false);
         icon.applyDummyInfo();
-        icon.measure(MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE, MeasureSpec.AT_MOST),
-                MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE, MeasureSpec.AT_MOST));
+        icon.measure(widthMeasureSpec, heightMeasureSpec);
         BubbleTextView predIcon = (BubbleTextView) layoutInflater.inflate(
                 R.layout.all_apps_prediction_bar_icon, this, false);
         predIcon.applyDummyInfo();
-        predIcon.measure(MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE, MeasureSpec.AT_MOST),
-                MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE, MeasureSpec.AT_MOST));
+        predIcon.measure(widthMeasureSpec, heightMeasureSpec);
         mAppsRecyclerView.setPremeasuredIconHeights(predIcon.getMeasuredHeight(),
                 icon.getMeasuredHeight());
 
@@ -360,8 +319,11 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         // Update the number of items in the grid before we measure the view
-        int availableWidth = !mContentBounds.isEmpty() ? mContentBounds.width() :
-                MeasureSpec.getSize(widthMeasureSpec);
+        // TODO: mSectionNamesMargin is currently 0, but also account for it,
+        // if it's enabled in the future.
+        int availableWidth = (!mContentBounds.isEmpty() ? mContentBounds.width() :
+                MeasureSpec.getSize(widthMeasureSpec))
+                    - 2 * mAppsRecyclerView.getMaxScrollbarWidth();
         DeviceProfile grid = mLauncher.getDeviceProfile();
         grid.updateAppsViewNumCols(getResources(), availableWidth);
         if (mNumAppsPerRow != grid.allAppsNumCols ||
@@ -380,6 +342,12 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
             mAppsRecyclerView.setNumAppsPerRow(grid, mNumAppsPerRow);
             mAdapter.setNumAppsPerRow(mNumAppsPerRow);
             mApps.setNumAppsPerRow(mNumAppsPerRow, mNumPredictedAppsPerRow, mergeAlgorithm);
+
+            if (mNumAppsPerRow > 0) {
+                int iconSize = availableWidth / mNumAppsPerRow;
+                int iconSpacing = (iconSize - grid.allAppsIconSizePx) / 2;
+                mSearchInput.setPaddingRelative(iconSpacing, 0, iconSpacing, 0);
+            }
         }
 
         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
@@ -391,51 +359,33 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
      * recycler view to handle touch events (for fast scrolling) all the way to the edge.
      */
     @Override
-    protected void onUpdateBackgroundAndPaddings(Rect searchBarBounds, Rect padding) {
-        boolean isRtl = Utilities.isRtl(getResources());
-
-        // TODO: Use quantum_panel instead of quantum_panel_shape
-        InsetDrawable background = new InsetDrawable(
-                getResources().getDrawable(R.drawable.quantum_panel_shape), padding.left, 0,
-                padding.right, 0);
-        Rect bgPadding = new Rect();
-        background.getPadding(bgPadding);
-        mContainerView.setBackground(background);
-        mRevealView.setBackground(background.getConstantState().newDrawable());
+    protected void onUpdateBgPadding(Rect padding, Rect bgPadding) {
         mAppsRecyclerView.updateBackgroundPadding(bgPadding);
         mAdapter.updateBackgroundPadding(bgPadding);
+        mElevationController.updateBackgroundPadding(bgPadding);
 
         // Hack: We are going to let the recycler view take the full width, so reset the padding on
         // the container to zero after setting the background and apply the top-bottom padding to
         // the content view instead so that the launcher transition clips correctly.
-        mContent.setPadding(0, padding.top, 0, padding.bottom);
-        mContainerView.setPadding(0, 0, 0, 0);
+        getContentView().setPadding(0, 0, 0, 0);
 
         // Pad the recycler view by the background padding plus the start margin (for the section
         // names)
-        int startInset = Math.max(mSectionNamesMargin, mAppsRecyclerView.getMaxScrollbarWidth());
+        int maxScrollBarWidth = mAppsRecyclerView.getMaxScrollbarWidth();
+        int startInset = Math.max(mSectionNamesMargin, maxScrollBarWidth);
         int topBottomPadding = mRecyclerViewTopBottomPadding;
-        if (isRtl) {
-            mAppsRecyclerView.setPadding(padding.left + mAppsRecyclerView.getMaxScrollbarWidth(),
+        if (Utilities.isRtl(getResources())) {
+            mAppsRecyclerView.setPadding(padding.left + maxScrollBarWidth,
                     topBottomPadding, padding.right + startInset, topBottomPadding);
         } else {
             mAppsRecyclerView.setPadding(padding.left + startInset, topBottomPadding,
-                    padding.right + mAppsRecyclerView.getMaxScrollbarWidth(), topBottomPadding);
+                    padding.right + maxScrollBarWidth, topBottomPadding);
         }
 
-        // Inset the search bar to fit its bounds above the container
-        if (mSearchBarView != null) {
-            Rect backgroundPadding = new Rect();
-            if (mSearchBarView.getBackground() != null) {
-                mSearchBarView.getBackground().getPadding(backgroundPadding);
-            }
-            LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)
-                    mSearchBarContainerView.getLayoutParams();
-            lp.leftMargin = searchBarBounds.left - backgroundPadding.left;
-            lp.topMargin = searchBarBounds.top - backgroundPadding.top;
-            lp.rightMargin = (getMeasuredWidth() - searchBarBounds.right) - backgroundPadding.right;
-            mSearchBarContainerView.requestLayout();
-        }
+        MarginLayoutParams lp = (MarginLayoutParams) mSearchContainer.getLayoutParams();
+        lp.leftMargin = padding.left;
+        lp.rightMargin = padding.right;
+        mSearchContainer.setLayoutParams(lp);
     }
 
     @Override
index 1cb03c9..2b3d061 100644 (file)
@@ -53,6 +53,8 @@ public class AllAppsRecyclerView extends BaseRecyclerView
     private AllAppsBackgroundDrawable mEmptySearchBackground;
     private int mEmptySearchBackgroundTopOffset;
 
+    private HeaderElevationController mElevationController;
+
     public AllAppsRecyclerView(Context context) {
         this(context, null);
     }
@@ -83,6 +85,10 @@ public class AllAppsRecyclerView extends BaseRecyclerView
         mFastScrollHelper = new AllAppsFastScrollHelper(this, apps);
     }
 
+    public void setElevationController(HeaderElevationController elevationController) {
+        mElevationController = elevationController;
+    }
+
     /**
      * Sets the number of apps per row in this recycler view.
      */
@@ -116,6 +122,9 @@ public class AllAppsRecyclerView extends BaseRecyclerView
             mScrollbar.reattachThumbToScroll();
         }
         scrollToPosition(0);
+        if (mElevationController != null) {
+            mElevationController.reset();
+        }
     }
 
     /**
index 2b363c0..fdce389 100644 (file)
  */
 package com.android.launcher3.allapps;
 
-import android.content.ComponentName;
+import android.content.Context;
 import android.graphics.Rect;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.KeyEvent;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.TextView;
+import android.widget.TextView.OnEditorActionListener;
 
+import com.android.launcher3.ExtendedEditText;
+import com.android.launcher3.Utilities;
 import com.android.launcher3.util.ComponentKey;
 
 import java.util.ArrayList;
+import java.util.List;
 
 /**
  * An interface to a search box that AllApps can command.
  */
-public abstract class AllAppsSearchBarController {
+public abstract class AllAppsSearchBarController
+        implements TextWatcher, OnEditorActionListener, ExtendedEditText.OnBackKeyListener {
 
+    private static final boolean ALLOW_SINGLE_APP_LAUNCH = true;
+
+    protected AllAppsRecyclerView mAppsRecyclerView;
     protected AlphabeticalAppsList mApps;
     protected Callbacks mCb;
+    protected ExtendedEditText mInput;
+
+    protected DefaultAppSearchAlgorithm mSearchAlgorithm;
+    protected InputMethodManager mInputMethodManager;
 
     /**
      * Sets the references to the apps model and the search result callback.
      */
-    public final void initialize(AlphabeticalAppsList apps, Callbacks cb) {
+    public final void initialize(
+            AlphabeticalAppsList apps, ExtendedEditText input,
+            AllAppsRecyclerView recycleView, Callbacks cb) {
         mApps = apps;
         mCb = cb;
-        onInitialize();
+        mAppsRecyclerView = recycleView;
+
+        mInput = input;
+        mInput.addTextChangedListener(this);
+        mInput.setOnEditorActionListener(this);
+        mInput.setOnBackKeyListener(this);
+
+        mInputMethodManager = (InputMethodManager)
+                mInput.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
+
+        mSearchAlgorithm = onInitializeSearch();
     }
 
     /**
-     * To be overridden by subclasses.  This method will get called when the controller is set,
-     * before getView().
+     * To be overridden by subclasses. This method will get called when the controller is set.
      */
-    protected abstract void onInitialize();
+    protected DefaultAppSearchAlgorithm onInitializeSearch() {
+        return null;
+    }
+
+    @Override
+    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+        // Do nothing
+    }
+
+    @Override
+    public void onTextChanged(CharSequence s, int start, int before, int count) {
+        // Do nothing
+    }
+
+    @Override
+    public void afterTextChanged(final Editable s) {
+        String query = s.toString();
+        if (query.isEmpty()) {
+            mSearchAlgorithm.cancel(true);
+            mCb.clearSearchResult();
+        } else {
+            mSearchAlgorithm.cancel(false);
+            mSearchAlgorithm.doSearch(query, mCb);
+        }
+    }
+
+    @Override
+    public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
+        // Skip if we disallow app-launch-on-enter
+        if (!ALLOW_SINGLE_APP_LAUNCH) {
+            return false;
+        }
+        // Skip if it's not the right action
+        if (actionId != EditorInfo.IME_ACTION_SEARCH) {
+            return false;
+        }
+        // Skip if there are more than one icon
+        if (mApps.getNumFilteredApps() > 1) {
+            return false;
+        }
+        // Otherwise, find the first icon, or fallback to the search-market-view and launch it
+        List<AlphabeticalAppsList.AdapterItem> items = mApps.getAdapterItems();
+        for (int i = 0; i < items.size(); i++) {
+            AlphabeticalAppsList.AdapterItem item = items.get(i);
+            switch (item.viewType) {
+                case AllAppsGridAdapter.ICON_VIEW_TYPE:
+                case AllAppsGridAdapter.SEARCH_MARKET_VIEW_TYPE:
+                    mAppsRecyclerView.getChildAt(i).performClick();
+                    mInputMethodManager.hideSoftInputFromWindow(mInput.getWindowToken(), 0);
+                    return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public boolean onBackKey() {
+        // Only hide the search field if there is no query, or if there
+        // are no filtered results
+        String query = Utilities.trim(mInput.getEditableText().toString());
+        if (query.isEmpty() || mApps.hasNoFilteredResults()) {
+            reset();
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Resets the search bar state.
+     */
+    public void reset() {
+        unfocusSearchField();
+        mCb.clearSearchResult();
+        mInput.setText("");
+        mInputMethodManager.hideSoftInputFromWindow(mInput.getWindowToken(), 0);
+    }
+
+    protected void unfocusSearchField() {
+        View nextFocus = mInput.focusSearch(View.FOCUS_DOWN);
+        if (nextFocus != null) {
+            nextFocus.requestFocus();
+        }
+    }
 
     /**
      * Returns the search bar view.
      * @param parent the parent to attach the search bar view to.
      */
-    public abstract View getView(ViewGroup parent);
+    public View getView(ViewGroup parent) {
+        return null;
+    }
 
     /**
      * Focuses the search field to handle key events.
      */
-    public abstract void focusSearchField();
+    public void focusSearchField() {
+        mInput.requestFocus();
+        mInputMethodManager.showSoftInput(mInput, InputMethodManager.SHOW_IMPLICIT);
+    }
 
     /**
      * Returns whether the search field is focused.
      */
-    public abstract boolean isSearchFieldFocused();
-
-    /**
-     * Resets the search bar state.
-     */
-    public abstract void reset();
+    public boolean isSearchFieldFocused() {
+        return mInput.isFocused();
+    }
 
     /**
      * Returns whether the prediction bar should currently be visible depending on the state of
      * the search bar.
      */
-    @Deprecated
-    public abstract boolean shouldShowPredictionBar();
+    public boolean shouldShowPredictionBar() {
+        return false;
+    }
 
     /**
      * Callback for getting search results.
index 3169f84..57747e3 100644 (file)
  */
 package com.android.launcher3.allapps;
 
-import android.content.Context;
-import android.text.Editable;
-import android.text.TextWatcher;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.inputmethod.EditorInfo;
-import android.view.inputmethod.InputMethodManager;
-import android.widget.TextView;
-import com.android.launcher3.ExtendedEditText;
-import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.util.Thunk;
-
-import java.util.List;
-
-
 /**
  * The default search controller.
  */
-final class DefaultAppSearchController extends AllAppsSearchBarController
-        implements TextWatcher, TextView.OnEditorActionListener, View.OnClickListener {
-
-    private static final boolean ALLOW_SINGLE_APP_LAUNCH = true;
-
-    private static final int FADE_IN_DURATION = 175;
-    private static final int FADE_OUT_DURATION = 100;
-    private static final int SEARCH_TRANSLATION_X_DP = 18;
-
-    private final Context mContext;
-    @Thunk final InputMethodManager mInputMethodManager;
-
-    private DefaultAppSearchAlgorithm mSearchManager;
-
-    private ViewGroup mContainerView;
-    private View mSearchView;
-    @Thunk View mSearchBarContainerView;
-    private View mSearchButtonView;
-    private View mDismissSearchButtonView;
-    @Thunk
-    ExtendedEditText mSearchBarEditView;
-    @Thunk AllAppsRecyclerView mAppsRecyclerView;
-    @Thunk Runnable mFocusRecyclerViewRunnable = new Runnable() {
-        @Override
-        public void run() {
-            mAppsRecyclerView.requestFocus();
-        }
-    };
-
-    public DefaultAppSearchController(Context context, ViewGroup containerView,
-            AllAppsRecyclerView appsRecyclerView) {
-        mContext = context;
-        mInputMethodManager = (InputMethodManager)
-                mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
-        mContainerView = containerView;
-        mAppsRecyclerView = appsRecyclerView;
-    }
-
-    @Override
-    public View getView(ViewGroup parent) {
-        LayoutInflater inflater = LayoutInflater.from(parent.getContext());
-        mSearchView = inflater.inflate(R.layout.all_apps_search_bar, parent, false);
-        mSearchView.setOnClickListener(this);
-
-        mSearchButtonView = mSearchView.findViewById(R.id.search_button);
-        mSearchBarContainerView = mSearchView.findViewById(R.id.search_container);
-        mDismissSearchButtonView = mSearchBarContainerView.findViewById(R.id.dismiss_search_button);
-        mDismissSearchButtonView.setOnClickListener(this);
-        mSearchBarEditView = (ExtendedEditText)
-                mSearchBarContainerView.findViewById(R.id.search_box_input);
-        mSearchBarEditView.addTextChangedListener(this);
-        mSearchBarEditView.setOnEditorActionListener(this);
-        mSearchBarEditView.setOnBackKeyListener(
-                new ExtendedEditText.OnBackKeyListener() {
-                    @Override
-                    public boolean onBackKey() {
-                        // Only hide the search field if there is no query, or if there
-                        // are no filtered results
-                        String query = Utilities.trim(
-                                mSearchBarEditView.getEditableText().toString());
-                        if (query.isEmpty() || mApps.hasNoFilteredResults()) {
-                            hideSearchField(true, mFocusRecyclerViewRunnable);
-                            return true;
-                        }
-                        return false;
-                    }
-                });
-        return mSearchView;
-    }
-
-    @Override
-    public void focusSearchField() {
-        mSearchBarEditView.requestFocus();
-        showSearchField();
-    }
-
-    @Override
-    public boolean isSearchFieldFocused() {
-        return mSearchBarEditView.isFocused();
-    }
-
-    @Override
-    protected void onInitialize() {
-        mSearchManager = new DefaultAppSearchAlgorithm(mApps.getApps());
-    }
-
-    @Override
-    public void reset() {
-        hideSearchField(false, null);
-    }
-
-    @Override
-    public boolean shouldShowPredictionBar() {
-        return false;
-    }
-
-    @Override
-    public void onClick(View v) {
-        if (v == mSearchView) {
-            showSearchField();
-        } else if (v == mDismissSearchButtonView) {
-            hideSearchField(true, mFocusRecyclerViewRunnable);
-        }
-    }
-
-    @Override
-    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
-        // Do nothing
-    }
-
-    @Override
-    public void onTextChanged(CharSequence s, int start, int before, int count) {
-        // Do nothing
-    }
-
-    @Override
-    public void afterTextChanged(final Editable s) {
-        String query = s.toString();
-        if (query.isEmpty()) {
-            mSearchManager.cancel(true);
-            mCb.clearSearchResult();
-        } else {
-            mSearchManager.cancel(false);
-            mSearchManager.doSearch(query, mCb);
-        }
-    }
-
-    @Override
-    public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
-        // Skip if we disallow app-launch-on-enter
-        if (!ALLOW_SINGLE_APP_LAUNCH) {
-            return false;
-        }
-        // Skip if it's not the right action
-        if (actionId != EditorInfo.IME_ACTION_SEARCH) {
-            return false;
-        }
-        // Skip if there are more than one icon
-        if (mApps.getNumFilteredApps() > 1) {
-            return false;
-        }
-        // Otherwise, find the first icon, or fallback to the search-market-view and launch it
-        List<AlphabeticalAppsList.AdapterItem> items = mApps.getAdapterItems();
-        for (int i = 0; i < items.size(); i++) {
-            AlphabeticalAppsList.AdapterItem item = items.get(i);
-            switch (item.viewType) {
-                case AllAppsGridAdapter.ICON_VIEW_TYPE:
-                case AllAppsGridAdapter.SEARCH_MARKET_VIEW_TYPE:
-                    mAppsRecyclerView.getChildAt(i).performClick();
-                    mInputMethodManager.hideSoftInputFromWindow(
-                            mContainerView.getWindowToken(), 0);
-                    return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Focuses the search field.
-     */
-    private void showSearchField() {
-        // Show the search bar and focus the search
-        final int translationX = Utilities.pxFromDp(SEARCH_TRANSLATION_X_DP,
-                mContext.getResources().getDisplayMetrics());
-        mSearchBarContainerView.setVisibility(View.VISIBLE);
-        mSearchBarContainerView.setAlpha(0f);
-        mSearchBarContainerView.setTranslationX(translationX);
-        mSearchBarContainerView.animate()
-                .alpha(1f)
-                .translationX(0)
-                .setDuration(FADE_IN_DURATION)
-                .withLayer()
-                .withEndAction(new Runnable() {
-                    @Override
-                    public void run() {
-                        mSearchBarEditView.requestFocus();
-                        mInputMethodManager.showSoftInput(mSearchBarEditView,
-                                InputMethodManager.SHOW_IMPLICIT);
-                    }
-                });
-        mSearchButtonView.animate()
-                .alpha(0f)
-                .translationX(-translationX)
-                .setDuration(FADE_OUT_DURATION)
-                .withLayer();
-    }
-
-    /**
-     * Unfocuses the search field.
-     */
-    @Thunk void hideSearchField(boolean animated, final Runnable postAnimationRunnable) {
-        mSearchManager.cancel(true);
+public class DefaultAppSearchController extends AllAppsSearchBarController {
 
-        final boolean resetTextField = mSearchBarEditView.getText().toString().length() > 0;
-        final int translationX = Utilities.pxFromDp(SEARCH_TRANSLATION_X_DP,
-                mContext.getResources().getDisplayMetrics());
-        if (animated) {
-            // Hide the search bar and focus the recycler view
-            mSearchBarContainerView.animate()
-                    .alpha(0f)
-                    .translationX(0)
-                    .setDuration(FADE_IN_DURATION)
-                    .withLayer()
-                    .withEndAction(new Runnable() {
-                        @Override
-                        public void run() {
-                            mSearchBarContainerView.setVisibility(View.INVISIBLE);
-                            if (resetTextField) {
-                                mSearchBarEditView.setText("");
-                            }
-                            mCb.clearSearchResult();
-                            if (postAnimationRunnable != null) {
-                                postAnimationRunnable.run();
-                            }
-                        }
-                    });
-            mSearchButtonView.setTranslationX(-translationX);
-            mSearchButtonView.animate()
-                    .alpha(1f)
-                    .translationX(0)
-                    .setDuration(FADE_OUT_DURATION)
-                    .withLayer();
-        } else {
-            mSearchBarContainerView.setVisibility(View.INVISIBLE);
-            if (resetTextField) {
-                mSearchBarEditView.setText("");
-            }
-            mCb.clearSearchResult();
-            mSearchButtonView.setAlpha(1f);
-            mSearchButtonView.setTranslationX(0f);
-            if (postAnimationRunnable != null) {
-                postAnimationRunnable.run();
-            }
-        }
-        mInputMethodManager.hideSoftInputFromWindow(mContainerView.getWindowToken(), 0);
+    public DefaultAppSearchAlgorithm onInitializeSearch() {
+        return new DefaultAppSearchAlgorithm(mApps.getApps());
     }
 }
diff --git a/src/com/android/launcher3/allapps/HeaderElevationController.java b/src/com/android/launcher3/allapps/HeaderElevationController.java
new file mode 100644 (file)
index 0000000..07f583c
--- /dev/null
@@ -0,0 +1,101 @@
+package com.android.launcher3.allapps;
+
+import android.annotation.TargetApi;
+import android.content.res.Resources;
+import android.graphics.Rect;
+import android.graphics.drawable.GradientDrawable;
+import android.os.Build;
+import android.support.v7.widget.RecyclerView;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewOutlineProvider;
+import android.widget.FrameLayout;
+
+import com.android.launcher3.R;
+
+/**
+ * Helper class for controlling the header elevation in response to RecyclerView scroll.
+ */
+public abstract class HeaderElevationController extends RecyclerView.OnScrollListener {
+
+    private int mCurrentY = 0;
+
+    public void reset() {
+        mCurrentY = 0;
+        onScroll(mCurrentY);
+    }
+
+    @Override
+    public final void onScrolled(RecyclerView recyclerView, int dx, int dy) {
+        mCurrentY += dy;
+        onScroll(mCurrentY);
+    }
+
+    public void updateBackgroundPadding(Rect bgPadding) { }
+
+    abstract void onScroll(int scrollY);
+
+    public static class ControllerV16 extends HeaderElevationController {
+
+        private final View mShadow;
+        private final float mScrollToElevation;
+
+        public ControllerV16(View header) {
+            Resources res = header.getContext().getResources();
+            mScrollToElevation = res.getDimension(R.dimen.all_apps_header_scroll_to_elevation);
+
+            mShadow = new View(header.getContext());
+            mShadow.setBackground(new GradientDrawable(
+                    GradientDrawable.Orientation.TOP_BOTTOM, new int[] {0x1E000000, 0x00000000}));
+            mShadow.setAlpha(0);
+
+            FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
+                    FrameLayout.LayoutParams.MATCH_PARENT,
+                    res.getDimensionPixelSize(R.dimen.all_apps_header_shadow_height));
+            lp.topMargin = ((FrameLayout.LayoutParams) header.getLayoutParams()).height;
+
+            ((ViewGroup) header.getParent()).addView(mShadow, lp);
+        }
+
+        @Override
+        public void onScroll(int scrollY) {
+            float elevationPct = (float) Math.min(scrollY, mScrollToElevation) /
+                    mScrollToElevation;
+            mShadow.setAlpha(elevationPct);
+        }
+
+        @Override
+        public void updateBackgroundPadding(Rect bgPadding) {
+            FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mShadow.getLayoutParams();
+            lp.leftMargin = bgPadding.left;
+            lp.rightMargin = bgPadding.right;
+            mShadow.requestLayout();
+        }
+    }
+
+    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+    public static class ControllerVL extends HeaderElevationController {
+
+        private final View mHeader;
+        private final float mMaxElevation;
+        private final float mScrollToElevation;
+
+        public ControllerVL(View header) {
+            mHeader = header;
+            mHeader.setOutlineProvider(ViewOutlineProvider.BOUNDS);
+
+            Resources res = header.getContext().getResources();
+            mMaxElevation = res.getDimension(R.dimen.all_apps_header_max_elevation);
+            mScrollToElevation = res.getDimension(R.dimen.all_apps_header_scroll_to_elevation);
+        }
+
+        @Override
+        public void onScroll(int scrollY) {
+            float elevationPct = Math.min(scrollY, mScrollToElevation) / mScrollToElevation;
+            float newElevation = mMaxElevation * elevationPct;
+            if (Float.compare(mHeader.getElevation(), newElevation) != 0) {
+                mHeader.setElevation(newElevation);
+            }
+        }
+    }
+}
index b780f59..8b9ac1f 100644 (file)
@@ -65,7 +65,6 @@ public class WidgetsContainerView extends BaseContainerView
     private IconCache mIconCache;
 
     /* Recycler view related member variables */
-    private View mContent;
     private WidgetsRecyclerView mView;
     private WidgetsListAdapter mAdapter;
 
@@ -99,8 +98,7 @@ public class WidgetsContainerView extends BaseContainerView
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
-        mContent = findViewById(R.id.content);
-        mView = (WidgetsRecyclerView) findViewById(R.id.widgets_list_view);
+        mView = (WidgetsRecyclerView) getContentView();
         mView.setAdapter(mAdapter);
 
         // This extends the layout space so that preloading happen for the {@link RecyclerView}
@@ -120,15 +118,6 @@ public class WidgetsContainerView extends BaseContainerView
     // Returns views used for launcher transitions.
     //
 
-    public View getContentView() {
-        return mView;
-    }
-
-    public View getRevealView() {
-        // TODO(hyunyoungs): temporarily use apps view transition.
-        return findViewById(R.id.widgets_reveal_view);
-    }
-
     public void scrollToTop() {
         mView.scrollToPosition(0);
     }
@@ -338,21 +327,8 @@ public class WidgetsContainerView extends BaseContainerView
     //
     // Container rendering related.
     //
-
     @Override
-    protected void onUpdateBackgroundAndPaddings(Rect searchBarBounds, Rect padding) {
-        // Apply the top-bottom padding to the content itself so that the launcher transition is
-        // clipped correctly
-        mContent.setPadding(0, padding.top, 0, padding.bottom);
-
-        // TODO: Use quantum_panel_dark instead of quantum_panel_shape_dark.
-        InsetDrawable background = new InsetDrawable(
-                getResources().getDrawable(R.drawable.quantum_panel_shape_dark), padding.left, 0,
-                padding.right, 0);
-        Rect bgPadding = new Rect();
-        background.getPadding(bgPadding);
-        mView.setBackground(background);
-        getRevealView().setBackground(background.getConstantState().newDrawable());
+    protected void onUpdateBgPadding(Rect padding, Rect bgPadding) {
         mView.updateBackgroundPadding(bgPadding);
     }