summaryrefslogtreecommitdiffstats
path: root/core/java/android/content/Intent.java
diff options
context:
space:
mode:
Diffstat (limited to 'core/java/android/content/Intent.java')
-rw-r--r--core/java/android/content/Intent.java229
1 files changed, 215 insertions, 14 deletions
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 9948985..4e5598b 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2315,6 +2315,11 @@ public class Intent implements Parcelable, Cloneable {
/**
* Used with {@link #ACTION_MAIN} to launch the browser application.
* The activity should be able to browse the Internet.
+ * <p>NOTE: This should not be used as the primary key of an Intent,
+ * since it will not result in the app launching with the correct
+ * action and category. Instead, use this with
+ * {@link #makeMainSelectorActivity(String, String) to generate a main
+ * Intent with this category in the selector.</p>
*/
@SdkConstant(SdkConstantType.INTENT_CATEGORY)
public static final String CATEGORY_APP_BROWSER = "android.intent.category.APP_BROWSER";
@@ -2322,6 +2327,11 @@ public class Intent implements Parcelable, Cloneable {
/**
* Used with {@link #ACTION_MAIN} to launch the calculator application.
* The activity should be able to perform standard arithmetic operations.
+ * <p>NOTE: This should not be used as the primary key of an Intent,
+ * since it will not result in the app launching with the correct
+ * action and category. Instead, use this with
+ * {@link #makeMainSelectorActivity(String, String) to generate a main
+ * Intent with this category in the selector.</p>
*/
@SdkConstant(SdkConstantType.INTENT_CATEGORY)
public static final String CATEGORY_APP_CALCULATOR = "android.intent.category.APP_CALCULATOR";
@@ -2329,6 +2339,11 @@ public class Intent implements Parcelable, Cloneable {
/**
* Used with {@link #ACTION_MAIN} to launch the calendar application.
* The activity should be able to view and manipulate calendar entries.
+ * <p>NOTE: This should not be used as the primary key of an Intent,
+ * since it will not result in the app launching with the correct
+ * action and category. Instead, use this with
+ * {@link #makeMainSelectorActivity(String, String) to generate a main
+ * Intent with this category in the selector.</p>
*/
@SdkConstant(SdkConstantType.INTENT_CATEGORY)
public static final String CATEGORY_APP_CALENDAR = "android.intent.category.APP_CALENDAR";
@@ -2336,6 +2351,11 @@ public class Intent implements Parcelable, Cloneable {
/**
* Used with {@link #ACTION_MAIN} to launch the contacts application.
* The activity should be able to view and manipulate address book entries.
+ * <p>NOTE: This should not be used as the primary key of an Intent,
+ * since it will not result in the app launching with the correct
+ * action and category. Instead, use this with
+ * {@link #makeMainSelectorActivity(String, String) to generate a main
+ * Intent with this category in the selector.</p>
*/
@SdkConstant(SdkConstantType.INTENT_CATEGORY)
public static final String CATEGORY_APP_CONTACTS = "android.intent.category.APP_CONTACTS";
@@ -2343,6 +2363,11 @@ public class Intent implements Parcelable, Cloneable {
/**
* Used with {@link #ACTION_MAIN} to launch the email application.
* The activity should be able to send and receive email.
+ * <p>NOTE: This should not be used as the primary key of an Intent,
+ * since it will not result in the app launching with the correct
+ * action and category. Instead, use this with
+ * {@link #makeMainSelectorActivity(String, String) to generate a main
+ * Intent with this category in the selector.</p>
*/
@SdkConstant(SdkConstantType.INTENT_CATEGORY)
public static final String CATEGORY_APP_EMAIL = "android.intent.category.APP_EMAIL";
@@ -2351,6 +2376,11 @@ public class Intent implements Parcelable, Cloneable {
* Used with {@link #ACTION_MAIN} to launch the gallery application.
* The activity should be able to view and manipulate image and video files
* stored on the device.
+ * <p>NOTE: This should not be used as the primary key of an Intent,
+ * since it will not result in the app launching with the correct
+ * action and category. Instead, use this with
+ * {@link #makeMainSelectorActivity(String, String) to generate a main
+ * Intent with this category in the selector.</p>
*/
@SdkConstant(SdkConstantType.INTENT_CATEGORY)
public static final String CATEGORY_APP_GALLERY = "android.intent.category.APP_GALLERY";
@@ -2358,6 +2388,11 @@ public class Intent implements Parcelable, Cloneable {
/**
* Used with {@link #ACTION_MAIN} to launch the maps application.
* The activity should be able to show the user's current location and surroundings.
+ * <p>NOTE: This should not be used as the primary key of an Intent,
+ * since it will not result in the app launching with the correct
+ * action and category. Instead, use this with
+ * {@link #makeMainSelectorActivity(String, String) to generate a main
+ * Intent with this category in the selector.</p>
*/
@SdkConstant(SdkConstantType.INTENT_CATEGORY)
public static final String CATEGORY_APP_MAPS = "android.intent.category.APP_MAPS";
@@ -2365,13 +2400,24 @@ public class Intent implements Parcelable, Cloneable {
/**
* Used with {@link #ACTION_MAIN} to launch the messaging application.
* The activity should be able to send and receive text messages.
+ * <p>NOTE: This should not be used as the primary key of an Intent,
+ * since it will not result in the app launching with the correct
+ * action and category. Instead, use this with
+ * {@link #makeMainSelectorActivity(String, String) to generate a main
+ * Intent with this category in the selector.</p>
*/
@SdkConstant(SdkConstantType.INTENT_CATEGORY)
public static final String CATEGORY_APP_MESSAGING = "android.intent.category.APP_MESSAGING";
/**
* Used with {@link #ACTION_MAIN} to launch the music application.
- * The activity should be able to play, browse, or manipulate music files stored on the device.
+ * The activity should be able to play, browse, or manipulate music files
+ * stored on the device.
+ * <p>NOTE: This should not be used as the primary key of an Intent,
+ * since it will not result in the app launching with the correct
+ * action and category. Instead, use this with
+ * {@link #makeMainSelectorActivity(String, String) to generate a main
+ * Intent with this category in the selector.</p>
*/
@SdkConstant(SdkConstantType.INTENT_CATEGORY)
public static final String CATEGORY_APP_MUSIC = "android.intent.category.APP_MUSIC";
@@ -2963,6 +3009,7 @@ public class Intent implements Parcelable, Cloneable {
private HashSet<String> mCategories;
private Bundle mExtras;
private Rect mSourceBounds;
+ private Intent mSelector;
// ---------------------------------------------------------------------
@@ -2991,6 +3038,9 @@ public class Intent implements Parcelable, Cloneable {
if (o.mSourceBounds != null) {
this.mSourceBounds = new Rect(o.mSourceBounds);
}
+ if (o.mSelector != null) {
+ this.mSelector = new Intent(o.mSelector);
+ }
}
@Override
@@ -3131,6 +3181,39 @@ public class Intent implements Parcelable, Cloneable {
}
/**
+ * Make an Intent for the main activity of an application, without
+ * specifying a specific activity to run but giving a selector to find
+ * the activity. This results in a final Intent that is structured
+ * the same as when the application is launched from
+ * Home. For anything else that wants to launch an application in the
+ * same way, it is important that they use an Intent structured the same
+ * way, and can use this function to ensure this is the case.
+ *
+ * <p>The returned Intent has {@link #ACTION_MAIN} as its action, and includes the
+ * category {@link #CATEGORY_LAUNCHER}. This does <em>not</em> have
+ * {@link #FLAG_ACTIVITY_NEW_TASK} set, though typically you will want
+ * to do that through {@link #addFlags(int)} on the returned Intent.
+ *
+ * @param selectorAction The action name of the Intent's selector.
+ * @param selectorCategory The name of a category to add to the Intent's
+ * selector.
+ * @return Returns a newly created Intent that can be used to launch the
+ * activity as a main application entry.
+ *
+ * @see #setSelector(Intent)
+ */
+ public static Intent makeMainSelectorActivity(String selectorAction,
+ String selectorCategory) {
+ Intent intent = new Intent(ACTION_MAIN);
+ intent.addCategory(CATEGORY_LAUNCHER);
+ Intent selector = new Intent();
+ selector.setAction(selectorAction);
+ selector.addCategory(selectorCategory);
+ intent.setSelector(selector);
+ return intent;
+ }
+
+ /**
* Make an Intent that can be used to re-launch an application's task
* in its base state. This is like {@link #makeMainActivity(ComponentName)},
* but also sets the flags {@link #FLAG_ACTIVITY_NEW_TASK} and
@@ -3205,6 +3288,7 @@ public class Intent implements Parcelable, Cloneable {
// new format
Intent intent = new Intent(ACTION_VIEW);
+ Intent baseIntent = intent;
// fetch data part, if present
String data = i >= 0 ? uri.substring(0, i) : null;
@@ -3214,8 +3298,9 @@ public class Intent implements Parcelable, Cloneable {
// loop over contents of Intent, all name=value;
while (!uri.startsWith("end", i)) {
int eq = uri.indexOf('=', i);
- int semi = uri.indexOf(';', eq);
- String value = Uri.decode(uri.substring(eq + 1, semi));
+ if (eq < 0) eq = i-1;
+ int semi = uri.indexOf(';', i);
+ String value = eq < semi ? Uri.decode(uri.substring(eq + 1, semi)) : "";
// action
if (uri.startsWith("action=", i)) {
@@ -3257,6 +3342,11 @@ public class Intent implements Parcelable, Cloneable {
intent.mSourceBounds = Rect.unflattenFromString(value);
}
+ // selector
+ else if (semi == (i+3) && uri.startsWith("SEL", i)) {
+ intent = new Intent();
+ }
+
// extra
else {
String key = Uri.decode(uri.substring(i + 2, eq));
@@ -3280,6 +3370,12 @@ public class Intent implements Parcelable, Cloneable {
i = semi + 1;
}
+ if (intent != baseIntent) {
+ // The Intent had a selector; fix it up.
+ baseIntent.setSelector(intent);
+ intent = baseIntent;
+ }
+
if (data != null) {
if (data.startsWith("intent:")) {
data = data.substring(7);
@@ -3605,7 +3701,7 @@ public class Intent implements Parcelable, Cloneable {
* Return the set of all categories in the intent. If there are no categories,
* returns NULL.
*
- * @return Set The set of categories you can examine. Do not modify!
+ * @return The set of categories you can examine. Do not modify!
*
* @see #hasCategory
* @see #addCategory
@@ -3615,6 +3711,16 @@ public class Intent implements Parcelable, Cloneable {
}
/**
+ * Return the specific selector associated with this Intent. If there is
+ * none, returns null. See {@link #setSelector} for more information.
+ *
+ * @see #setSelector
+ */
+ public Intent getSelector() {
+ return mSelector;
+ }
+
+ /**
* Sets the ClassLoader that will be used when unmarshalling
* any Parcelable values from the extras of this Intent.
*
@@ -4433,6 +4539,49 @@ public class Intent implements Parcelable, Cloneable {
}
/**
+ * Set a selector for this Intent. This is a modification to the kinds of
+ * things the Intent will match. If the selector is set, it will be used
+ * when trying to find entities that can handle the Intent, instead of the
+ * main contents of the Intent. This allows you build an Intent containing
+ * a generic protocol while targeting it more specifically.
+ *
+ * <p>An example of where this may be used is with things like
+ * {@link #CATEGORY_APP_BROWSER}. This category allows you to build an
+ * Intent that will launch the Browser application. However, the correct
+ * main entry point of an application is actually {@link #ACTION_MAIN}
+ * {@link #CATEGORY_LAUNCHER} with {@link #setComponent(ComponentName)}
+ * used to specify the actual Activity to launch. If you launch the browser
+ * with something different, undesired behavior may happen if the user has
+ * previously or later launches it the normal way, since they do not match.
+ * Instead, you can build an Intent with the MAIN action (but no ComponentName
+ * yet specified) and set a selector with {@link #ACTION_MAIN} and
+ * {@link #CATEGORY_APP_BROWSER} to point it specifically to the browser activity.
+ *
+ * <p>Setting a selector does not impact the behavior of
+ * {@link #filterEquals(Intent)} and {@link #filterHashCode()}. This is part of the
+ * desired behavior of a selector -- it does not impact the base meaning
+ * of the Intent, just what kinds of things will be matched against it
+ * when determining who can handle it.</p>
+ *
+ * <p>You can not use both a selector and {@link #setPackage(String)} on
+ * the same base Intent.</p>
+ *
+ * @param selector The desired selector Intent; set to null to not use
+ * a special selector.
+ */
+ public void setSelector(Intent selector) {
+ if (selector == this) {
+ throw new IllegalArgumentException(
+ "Intent being set as a selector of itself");
+ }
+ if (selector != null && mPackage != null) {
+ throw new IllegalArgumentException(
+ "Can't set selector when package name is already set");
+ }
+ mSelector = selector;
+ }
+
+ /**
* Add extended data to the intent. The name must include a package
* prefix, for example the app com.android.contacts would use names
* like "com.android.contacts.ShowAll".
@@ -5259,6 +5408,10 @@ public class Intent implements Parcelable, Cloneable {
* @see #resolveActivity
*/
public Intent setPackage(String packageName) {
+ if (packageName != null && mSelector != null) {
+ throw new IllegalArgumentException(
+ "Can't set package name when selector is already set");
+ }
mPackage = packageName;
return this;
}
@@ -5394,12 +5547,18 @@ public class Intent implements Parcelable, Cloneable {
public static final int FILL_IN_PACKAGE = 1<<4;
/**
- * Use with {@link #fillIn} to allow the current package value to be
+ * Use with {@link #fillIn} to allow the current bounds rectangle to be
* overwritten, even if it is already set.
*/
public static final int FILL_IN_SOURCE_BOUNDS = 1<<5;
/**
+ * Use with {@link #fillIn} to allow the current selector to be
+ * overwritten, even if it is already set.
+ */
+ public static final int FILL_IN_SELECTOR = 1<<6;
+
+ /**
* Copy the contents of <var>other</var> in to this object, but only
* where fields are not defined by this object. For purposes of a field
* being defined, the following pieces of data in the Intent are
@@ -5419,11 +5578,13 @@ public class Intent implements Parcelable, Cloneable {
*
* <p>In addition, you can use the {@link #FILL_IN_ACTION},
* {@link #FILL_IN_DATA}, {@link #FILL_IN_CATEGORIES}, {@link #FILL_IN_PACKAGE},
- * and {@link #FILL_IN_COMPONENT} to override the restriction where the
+ * {@link #FILL_IN_COMPONENT}, {@link #FILL_IN_SOURCE_BOUNDS}, and
+ * {@link #FILL_IN_SELECTOR} to override the restriction where the
* corresponding field will not be replaced if it is already set.
*
* <p>Note: The component field will only be copied if {@link #FILL_IN_COMPONENT} is explicitly
- * specified.
+ * specified. The selector will only be copied if {@link #FILL_IN_SELECTOR} is
+ * explicitly specified.
*
* <p>For example, consider Intent A with {data="foo", categories="bar"}
* and Intent B with {action="gotit", data-type="some/thing",
@@ -5439,7 +5600,8 @@ public class Intent implements Parcelable, Cloneable {
*
* @return Returns a bit mask of {@link #FILL_IN_ACTION},
* {@link #FILL_IN_DATA}, {@link #FILL_IN_CATEGORIES}, {@link #FILL_IN_PACKAGE},
- * and {@link #FILL_IN_COMPONENT} indicating which fields were changed.
+ * {@link #FILL_IN_COMPONENT}, {@link #FILL_IN_SOURCE_BOUNDS}, and
+ * {@link #FILL_IN_SELECTOR} indicating which fields were changed.
*/
public int fillIn(Intent other, int flags) {
int changes = 0;
@@ -5464,8 +5626,20 @@ public class Intent implements Parcelable, Cloneable {
}
if (other.mPackage != null
&& (mPackage == null || (flags&FILL_IN_PACKAGE) != 0)) {
- mPackage = other.mPackage;
- changes |= FILL_IN_PACKAGE;
+ // Only do this if mSelector is not set.
+ if (mSelector == null) {
+ mPackage = other.mPackage;
+ changes |= FILL_IN_PACKAGE;
+ }
+ }
+ // Selector is special: it can only be set if explicitly allowed,
+ // for the same reason as the component name.
+ if (other.mSelector != null && (flags&FILL_IN_SELECTOR) != 0) {
+ if (mPackage == null) {
+ mSelector = new Intent(other.mSelector);
+ mPackage = null;
+ changes |= FILL_IN_SELECTOR;
+ }
}
// Component is special: it can -only- be set if explicitly allowed,
// since otherwise the sender could force the intent somewhere the
@@ -5763,6 +5937,11 @@ public class Intent implements Parcelable, Cloneable {
first = false;
b.append("(has extras)");
}
+ if (mSelector != null) {
+ b.append(" sel={");
+ mSelector.toShortString(b, secure, comp, extras);
+ b.append("}");
+ }
}
/**
@@ -5823,6 +6002,21 @@ public class Intent implements Parcelable, Cloneable {
uri.append("#Intent;");
+ toUriInner(uri, scheme, flags);
+ if (mSelector != null) {
+ uri.append("SEL;");
+ // Note that for now we are not going to try to handle the
+ // data part; not clear how to represent this as a URI, and
+ // not much utility in it.
+ mSelector.toUriInner(uri, null, flags);
+ }
+
+ uri.append("end");
+
+ return uri.toString();
+ }
+
+ private void toUriInner(StringBuilder uri, String scheme, int flags) {
if (scheme != null) {
uri.append("scheme=").append(scheme).append(';');
}
@@ -5877,10 +6071,6 @@ public class Intent implements Parcelable, Cloneable {
}
}
}
-
- uri.append("end");
-
- return uri.toString();
}
public int describeContents() {
@@ -5911,6 +6101,13 @@ public class Intent implements Parcelable, Cloneable {
out.writeInt(0);
}
+ if (mSelector != null) {
+ out.writeInt(1);
+ mSelector.writeToParcel(out, flags);
+ } else {
+ out.writeInt(0);
+ }
+
out.writeBundle(mExtras);
}
@@ -5952,6 +6149,10 @@ public class Intent implements Parcelable, Cloneable {
mCategories = null;
}
+ if (in.readInt() != 0) {
+ mSelector = new Intent(in);
+ }
+
mExtras = in.readBundle();
}