summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/current.xml11
-rw-r--r--core/java/android/app/SearchDialog.java19
-rw-r--r--core/java/android/app/SearchManager.java10
-rw-r--r--core/java/android/app/SearchSourceSelector.java197
-rw-r--r--core/res/res/drawable-hdpi/search_source_selector_indicator.pngbin0 -> 252 bytes
-rw-r--r--core/res/res/drawable-mdpi/search_source_selector_indicator.pngbin0 -> 195 bytes
-rw-r--r--core/res/res/drawable/search_source_selector_background.xml21
-rw-r--r--core/res/res/layout/search_bar.xml11
-rw-r--r--core/res/res/layout/search_source_selector.xml35
9 files changed, 290 insertions, 14 deletions
diff --git a/api/current.xml b/api/current.xml
index cbe47ff7af6a..64a7d7a29632 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -23917,6 +23917,17 @@
visibility="public"
>
</field>
+<field name="INTENT_ACTION_SELECT_SEARCH_SOURCE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.intent.action.SELECT_SEARCH_SOURCE&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="INTENT_ACTION_WEB_SEARCH_SETTINGS"
type="java.lang.String"
transient="false"
diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java
index 8968553ff07c..b3963968b09a 100644
--- a/core/java/android/app/SearchDialog.java
+++ b/core/java/android/app/SearchDialog.java
@@ -60,7 +60,6 @@ import android.widget.AdapterView;
import android.widget.AutoCompleteTextView;
import android.widget.Button;
import android.widget.ImageButton;
-import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
@@ -106,7 +105,7 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
// views & widgets
private TextView mBadgeLabel;
- private ImageView mAppIcon;
+ private SearchSourceSelector mSourceSelector;
private SearchAutoComplete mSearchAutoComplete;
private Button mGoButton;
private ImageButton mVoiceButton;
@@ -209,7 +208,8 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
mBadgeLabel = (TextView) findViewById(com.android.internal.R.id.search_badge);
mSearchAutoComplete = (SearchAutoComplete)
findViewById(com.android.internal.R.id.search_src_text);
- mAppIcon = (ImageView) findViewById(com.android.internal.R.id.search_app_icon);
+ mSourceSelector = new SearchSourceSelector(
+ findViewById(com.android.internal.R.id.search_source_selector));
mGoButton = (Button) findViewById(com.android.internal.R.id.search_go_btn);
mVoiceButton = (ImageButton) findViewById(com.android.internal.R.id.search_voice_btn);
mSearchPlate = findViewById(com.android.internal.R.id.search_plate);
@@ -606,13 +606,16 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
}
private void updateSearchAppIcon() {
+ mSourceSelector.setSource(mSearchable.getSearchActivity());
+ mSourceSelector.setAppSearchData(mAppSearchData);
+
// In Donut, we special-case the case of the browser to hide the app icon as if it were
// global search, for extra space for url entry.
//
// TODO: Remove this special case once the issue has been reconciled in Eclair.
if (mGlobalSearchMode || isBrowserSearch()) {
- mAppIcon.setImageResource(0);
- mAppIcon.setVisibility(View.GONE);
+ mSourceSelector.setSourceIcon(null);
+ mSourceSelector.setVisibility(View.GONE);
mSearchPlate.setPadding(SEARCH_PLATE_LEFT_PADDING_GLOBAL,
mSearchPlate.getPaddingTop(),
mSearchPlate.getPaddingRight(),
@@ -628,8 +631,8 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
icon = pm.getDefaultActivityIcon();
Log.w(LOG_TAG, mLaunchComponent + " not found, using generic app icon");
}
- mAppIcon.setImageDrawable(icon);
- mAppIcon.setVisibility(View.VISIBLE);
+ mSourceSelector.setSourceIcon(icon);
+ mSourceSelector.setVisibility(View.VISIBLE);
mSearchPlate.setPadding(SEARCH_PLATE_LEFT_PADDING_NON_GLOBAL,
mSearchPlate.getPaddingTop(),
mSearchPlate.getPaddingRight(),
@@ -812,6 +815,7 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
if (!mSearchAutoComplete.isPerformingCompletion()) {
// The user changed the query, remember it.
mUserQuery = s == null ? "" : s.toString();
+ mSourceSelector.setQuery(mUserQuery);
}
}
@@ -1927,6 +1931,7 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
query = "";
}
mUserQuery = query;
+ mSourceSelector.setQuery(query);
mSearchAutoComplete.setText(query);
mSearchAutoComplete.setSelection(query.length());
}
diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java
index 5d9034b516a8..5961ef55924e 100644
--- a/core/java/android/app/SearchManager.java
+++ b/core/java/android/app/SearchManager.java
@@ -1346,6 +1346,7 @@ public class SearchManager
* @hide Pending API council approval
*/
public final static String SELECT_INITIAL_QUERY = "select_initial_query";
+
/**
* Defines the constants used in the communication between {@link android.app.SearchDialog} and
* the global search provider via {@link Cursor#respond(android.os.Bundle)}.
@@ -1612,6 +1613,15 @@ public class SearchManager
public final static String SUGGEST_PARAMETER_LIMIT = "limit";
/**
+ * Intent action for opening the search source selection activity.
+ * The intent may include these extra values:
+ * {@link #QUERY},
+ * {@link #APP_DATA}.
+ */
+ public static final String INTENT_ACTION_SELECT_SEARCH_SOURCE
+ = "android.intent.action.SELECT_SEARCH_SOURCE";
+
+ /**
* If a suggestion has this value in {@link #SUGGEST_COLUMN_INTENT_ACTION},
* the search dialog will switch to a different suggestion source when the
* suggestion is clicked.
diff --git a/core/java/android/app/SearchSourceSelector.java b/core/java/android/app/SearchSourceSelector.java
new file mode 100644
index 000000000000..fabf858a52a3
--- /dev/null
+++ b/core/java/android/app/SearchSourceSelector.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2009 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 android.app;
+
+import com.android.internal.R;
+
+import android.content.ActivityNotFoundException;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Intent;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.View;
+import android.widget.ImageButton;
+
+import java.util.List;
+
+/**
+ * Utilities for setting up the search source selector.
+ *
+ * This class has two copies:
+ * android.app.SearchSourceSelector
+ * com.android.quicksearchbox.ui.SearchSourceSelector
+ *
+ * They should keep the same look and feel as much as possible,
+ * but only the intent details must absolutely stay in sync.
+ *
+ * @hide
+ */
+public class SearchSourceSelector implements View.OnClickListener {
+
+ private static final String TAG = "SearchSourceSelector";
+
+ // TODO: This should be defined in android.provider.Applications,
+ // and have a less made-up value.
+ private static final String APPLICATION_TYPE = "application/vnd.android.application";
+
+ public static final int ICON_VIEW_ID = R.id.search_source_selector_icon;
+
+ private final View mView;
+
+ private final ImageButton mIconView;
+
+ private ComponentName mSource;
+
+ private Bundle mAppSearchData;
+
+ private String mQuery;
+
+ public SearchSourceSelector(View view) {
+ mView = view;
+ mIconView = (ImageButton) view.findViewById(ICON_VIEW_ID);
+ mIconView.setOnClickListener(this);
+ }
+
+ /**
+ * Sets the icon displayed in the search source selector.
+ */
+ public void setSourceIcon(Drawable icon) {
+ mIconView.setImageDrawable(icon);
+ }
+
+ /**
+ * Sets the current search source.
+ */
+ public void setSource(ComponentName source) {
+ mSource = source;
+ }
+
+ /**
+ * Sets the app-specific data that will be passed to the search activity if
+ * the user opens the source selector and chooses a source.
+ */
+ public void setAppSearchData(Bundle appSearchData) {
+ mAppSearchData = appSearchData;
+ }
+
+ /**
+ * Sets the initial query that will be passed to the search activity if
+ * the user opens the source selector and chooses a source.
+ */
+ public void setQuery(String query) {
+ mQuery = query;
+ }
+
+ public void setVisibility(int visibility) {
+ mView.setVisibility(visibility);
+ }
+
+ /**
+ * Creates an intent for opening the search source selector activity.
+ *
+ * @param source The current search source.
+ * @param query The initial query that will be passed to the search activity if
+ * the user opens the source selector and chooses a source.
+ * @param appSearchData The app-specific data that will be passed to the search
+ * activity if the user opens the source selector and chooses a source.
+ */
+ public static Intent createIntent(ComponentName source, String query, Bundle appSearchData) {
+ Intent intent = new Intent(SearchManager.INTENT_ACTION_SELECT_SEARCH_SOURCE);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_CLEAR_TOP
+ | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+ Uri sourceUri = componentNameToUri(source);
+ if (sourceUri != null) {
+ intent.setDataAndType(sourceUri, APPLICATION_TYPE);
+ }
+ if (query != null) {
+ intent.putExtra(SearchManager.QUERY, query);
+ }
+ if (query != null) {
+ intent.putExtra(SearchManager.APP_DATA, appSearchData);
+ }
+ return intent;
+ }
+
+ /**
+ * Gets the search source from which the given
+ * {@link SearchManager.INTENT_ACTION_SELECT_SEARCH_SOURCE} intent was sent.
+ */
+ public static ComponentName getSource(Intent intent) {
+ return uriToComponentName(intent.getData());
+ }
+
+ private static Uri componentNameToUri(ComponentName name) {
+ if (name == null) return null;
+ // TODO: This URI format is specificed in android.provider.Applications which is @hidden
+ return new Uri.Builder()
+ .scheme(ContentResolver.SCHEME_CONTENT)
+ .authority("applications")
+ .appendEncodedPath("applications")
+ .appendPath(name.getPackageName())
+ .appendPath(name.getClassName())
+ .build();
+ }
+
+ private static ComponentName uriToComponentName(Uri uri) {
+ if (uri == null) return null;
+ List<String> path = uri.getPathSegments();
+ if (path == null || path.size() != 3) return null;
+ String pkg = path.get(1);
+ String cls = path.get(2);
+ if (TextUtils.isEmpty(pkg) || TextUtils.isEmpty(cls)) return null;
+ return new ComponentName(pkg, cls);
+ }
+
+ public void onClick(View v) {
+ trigger();
+ }
+
+ private void trigger() {
+ try {
+ Intent intent = createIntent(mSource, mQuery, mAppSearchData);
+ intent.setSourceBounds(getOnScreenRect(mIconView));
+ mIconView.getContext().startActivity(intent);
+ } catch (ActivityNotFoundException ex) {
+ Log.e(TAG, "No source selector activity found", ex);
+ }
+ }
+
+ // TODO: This code is replicated in lots of places:
+ // - android.provider.ContactsContract.QuickContact.showQuickContact()
+ // - android.widget.RemoteViews.setOnClickPendingIntent()
+ // - com.android.launcher2.Launcher.onClick()
+ // - com.android.launcher.Launcher.onClick()
+ // - com.android.server.status.StatusBarService.Launcher.onClick()
+ private static Rect getOnScreenRect(View v) {
+ final float appScale = v.getResources().getCompatibilityInfo().applicationScale;
+ final int[] pos = new int[2];
+ v.getLocationOnScreen(pos);
+ final Rect rect = new Rect();
+ rect.left = (int) (pos[0] * appScale + 0.5f);
+ rect.top = (int) (pos[1] * appScale + 0.5f);
+ rect.right = (int) ((pos[0] + v.getWidth()) * appScale + 0.5f);
+ rect.bottom = (int) ((pos[1] + v.getHeight()) * appScale + 0.5f);
+ return rect;
+ }
+
+}
diff --git a/core/res/res/drawable-hdpi/search_source_selector_indicator.png b/core/res/res/drawable-hdpi/search_source_selector_indicator.png
new file mode 100644
index 000000000000..b93a0c0bbfb3
--- /dev/null
+++ b/core/res/res/drawable-hdpi/search_source_selector_indicator.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/search_source_selector_indicator.png b/core/res/res/drawable-mdpi/search_source_selector_indicator.png
new file mode 100644
index 000000000000..26bf18a68870
--- /dev/null
+++ b/core/res/res/drawable-mdpi/search_source_selector_indicator.png
Binary files differ
diff --git a/core/res/res/drawable/search_source_selector_background.xml b/core/res/res/drawable/search_source_selector_background.xml
new file mode 100644
index 000000000000..fcacd892f3b7
--- /dev/null
+++ b/core/res/res/drawable/search_source_selector_background.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 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">
+
+ <!-- TODO: Need focused and pressed backgrounds -->
+
+</selector>
diff --git a/core/res/res/layout/search_bar.xml b/core/res/res/layout/search_bar.xml
index cf246ba3906a..12285fde6cee 100644
--- a/core/res/res/layout/search_bar.xml
+++ b/core/res/res/layout/search_bar.xml
@@ -55,14 +55,11 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
-
- <ImageView
- android:id="@+id/search_app_icon"
- android:layout_height="36dip"
- android:layout_width="36dip"
+
+ <include android:id="@+id/search_source_selector"
+ layout="@layout/search_source_selector"
android:layout_marginRight="7dip"
- android:layout_gravity="center_vertical"
- />
+ android:layout_gravity="center_vertical" />
<view class="android.app.SearchDialog$SearchAutoComplete"
android:id="@+id/search_src_text"
diff --git a/core/res/res/layout/search_source_selector.xml b/core/res/res/layout/search_source_selector.xml
new file mode 100644
index 000000000000..c69dfc0e2159
--- /dev/null
+++ b/core/res/res/layout/search_source_selector.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 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.
+-->
+
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="48dip"
+ android:layout_height="match_parent"
+ android:foreground="@drawable/search_source_selector_indicator"
+ android:foregroundGravity="bottom|right"
+ >
+
+ <ImageButton
+ android:id="@+id/search_source_selector_icon"
+ android:background="@drawable/search_source_selector_background"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:scaleType="centerInside"
+ android:focusable="true"
+ android:clickable="true"
+ />
+
+</FrameLayout>