summaryrefslogtreecommitdiffstats
path: root/src/com/android/launcher3/allapps
diff options
context:
space:
mode:
authorSunny Goyal <sunnygoyal@google.com>2016-01-29 13:14:14 -0800
committerSunny Goyal <sunnygoyal@google.com>2016-02-08 14:55:22 -0800
commit0ac7ede56afebe4401c0636196f5844be573ad68 (patch)
treec4bdfce0b5f788880354845ab51ae293bd608d1b /src/com/android/launcher3/allapps
parent0e0498031092488ff166145c12ce36cc0a80c490 (diff)
downloadandroid_packages_apps_Trebuchet-0ac7ede56afebe4401c0636196f5844be573ad68.tar.gz
android_packages_apps_Trebuchet-0ac7ede56afebe4401c0636196f5844be573ad68.tar.bz2
android_packages_apps_Trebuchet-0ac7ede56afebe4401c0636196f5844be573ad68.zip
Merging search bar with all apps
Change-Id: I78577124cd3c05d52669c3e52b0294d6eb1d194d
Diffstat (limited to 'src/com/android/launcher3/allapps')
-rw-r--r--src/com/android/launcher3/allapps/AllAppsContainerView.java166
-rw-r--r--src/com/android/launcher3/allapps/AllAppsRecyclerView.java9
-rw-r--r--src/com/android/launcher3/allapps/AllAppsSearchBarController.java148
-rw-r--r--src/com/android/launcher3/allapps/DefaultAppSearchController.java255
-rw-r--r--src/com/android/launcher3/allapps/HeaderElevationController.java101
5 files changed, 302 insertions, 377 deletions
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);
+ }
+ }
+ }
+}