summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xres/drawable-hdpi/ic_arrow_back_grey.pngbin190 -> 152 bytes
-rwxr-xr-xres/drawable-hdpi/ic_search_grey.pngbin743 -> 419 bytes
-rwxr-xr-xres/drawable-mdpi/ic_arrow_back_grey.pngbin151 -> 117 bytes
-rwxr-xr-xres/drawable-mdpi/ic_search_grey.pngbin497 -> 263 bytes
-rw-r--r--res/drawable-v21/all_apps_search_market_bg.xml19
-rwxr-xr-xres/drawable-xhdpi/ic_arrow_back_grey.pngbin234 -> 151 bytes
-rwxr-xr-xres/drawable-xhdpi/ic_search_grey.pngbin972 -> 497 bytes
-rwxr-xr-xres/drawable-xxhdpi/ic_arrow_back_grey.pngbin308 -> 190 bytes
-rwxr-xr-xres/drawable-xxhdpi/ic_search_grey.pngbin1473 -> 743 bytes
-rwxr-xr-xres/drawable-xxxhdpi/ic_arrow_back_grey.pngbin359 -> 234 bytes
-rwxr-xr-xres/drawable-xxxhdpi/ic_search_grey.pngbin1996 -> 972 bytes
-rw-r--r--res/drawable/all_apps_search_market_bg.xml20
-rw-r--r--res/drawable/horizontal_line.xml21
-rw-r--r--res/layout/all_apps_empty_search.xml15
-rw-r--r--res/layout/all_apps_search_bar.xml13
-rw-r--r--res/layout/all_apps_search_market.xml29
-rw-r--r--res/layout/all_apps_search_market_divider.xml27
-rw-r--r--res/values/colors.xml1
-rw-r--r--res/values/strings.xml7
-rw-r--r--src/com/android/launcher3/Launcher.java15
-rw-r--r--src/com/android/launcher3/LauncherCallbacks.java1
-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
-rw-r--r--src/com/android/launcher3/testing/LauncherExtension.java5
27 files changed, 326 insertions, 87 deletions
diff --git a/res/drawable-hdpi/ic_arrow_back_grey.png b/res/drawable-hdpi/ic_arrow_back_grey.png
index ccd3900dd..c7c00886f 100755
--- a/res/drawable-hdpi/ic_arrow_back_grey.png
+++ b/res/drawable-hdpi/ic_arrow_back_grey.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_search_grey.png b/res/drawable-hdpi/ic_search_grey.png
index f4c5e27d2..bd20ba062 100755
--- a/res/drawable-hdpi/ic_search_grey.png
+++ b/res/drawable-hdpi/ic_search_grey.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_arrow_back_grey.png b/res/drawable-mdpi/ic_arrow_back_grey.png
index 11996efe3..5892c77d5 100755
--- a/res/drawable-mdpi/ic_arrow_back_grey.png
+++ b/res/drawable-mdpi/ic_arrow_back_grey.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_search_grey.png b/res/drawable-mdpi/ic_search_grey.png
index e83891c11..c386dbb38 100755
--- a/res/drawable-mdpi/ic_search_grey.png
+++ b/res/drawable-mdpi/ic_search_grey.png
Binary files differ
diff --git a/res/drawable-v21/all_apps_search_market_bg.xml b/res/drawable-v21/all_apps_search_market_bg.xml
new file mode 100644
index 000000000..7bd2f8816
--- /dev/null
+++ b/res/drawable-v21/all_apps_search_market_bg.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="@color/all_apps_search_market_button_focused_bg_color">
+ <item android:drawable="@color/quantum_panel_bg_color" />
+</ripple>
diff --git a/res/drawable-xhdpi/ic_arrow_back_grey.png b/res/drawable-xhdpi/ic_arrow_back_grey.png
index 79b9b486c..11996efe3 100755
--- a/res/drawable-xhdpi/ic_arrow_back_grey.png
+++ b/res/drawable-xhdpi/ic_arrow_back_grey.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_search_grey.png b/res/drawable-xhdpi/ic_search_grey.png
index bd5fdf444..e83891c11 100755
--- a/res/drawable-xhdpi/ic_search_grey.png
+++ b/res/drawable-xhdpi/ic_search_grey.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_arrow_back_grey.png b/res/drawable-xxhdpi/ic_arrow_back_grey.png
index 8e42e091d..ccd3900dd 100755
--- a/res/drawable-xxhdpi/ic_arrow_back_grey.png
+++ b/res/drawable-xxhdpi/ic_arrow_back_grey.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_search_grey.png b/res/drawable-xxhdpi/ic_search_grey.png
index 1d5c91361..f4c5e27d2 100755
--- a/res/drawable-xxhdpi/ic_search_grey.png
+++ b/res/drawable-xxhdpi/ic_search_grey.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_arrow_back_grey.png b/res/drawable-xxxhdpi/ic_arrow_back_grey.png
index 854a9bd1a..79b9b486c 100755
--- a/res/drawable-xxxhdpi/ic_arrow_back_grey.png
+++ b/res/drawable-xxxhdpi/ic_arrow_back_grey.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_search_grey.png b/res/drawable-xxxhdpi/ic_search_grey.png
index 28519fda6..bd5fdf444 100755
--- a/res/drawable-xxxhdpi/ic_search_grey.png
+++ b/res/drawable-xxxhdpi/ic_search_grey.png
Binary files differ
diff --git a/res/drawable/all_apps_search_market_bg.xml b/res/drawable/all_apps_search_market_bg.xml
new file mode 100644
index 000000000..5278e00a6
--- /dev/null
+++ b/res/drawable/all_apps_search_market_bg.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_focused="true" android:drawable="@color/all_apps_search_market_button_focused_bg_color" />
+ <item android:state_pressed="true" android:drawable="@color/all_apps_search_market_button_focused_bg_color" />
+ <item android:drawable="@android:color/transparent" />
+</selector>
diff --git a/res/drawable/horizontal_line.xml b/res/drawable/horizontal_line.xml
new file mode 100644
index 000000000..3f3f17e35
--- /dev/null
+++ b/res/drawable/horizontal_line.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <size android:height="1dp" />
+ <solid android:color="#ddd" />
+</shape>
diff --git a/res/layout/all_apps_empty_search.xml b/res/layout/all_apps_empty_search.xml
index f60c4a09a..b9b493eab 100644
--- a/res/layout/all_apps_empty_search.xml
+++ b/res/layout/all_apps_empty_search.xml
@@ -18,11 +18,14 @@
android:id="@+id/empty_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:gravity="center"
- android:paddingTop="24dp"
- android:paddingBottom="24dp"
- android:paddingRight="@dimen/all_apps_grid_view_start_margin"
- android:textSize="16sp"
- android:textColor="#4c4c4c"
+ android:gravity="start"
+ android:paddingTop="20dp"
+ android:paddingBottom="8dp"
+ android:paddingLeft="16dp"
+ android:paddingRight="16dp"
+ android:fontFamily="sans-serif-medium"
+ android:textSize="14sp"
+ android:textColor="#212121"
+ android:alpha="0.56"
android:focusable="false" />
diff --git a/res/layout/all_apps_search_bar.xml b/res/layout/all_apps_search_bar.xml
index cf30eac36..4947203df 100644
--- a/res/layout/all_apps_search_bar.xml
+++ b/res/layout/all_apps_search_bar.xml
@@ -32,11 +32,10 @@
android:id="@+id/dismiss_search_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginLeft="4dp"
- android:layout_marginStart="4dp"
+ android:layout_gravity="center_vertical"
+ android:layout_marginLeft="16dp"
+ android:layout_marginStart="16dp"
android:contentDescription="@string/all_apps_button_label"
- android:paddingBottom="13dp"
- android:paddingTop="13dp"
android:src="@drawable/ic_arrow_back_grey" />
<com.android.launcher3.allapps.AllAppsSearchEditView
@@ -63,10 +62,8 @@
android:layout_width="wrap_content"
android:layout_height="@dimen/all_apps_search_bar_height"
android:layout_gravity="end|center_vertical"
- android:layout_marginEnd="4dp"
- android:layout_marginRight="4dp"
+ android:layout_marginEnd="16dp"
+ android:layout_marginRight="16dp"
android:contentDescription="@string/all_apps_search_bar_hint"
- android:paddingBottom="13dp"
- android:paddingTop="13dp"
android:src="@drawable/ic_search_grey" />
</FrameLayout> \ No newline at end of file
diff --git a/res/layout/all_apps_search_market.xml b/res/layout/all_apps_search_market.xml
new file mode 100644
index 000000000..1282069c8
--- /dev/null
+++ b/res/layout/all_apps_search_market.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<TextView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/search_market_text"
+ android:layout_width="wrap_content"
+ android:layout_height="48dp"
+ android:gravity="start|center_vertical"
+ android:paddingLeft="16dp"
+ android:paddingRight="16dp"
+ android:fontFamily="sans-serif-medium"
+ android:textSize="14sp"
+ android:textColor="#009688"
+ android:textAllCaps="true"
+ android:focusable="false"
+ android:background="@drawable/all_apps_search_market_bg" />
diff --git a/res/layout/all_apps_search_market_divider.xml b/res/layout/all_apps_search_market_divider.xml
new file mode 100644
index 000000000..39097818f
--- /dev/null
+++ b/res/layout/all_apps_search_market_divider.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<ImageView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:paddingTop="16dp"
+ android:paddingBottom="8dp"
+ android:paddingLeft="16dp"
+ android:paddingRight="16dp"
+ android:focusable="false"
+ android:scaleType="matrix"
+ android:src="@drawable/horizontal_line" /> \ No newline at end of file
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 51e4d40a5..0add48cd8 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -44,6 +44,7 @@
<!-- All Apps -->
<color name="all_apps_grid_section_text_color">#009688</color>
+ <color name="all_apps_search_market_button_focused_bg_color">#DDDDDD</color>
<!-- Widgets view -->
<color name="widgets_view_fastscroll_thumb_inactive_color">#42FFFFFF</color>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 88f149bd0..fefadef28 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -24,10 +24,10 @@
<!-- URI used to import old favorites. [DO NOT TRANSLATE] -->
<string name="old_launcher_provider_uri" translatable="false">content://com.android.launcher2.settings/favorites?notify=true</string>
- <!-- Permission to receive the com.android.launcher3.action.LAUNCH intent -->
+ <!-- Permission to receive the com.android.launcher3.action.LAUNCH intent. [DO NOT TRANSLATE] -->
<string name="receive_launch_broadcasts_permission" translatable="false">com.android.launcher3.permission.RECEIVE_LAUNCH_BROADCASTS</string>
- <!-- Permission to receive the com.android.launcher3.action.FIRST_LOAD_COMPLETE intent -->
+ <!-- Permission to receive the com.android.launcher3.action.FIRST_LOAD_COMPLETE intent. [DO NOT TRANSLATE] -->
<string name="receive_first_load_broadcast_permission" translatable="false">com.android.launcher3.permission.RECEIVE_FIRST_LOAD_BROADCAST</string>
<!-- Application name -->
@@ -61,6 +61,9 @@
<string name="all_apps_loading_message">Loading Apps&#8230;</string>
<!-- No-search-results text. [CHAR_LIMIT=50] -->
<string name="all_apps_no_search_results">No Apps found matching \"<xliff:g id="query" example="Android">%1$s</xliff:g>\"</string>
+ <!-- Search market text. This is a format string where the first argument is the name of the activity
+ handling the search. The format string does not need to handle both of these arguments. [CHAR_LIMIT=50] -->
+ <string name="all_apps_search_market_message">Go to <xliff:g id="query" example="Play Store">%1$s</xliff:g></string>
<!-- Drag and drop -->
<skip />
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 32e7ee681..298b2c469 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -2137,6 +2137,15 @@ public class Launcher extends Activity
}
}
+ public void startSearchFromAllApps(View v, Intent searchIntent, String searchQuery) {
+ if (mLauncherCallbacks != null && mLauncherCallbacks.startSearchFromAllApps(searchQuery)) {
+ return;
+ }
+
+ // If not handled, then just start the provided search intent
+ startActivitySafely(v, searchIntent, null);
+ }
+
public boolean isOnCustomContent() {
return mWorkspace.isOnOrMovingToCustomContent();
}
@@ -2538,6 +2547,10 @@ public class Launcher extends Activity
if (!isAppsViewVisible()) {
showAppsView(true /* animated */, false /* resetListToTop */,
true /* updatePredictedApps */, false /* focusSearchBar */);
+
+ if (mLauncherCallbacks != null) {
+ mLauncherCallbacks.onClickAllAppsButton(v);
+ }
}
}
@@ -2929,7 +2942,7 @@ public class Launcher extends Activity
return false;
}
- @Thunk boolean startActivitySafely(View v, Intent intent, Object tag) {
+ public boolean startActivitySafely(View v, Intent intent, Object tag) {
boolean success = false;
if (mIsSafeModeEnabled && !Utilities.isSystemApp(this, intent)) {
Toast.makeText(this, R.string.safemode_shortcut_error, Toast.LENGTH_SHORT).show();
diff --git a/src/com/android/launcher3/LauncherCallbacks.java b/src/com/android/launcher3/LauncherCallbacks.java
index 6618cca78..e34bd57fd 100644
--- a/src/com/android/launcher3/LauncherCallbacks.java
+++ b/src/com/android/launcher3/LauncherCallbacks.java
@@ -77,6 +77,7 @@ public interface LauncherCallbacks {
public boolean providesSearch();
public boolean startSearch(String initialQuery, boolean selectInitialQuery,
Bundle appSearchData, Rect sourceBounds);
+ public boolean startSearchFromAllApps(String query);
@Deprecated
public void startVoice();
public boolean hasCustomContentToLeft();
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;
diff --git a/src/com/android/launcher3/testing/LauncherExtension.java b/src/com/android/launcher3/testing/LauncherExtension.java
index 34492e4ca..8702877bf 100644
--- a/src/com/android/launcher3/testing/LauncherExtension.java
+++ b/src/com/android/launcher3/testing/LauncherExtension.java
@@ -202,6 +202,11 @@ public class LauncherExtension extends Launcher {
}
@Override
+ public boolean startSearchFromAllApps(String query) {
+ return false;
+ }
+
+ @Override
public void startVoice() {
}