diff options
author | Sunny Goyal <sunnygoyal@google.com> | 2017-05-07 11:56:00 -0700 |
---|---|---|
committer | Sunny Goyal <sunnygoyal@google.com> | 2017-05-08 14:43:32 -0700 |
commit | 161f96bc77805ed87f831b68e51fad61a23153bc (patch) | |
tree | a3f74eb9dcac6dd4673a51122ac62e5e92aea676 /src/com/android/launcher3 | |
parent | b73fa5d7a46e840df13b2d5fb8ae956344524c3e (diff) | |
download | android_packages_apps_Trebuchet-161f96bc77805ed87f831b68e51fad61a23153bc.tar.gz android_packages_apps_Trebuchet-161f96bc77805ed87f831b68e51fad61a23153bc.tar.bz2 android_packages_apps_Trebuchet-161f96bc77805ed87f831b68e51fad61a23153bc.zip |
Moving apps search related logic into a custom layout file
This will allow derivative projects to easily change the search behavior
by simply overriding the xml file
Bug: 37616877
Change-Id: Ib8d6a2dab06819a52611e9a3d97c70c5a49bbf97
Diffstat (limited to 'src/com/android/launcher3')
14 files changed, 305 insertions, 291 deletions
diff --git a/src/com/android/launcher3/BaseRecyclerView.java b/src/com/android/launcher3/BaseRecyclerView.java index 6fdf45450..c05633615 100644 --- a/src/com/android/launcher3/BaseRecyclerView.java +++ b/src/com/android/launcher3/BaseRecyclerView.java @@ -82,10 +82,6 @@ public abstract class BaseRecyclerView extends RecyclerView } } - public void reset() { - mScrollbar.reattachThumbToScroll(); - } - @Override protected void onFinishInflate() { super.onFinishInflate(); diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index d0c01f474..c96c2a7b9 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -85,7 +85,6 @@ import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.accessibility.LauncherAccessibilityDelegate; import com.android.launcher3.allapps.AllAppsContainerView; import com.android.launcher3.allapps.AllAppsTransitionController; -import com.android.launcher3.allapps.DefaultAppSearchController; import com.android.launcher3.anim.AnimationLayerSet; import com.android.launcher3.compat.AppWidgetManagerCompat; import com.android.launcher3.compat.LauncherAppsCompat; @@ -560,47 +559,6 @@ public class Launcher extends BaseActivity public boolean setLauncherCallbacks(LauncherCallbacks callbacks) { mLauncherCallbacks = callbacks; - mLauncherCallbacks.setLauncherSearchCallback(new Launcher.LauncherSearchCallbacks() { - private boolean mWorkspaceImportanceStored = false; - private boolean mHotseatImportanceStored = false; - private int mWorkspaceImportanceForAccessibility = - View.IMPORTANT_FOR_ACCESSIBILITY_AUTO; - private int mHotseatImportanceForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_AUTO; - - @Override - public void onSearchOverlayOpened() { - if (mWorkspaceImportanceStored || mHotseatImportanceStored) { - return; - } - // The underlying workspace and hotseat are temporarily suppressed by the search - // overlay. So they shouldn't be accessible. - if (mWorkspace != null) { - mWorkspaceImportanceForAccessibility = - mWorkspace.getImportantForAccessibility(); - mWorkspace.setImportantForAccessibility( - View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS); - mWorkspaceImportanceStored = true; - } - if (mHotseat != null) { - mHotseatImportanceForAccessibility = mHotseat.getImportantForAccessibility(); - mHotseat.setImportantForAccessibility( - View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS); - mHotseatImportanceStored = true; - } - } - - @Override - public void onSearchOverlayClosed() { - if (mWorkspaceImportanceStored && mWorkspace != null) { - mWorkspace.setImportantForAccessibility(mWorkspaceImportanceForAccessibility); - } - if (mHotseatImportanceStored && mHotseat != null) { - mHotseat.setImportantForAccessibility(mHotseatImportanceForAccessibility); - } - mWorkspaceImportanceStored = false; - mHotseatImportanceStored = false; - } - }); return true; } @@ -1140,18 +1098,6 @@ public class Launcher extends BaseActivity public void setOverlayCallbacks(LauncherOverlayCallbacks callbacks); } - public interface LauncherSearchCallbacks { - /** - * Called when the search overlay is shown. - */ - public void onSearchOverlayOpened(); - - /** - * Called when the search overlay is dismissed. - */ - public void onSearchOverlayClosed(); - } - public interface LauncherOverlayCallbacks { public void onScrollChanged(float progress); } @@ -1344,11 +1290,6 @@ public class Launcher extends BaseActivity // Setup Apps and Widgets mAppsView = (AllAppsContainerView) findViewById(R.id.apps_view); mWidgetsView = (WidgetsContainerView) findViewById(R.id.widgets_view); - if (mLauncherCallbacks != null && mLauncherCallbacks.getAllAppsSearchBarController() != null) { - mAppsView.setSearchBarController(mLauncherCallbacks.getAllAppsSearchBarController()); - } else { - mAppsView.setSearchBarController(new DefaultAppSearchController()); - } // Setup the drag controller (drop targets have to be added in reverse order in priority) mDragController.setMoveTarget(mWorkspace); @@ -1777,7 +1718,7 @@ public class Launcher extends BaseActivity // Reset the apps view if (!alreadyOnHome && mAppsView != null) { - mAppsView.scrollToTop(); + mAppsView.reset(); } // Reset the widgets view diff --git a/src/com/android/launcher3/LauncherCallbacks.java b/src/com/android/launcher3/LauncherCallbacks.java index 32f179f46..ea4aeb929 100644 --- a/src/com/android/launcher3/LauncherCallbacks.java +++ b/src/com/android/launcher3/LauncherCallbacks.java @@ -21,7 +21,6 @@ import android.os.Bundle; import android.view.Menu; import android.view.View; -import com.android.launcher3.allapps.AllAppsSearchBarController; import com.android.launcher3.util.ComponentKey; import java.io.FileDescriptor; @@ -92,20 +91,11 @@ public interface LauncherCallbacks { */ boolean shouldMoveToDefaultScreenOnHomeIntent(); boolean hasSettings(); - AllAppsSearchBarController getAllAppsSearchBarController(); List<ComponentKey> getPredictedApps(); int SEARCH_BAR_HEIGHT_NORMAL = 0, SEARCH_BAR_HEIGHT_TALL = 1; /** Must return one of {@link #SEARCH_BAR_HEIGHT_NORMAL} or {@link #SEARCH_BAR_HEIGHT_TALL} */ int getSearchBarHeight(); - /** - * Sets the callbacks to allow reacting the actions of search overlays of the launcher. - * - * @param callbacks A set of callbacks to the Launcher, is actually a LauncherSearchCallback, - * but for implementation purposes is passed around as an object. - */ - void setLauncherSearchCallback(Object callbacks); - boolean shouldShowDiscoveryBounce(); void onExtractedColorsChanged(); diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java index 7be8e8f0e..0ea61f430 100644 --- a/src/com/android/launcher3/allapps/AllAppsContainerView.java +++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java @@ -20,15 +20,9 @@ import android.graphics.Color; import android.graphics.Rect; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.InsetDrawable; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; import android.support.v7.widget.RecyclerView; import android.text.Selection; -import android.text.Spannable; -import android.text.SpannableString; import android.text.SpannableStringBuilder; -import android.text.TextUtils; -import android.text.method.TextKeyListener; import android.util.AttributeSet; import android.view.KeyEvent; import android.view.MotionEvent; @@ -42,7 +36,6 @@ 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.Insettable; import com.android.launcher3.ItemInfo; import com.android.launcher3.Launcher; @@ -50,18 +43,14 @@ import com.android.launcher3.PromiseAppInfo; import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.config.FeatureFlags; -import com.android.launcher3.discovery.AppDiscoveryItem; -import com.android.launcher3.discovery.AppDiscoveryUpdateState; import com.android.launcher3.dragndrop.DragController; import com.android.launcher3.dragndrop.DragOptions; import com.android.launcher3.folder.Folder; -import com.android.launcher3.graphics.TintedDrawableSpan; import com.android.launcher3.keyboard.FocusedItemDecorator; import com.android.launcher3.userevent.nano.LauncherLogProto.Target; import com.android.launcher3.util.ComponentKey; import com.android.launcher3.util.PackageUserKey; -import java.util.ArrayList; import java.util.List; import java.util.Set; @@ -69,7 +58,7 @@ import java.util.Set; * The all apps view container. */ public class AllAppsContainerView extends BaseContainerView implements DragSource, - View.OnLongClickListener, AllAppsSearchBarController.Callbacks, Insettable { + View.OnLongClickListener, Insettable { private final Launcher mLauncher; private final AlphabeticalAppsList mApps; @@ -77,12 +66,8 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc private final RecyclerView.LayoutManager mLayoutManager; private AllAppsRecyclerView mAppsRecyclerView; - private AllAppsSearchBarController mSearchBarController; - + private SearchUiManager mSearchUiManager; private View mSearchContainer; - private int mSearchContainerMinHeight; - private ExtendedEditText mSearchInput; - private HeaderElevationController mElevationController; private SpannableStringBuilder mSearchQueryBuilder = null; @@ -106,8 +91,6 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc mApps.setAdapter(mAdapter); mLayoutManager = mAdapter.getLayoutManager(); mSearchQueryBuilder = new SpannableStringBuilder(); - mSearchContainerMinHeight - = getResources().getDimensionPixelSize(R.dimen.all_apps_search_bar_height); Selection.setSelection(mSearchQueryBuilder, 0); } @@ -149,7 +132,7 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc */ public void addApps(List<AppInfo> apps) { mApps.addApps(apps); - mSearchBarController.refreshSearchResult(); + mSearchUiManager.refreshSearchResult(); } /** @@ -157,7 +140,7 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc */ public void updateApps(List<AppInfo> apps) { mApps.updateApps(apps); - mSearchBarController.refreshSearchResult(); + mSearchUiManager.refreshSearchResult(); } public void updatePromiseAppProgress(PromiseAppInfo app) { @@ -176,34 +159,7 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc */ public void removeApps(List<AppInfo> apps) { mApps.removeApps(apps); - mSearchBarController.refreshSearchResult(); - } - - public void setSearchBarVisible(boolean visible) { - if (visible) { - mSearchBarController.setVisibility(View.VISIBLE); - } else { - mSearchBarController.setVisibility(View.INVISIBLE); - } - } - - /** - * Sets the search bar that shows above the a-z list. - */ - public void setSearchBarController(AllAppsSearchBarController searchController) { - if (mSearchBarController != null) { - throw new RuntimeException("Expected search bar controller to only be set once"); - } - mSearchBarController = searchController; - mSearchBarController.initialize(mApps, mSearchInput, mLauncher, this); - mAdapter.setSearchController(mSearchBarController); - } - - /** - * Scrolls this list view to the top. - */ - public void scrollToTop() { - mAppsRecyclerView.scrollToTop(); + mSearchUiManager.refreshSearchResult(); } /** @@ -238,9 +194,7 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc * Focuses the search field and begins an app search. */ public void startAppsSearch() { - if (mSearchBarController != null) { - mSearchBarController.focusSearchField(); - } + mSearchUiManager.startAppsSearch(); } /** @@ -248,9 +202,8 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc */ public void reset() { // Reset the search bar and base recycler view after transitioning home - scrollToTop(); - mSearchBarController.reset(); - mAppsRecyclerView.reset(); + mAppsRecyclerView.scrollToTop(); + mSearchUiManager.reset(); } @Override @@ -268,28 +221,17 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc } }); - mSearchContainer = findViewById(R.id.search_container); - mSearchInput = (ExtendedEditText) findViewById(R.id.search_box_input); - - // Update the hint to contain the icon. - // Prefix the original hint with two spaces. The first space gets replaced by the icon - // using span. The second space is used for a singe space character between the hint - // and the icon. - SpannableString spanned = new SpannableString(" " + mSearchInput.getHint()); - spanned.setSpan(new TintedDrawableSpan(getContext(), R.drawable.ic_allapps_search), - 0, 1, Spannable.SPAN_EXCLUSIVE_INCLUSIVE); - mSearchInput.setHint(spanned); - - mElevationController = new HeaderElevationController(mSearchContainer); - // Load the all apps recycler view mAppsRecyclerView = (AllAppsRecyclerView) findViewById(R.id.apps_list_view); mAppsRecyclerView.setApps(mApps); mAppsRecyclerView.setLayoutManager(mLayoutManager); mAppsRecyclerView.setAdapter(mAdapter); mAppsRecyclerView.setHasFixedSize(true); - mAppsRecyclerView.addOnScrollListener(mElevationController); - mAppsRecyclerView.setElevationController(mElevationController); + + mSearchContainer = findViewById(R.id.search_container); + mSearchUiManager = (SearchUiManager) mSearchContainer; + mSearchUiManager.initialize(mApps, mAppsRecyclerView); + FocusedItemDecorator focusedItemDecorator = new FocusedItemDecorator(mAppsRecyclerView); mAppsRecyclerView.addItemDecoration(focusedItemDecorator); @@ -309,12 +251,11 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc } @Override - public void onBoundsChanged(Rect newBounds) { } - - @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { DeviceProfile grid = mLauncher.getDeviceProfile(); + // Update the number of items in the grid before we measure the view grid.updateAppsViewNumCols(); + if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP) { if (mNumAppsPerRow != grid.inv.numColumns || mNumPredictedAppsPerRow != grid.inv.numColumns) { @@ -325,22 +266,11 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc mAdapter.setNumAppsPerRow(mNumAppsPerRow); mApps.setNumAppsPerRow(mNumAppsPerRow, mNumPredictedAppsPerRow); } - if (!grid.isVerticalBarLayout()) { - MarginLayoutParams searchContainerLp = - (MarginLayoutParams) mSearchContainer.getLayoutParams(); - - searchContainerLp.height = mLauncher.getDragLayer().getInsets().top - + mSearchContainerMinHeight; - mSearchContainer.setLayoutParams(searchContainerLp); - } super.onMeasure(widthMeasureSpec, heightMeasureSpec); return; } // --- remove START when {@code FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP} is enabled. --- - - // Update the number of items in the grid before we measure the view - grid.updateAppsViewNumCols(); if (mNumAppsPerRow != grid.allAppsNumCols || mNumPredictedAppsPerRow != grid.allAppsNumPredictiveCols) { mNumAppsPerRow = grid.allAppsNumCols; @@ -357,22 +287,7 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc @Override public boolean dispatchKeyEvent(KeyEvent event) { - // Determine if the key event was actual text, if so, focus the search bar and then dispatch - // the key normally so that it can process this key event - if (!mSearchBarController.isSearchFieldFocused() && - event.getAction() == KeyEvent.ACTION_DOWN) { - final int unicodeChar = event.getUnicodeChar(); - final boolean isKeyNotWhitespace = unicodeChar > 0 && - !Character.isWhitespace(unicodeChar) && !Character.isSpaceChar(unicodeChar); - if (isKeyNotWhitespace) { - boolean gotKey = TextKeyListener.getInstance().onKeyDown(this, mSearchQueryBuilder, - event.getKeyCode(), event); - if (gotKey && mSearchQueryBuilder.length() > 0) { - mSearchBarController.focusSearchField(); - } - } - } - + mSearchUiManager.preDispatchKeyEvent(event); return super.dispatchKeyEvent(event); } @@ -440,42 +355,12 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc } @Override - public void onSearchResult(String query, ArrayList<ComponentKey> apps) { - if (apps != null) { - mApps.setOrderedFilter(apps); - mAppsRecyclerView.onSearchResultsChanged(); - mAdapter.setLastSearchQuery(query); - } - } - - @Override - public void onAppDiscoverySearchUpdate(@Nullable AppDiscoveryItem app, - @NonNull AppDiscoveryUpdateState state) { - if (!mLauncher.isDestroyed()) { - mApps.onAppDiscoverySearchUpdate(app, state); - mAppsRecyclerView.onSearchResultsChanged(); - } - } - - @Override - public void clearSearchResult() { - if (mApps.setOrderedFilter(null)) { - mAppsRecyclerView.onSearchResultsChanged(); - } - - // Clear the search query - mSearchQueryBuilder.clear(); - mSearchQueryBuilder.clearSpans(); - Selection.setSelection(mSearchQueryBuilder, 0); - } - - @Override public void fillInLogContainerData(View v, ItemInfo info, Target target, Target targetParent) { targetParent.containerType = mAppsRecyclerView.getContainerType(v); } public boolean shouldRestoreImeState() { - return !TextUtils.isEmpty(mSearchInput.getText()); + return mSearchUiManager.shouldRestoreImeState(); } @Override diff --git a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java index 938e84ed0..e12610257 100644 --- a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java +++ b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java @@ -40,6 +40,7 @@ import com.android.launcher3.R; import com.android.launcher3.allapps.AlphabeticalAppsList.AdapterItem; import com.android.launcher3.discovery.AppDiscoveryAppInfo; import com.android.launcher3.discovery.AppDiscoveryItemView; +import com.android.launcher3.util.PackageManagerHelper; import java.util.List; @@ -199,7 +200,6 @@ public class AllAppsGridAdapter extends RecyclerView.Adapter<AllAppsGridAdapter. private int mAppsPerRow; private BindViewCallback mBindViewCallback; - private AllAppsSearchBarController mSearchController; private OnFocusChangeListener mIconFocusListener; // The text to show when there are no search results and no market search handler. @@ -241,10 +241,6 @@ public class AllAppsGridAdapter extends RecyclerView.Adapter<AllAppsGridAdapter. mGridLayoutMgr.setSpanCount(appsPerRow); } - public void setSearchController(AllAppsSearchBarController searchController) { - mSearchController = searchController; - } - public void setIconFocusListener(OnFocusChangeListener focusListener) { mIconFocusListener = focusListener; } @@ -256,7 +252,7 @@ public class AllAppsGridAdapter extends RecyclerView.Adapter<AllAppsGridAdapter. public void setLastSearchQuery(String query) { Resources res = mLauncher.getResources(); mEmptySearchMessage = res.getString(R.string.all_apps_no_search_results, query); - mMarketSearchIntent = mSearchController.createMarketSearchIntent(query); + mMarketSearchIntent = PackageManagerHelper.getMarketSearchIntent(mLauncher, query); } /** diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java index 64e2fcb3d..f3089d2cd 100644 --- a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java +++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java @@ -53,8 +53,6 @@ public class AllAppsRecyclerView extends BaseRecyclerView { private AllAppsBackgroundDrawable mEmptySearchBackground; private int mEmptySearchBackgroundTopOffset; - private HeaderElevationController mElevationController; - public AllAppsRecyclerView(Context context) { this(context, null); } @@ -85,10 +83,6 @@ 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. */ @@ -152,13 +146,8 @@ public class AllAppsRecyclerView extends BaseRecyclerView { */ public void scrollToTop() { // Ensure we reattach the scrollbar if it was previously detached while fast-scrolling - if (mScrollbar.isThumbDetached()) { - mScrollbar.reattachThumbToScroll(); - } + mScrollbar.reattachThumbToScroll(); scrollToPosition(0); - if (mElevationController != null) { - mElevationController.reset(); - } } @Override diff --git a/src/com/android/launcher3/allapps/DefaultAppSearchController.java b/src/com/android/launcher3/allapps/DefaultAppSearchController.java deleted file mode 100644 index 57747e367..000000000 --- a/src/com/android/launcher3/allapps/DefaultAppSearchController.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.launcher3.allapps; - -/** - * The default search controller. - */ -public class DefaultAppSearchController extends AllAppsSearchBarController { - - public DefaultAppSearchAlgorithm onInitializeSearch() { - return new DefaultAppSearchAlgorithm(mApps.getApps()); - } -} diff --git a/src/com/android/launcher3/allapps/SearchUiManager.java b/src/com/android/launcher3/allapps/SearchUiManager.java new file mode 100644 index 000000000..15455bcc3 --- /dev/null +++ b/src/com/android/launcher3/allapps/SearchUiManager.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.launcher3.allapps; + +import android.view.KeyEvent; + +/** + * Interface for controlling the Apps search UI. + */ +public interface SearchUiManager { + + /** + * Initializes the search manager. + */ + void initialize(AlphabeticalAppsList appsList, AllAppsRecyclerView recyclerView); + + /** + * Notifies the search manager that the apps-list has changed and the search UI should be + * updated accordingly. + */ + void refreshSearchResult(); + + /** + * Notifies the search manager to close any active search session. + */ + void reset(); + + /** + * Called before dispatching a key event, in case the search manager wants to initialize + * some UI beforehand. + */ + void preDispatchKeyEvent(KeyEvent keyEvent); + + /** + * Returns true if the IME should be brought back. + * TODO: Remove when removing support for opening all-apps in search mode. + */ + boolean shouldRestoreImeState(); + + /** + * Starts the search UI + * TODO: Remove when removing support for opening all-apps in search mode. + */ + void startAppsSearch(); +} diff --git a/src/com/android/launcher3/allapps/AllAppsSearchBarController.java b/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java index c7ba3abc6..547d9e185 100644 --- a/src/com/android/launcher3/allapps/AllAppsSearchBarController.java +++ b/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java @@ -13,12 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.launcher3.allapps; +package com.android.launcher3.allapps.search; import android.content.Context; -import android.content.Intent; -import android.graphics.Rect; -import android.net.Uri; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.text.Editable; @@ -34,16 +31,18 @@ import android.widget.TextView.OnEditorActionListener; import com.android.launcher3.ExtendedEditText; import com.android.launcher3.Launcher; import com.android.launcher3.Utilities; +import com.android.launcher3.allapps.AlphabeticalAppsList; import com.android.launcher3.discovery.AppDiscoveryItem; import com.android.launcher3.discovery.AppDiscoveryUpdateState; import com.android.launcher3.util.ComponentKey; +import com.android.launcher3.util.PackageManagerHelper; import java.util.ArrayList; /** * An interface to a search box that AllApps can command. */ -public abstract class AllAppsSearchBarController +public class AllAppsSearchBarController implements TextWatcher, OnEditorActionListener, ExtendedEditText.OnBackKeyListener { protected Launcher mLauncher; @@ -88,9 +87,11 @@ public abstract class AllAppsSearchBarController } /** - * To be implemented by subclasses. This method will get called when the controller is set. + * This method will get called when the controller is set. */ - protected abstract DefaultAppSearchAlgorithm onInitializeSearch(); + public DefaultAppSearchAlgorithm onInitializeSearch() { + return new DefaultAppSearchAlgorithm(mApps.getApps()); + } @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { @@ -114,7 +115,7 @@ public abstract class AllAppsSearchBarController } } - protected void refreshSearchResult() { + public void refreshSearchResult() { if (TextUtils.isEmpty(mQuery)) { return; } @@ -135,7 +136,8 @@ public abstract class AllAppsSearchBarController if (query.isEmpty()) { return false; } - return mLauncher.startActivitySafely(v, createMarketSearchIntent(query), null); + return mLauncher.startActivitySafely(v, + PackageManagerHelper.getMarketSearchIntent(mLauncher, query), null); } @Override @@ -186,29 +188,11 @@ public abstract class AllAppsSearchBarController } /** - * Creates a new market search intent. - */ - public Intent createMarketSearchIntent(String query) { - Uri marketSearchUri = Uri.parse("market://search") - .buildUpon() - .appendQueryParameter("c", "apps") - .appendQueryParameter("q", query) - .build(); - return new Intent(Intent.ACTION_VIEW).setData(marketSearchUri); - } - - /** * Callback for getting search results. */ public interface Callbacks { /** - * Called when the bounds of the search bar has changed. - */ - @Deprecated - void onBoundsChanged(Rect newBounds); - - /** * Called when the search is complete. * * @param apps sorted list of matching components or null if in case of failure. @@ -220,7 +204,6 @@ public abstract class AllAppsSearchBarController */ void clearSearchResult(); - /** * Called when the app discovery is providing an update of search, which can either be * START for starting a new discovery, diff --git a/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java b/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java new file mode 100644 index 000000000..116ec8866 --- /dev/null +++ b/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java @@ -0,0 +1,195 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.launcher3.allapps.search; + +import android.content.Context; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.text.Selection; +import android.text.Spannable; +import android.text.SpannableString; +import android.text.SpannableStringBuilder; +import android.text.TextUtils; +import android.text.method.TextKeyListener; +import android.util.AttributeSet; +import android.view.KeyEvent; +import android.widget.FrameLayout; + +import com.android.launcher3.ExtendedEditText; +import com.android.launcher3.Launcher; +import com.android.launcher3.R; +import com.android.launcher3.allapps.AllAppsGridAdapter; +import com.android.launcher3.allapps.AllAppsRecyclerView; +import com.android.launcher3.allapps.AlphabeticalAppsList; +import com.android.launcher3.allapps.SearchUiManager; +import com.android.launcher3.config.FeatureFlags; +import com.android.launcher3.discovery.AppDiscoveryItem; +import com.android.launcher3.discovery.AppDiscoveryUpdateState; +import com.android.launcher3.graphics.TintedDrawableSpan; +import com.android.launcher3.util.ComponentKey; + +import java.util.ArrayList; + +/** + * Layout to contain the All-apps search UI. + */ +public class AppsSearchContainerLayout extends FrameLayout + implements SearchUiManager, AllAppsSearchBarController.Callbacks { + + private final Launcher mLauncher; + private final int mMinHeight; + private final AllAppsSearchBarController mSearchBarController; + private final SpannableStringBuilder mSearchQueryBuilder; + private final HeaderElevationController mElevationController; + + private ExtendedEditText mSearchInput; + private AlphabeticalAppsList mApps; + private AllAppsRecyclerView mAppsRecyclerView; + private AllAppsGridAdapter mAdapter; + + public AppsSearchContainerLayout(Context context) { + this(context, null); + } + + public AppsSearchContainerLayout(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public AppsSearchContainerLayout(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + + mLauncher = Launcher.getLauncher(context); + mMinHeight = getResources().getDimensionPixelSize(R.dimen.all_apps_search_bar_height); + mSearchBarController = new AllAppsSearchBarController(); + mElevationController = new HeaderElevationController(this); + + mSearchQueryBuilder = new SpannableStringBuilder(); + Selection.setSelection(mSearchQueryBuilder, 0); + } + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + mSearchInput = findViewById(R.id.search_box_input); + + // Update the hint to contain the icon. + // Prefix the original hint with two spaces. The first space gets replaced by the icon + // using span. The second space is used for a singe space character between the hint + // and the icon. + SpannableString spanned = new SpannableString(" " + mSearchInput.getHint()); + spanned.setSpan(new TintedDrawableSpan(getContext(), R.drawable.ic_allapps_search), + 0, 1, Spannable.SPAN_EXCLUSIVE_INCLUSIVE); + mSearchInput.setHint(spanned); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP && + !mLauncher.getDeviceProfile().isVerticalBarLayout()) { + getLayoutParams().height = mLauncher.getDragLayer().getInsets().top + mMinHeight; + } + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } + + + @Override + public void initialize( + AlphabeticalAppsList appsList, AllAppsRecyclerView recyclerView) { + mApps = appsList; + mAppsRecyclerView = recyclerView; + mAppsRecyclerView.addOnScrollListener(mElevationController); + mAdapter = (AllAppsGridAdapter) mAppsRecyclerView.getAdapter(); + + mSearchBarController.initialize(appsList, mSearchInput, mLauncher, this); + } + + @Override + public void refreshSearchResult() { + mSearchBarController.refreshSearchResult(); + } + + @Override + public void reset() { + mElevationController.reset(); + mSearchBarController.reset(); + } + + @Override + public void preDispatchKeyEvent(KeyEvent event) { + // Determine if the key event was actual text, if so, focus the search bar and then dispatch + // the key normally so that it can process this key event + if (!mSearchBarController.isSearchFieldFocused() && + event.getAction() == KeyEvent.ACTION_DOWN) { + final int unicodeChar = event.getUnicodeChar(); + final boolean isKeyNotWhitespace = unicodeChar > 0 && + !Character.isWhitespace(unicodeChar) && !Character.isSpaceChar(unicodeChar); + if (isKeyNotWhitespace) { + boolean gotKey = TextKeyListener.getInstance().onKeyDown(this, mSearchQueryBuilder, + event.getKeyCode(), event); + if (gotKey && mSearchQueryBuilder.length() > 0) { + mSearchBarController.focusSearchField(); + } + } + } + } + + @Override + public boolean shouldRestoreImeState() { + return !TextUtils.isEmpty(mSearchInput.getText()); + } + + @Override + public void startAppsSearch() { + if (mApps != null) { + mSearchBarController.focusSearchField(); + } + } + + @Override + public void onSearchResult(String query, ArrayList<ComponentKey> apps) { + if (apps != null) { + mApps.setOrderedFilter(apps); + notifyResultChanged(); + mAdapter.setLastSearchQuery(query); + } + } + + @Override + public void clearSearchResult() { + if (mApps.setOrderedFilter(null)) { + notifyResultChanged(); + } + + // Clear the search query + mSearchQueryBuilder.clear(); + mSearchQueryBuilder.clearSpans(); + Selection.setSelection(mSearchQueryBuilder, 0); + } + + @Override + public void onAppDiscoverySearchUpdate( + @Nullable AppDiscoveryItem app, @NonNull AppDiscoveryUpdateState state) { + if (!mLauncher.isDestroyed()) { + mApps.onAppDiscoverySearchUpdate(app, state); + notifyResultChanged(); + } + } + + private void notifyResultChanged() { + mElevationController.reset(); + mAppsRecyclerView.onSearchResultsChanged(); + } +} diff --git a/src/com/android/launcher3/allapps/DefaultAppSearchAlgorithm.java b/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java index 06cf9aa71..457b454ef 100644 --- a/src/com/android/launcher3/allapps/DefaultAppSearchAlgorithm.java +++ b/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.launcher3.allapps; +package com.android.launcher3.allapps.search; import android.os.Handler; diff --git a/src/com/android/launcher3/allapps/HeaderElevationController.java b/src/com/android/launcher3/allapps/search/HeaderElevationController.java index b167fed33..ab4e88fc8 100644 --- a/src/com/android/launcher3/allapps/HeaderElevationController.java +++ b/src/com/android/launcher3/allapps/search/HeaderElevationController.java @@ -1,4 +1,4 @@ -package com.android.launcher3.allapps; +package com.android.launcher3.allapps.search; import android.content.res.Resources; import android.graphics.Outline; diff --git a/src/com/android/launcher3/testing/LauncherExtension.java b/src/com/android/launcher3/testing/LauncherExtension.java index 031da2061..36df22cd5 100644 --- a/src/com/android/launcher3/testing/LauncherExtension.java +++ b/src/com/android/launcher3/testing/LauncherExtension.java @@ -10,7 +10,6 @@ import android.widget.FrameLayout; import com.android.launcher3.AppInfo; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherCallbacks; -import com.android.launcher3.allapps.AllAppsSearchBarController; import com.android.launcher3.util.ComponentKey; import java.io.FileDescriptor; @@ -198,11 +197,6 @@ public class LauncherExtension extends Launcher { } @Override - public AllAppsSearchBarController getAllAppsSearchBarController() { - return null; - } - - @Override public List<ComponentKey> getPredictedApps() { // To debug app predictions, enable AlphabeticalAppsList#DEBUG_PREDICTIONS return new ArrayList<>(); @@ -214,11 +208,6 @@ public class LauncherExtension extends Launcher { } @Override - public void setLauncherSearchCallback(Object callbacks) { - // Do nothing - } - - @Override public void onAttachedToWindow() { } diff --git a/src/com/android/launcher3/util/PackageManagerHelper.java b/src/com/android/launcher3/util/PackageManagerHelper.java index e12b2d4f1..13034dd9e 100644 --- a/src/com/android/launcher3/util/PackageManagerHelper.java +++ b/src/com/android/launcher3/util/PackageManagerHelper.java @@ -30,9 +30,11 @@ import android.os.UserHandle; import android.text.TextUtils; import com.android.launcher3.AppInfo; +import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.compat.LauncherAppsCompat; +import java.net.URISyntaxException; import java.util.List; /** @@ -149,4 +151,20 @@ public class PackageManagerHelper { .appendQueryParameter("id", packageName) .build()); } + + /** + * Creates a new market search intent. + */ + public static Intent getMarketSearchIntent(Context context, String query) { + try { + Intent intent = Intent.parseUri(context.getString(R.string.market_search_intent), 0); + if (!TextUtils.isEmpty(query)) { + intent.setData( + intent.getData().buildUpon().appendQueryParameter("q", query).build()); + } + return intent; + } catch (URISyntaxException e) { + throw new RuntimeException(e); + } + } } |