diff options
| author | Dianne Hackborn <hackbod@google.com> | 2012-03-08 14:38:09 -0800 |
|---|---|---|
| committer | Android (Google) Code Review <android-gerrit@google.com> | 2012-03-08 14:38:09 -0800 |
| commit | c9ab47b4fc545db531488bf2f49fcde33eca363c (patch) | |
| tree | 7354847fd85d05fcdbd96858c4c24d31ec72fb88 /core/java | |
| parent | c53254ec92260a01605b96bd147c03c267641682 (diff) | |
| parent | 21c241e061de29a538008ca42df9c878184bcfb8 (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.java | 24 | ||||
| -rw-r--r-- | core/java/android/app/Service.java | 14 | ||||
| -rw-r--r-- | core/java/android/content/ClipData.java | 84 | ||||
| -rw-r--r-- | core/java/android/content/ClipDescription.java | 33 | ||||
| -rw-r--r-- | core/java/android/content/Intent.java | 133 |
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 <uses-permission>} * 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 <uses-permission>} * 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(); } |
