summaryrefslogtreecommitdiffstats
path: root/src/com/android/launcher3/allapps
diff options
context:
space:
mode:
authorWinson Chung <winsonc@google.com>2015-07-10 12:38:30 -0700
committerWinson <winsonc@google.com>2015-08-06 12:22:38 -0700
commitbedf9232eb67a420f0372d3ca135ca13194e603b (patch)
treebcce2d55b9b90d760e874a506b3a0597b6006380 /src/com/android/launcher3/allapps
parentd1ea63f24a751521e6c35cc06be0e548e0b04f23 (diff)
downloadandroid_packages_apps_Trebuchet-bedf9232eb67a420f0372d3ca135ca13194e603b.tar.gz
android_packages_apps_Trebuchet-bedf9232eb67a420f0372d3ca135ca13194e603b.tar.bz2
android_packages_apps_Trebuchet-bedf9232eb67a420f0372d3ca135ca13194e603b.zip
Adding market search.
Change-Id: Id41615653cd4fa76213add4595418ad0cc6e7852
Diffstat (limited to 'src/com/android/launcher3/allapps')
-rw-r--r--src/com/android/launcher3/allapps/AllAppsContainerView.java31
-rw-r--r--src/com/android/launcher3/allapps/AllAppsGridAdapter.java130
-rw-r--r--src/com/android/launcher3/allapps/AllAppsRecyclerView.java2
-rw-r--r--src/com/android/launcher3/allapps/AlphabeticalAppsList.java59
-rw-r--r--src/com/android/launcher3/allapps/DefaultAppSearchController.java18
5 files changed, 170 insertions, 70 deletions
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index 010b2cb48..e129dc6d3 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -16,34 +16,26 @@
package com.android.launcher3.allapps;
import android.annotation.SuppressLint;
-import android.annotation.TargetApi;
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.os.Build;
-import android.os.Bundle;
import android.support.v7.widget.RecyclerView;
import android.text.Selection;
import android.text.SpannableStringBuilder;
import android.text.method.TextKeyListener;
import android.util.AttributeSet;
import android.view.KeyEvent;
-import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
-import android.view.ViewTreeObserver;
-import android.widget.FrameLayout;
import android.widget.LinearLayout;
-
import com.android.launcher3.AppInfo;
import com.android.launcher3.BaseContainerView;
-import com.android.launcher3.BubbleTextView;
import com.android.launcher3.CellLayout;
-import com.android.launcher3.CheckLongPressHelper;
import com.android.launcher3.DeleteDropTarget;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.DragSource;
@@ -53,7 +45,6 @@ import com.android.launcher3.ItemInfo;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherTransitionable;
import com.android.launcher3.R;
-import com.android.launcher3.Stats;
import com.android.launcher3.Utilities;
import com.android.launcher3.Workspace;
import com.android.launcher3.util.ComponentKey;
@@ -155,6 +146,7 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
@Thunk AllAppsSearchBarController mSearchBarController;
private ViewGroup mSearchBarContainerView;
private View mSearchBarView;
+ private SpannableStringBuilder mSearchQueryBuilder = null;
private int mSectionNamesMargin;
private int mNumAppsPerRow;
@@ -165,7 +157,13 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
// This coordinate is relative to its parent
private final Point mIconLastTouchPos = new Point();
- private SpannableStringBuilder mSearchQueryBuilder = null;
+ 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);
@@ -182,8 +180,7 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
mLauncher = (Launcher) context;
mSectionNamesMargin = res.getDimensionPixelSize(R.dimen.all_apps_grid_view_start_margin);
mApps = new AlphabeticalAppsList(context);
- mAdapter = new AllAppsGridAdapter(context, mApps, this, mLauncher, this);
- mAdapter.setEmptySearchText(res.getString(R.string.all_apps_loading_message));
+ mAdapter = new AllAppsGridAdapter(mLauncher, mApps, this, mLauncher, this);
mApps.setAdapter(mAdapter);
mLayoutManager = mAdapter.getLayoutManager();
mItemDecoration = mAdapter.getItemDecoration();
@@ -615,13 +612,9 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
@Override
public void onSearchResult(String query, ArrayList<ComponentKey> apps) {
if (apps != null) {
- if (apps.isEmpty()) {
- String formatStr = getResources().getString(R.string.all_apps_no_search_results);
- mAdapter.setEmptySearchText(String.format(formatStr, query));
- } else {
- mAppsRecyclerView.scrollToTop();
- }
mApps.setOrderedFilter(apps);
+ mAdapter.setLastSearchQuery(query);
+ mAppsRecyclerView.scrollToTop();
}
}
diff --git a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
index e96567c41..4acfc5ca6 100644
--- a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
+++ b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
@@ -16,14 +16,17 @@
package com.android.launcher3.allapps;
import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.Rect;
-import android.os.Handler;
import android.support.v4.view.accessibility.AccessibilityRecordCompat;
import android.support.v4.view.accessibility.AccessibilityEventCompat;
+import android.net.Uri;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
@@ -34,6 +37,7 @@ import android.view.accessibility.AccessibilityEvent;
import android.widget.TextView;
import com.android.launcher3.AppInfo;
import com.android.launcher3.BubbleTextView;
+import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.util.Thunk;
@@ -58,6 +62,10 @@ class AllAppsGridAdapter extends RecyclerView.Adapter<AllAppsGridAdapter.ViewHol
public static final int PREDICTION_ICON_VIEW_TYPE = 2;
// The message shown when there are no filtered results
public static final int EMPTY_SEARCH_VIEW_TYPE = 3;
+ // A divider that separates the apps list and the search market button
+ public static final int SEARCH_MARKET_DIVIDER_VIEW_TYPE = 4;
+ // The message to continue to a market search when there are no filtered results
+ public static final int SEARCH_MARKET_VIEW_TYPE = 5;
/**
* ViewHolder for each icon.
@@ -83,12 +91,12 @@ class AllAppsGridAdapter extends RecyclerView.Adapter<AllAppsGridAdapter.ViewHol
@Override
public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
super.onInitializeAccessibilityEvent(event);
- if (mApps.hasNoFilteredResults()) {
- // Disregard the no-search-results text as a list item for accessibility
- final AccessibilityRecordCompat record = AccessibilityEventCompat
- .asRecord(event);
- record.setItemCount(0);
- }
+
+ // Ensure that we only report the number apps for accessibility not including other
+ // adapter views
+ final AccessibilityRecordCompat record = AccessibilityEventCompat
+ .asRecord(event);
+ record.setItemCount(mApps.getNumFilteredApps());
}
@Override
@@ -115,11 +123,6 @@ class AllAppsGridAdapter extends RecyclerView.Adapter<AllAppsGridAdapter.ViewHol
@Override
public int getSpanSize(int position) {
- if (mApps.hasNoFilteredResults()) {
- // Empty view spans full width
- return mAppsPerRow;
- }
-
switch (mApps.getAdapterItems().get(position).viewType) {
case AllAppsGridAdapter.ICON_VIEW_TYPE:
case AllAppsGridAdapter.PREDICTION_ICON_VIEW_TYPE:
@@ -314,6 +317,7 @@ class AllAppsGridAdapter extends RecyclerView.Adapter<AllAppsGridAdapter.ViewHol
}
}
+ private Launcher mLauncher;
private LayoutInflater mLayoutInflater;
@Thunk AlphabeticalAppsList mApps;
private GridLayoutManager mGridLayoutMgr;
@@ -326,7 +330,19 @@ class AllAppsGridAdapter extends RecyclerView.Adapter<AllAppsGridAdapter.ViewHol
@Thunk int mPredictionBarDividerOffset;
@Thunk int mAppsPerRow;
@Thunk boolean mIsRtl;
- private String mEmptySearchText;
+
+ // The text to show when there are no search results and no market search handler.
+ private String mEmptySearchMessage;
+ // The name of the market app which handles searches, to be used in the format str
+ // below when updating the search-market view. Only needs to be loaded once.
+ private String mMarketAppName;
+ // The text to show when there is a market app which can handle a specific query, updated
+ // each time the search query changes.
+ private String mMarketSearchMessage;
+ // The intent to send off to the market app, updated each time the search query changes.
+ private Intent mMarketSearchIntent;
+ // The last query that the user entered into the search field
+ private String mLastSearchQuery;
// Section drawing
@Thunk int mSectionNamesMargin;
@@ -334,16 +350,18 @@ class AllAppsGridAdapter extends RecyclerView.Adapter<AllAppsGridAdapter.ViewHol
@Thunk Paint mSectionTextPaint;
@Thunk Paint mPredictedAppsDividerPaint;
- public AllAppsGridAdapter(Context context, AlphabeticalAppsList apps,
+ public AllAppsGridAdapter(Launcher launcher, AlphabeticalAppsList apps,
View.OnTouchListener touchListener, View.OnClickListener iconClickListener,
View.OnLongClickListener iconLongClickListener) {
- Resources res = context.getResources();
+ Resources res = launcher.getResources();
+ mLauncher = launcher;
mApps = apps;
+ mEmptySearchMessage = res.getString(R.string.all_apps_loading_message);
mGridSizer = new GridSpanSizer();
- mGridLayoutMgr = new AppsGridLayoutManager(context);
+ mGridLayoutMgr = new AppsGridLayoutManager(launcher);
mGridLayoutMgr.setSpanSizeLookup(mGridSizer);
mItemDecoration = new GridItemDecoration();
- mLayoutInflater = LayoutInflater.from(context);
+ mLayoutInflater = LayoutInflater.from(launcher);
mTouchListener = touchListener;
mIconClickListener = iconClickListener;
mIconLongClickListener = iconLongClickListener;
@@ -363,6 +381,14 @@ class AllAppsGridAdapter extends RecyclerView.Adapter<AllAppsGridAdapter.ViewHol
mPredictionBarDividerOffset =
(-res.getDimensionPixelSize(R.dimen.all_apps_prediction_icon_bottom_padding) +
res.getDimensionPixelSize(R.dimen.all_apps_icon_top_bottom_padding)) / 2;
+
+ // Resolve the market app handling additional searches
+ PackageManager pm = launcher.getPackageManager();
+ ResolveInfo marketInfo = pm.resolveActivity(createMarketSearchIntent(""),
+ PackageManager.MATCH_DEFAULT_ONLY);
+ if (marketInfo != null) {
+ mMarketAppName = marketInfo.loadLabel(pm).toString();
+ }
}
/**
@@ -381,10 +407,19 @@ class AllAppsGridAdapter extends RecyclerView.Adapter<AllAppsGridAdapter.ViewHol
}
/**
- * Sets the text to show when there are no apps.
+ * Sets the last search query that was made, used to show when there are no results and to also
+ * seed the intent for searching the market.
*/
- public void setEmptySearchText(String query) {
- mEmptySearchText = query;
+ public void setLastSearchQuery(String query) {
+ Resources res = mLauncher.getResources();
+ String formatStr = res.getString(R.string.all_apps_no_search_results);
+ mLastSearchQuery = query;
+ mEmptySearchMessage = String.format(formatStr, query);
+ if (mMarketAppName != null) {
+ mMarketSearchMessage = String.format(res.getString(R.string.all_apps_search_market_message),
+ mMarketAppName);
+ mMarketSearchIntent = createMarketSearchIntent(query);
+ }
}
/**
@@ -413,9 +448,6 @@ class AllAppsGridAdapter extends RecyclerView.Adapter<AllAppsGridAdapter.ViewHol
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
switch (viewType) {
- case EMPTY_SEARCH_VIEW_TYPE:
- return new ViewHolder(mLayoutInflater.inflate(R.layout.all_apps_empty_search, parent,
- false));
case SECTION_BREAK_VIEW_TYPE:
return new ViewHolder(new View(parent.getContext()));
case ICON_VIEW_TYPE: {
@@ -440,6 +472,22 @@ class AllAppsGridAdapter extends RecyclerView.Adapter<AllAppsGridAdapter.ViewHol
icon.setFocusable(true);
return new ViewHolder(icon);
}
+ case EMPTY_SEARCH_VIEW_TYPE:
+ return new ViewHolder(mLayoutInflater.inflate(R.layout.all_apps_empty_search,
+ parent, false));
+ case SEARCH_MARKET_DIVIDER_VIEW_TYPE:
+ return new ViewHolder(mLayoutInflater.inflate(R.layout.all_apps_search_market_divider,
+ parent, false));
+ case SEARCH_MARKET_VIEW_TYPE:
+ View searchMarketView = mLayoutInflater.inflate(R.layout.all_apps_search_market,
+ parent, false);
+ searchMarketView.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mLauncher.startSearchFromAllApps(v, mMarketSearchIntent, mLastSearchQuery);
+ }
+ });
+ return new ViewHolder(searchMarketView);
default:
throw new RuntimeException("Unexpected view type");
}
@@ -461,28 +509,44 @@ class AllAppsGridAdapter extends RecyclerView.Adapter<AllAppsGridAdapter.ViewHol
break;
}
case EMPTY_SEARCH_VIEW_TYPE:
- TextView emptyViewText = (TextView) holder.mContent.findViewById(R.id.empty_text);
- emptyViewText.setText(mEmptySearchText);
+ TextView emptyViewText = (TextView) holder.mContent;
+ emptyViewText.setText(mEmptySearchMessage);
+ break;
+ case SEARCH_MARKET_VIEW_TYPE:
+ View searchView = holder.mContent;
+ if (mMarketSearchIntent != null) {
+ searchView.setVisibility(View.VISIBLE);
+ searchView.setContentDescription(mMarketSearchMessage);
+ ((TextView) searchView.findViewById(R.id.search_market_text))
+ .setText(mMarketSearchMessage);
+ } else {
+ searchView.setVisibility(View.GONE);
+ }
break;
}
}
@Override
public int getItemCount() {
- if (mApps.hasNoFilteredResults()) {
- // For the empty view
- return 1;
- }
return mApps.getAdapterItems().size();
}
@Override
public int getItemViewType(int position) {
- if (mApps.hasNoFilteredResults()) {
- return EMPTY_SEARCH_VIEW_TYPE;
- }
-
AlphabeticalAppsList.AdapterItem item = mApps.getAdapterItems().get(position);
return item.viewType;
}
+
+ /**
+ * Creates a new market search intent.
+ */
+ private Intent createMarketSearchIntent(String query) {
+ Uri marketSearchUri = Uri.parse("market://search")
+ .buildUpon()
+ .appendQueryParameter("q", query)
+ .build();
+ Intent marketSearchIntent = new Intent(Intent.ACTION_VIEW);
+ marketSearchIntent.setData(marketSearchUri);
+ return marketSearchIntent;
+ }
}
diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
index 730c8d15a..5aa973a15 100644
--- a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
@@ -90,6 +90,8 @@ public class AllAppsRecyclerView extends BaseRecyclerView
RecyclerView.RecycledViewPool pool = getRecycledViewPool();
int approxRows = (int) Math.ceil(grid.availableHeightPx / grid.allAppsIconSizePx);
pool.setMaxRecycledViews(AllAppsGridAdapter.EMPTY_SEARCH_VIEW_TYPE, 1);
+ pool.setMaxRecycledViews(AllAppsGridAdapter.SEARCH_MARKET_DIVIDER_VIEW_TYPE, 1);
+ pool.setMaxRecycledViews(AllAppsGridAdapter.SEARCH_MARKET_VIEW_TYPE, 1);
pool.setMaxRecycledViews(AllAppsGridAdapter.ICON_VIEW_TYPE, approxRows * mNumAppsPerRow);
pool.setMaxRecycledViews(AllAppsGridAdapter.PREDICTION_ICON_VIEW_TYPE, mNumAppsPerRow);
pool.setMaxRecycledViews(AllAppsGridAdapter.SECTION_BREAK_VIEW_TYPE, approxRows);
diff --git a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
index 47241ce5d..396f75790 100644
--- a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
+++ b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
@@ -81,12 +81,12 @@ public class AlphabeticalAppsList {
public int position;
// The type of this item
public int viewType;
- // The row that this item shows up on
- public int rowIndex;
/** Section & App properties */
// The section for this item
public SectionInfo sectionInfo;
+ // The row that this item shows up on
+ public int rowIndex;
/** App-only properties */
// The section name of this app. Note that there can be multiple items with different
@@ -111,14 +111,14 @@ public class AlphabeticalAppsList {
}
public static AdapterItem asPredictedApp(int pos, SectionInfo section, String sectionName,
- int sectionAppIndex, AppInfo appInfo, int appIndex) {
+ int sectionAppIndex, AppInfo appInfo, int appIndex) {
AdapterItem item = asApp(pos, section, sectionName, sectionAppIndex, appInfo, appIndex);
item.viewType = AllAppsGridAdapter.PREDICTION_ICON_VIEW_TYPE;
return item;
}
public static AdapterItem asApp(int pos, SectionInfo section, String sectionName,
- int sectionAppIndex, AppInfo appInfo, int appIndex) {
+ int sectionAppIndex, AppInfo appInfo, int appIndex) {
AdapterItem item = new AdapterItem();
item.viewType = AllAppsGridAdapter.ICON_VIEW_TYPE;
item.position = pos;
@@ -129,6 +129,27 @@ public class AlphabeticalAppsList {
item.appIndex = appIndex;
return item;
}
+
+ public static AdapterItem asEmptySearch(int pos) {
+ AdapterItem item = new AdapterItem();
+ item.viewType = AllAppsGridAdapter.EMPTY_SEARCH_VIEW_TYPE;
+ item.position = pos;
+ return item;
+ }
+
+ public static AdapterItem asDivider(int pos) {
+ AdapterItem item = new AdapterItem();
+ item.viewType = AllAppsGridAdapter.SEARCH_MARKET_DIVIDER_VIEW_TYPE;
+ item.position = pos;
+ return item;
+ }
+
+ public static AdapterItem asMarketSearch(int pos) {
+ AdapterItem item = new AdapterItem();
+ item.viewType = AllAppsGridAdapter.SEARCH_MARKET_VIEW_TYPE;
+ item.position = pos;
+ return item;
+ }
}
/**
@@ -167,6 +188,7 @@ public class AlphabeticalAppsList {
private int mNumAppsPerRow;
private int mNumPredictedAppsPerRow;
private int mNumAppRowsInAdapter;
+ private boolean mDisableEmptyText;
public AlphabeticalAppsList(Context context) {
mLauncher = (Launcher) context;
@@ -194,6 +216,13 @@ public class AlphabeticalAppsList {
}
/**
+ * Disables the empty text message when there are no search results.
+ */
+ public void disableEmptyText() {
+ mDisableEmptyText = true;
+ }
+
+ /**
* Returns all the apps.
*/
public List<AppInfo> getApps() {
@@ -222,17 +251,17 @@ public class AlphabeticalAppsList {
}
/**
- * Returns the number of applications in this list.
+ * Returns the number of rows of applications (not including predictions)
*/
- public int getSize() {
- return mFilteredApps.size();
+ public int getNumAppRows() {
+ return mNumAppRowsInAdapter;
}
/**
- * Returns the number of rows of applications (not including predictions)
+ * Returns the number of applications in this list.
*/
- public int getNumAppRows() {
- return mNumAppRowsInAdapter;
+ public int getNumFilteredApps() {
+ return mFilteredApps.size();
}
/**
@@ -457,6 +486,16 @@ public class AlphabeticalAppsList {
mFilteredApps.add(info);
}
+ // Append the search market item if we are currently searching
+ if (hasFilter()) {
+ if (hasNoFilteredResults()) {
+ mAdapterItems.add(AdapterItem.asEmptySearch(position++));
+ } else {
+ mAdapterItems.add(AdapterItem.asDivider(position++));
+ }
+ mAdapterItems.add(AdapterItem.asMarketSearch(position++));
+ }
+
// Merge multiple sections together as requested by the merge strategy for this device
mergeSections();
diff --git a/src/com/android/launcher3/allapps/DefaultAppSearchController.java b/src/com/android/launcher3/allapps/DefaultAppSearchController.java
index 83b920589..14cbb9534 100644
--- a/src/com/android/launcher3/allapps/DefaultAppSearchController.java
+++ b/src/com/android/launcher3/allapps/DefaultAppSearchController.java
@@ -169,19 +169,21 @@ final class DefaultAppSearchController extends AllAppsSearchBarController
if (actionId != EditorInfo.IME_ACTION_DONE) {
return false;
}
- // Skip if there isn't exactly one item
- if (mApps.getSize() != 1) {
+ // Skip if there are more than one icon
+ if (mApps.getNumFilteredApps() > 1) {
return false;
}
- // If there is exactly one icon, then quick-launch it
+ // 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);
- if (item.viewType == AllAppsGridAdapter.ICON_VIEW_TYPE) {
- mAppsRecyclerView.getChildAt(i).performClick();
- mInputMethodManager.hideSoftInputFromWindow(
- mContainerView.getWindowToken(), 0);
- return true;
+ 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;