diff options
author | Sunny Goyal <sunnygoyal@google.com> | 2016-02-10 19:18:12 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2016-02-10 19:18:13 +0000 |
commit | 3826bab27ef3e7608aba112bd0f5ce2e7c3eac5b (patch) | |
tree | 854be300ed1ff63cb1f52467b3c35c3c83dd3da5 | |
parent | f97083245c440e0c09e2485094157bb8389cdd95 (diff) | |
parent | 0ac7ede56afebe4401c0636196f5844be573ad68 (diff) | |
download | android_packages_apps_Trebuchet-3826bab27ef3e7608aba112bd0f5ce2e7c3eac5b.tar.gz android_packages_apps_Trebuchet-3826bab27ef3e7608aba112bd0f5ce2e7c3eac5b.tar.bz2 android_packages_apps_Trebuchet-3826bab27ef3e7608aba112bd0f5ce2e7c3eac5b.zip |
Merge "Merging search bar with all apps" into ub-launcher3-burnaby-polish
20 files changed, 645 insertions, 683 deletions
diff --git a/res/drawable/all_apps_search_bg.xml b/res/drawable/all_apps_search_bg.xml index a09f88fd4..5a2c9e836 100644 --- a/res/drawable/all_apps_search_bg.xml +++ b/res/drawable/all_apps_search_bg.xml @@ -14,7 +14,25 @@ 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 diff --git a/res/layout-land/launcher.xml b/res/layout-land/launcher.xml index 6500ebcd2..1a951f1b7 100644 --- a/res/layout-land/launcher.xml +++ b/res/layout-land/launcher.xml @@ -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"> diff --git a/res/layout-port/launcher.xml b/res/layout-port/launcher.xml index d0772ee70..8bf9d6427 100644 --- a/res/layout-port/launcher.xml +++ b/res/layout-port/launcher.xml @@ -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"> diff --git a/res/layout-sw720dp/launcher.xml b/res/layout-sw720dp/launcher.xml index 802922ec1..2fc62c500 100644 --- a/res/layout-sw720dp/launcher.xml +++ b/res/layout-sw720dp/launcher.xml @@ -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"> diff --git a/res/layout/all_apps.xml b/res/layout/all_apps.xml index 1bf54eefb..c2b1e6fef 100644 --- a/res/layout/all_apps.xml +++ b/res/layout/all_apps.xml @@ -18,40 +18,72 @@ 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 diff --git a/res/layout/widgets_view.xml b/res/layout/widgets_view.xml index 755634f82..e64f83ae1 100644 --- a/res/layout/widgets_view.xml +++ b/res/layout/widgets_view.xml @@ -18,34 +18,29 @@ 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 diff --git a/res/values/attrs.xml b/res/values/attrs.xml index 827332ad7..82f33d1c0 100644 --- a/res/values/attrs.xml +++ b/res/values/attrs.xml @@ -83,6 +83,13 @@ <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" /> diff --git a/res/values/dimens.xml b/res/values/dimens.xml index 076853e8d..a303daba8 100644 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -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> @@ -90,7 +90,20 @@ <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> diff --git a/res/values/strings.xml b/res/values/strings.xml index 6daa4526c..2838a22f0 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -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…</string> <!-- Loading apps text. [CHAR_LIMIT=50] --> <string name="all_apps_loading_message">Loading Apps…</string> <!-- No-search-results text. [CHAR_LIMIT=50] --> diff --git a/src/com/android/launcher3/BaseContainerView.java b/src/com/android/launcher3/BaseContainerView.java index c11824054..8bb8c55fd 100644 --- a/src/com/android/launcher3/BaseContainerView.java +++ b/src/com/android/launcher3/BaseContainerView.java @@ -17,32 +17,38 @@ 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 diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index b686c7cf4..fc2b5f431 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -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) diff --git a/src/com/android/launcher3/LauncherStateTransitionAnimation.java b/src/com/android/launcher3/LauncherStateTransitionAnimation.java index 83b12a99d..30cae3114 100644 --- a/src/com/android/launcher3/LauncherStateTransitionAnimation.java +++ b/src/com/android/launcher3/LauncherStateTransitionAnimation.java @@ -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); } /** diff --git a/src/com/android/launcher3/SearchDropTargetBar.java b/src/com/android/launcher3/SearchDropTargetBar.java index aad6dbc9f..f7288a0a0 100644 --- a/src/com/android/launcher3/SearchDropTargetBar.java +++ b/src/com/android/launcher3/SearchDropTargetBar.java @@ -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); + } + + } } diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index 56801ff61..7b873d420 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -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); diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java index f9bb13450..8f8858fb6 100644 --- a/src/com/android/launcher3/allapps/AllAppsContainerView.java +++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java @@ -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 diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java index 1cb03c989..2b3d061e6 100644 --- a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java +++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java @@ -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(); + } } /** diff --git a/src/com/android/launcher3/allapps/AllAppsSearchBarController.java b/src/com/android/launcher3/allapps/AllAppsSearchBarController.java index 2b363c0cb..fdce3895f 100644 --- a/src/com/android/launcher3/allapps/AllAppsSearchBarController.java +++ b/src/com/android/launcher3/allapps/AllAppsSearchBarController.java @@ -15,65 +15,179 @@ */ 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. diff --git a/src/com/android/launcher3/allapps/DefaultAppSearchController.java b/src/com/android/launcher3/allapps/DefaultAppSearchController.java index 3169f842a..57747e367 100644 --- a/src/com/android/launcher3/allapps/DefaultAppSearchController.java +++ b/src/com/android/launcher3/allapps/DefaultAppSearchController.java @@ -15,261 +15,12 @@ */ 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 index 000000000..07f583caa --- /dev/null +++ b/src/com/android/launcher3/allapps/HeaderElevationController.java @@ -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); + } + } + } +} diff --git a/src/com/android/launcher3/widget/WidgetsContainerView.java b/src/com/android/launcher3/widget/WidgetsContainerView.java index b780f590b..8b9ac1f75 100644 --- a/src/com/android/launcher3/widget/WidgetsContainerView.java +++ b/src/com/android/launcher3/widget/WidgetsContainerView.java @@ -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); } |