summaryrefslogtreecommitdiff
path: root/core/java
diff options
context:
space:
mode:
authorDianne Hackborn <hackbod@google.com>2012-03-08 14:38:09 -0800
committerAndroid (Google) Code Review <android-gerrit@google.com>2012-03-08 14:38:09 -0800
commitc9ab47b4fc545db531488bf2f49fcde33eca363c (patch)
tree7354847fd85d05fcdbd96858c4c24d31ec72fb88 /core/java
parentc53254ec92260a01605b96bd147c03c267641682 (diff)
parent21c241e061de29a538008ca42df9c878184bcfb8 (diff)
Merge "Add new Intent API for associating a ClipData with an Intent."
Diffstat (limited to 'core/java')
-rw-r--r--core/java/android/app/Activity.java24
-rw-r--r--core/java/android/app/Service.java14
-rw-r--r--core/java/android/content/ClipData.java84
-rw-r--r--core/java/android/content/ClipDescription.java33
-rw-r--r--core/java/android/content/Intent.java133
5 files changed, 269 insertions, 19 deletions
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 8e8d37d645c9..f8954315630b 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -570,7 +570,18 @@ import java.util.HashMap;
* tag. By doing so, other applications will need to declare a corresponding
* {@link android.R.styleable#AndroidManifestUsesPermission &lt;uses-permission&gt;}
* element in their own manifest to be able to start that activity.
- *
+ *
+ * <p>When starting an Activity you can set {@link Intent#FLAG_GRANT_READ_URI_PERMISSION
+ * Intent.FLAG_GRANT_READ_URI_PERMISSION} and/or {@link Intent#FLAG_GRANT_WRITE_URI_PERMISSION
+ * Intent.FLAG_GRANT_WRITE_URI_PERMISSION} on the Intent. This will grant the
+ * Activity access to the specific URIs in the Intent. Access will remain
+ * until the Activity has finished (it will remain across the hosting
+ * process being killed and other temporary destruction). As of
+ * {@link android.os.Build.VERSION_CODES#GINGERBREAD}, if the Activity
+ * was already created and a new Intent is being delivered to
+ * {@link #onNewIntent(Intent)}, any newly granted URI permissions will be added
+ * to the existing ones it holds.
+ *
* <p>See the <a href="{@docRoot}guide/topics/security/security.html">Security and Permissions</a>
* document for more information on permissions and security in general.
*
@@ -3549,7 +3560,16 @@ public class Activity extends ContextThemeWrapper
/**
* Call this to set the result that your activity will return to its
* caller.
- *
+ *
+ * <p>As of {@link android.os.Build.VERSION_CODES#GINGERBREAD}, the Intent
+ * you supply here can have {@link Intent#FLAG_GRANT_READ_URI_PERMISSION
+ * Intent.FLAG_GRANT_READ_URI_PERMISSION} and/or {@link Intent#FLAG_GRANT_WRITE_URI_PERMISSION
+ * Intent.FLAG_GRANT_WRITE_URI_PERMISSION} set. This will grant the
+ * Activity receiving the result access to the specific URIs in the Intent.
+ * Access will remain until the Activity has finished (it will remain across the hosting
+ * process being killed and other temporary destruction) and will be added
+ * to any existing set of URI permissions it already holds.
+ *
* @param resultCode The result code to propagate back to the originating
* activity, often RESULT_CANCELED or RESULT_OK
* @param data The data to propagate back to the originating activity.
diff --git a/core/java/android/app/Service.java b/core/java/android/app/Service.java
index 35bd8c08a713..be4b8af6fb49 100644
--- a/core/java/android/app/Service.java
+++ b/core/java/android/app/Service.java
@@ -163,7 +163,19 @@ import java.io.PrintWriter;
* {@link android.R.styleable#AndroidManifestUsesPermission &lt;uses-permission&gt;}
* element in their own manifest to be able to start, stop, or bind to
* the service.
- *
+ *
+ * <p>As of {@link android.os.Build.VERSION_CODES#GINGERBREAD}, when using
+ * {@link Context#startService(Intent) Context.startService(Intent)}, you can
+ * also set {@link Intent#FLAG_GRANT_READ_URI_PERMISSION
+ * Intent.FLAG_GRANT_READ_URI_PERMISSION} and/or {@link Intent#FLAG_GRANT_WRITE_URI_PERMISSION
+ * Intent.FLAG_GRANT_WRITE_URI_PERMISSION} on the Intent. This will grant the
+ * Service temporary access to the specific URIs in the Intent. Access will
+ * remain until the Service has called {@link #stopSelf(int)} for that start
+ * command or a later one, or until the Service has been completely stopped.
+ * This works for granting access to the other apps that have not requested
+ * the permission protecting the Service, or even when the Service is not
+ * exported at all.
+ *
* <p>In addition, a service can protect individual IPC calls into it with
* permissions, by calling the
* {@link #checkCallingPermission}
diff --git a/core/java/android/content/ClipData.java b/core/java/android/content/ClipData.java
index a8b1bf47d624..a655dd424aa9 100644
--- a/core/java/android/content/ClipData.java
+++ b/core/java/android/content/ClipData.java
@@ -153,7 +153,7 @@ public class ClipData implements Parcelable {
final Bitmap mIcon;
- final ArrayList<Item> mItems = new ArrayList<Item>();
+ final ArrayList<Item> mItems;
/**
* Description of a single item in a ClippedData.
@@ -321,6 +321,33 @@ public class ClipData implements Parcelable {
return "";
}
//END_INCLUDE(coerceToText)
+
+ @Override
+ public String toString() {
+ StringBuilder b = new StringBuilder(128);
+
+ b.append("ClipData.Item { ");
+ toShortString(b);
+ b.append(" }");
+
+ return b.toString();
+ }
+
+ /** @hide */
+ public void toShortString(StringBuilder b) {
+ if (mText != null) {
+ b.append("T:");
+ b.append(mText);
+ } else if (mUri != null) {
+ b.append("U:");
+ b.append(mUri);
+ } else if (mIntent != null) {
+ b.append("I:");
+ mIntent.toShortString(b, true, true, true, true);
+ } else {
+ b.append("NULL");
+ }
+ }
}
/**
@@ -336,6 +363,7 @@ public class ClipData implements Parcelable {
throw new NullPointerException("item is null");
}
mIcon = null;
+ mItems = new ArrayList<Item>();
mItems.add(item);
}
@@ -351,10 +379,23 @@ public class ClipData implements Parcelable {
throw new NullPointerException("item is null");
}
mIcon = null;
+ mItems = new ArrayList<Item>();
mItems.add(item);
}
/**
+ * Create a new clip that is a copy of another clip. This does a deep-copy
+ * of all items in the clip.
+ *
+ * @param other The existing ClipData that is to be copied.
+ */
+ public ClipData(ClipData other) {
+ mClipDescription = other.mClipDescription;
+ mIcon = other.mIcon;
+ mItems = new ArrayList<Item>(other.mItems);
+ }
+
+ /**
* Create a new ClipData holding data of the type
* {@link ClipDescription#MIMETYPE_TEXT_PLAIN}.
*
@@ -475,6 +516,46 @@ public class ClipData implements Parcelable {
}
@Override
+ public String toString() {
+ StringBuilder b = new StringBuilder(128);
+
+ b.append("ClipData { ");
+ toShortString(b);
+ b.append(" }");
+
+ return b.toString();
+ }
+
+ /** @hide */
+ public void toShortString(StringBuilder b) {
+ boolean first;
+ if (mClipDescription != null) {
+ first = !mClipDescription.toShortString(b);
+ } else {
+ first = true;
+ }
+ if (mIcon != null) {
+ if (!first) {
+ b.append(' ');
+ }
+ first = false;
+ b.append("I:");
+ b.append(mIcon.getWidth());
+ b.append('x');
+ b.append(mIcon.getHeight());
+ }
+ for (int i=0; i<mItems.size(); i++) {
+ if (!first) {
+ b.append(' ');
+ }
+ first = false;
+ b.append('{');
+ mItems.get(i).toShortString(b);
+ b.append('}');
+ }
+ }
+
+ @Override
public int describeContents() {
return 0;
}
@@ -515,6 +596,7 @@ public class ClipData implements Parcelable {
} else {
mIcon = null;
}
+ mItems = new ArrayList<Item>();
final int N = in.readInt();
for (int i=0; i<N; i++) {
CharSequence text = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
diff --git a/core/java/android/content/ClipDescription.java b/core/java/android/content/ClipDescription.java
index b5fa20cda7ff..c6b51efbc362 100644
--- a/core/java/android/content/ClipDescription.java
+++ b/core/java/android/content/ClipDescription.java
@@ -184,6 +184,39 @@ public class ClipDescription implements Parcelable {
}
@Override
+ public String toString() {
+ StringBuilder b = new StringBuilder(128);
+
+ b.append("ClipDescription { ");
+ toShortString(b);
+ b.append(" }");
+
+ return b.toString();
+ }
+
+ /** @hide */
+ public boolean toShortString(StringBuilder b) {
+ boolean first = true;
+ for (int i=0; i<mMimeTypes.length; i++) {
+ if (!first) {
+ b.append(' ');
+ }
+ first = false;
+ b.append(mMimeTypes[i]);
+ }
+ if (mLabel != null) {
+ if (!first) {
+ b.append(' ');
+ }
+ first = false;
+ b.append('"');
+ b.append(mLabel);
+ b.append('"');
+ }
+ return !first;
+ }
+
+ @Override
public int describeContents() {
return 0;
}
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index b1b09d56c363..57391199a31a 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2688,12 +2688,20 @@ public class Intent implements Parcelable, Cloneable {
/**
* If set, the recipient of this Intent will be granted permission to
- * perform read operations on the Uri in the Intent's data.
+ * perform read operations on the Uri in the Intent's data and any URIs
+ * specified in its ClipData. When applying to an Intent's ClipData,
+ * all URIs as well as recursive traversals through data or other ClipData
+ * in Intent items will be granted; only the grant flags of the top-level
+ * Intent are used.
*/
public static final int FLAG_GRANT_READ_URI_PERMISSION = 0x00000001;
/**
* If set, the recipient of this Intent will be granted permission to
- * perform write operations on the Uri in the Intent's data.
+ * perform write operations on the Uri in the Intent's data and any URIs
+ * specified in its ClipData. When applying to an Intent's ClipData,
+ * all URIs as well as recursive traversals through data or other ClipData
+ * in Intent items will be granted; only the grant flags of the top-level
+ * Intent are used.
*/
public static final int FLAG_GRANT_WRITE_URI_PERMISSION = 0x00000002;
/**
@@ -3018,6 +3026,7 @@ public class Intent implements Parcelable, Cloneable {
private Bundle mExtras;
private Rect mSourceBounds;
private Intent mSelector;
+ private ClipData mClipData;
// ---------------------------------------------------------------------
@@ -3049,6 +3058,9 @@ public class Intent implements Parcelable, Cloneable {
if (o.mSelector != null) {
this.mSelector = new Intent(o.mSelector);
}
+ if (o.mClipData != null) {
+ this.mClipData = new ClipData(o.mClipData);
+ }
}
@Override
@@ -3729,6 +3741,16 @@ public class Intent implements Parcelable, Cloneable {
}
/**
+ * Return the {@link ClipData} associated with this Intent. If there is
+ * none, returns null. See {@link #setClipData} for more information.
+ *
+ * @see #setClipData;
+ */
+ public ClipData getClipData() {
+ return mClipData;
+ }
+
+ /**
* Sets the ClassLoader that will be used when unmarshalling
* any Parcelable values from the extras of this Intent.
*
@@ -4683,6 +4705,37 @@ public class Intent implements Parcelable, Cloneable {
}
/**
+ * Set a {@link ClipData} associated with this Intent. This replaces any
+ * previously set ClipData.
+ *
+ * <p>The ClipData in an intent is not used for Intent matching or other
+ * such operations. Semantically it is like extras, used to transmit
+ * additional data with the Intent. The main feature of using this over
+ * the extras for data is that {@link #FLAG_GRANT_READ_URI_PERMISSION}
+ * and {@link #FLAG_GRANT_WRITE_URI_PERMISSION} will operate on any URI
+ * items included in the clip data. This is useful, in particular, if
+ * you want to transmit an Intent containing multiple <code>content:</code>
+ * URIs for which the recipient may not have global permission to access the
+ * content provider.
+ *
+ * <p>If the ClipData contains items that are themselves Intents, any
+ * grant flags in those Intents will be ignored. Only the top-level flags
+ * of the main Intent are respected, and will be applied to all Uri or
+ * Intent items in the clip (or sub-items of the clip).
+ *
+ * <p>The MIME type, label, and icon in the ClipData object are not
+ * directly used by Intent. Applications should generally rely on the
+ * MIME type of the Intent itself, not what it may find in the ClipData.
+ * A common practice is to construct a ClipData for use with an Intent
+ * with a MIME type of "*\/*".
+ *
+ * @param clip The new clip to set. May be null to clear the current clip.
+ */
+ public void setClipData(ClipData clip) {
+ mClipData = clip;
+ }
+
+ /**
* 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".
@@ -5660,6 +5713,12 @@ public class Intent implements Parcelable, Cloneable {
public static final int FILL_IN_SELECTOR = 1<<6;
/**
+ * Use with {@link #fillIn} to allow the current ClipData to be
+ * overwritten, even if it is already set.
+ */
+ public static final int FILL_IN_CLIP_DATA = 1<<7;
+
+ /**
* 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
@@ -5673,19 +5732,22 @@ public class Intent implements Parcelable, Cloneable {
* <li> package, as set by {@link #setPackage}.
* <li> component, as set by {@link #setComponent(ComponentName)} or
* related methods.
- * <li> source bounds, as set by {@link #setSourceBounds}
+ * <li> source bounds, as set by {@link #setSourceBounds}.
+ * <li> selector, as set by {@link #setSelector(Intent)}.
+ * <li> clip data, as set by {@link #setClipData(ClipData)}.
* <li> each top-level name in the associated extras.
* </ul>
*
* <p>In addition, you can use the {@link #FILL_IN_ACTION},
* {@link #FILL_IN_DATA}, {@link #FILL_IN_CATEGORIES}, {@link #FILL_IN_PACKAGE},
- * {@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.
+ * {@link #FILL_IN_COMPONENT}, {@link #FILL_IN_SOURCE_BOUNDS},
+ * {@link #FILL_IN_SELECTOR}, and {@link #FILL_IN_CLIP_DATA} 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. The selector will only be copied if {@link #FILL_IN_SELECTOR} is
- * explicitly specified.
+ * <p>Note: The component field will only be copied if {@link #FILL_IN_COMPONENT}
+ * is explicitly 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",
@@ -5742,6 +5804,11 @@ public class Intent implements Parcelable, Cloneable {
changes |= FILL_IN_SELECTOR;
}
}
+ if (other.mClipData != null
+ && (mClipData == null || (flags&FILL_IN_CLIP_DATA) != 0)) {
+ mClipData = other.mClipData;
+ changes |= FILL_IN_CLIP_DATA;
+ }
// Component is special: it can -only- be set if explicitly allowed,
// since otherwise the sender could force the intent somewhere the
// originator didn't intend.
@@ -5938,7 +6005,7 @@ public class Intent implements Parcelable, Cloneable {
StringBuilder b = new StringBuilder(128);
b.append("Intent { ");
- toShortString(b, true, true, true);
+ toShortString(b, true, true, true, false);
b.append(" }");
return b.toString();
@@ -5949,21 +6016,33 @@ public class Intent implements Parcelable, Cloneable {
StringBuilder b = new StringBuilder(128);
b.append("Intent { ");
- toShortString(b, false, true, true);
+ toShortString(b, false, true, true, false);
+ b.append(" }");
+
+ return b.toString();
+ }
+
+ /** @hide */
+ public String toInsecureStringWithClip() {
+ StringBuilder b = new StringBuilder(128);
+
+ b.append("Intent { ");
+ toShortString(b, false, true, true, true);
b.append(" }");
return b.toString();
}
/** @hide */
- public String toShortString(boolean secure, boolean comp, boolean extras) {
+ public String toShortString(boolean secure, boolean comp, boolean extras, boolean clip) {
StringBuilder b = new StringBuilder(128);
- toShortString(b, secure, comp, extras);
+ toShortString(b, secure, comp, extras, clip);
return b.toString();
}
/** @hide */
- public void toShortString(StringBuilder b, boolean secure, boolean comp, boolean extras) {
+ public void toShortString(StringBuilder b, boolean secure, boolean comp, boolean extras,
+ boolean clip) {
boolean first = true;
if (mAction != null) {
b.append("act=").append(mAction);
@@ -6031,6 +6110,19 @@ public class Intent implements Parcelable, Cloneable {
first = false;
b.append("bnds=").append(mSourceBounds.toShortString());
}
+ if (mClipData != null) {
+ if (!first) {
+ b.append(' ');
+ }
+ first = false;
+ if (clip) {
+ b.append("clip={");
+ mClipData.toShortString(b);
+ b.append('}');
+ } else {
+ b.append("(has clip)");
+ }
+ }
if (extras && mExtras != null) {
if (!first) {
b.append(' ');
@@ -6040,7 +6132,7 @@ public class Intent implements Parcelable, Cloneable {
}
if (mSelector != null) {
b.append(" sel={");
- mSelector.toShortString(b, secure, comp, extras);
+ mSelector.toShortString(b, secure, comp, extras, clip);
b.append("}");
}
}
@@ -6209,6 +6301,13 @@ public class Intent implements Parcelable, Cloneable {
out.writeInt(0);
}
+ if (mClipData != null) {
+ out.writeInt(1);
+ mClipData.writeToParcel(out, flags);
+ } else {
+ out.writeInt(0);
+ }
+
out.writeBundle(mExtras);
}
@@ -6254,6 +6353,10 @@ public class Intent implements Parcelable, Cloneable {
mSelector = new Intent(in);
}
+ if (in.readInt() != 0) {
+ mClipData = new ClipData(in);
+ }
+
mExtras = in.readBundle();
}