diff options
author | Nick Pelly <npelly@google.com> | 2012-01-09 14:12:58 -0800 |
---|---|---|
committer | Nick Pelly <npelly@google.com> | 2012-01-24 20:04:13 -0800 |
commit | ccae412deda8b0c165c86f395752c0667a3411a6 (patch) | |
tree | 3ddc03df0182a5b372c2d38e27d5a7c312cf9e31 | |
parent | 07d7d5a22dbb0a8df5631c8014f4706dd1e449da (diff) | |
download | frameworks_base-ccae412deda8b0c165c86f395752c0667a3411a6.zip frameworks_base-ccae412deda8b0c165c86f395752c0667a3411a6.tar.gz frameworks_base-ccae412deda8b0c165c86f395752c0667a3411a6.tar.bz2 |
Add API's for normalizing MIME's and URI's.
Helps developers create well-behaved intents:
- lower case MIME data type
- strip parameters from MIME content types
- lowercase URI scheme
The new API's are
normalizeAndSetType()
normalizeAndSetData()
normalizeAndSetDataAndType()
Uri.normalize()
normalizeMimeType()
Change-Id: Ib5c907897f39b1f705bcc4c9103ba1e6f316380b
-rw-r--r-- | api/current.txt | 5 | ||||
-rw-r--r-- | core/java/android/content/Intent.java | 174 | ||||
-rw-r--r-- | core/java/android/net/Uri.java | 33 |
3 files changed, 189 insertions, 23 deletions
diff --git a/api/current.txt b/api/current.txt index 1f6ba1b..80fbaaa 100644 --- a/api/current.txt +++ b/api/current.txt @@ -5350,6 +5350,7 @@ package android.content { method public static android.content.Intent makeMainActivity(android.content.ComponentName); method public static android.content.Intent makeMainSelectorActivity(java.lang.String, java.lang.String); method public static android.content.Intent makeRestartActivityTask(android.content.ComponentName); + method public static java.lang.String normalizeMimeType(java.lang.String); method public static android.content.Intent parseIntent(android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.util.AttributeSet) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException; method public static android.content.Intent parseUri(java.lang.String, int) throws java.net.URISyntaxException; method public android.content.Intent putCharSequenceArrayListExtra(java.lang.String, java.util.ArrayList<java.lang.CharSequence>); @@ -5398,13 +5399,16 @@ package android.content { method public android.content.Intent setClassName(java.lang.String, java.lang.String); method public android.content.Intent setComponent(android.content.ComponentName); method public android.content.Intent setData(android.net.Uri); + method public android.content.Intent setDataAndNormalize(android.net.Uri); method public android.content.Intent setDataAndType(android.net.Uri, java.lang.String); + method public android.content.Intent setDataAndTypeAndNormalize(android.net.Uri, java.lang.String); method public void setExtrasClassLoader(java.lang.ClassLoader); method public android.content.Intent setFlags(int); method public android.content.Intent setPackage(java.lang.String); method public void setSelector(android.content.Intent); method public void setSourceBounds(android.graphics.Rect); method public android.content.Intent setType(java.lang.String); + method public android.content.Intent setTypeAndNormalize(java.lang.String); method public deprecated java.lang.String toURI(); method public java.lang.String toUri(int); method public void writeToParcel(android.os.Parcel, int); @@ -11828,6 +11832,7 @@ package android.net { method public abstract boolean isHierarchical(); method public boolean isOpaque(); method public abstract boolean isRelative(); + method public android.net.Uri normalize(); method public static android.net.Uri parse(java.lang.String); method public abstract java.lang.String toString(); method public static android.net.Uri withAppendedPath(android.net.Uri, java.lang.String); diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index e3b1f54..fbc1b2b 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -43,6 +43,7 @@ import java.net.URISyntaxException; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; +import java.util.Locale; import java.util.Set; /** @@ -4420,22 +4421,24 @@ public class Intent implements Parcelable, Cloneable { /** * Set the data this intent is operating on. This method automatically - * clears any type that was previously set by {@link #setType}. + * clears any type that was previously set by {@link #setType} or + * {@link #setTypeAndNormalize}. * - * <p><em>Note: scheme and host name matching in the Android framework is - * case-sensitive, unlike the formal RFC. As a result, - * you should always ensure that you write your Uri with these elements - * using lower case letters, and normalize any Uris you receive from - * outside of Android to ensure the scheme and host is lower case.</em></p> + * <p><em>Note: scheme matching in the Android framework is + * case-sensitive, unlike the formal RFC. As a result, + * you should always write your Uri with a lower case scheme, + * or use {@link Uri#normalize} or + * {@link #setDataAndNormalize} + * to ensure that the scheme is converted to lower case.</em> * - * @param data The URI of the data this intent is now targeting. + * @param data The Uri of the data this intent is now targeting. * * @return Returns the same Intent object, for chaining multiple calls * into a single statement. * * @see #getData - * @see #setType - * @see #setDataAndType + * @see #setDataAndNormalize + * @see android.net.Intent#normalize */ public Intent setData(Uri data) { mData = data; @@ -4444,16 +4447,45 @@ public class Intent implements Parcelable, Cloneable { } /** - * Set an explicit MIME data type. This is used to create intents that - * only specify a type and not data, for example to indicate the type of - * data to return. This method automatically clears any data that was - * previously set by {@link #setData}. + * Normalize and set the data this intent is operating on. + * + * <p>This method automatically clears any type that was + * previously set (for example, by {@link #setType}). + * + * <p>The data Uri is normalized using + * {@link android.net.Uri#normalize} before it is set, + * so really this is just a convenience method for + * <pre> + * setData(data.normalize()) + * </pre> + * + * @param data The Uri of the data this intent is now targeting. + * + * @return Returns the same Intent object, for chaining multiple calls + * into a single statement. + * + * @see #getData + * @see #setType + * @see android.net.Uri#normalize + */ + public Intent setDataAndNormalize(Uri data) { + return setData(data.normalize()); + } + + /** + * Set an explicit MIME data type. + * + * <p>This is used to create intents that only specify a type and not data, + * for example to indicate the type of data to return. + * + * <p>This method automatically clears any data that was + * previously set (for example by {@link #setData}). * * <p><em>Note: MIME type matching in the Android framework is * case-sensitive, unlike formal RFC MIME types. As a result, * you should always write your MIME types with lower case letters, - * and any MIME types you receive from outside of Android should be - * converted to lower case before supplying them here.</em></p> + * or use {@link #normalizeMimeType} or {@link #setTypeAndNormalize} + * to ensure that it is converted to lower case.</em> * * @param type The MIME type of the data being handled by this intent. * @@ -4461,8 +4493,9 @@ public class Intent implements Parcelable, Cloneable { * into a single statement. * * @see #getType - * @see #setData + * @see #setTypeAndNormalize * @see #setDataAndType + * @see #normalizeMimeType */ public Intent setType(String type) { mData = null; @@ -4471,26 +4504,58 @@ public class Intent implements Parcelable, Cloneable { } /** + * Normalize and set an explicit MIME data type. + * + * <p>This is used to create intents that only specify a type and not data, + * for example to indicate the type of data to return. + * + * <p>This method automatically clears any data that was + * previously set (for example by {@link #setData}). + * + * <p>The MIME type is normalized using + * {@link #normalizeMimeType} before it is set, + * so really this is just a convenience method for + * <pre> + * setType(Intent.normalizeMimeType(type)) + * </pre> + * + * @param type The MIME type of the data being handled by this intent. + * + * @return Returns the same Intent object, for chaining multiple calls + * into a single statement. + * + * @see #getType + * @see #setData + * @see #normalizeMimeType + */ + public Intent setTypeAndNormalize(String type) { + return setType(normalizeMimeType(type)); + } + + /** * (Usually optional) Set the data for the intent along with an explicit * MIME data type. This method should very rarely be used -- it allows you * to override the MIME type that would ordinarily be inferred from the * data with your own type given here. * - * <p><em>Note: MIME type, Uri scheme, and host name matching in the + * <p><em>Note: MIME type and Uri scheme matching in the * Android framework is case-sensitive, unlike the formal RFC definitions. * As a result, you should always write these elements with lower case letters, - * and normalize any MIME types or Uris you receive from - * outside of Android to ensure these elements are lower case before - * supplying them here.</em></p> + * or use {@link #normalizeMimeType} or {@link android.net.Uri#normalize} or + * {@link #setDataAndTypeAndNormalize} + * to ensure that they are converted to lower case.</em> * - * @param data The URI of the data this intent is now targeting. + * @param data The Uri of the data this intent is now targeting. * @param type The MIME type of the data being handled by this intent. * * @return Returns the same Intent object, for chaining multiple calls * into a single statement. * - * @see #setData * @see #setType + * @see #setData + * @see #normalizeMimeType + * @see android.net.Uri#normalize + * @see #setDataAndTypeAndNormalize */ public Intent setDataAndType(Uri data, String type) { mData = data; @@ -4499,6 +4564,35 @@ public class Intent implements Parcelable, Cloneable { } /** + * (Usually optional) Normalize and set both the data Uri and an explicit + * MIME data type. This method should very rarely be used -- it allows you + * to override the MIME type that would ordinarily be inferred from the + * data with your own type given here. + * + * <p>The data Uri and the MIME type are normalize using + * {@link android.net.Uri#normalize} and {@link #normalizeMimeType} + * before they are set, so really this is just a convenience method for + * <pre> + * setDataAndType(data.normalize(), Intent.normalizeMimeType(type)) + * </pre> + * + * @param data The Uri of the data this intent is now targeting. + * @param type The MIME type of the data being handled by this intent. + * + * @return Returns the same Intent object, for chaining multiple calls + * into a single statement. + * + * @see #setType + * @see #setData + * @see #setDataAndType + * @see #normalizeMimeType + * @see android.net.Uri#normalize + */ + public Intent setDataAndTypeAndNormalize(Uri data, String type) { + return setDataAndType(data.normalize(), normalizeMimeType(type)); + } + + /** * Add a new category to the intent. Categories provide additional detail * about the action the intent is perform. When resolving an intent, only * activities that provide <em>all</em> of the requested categories will be @@ -5566,7 +5660,7 @@ public class Intent implements Parcelable, Cloneable { * * <ul> * <li> action, as set by {@link #setAction}. - * <li> data URI and MIME type, as set by {@link #setData(Uri)}, + * <li> data Uri and MIME type, as set by {@link #setData(Uri)}, * {@link #setType(String)}, or {@link #setDataAndType(Uri, String)}. * <li> categories, as set by {@link #addCategory}. * <li> package, as set by {@link #setPackage}. @@ -6229,4 +6323,38 @@ public class Intent implements Parcelable, Cloneable { return intent; } + + /** + * Normalize a MIME data type. + * + * <p>A normalized MIME type has white-space trimmed, + * content-type parameters removed, and is lower-case. + * This aligns the type with Android best practices for + * intent filtering. + * + * <p>For example, "text/plain; charset=utf-8" becomes "text/plain". + * "text/x-vCard" becomes "text/x-vcard". + * + * <p>All MIME types received from outside Android (such as user input, + * or external sources like Bluetooth, NFC, or the Internet) should + * be normalized before they are used to create an Intent. + * + * @param type MIME data type to normalize + * @return normalized MIME data type, or null if the input was null + * @see {@link #setType} + * @see {@link #setTypeAndNormalize} + */ + public static String normalizeMimeType(String type) { + if (type == null) { + return null; + } + + type = type.trim().toLowerCase(Locale.US); + + final int semicolonIndex = type.indexOf(';'); + if (semicolonIndex != -1) { + type = type.substring(0, semicolonIndex); + } + return type; + } } diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java index 0fb49bc..defe7aa 100644 --- a/core/java/android/net/Uri.java +++ b/core/java/android/net/Uri.java @@ -28,6 +28,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.LinkedHashSet; import java.util.List; +import java.util.Locale; import java.util.RandomAccess; import java.util.Set; import libcore.net.UriCodec; @@ -1716,6 +1717,38 @@ public abstract class Uri implements Parcelable, Comparable<Uri> { return (!"false".equals(flag) && !"0".equals(flag)); } + /** + * Return a normalized representation of this Uri. + * + * <p>A normalized Uri has a lowercase scheme component. + * This aligns the Uri with Android best practices for + * intent filtering. + * + * <p>For example, "HTTP://www.android.com" becomes + * "http://www.android.com" + * + * <p>All URIs received from outside Android (such as user input, + * or external sources like Bluetooth, NFC, or the Internet) should + * be normalized before they are used to create an Intent. + * + * <p class="note">This method does <em>not</em> validate bad URI's, + * or 'fix' poorly formatted URI's - so do not use it for input validation. + * A Uri will always be returned, even if the Uri is badly formatted to + * begin with and a scheme component cannot be found. + * + * @return normalized Uri (never null) + * @see {@link android.content.Intent#setData} + * @see {@link #setNormalizedData} + */ + public Uri normalize() { + String scheme = getScheme(); + if (scheme == null) return this; // give up + String lowerScheme = scheme.toLowerCase(Locale.US); + if (scheme.equals(lowerScheme)) return this; // no change + + return buildUpon().scheme(lowerScheme).build(); + } + /** Identifies a null parcelled Uri. */ private static final int NULL_TYPE_ID = 0; |