Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ccae412d authored by Nick Pelly's avatar Nick Pelly
Browse files

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
parent 07d7d5a2
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -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);
+151 −23
Original line number Diff line number Diff line
@@ -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
     * <p><em>Note: scheme 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>
     * 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;
@@ -4470,27 +4503,59 @@ public class Intent implements Parcelable, Cloneable {
        return this;
    }

    /**
     * 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;
@@ -4498,6 +4563,35 @@ public class Intent implements Parcelable, Cloneable {
        return this;
    }

    /**
     * (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
@@ -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;
    }
}
+33 −0
Original line number Diff line number Diff line
@@ -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;