Merge change I7daa7ae8 into eclair-mr2
* changes:
move event log tags used by SyncAdapter into a local .logtags file
diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java
index 1f17476..5d9034b 100644
--- a/core/java/android/app/SearchManager.java
+++ b/core/java/android/app/SearchManager.java
@@ -16,10 +16,16 @@
package android.app;
+import android.Manifest;
+import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
@@ -1326,6 +1332,21 @@
public final static String EXTRA_DATA_KEY = "intent_extra_data_key";
/**
+ * String extra data key for {@link Intent#ACTION_GLOBAL_SEARCH} intents. Contains the initial
+ * query to show in the global search activity.
+ *
+ * @hide Pending API council approval
+ */
+ public final static String INITIAL_QUERY = "initial_query";
+
+ /**
+ * Boolean extra data key for {@link Intent#ACTION_GLOBAL_SEARCH} intents. If {@code true},
+ * the initial query should be selected.
+ *
+ * @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)}.
*
@@ -1756,7 +1777,13 @@
boolean globalSearch) {
if (mIdent == 0) throw new IllegalArgumentException(
"Called from outside of an Activity context");
- if (!globalSearch && !mAssociatedPackage.equals(launchActivity.getPackageName())) {
+
+ if (globalSearch) {
+ startGlobalSearch(initialQuery, selectInitialQuery, appSearchData);
+ return;
+ }
+
+ if (!mAssociatedPackage.equals(launchActivity.getPackageName())) {
Log.w(TAG, "invoking app search on a different package " +
"not associated with this search manager");
}
@@ -1770,6 +1797,65 @@
}
/**
+ * Starts the global search activity.
+ */
+ private void startGlobalSearch(String initialQuery, boolean selectInitialQuery,
+ Bundle appSearchData) {
+ ComponentName globalSearchActivity = getGlobalSearchActivity();
+ if (globalSearchActivity == null) {
+ Log.w(TAG, "No global search activity found.");
+ return;
+ }
+ Intent intent = new Intent(Intent.ACTION_GLOBAL_SEARCH);
+ intent.setComponent(globalSearchActivity);
+ // TODO: Always pass name of calling package as an extra?
+ if (appSearchData != null) {
+ intent.putExtra(APP_DATA, appSearchData);
+ }
+ if (!TextUtils.isEmpty(initialQuery)) {
+ intent.putExtra(INITIAL_QUERY, initialQuery);
+ }
+ if (selectInitialQuery) {
+ intent.putExtra(SELECT_INITIAL_QUERY, selectInitialQuery);
+ }
+ try {
+ if (DBG) Log.d(TAG, "Starting global search: " + intent.toUri(0));
+ mContext.startActivity(intent);
+ } catch (ActivityNotFoundException ex) {
+ Log.e(TAG, "Global search activity not found: " + globalSearchActivity);
+ }
+ }
+
+ /**
+ * Gets the name of the global search activity.
+ *
+ * This is currently implemented by returning the first activity that handles
+ * the GLOBAL_SEARCH intent and has the GLOBAL_SEARCH permission. If we allow
+ * more than one global search acitivity to be installed, this code must be changed.
+ *
+ * TODO: Doing this every time we start global search is inefficient. Will fix that once
+ * we have settled on the right mechanism for finding the global search activity.
+ */
+ private ComponentName getGlobalSearchActivity() {
+ Intent intent = new Intent(Intent.ACTION_GLOBAL_SEARCH);
+ PackageManager pm = mContext.getPackageManager();
+ List<ResolveInfo> activities =
+ pm.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
+ int count = activities.size();
+ for (int i = 0; i < count; i++) {
+ ActivityInfo ai = activities.get(i).activityInfo;
+ if (pm.checkPermission(Manifest.permission.GLOBAL_SEARCH,
+ ai.packageName) == PackageManager.PERMISSION_GRANTED) {
+ return new ComponentName(ai.packageName, ai.name);
+ } else {
+ Log.w(TAG, "Package " + ai.packageName + " wants to handle GLOBAL_SEARCH, "
+ + "but does not have the GLOBAL_SEARCH permission.");
+ }
+ }
+ return null;
+ }
+
+ /**
* Similar to {@link #startSearch} but actually fires off the search query after invoking
* the search dialog. Made available for testing purposes.
*
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index a96e896..dfdfa15 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1102,6 +1102,16 @@
public static final String ACTION_SEARCH_LONG_PRESS = "android.intent.action.SEARCH_LONG_PRESS";
/**
+ * Activity Action: Start the global search activity.
+ * <p>Input: Nothing.
+ * <p>Output: Nothing.
+ *
+ * @hide Pending API council approval
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_GLOBAL_SEARCH = "android.intent.action.GLOBAL_SEARCH";
+
+ /**
* Activity Action: The user pressed the "Report" button in the crash/ANR dialog.
* This intent is delivered to the package which installed the application, usually
* the Market.
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index a796fe9..ae53dbe2 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -1252,6 +1252,28 @@
}
/**
+ * Convenience method to move a playlist item to a new location
+ * @param res The content resolver to use
+ * @param playlistId The numeric id of the playlist
+ * @param from The position of the item to move
+ * @param to The position to move the item to
+ * @return true on success
+ * @hide
+ */
+ public static final boolean moveItem(ContentResolver res,
+ long playlistId, int from, int to) {
+ Uri uri = MediaStore.Audio.Playlists.Members.getContentUri("external",
+ playlistId)
+ .buildUpon()
+ .appendEncodedPath(String.valueOf(from))
+ .appendQueryParameter("move", "true")
+ .build();
+ ContentValues values = new ContentValues();
+ values.put(MediaStore.Audio.Playlists.Members.PLAY_ORDER, to);
+ return res.update(uri, values, null, null) != 0;
+ }
+
+ /**
* The ID within the playlist.
*/
public static final String _ID = "_id";
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index b8f0a7e..8f24041 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -16,6 +16,7 @@
package android.widget;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
@@ -489,7 +490,10 @@
mUri = null;
}
} else if (mUri != null) {
- if ("content".equals(mUri.getScheme())) {
+ String scheme = mUri.getScheme();
+ if (ContentResolver.SCHEME_CONTENT.equals(scheme)
+ || ContentResolver.SCHEME_ANDROID_RESOURCE.equals(scheme)
+ || ContentResolver.SCHEME_FILE.equals(scheme)) {
try {
d = Drawable.createFromStream(
mContext.getContentResolver().openInputStream(mUri),