diff options
author | Sunny Goyal <sunnygoyal@google.com> | 2016-01-29 13:14:14 -0800 |
---|---|---|
committer | Sunny Goyal <sunnygoyal@google.com> | 2016-02-08 14:55:22 -0800 |
commit | 0ac7ede56afebe4401c0636196f5844be573ad68 (patch) | |
tree | c4bdfce0b5f788880354845ab51ae293bd608d1b /src/com/android/launcher3/allapps | |
parent | 0e0498031092488ff166145c12ce36cc0a80c490 (diff) | |
download | android_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')
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); + } + } + } +} |