Loading api/current.txt +9 −0 Original line number Diff line number Diff line Loading @@ -4833,6 +4833,7 @@ package android.content { method public android.content.ClipDescription getDescription(); method public android.content.ClipData.Item getItemAt(int); method public int getItemCount(); method public static android.content.ClipData newHtmlText(java.lang.CharSequence, java.lang.CharSequence, java.lang.String); method public static android.content.ClipData newIntent(java.lang.CharSequence, android.content.Intent); method public static android.content.ClipData newPlainText(java.lang.CharSequence, java.lang.CharSequence); method public static android.content.ClipData newRawUri(java.lang.CharSequence, android.net.Uri); Loading @@ -4843,10 +4844,15 @@ package android.content { public static class ClipData.Item { ctor public ClipData.Item(java.lang.CharSequence); ctor public ClipData.Item(java.lang.CharSequence, java.lang.String); ctor public ClipData.Item(android.content.Intent); ctor public ClipData.Item(android.net.Uri); ctor public ClipData.Item(java.lang.CharSequence, android.content.Intent, android.net.Uri); ctor public ClipData.Item(java.lang.CharSequence, java.lang.String, android.content.Intent, android.net.Uri); method public java.lang.String coerceToHtmlText(android.content.Context); method public java.lang.CharSequence coerceToStyledText(android.content.Context); method public java.lang.CharSequence coerceToText(android.content.Context); method public java.lang.String getHtmlText(); method public android.content.Intent getIntent(); method public java.lang.CharSequence getText(); method public android.net.Uri getUri(); Loading @@ -4864,6 +4870,7 @@ package android.content { method public boolean hasMimeType(java.lang.String); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator CREATOR; field public static final java.lang.String MIMETYPE_TEXT_HTML = "text/html"; field public static final java.lang.String MIMETYPE_TEXT_INTENT = "text/vnd.android.intent"; field public static final java.lang.String MIMETYPE_TEXT_PLAIN = "text/plain"; field public static final java.lang.String MIMETYPE_TEXT_URILIST = "text/uri-list"; Loading Loading @@ -5701,6 +5708,7 @@ package android.content { field public static final int EXTRA_DOCK_STATE_UNDOCKED = 0; // 0x0 field public static final java.lang.String EXTRA_DONT_KILL_APP = "android.intent.extra.DONT_KILL_APP"; field public static final java.lang.String EXTRA_EMAIL = "android.intent.extra.EMAIL"; field public static final java.lang.String EXTRA_HTML_TEXT = "android.intent.extra.HTML_TEXT"; field public static final java.lang.String EXTRA_INITIAL_INTENTS = "android.intent.extra.INITIAL_INTENTS"; field public static final java.lang.String EXTRA_INSTALLER_PACKAGE_NAME = "android.intent.extra.INSTALLER_PACKAGE_NAME"; field public static final java.lang.String EXTRA_INTENT = "android.intent.extra.INTENT"; Loading Loading @@ -20406,6 +20414,7 @@ package android.text { } public class Html { method public static java.lang.String escapeHtml(java.lang.CharSequence); method public static android.text.Spanned fromHtml(java.lang.String); method public static android.text.Spanned fromHtml(java.lang.String, android.text.Html.ImageGetter, android.text.Html.TagHandler); method public static java.lang.String toHtml(android.text.Spanned); core/java/android/content/ClipData.java +288 −11 Original line number Diff line number Diff line Loading @@ -21,7 +21,12 @@ import android.graphics.Bitmap; import android.net.Uri; import android.os.Parcel; import android.os.Parcelable; import android.text.Html; import android.text.Spannable; import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.TextUtils; import android.text.style.URLSpan; import android.util.Log; import java.io.FileInputStream; Loading Loading @@ -144,6 +149,8 @@ import java.util.ArrayList; public class ClipData implements Parcelable { static final String[] MIMETYPES_TEXT_PLAIN = new String[] { ClipDescription.MIMETYPE_TEXT_PLAIN }; static final String[] MIMETYPES_TEXT_HTML = new String[] { ClipDescription.MIMETYPE_TEXT_HTML }; static final String[] MIMETYPES_TEXT_URILIST = new String[] { ClipDescription.MIMETYPE_TEXT_URILIST }; static final String[] MIMETYPES_TEXT_INTENT = new String[] { Loading Loading @@ -176,6 +183,7 @@ public class ClipData implements Parcelable { */ public static class Item { final CharSequence mText; final String mHtmlText; final Intent mIntent; final Uri mUri; Loading @@ -184,6 +192,20 @@ public class ClipData implements Parcelable { */ public Item(CharSequence text) { mText = text; mHtmlText = null; mIntent = null; mUri = null; } /** * Create an Item consisting of a single block of (possibly styled) text, * with an alternative HTML formatted representation. You <em>must</em> * supply a plain text representation in addition to HTML text; coercion * will not be done from HTML formated text into plain text. */ public Item(CharSequence text, String htmlText) { mText = text; mHtmlText = htmlText; mIntent = null; mUri = null; } Loading @@ -193,6 +215,7 @@ public class ClipData implements Parcelable { */ public Item(Intent intent) { mText = null; mHtmlText = null; mIntent = intent; mUri = null; } Loading @@ -202,16 +225,35 @@ public class ClipData implements Parcelable { */ public Item(Uri uri) { mText = null; mHtmlText = null; mIntent = null; mUri = uri; } /** * Create a complex Item, containing multiple representations of * text, intent, and/or URI. * text, Intent, and/or URI. */ public Item(CharSequence text, Intent intent, Uri uri) { mText = text; mHtmlText = null; mIntent = intent; mUri = uri; } /** * Create a complex Item, containing multiple representations of * text, HTML text, Intent, and/or URI. If providing HTML text, you * <em>must</em> supply a plain text representation as well; coercion * will not be done from HTML formated text into plain text. */ public Item(CharSequence text, String htmlText, Intent intent, Uri uri) { if (htmlText != null && text == null) { throw new IllegalArgumentException( "Plain text must be supplied if HTML text is supplied"); } mText = text; mHtmlText = htmlText; mIntent = intent; mUri = uri; } Loading @@ -223,6 +265,13 @@ public class ClipData implements Parcelable { return mText; } /** * Retrieve the raw HTML text contained in this Item. */ public String getHtmlText() { return mHtmlText; } /** * Retrieve the raw Intent contained in this Item. */ Loading Loading @@ -261,12 +310,14 @@ public class ClipData implements Parcelable { //BEGIN_INCLUDE(coerceToText) public CharSequence coerceToText(Context context) { // If this Item has an explicit textual value, simply return that. if (mText != null) { return mText; CharSequence text = getText(); if (text != null) { return text; } // If this Item has a URI value, try using that. if (mUri != null) { Uri uri = getUri(); if (uri != null) { // First see if the URI can be opened as a plain text stream // (of any sub-type). If so, this is the best textual Loading @@ -275,7 +326,7 @@ public class ClipData implements Parcelable { try { // Ask for a stream of the desired type. AssetFileDescriptor descr = context.getContentResolver() .openTypedAssetFileDescriptor(mUri, "text/*", null); .openTypedAssetFileDescriptor(uri, "text/*", null); stream = descr.createInputStream(); InputStreamReader reader = new InputStreamReader(stream, "UTF-8"); Loading Loading @@ -308,13 +359,14 @@ public class ClipData implements Parcelable { // If we couldn't open the URI as a stream, then the URI itself // probably serves fairly well as a textual representation. return mUri.toString(); return uri.toString(); } // Finally, if all we have is an Intent, then we can just turn that // into text. Not the most user-friendly thing, but it's something. if (mIntent != null) { return mIntent.toUri(Intent.URI_INTENT_SCHEME); Intent intent = getIntent(); if (intent != null) { return intent.toUri(Intent.URI_INTENT_SCHEME); } // Shouldn't get here, but just in case... Loading @@ -322,6 +374,210 @@ public class ClipData implements Parcelable { } //END_INCLUDE(coerceToText) /** * Like {@link #coerceToHtmlText(Context)}, but any text that would * be returned as HTML formatting will be returned as text with * style spans. * @param context The caller's Context, from which its ContentResolver * and other things can be retrieved. * @return Returns the item's textual representation. */ public CharSequence coerceToStyledText(Context context) { CharSequence text = getText(); if (text instanceof Spanned) { return text; } String htmlText = getHtmlText(); if (htmlText != null) { try { CharSequence newText = Html.fromHtml(htmlText); if (newText != null) { return newText; } } catch (RuntimeException e) { // If anything bad happens, we'll fall back on the plain text. } } if (text != null) { return text; } return coerceToHtmlOrStyledText(context, true); } /** * Turn this item into HTML text, regardless of the type of data it * actually contains. * * <p>The algorithm for deciding what text to return is: * <ul> * <li> If {@link #getHtmlText} is non-null, return that. * <li> If {@link #getText} is non-null, return that, converting to * valid HTML text. If this text contains style spans, * {@link Html#toHtml(Spanned) Html.toHtml(Spanned)} is used to * convert them to HTML formatting. * <li> If {@link #getUri} is non-null, try to retrieve its data * as a text stream from its content provider. If the provider can * supply text/html data, that will be preferred and returned as-is. * Otherwise, any text/* data will be returned and escaped to HTML. * If it is not a content: URI or the content provider does not supply * a text representation, HTML text containing a link to the URI * will be returned. * <li> If {@link #getIntent} is non-null, convert that to an intent: * URI and return as an HTML link. * <li> Otherwise, return an empty string. * </ul> * * @param context The caller's Context, from which its ContentResolver * and other things can be retrieved. * @return Returns the item's representation as HTML text. */ public String coerceToHtmlText(Context context) { // If the item has an explicit HTML value, simply return that. String htmlText = getHtmlText(); if (htmlText != null) { return htmlText; } // If this Item has a plain text value, return it as HTML. CharSequence text = getText(); if (text != null) { if (text instanceof Spanned) { return Html.toHtml((Spanned)text); } return Html.escapeHtml(text); } text = coerceToHtmlOrStyledText(context, false); return text != null ? text.toString() : null; } private CharSequence coerceToHtmlOrStyledText(Context context, boolean styled) { // If this Item has a URI value, try using that. if (mUri != null) { // Check to see what data representations the content // provider supports. We would like HTML text, but if that // is not possible we'll live with plan text. String[] types = context.getContentResolver().getStreamTypes(mUri, "text/*"); boolean hasHtml = false; boolean hasText = false; if (types != null) { for (String type : types) { if ("text/html".equals(type)) { hasHtml = true; } else if (type.startsWith("text/")) { hasText = true; } } } // If the provider can serve data we can use, open and load it. if (hasHtml || hasText) { FileInputStream stream = null; try { // Ask for a stream of the desired type. AssetFileDescriptor descr = context.getContentResolver() .openTypedAssetFileDescriptor(mUri, hasHtml ? "text/html" : "text/plain", null); stream = descr.createInputStream(); InputStreamReader reader = new InputStreamReader(stream, "UTF-8"); // Got it... copy the stream into a local string and return it. StringBuilder builder = new StringBuilder(128); char[] buffer = new char[8192]; int len; while ((len=reader.read(buffer)) > 0) { builder.append(buffer, 0, len); } String text = builder.toString(); if (hasHtml) { if (styled) { // We loaded HTML formatted text and the caller // want styled text, convert it. try { CharSequence newText = Html.fromHtml(text); return newText != null ? newText : text; } catch (RuntimeException e) { return text; } } else { // We loaded HTML formatted text and that is what // the caller wants, just return it. return text.toString(); } } if (styled) { // We loaded plain text and the caller wants styled // text, that is all we have so return it. return text; } else { // We loaded plain text and the caller wants HTML // text, escape it for HTML. return Html.escapeHtml(text); } } catch (FileNotFoundException e) { // Unable to open content URI as text... not really an // error, just something to ignore. } catch (IOException e) { // Something bad has happened. Log.w("ClippedData", "Failure loading text", e); return Html.escapeHtml(e.toString()); } finally { if (stream != null) { try { stream.close(); } catch (IOException e) { } } } } // If we couldn't open the URI as a stream, then we can build // some HTML text with the URI itself. // probably serves fairly well as a textual representation. if (styled) { return uriToStyledText(mUri.toString()); } else { return uriToHtml(mUri.toString()); } } // Finally, if all we have is an Intent, then we can just turn that // into text. Not the most user-friendly thing, but it's something. if (mIntent != null) { if (styled) { return uriToStyledText(mIntent.toUri(Intent.URI_INTENT_SCHEME)); } else { return uriToHtml(mIntent.toUri(Intent.URI_INTENT_SCHEME)); } } // Shouldn't get here, but just in case... return ""; } private String uriToHtml(String uri) { StringBuilder builder = new StringBuilder(256); builder.append("<a href=\""); builder.append(uri); builder.append("\">"); builder.append(Html.escapeHtml(uri)); builder.append("</a>"); return builder.toString(); } private CharSequence uriToStyledText(String uri) { SpannableStringBuilder builder = new SpannableStringBuilder(); builder.append(uri); builder.setSpan(new URLSpan(uri), 0, builder.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); return builder; } @Override public String toString() { StringBuilder b = new StringBuilder(128); Loading @@ -335,7 +591,10 @@ public class ClipData implements Parcelable { /** @hide */ public void toShortString(StringBuilder b) { if (mText != null) { if (mHtmlText != null) { b.append("H:"); b.append(mHtmlText); } else if (mText != null) { b.append("T:"); b.append(mText); } else if (mUri != null) { Loading Loading @@ -408,6 +667,22 @@ public class ClipData implements Parcelable { return new ClipData(label, MIMETYPES_TEXT_PLAIN, item); } /** * Create a new ClipData holding data of the type * {@link ClipDescription#MIMETYPE_TEXT_HTML}. * * @param label User-visible label for the clip data. * @param text The text of clip as plain text, for receivers that don't * handle HTML. This is required. * @param htmlText The actual HTML text in the clip. * @return Returns a new ClipData containing the specified data. */ static public ClipData newHtmlText(CharSequence label, CharSequence text, String htmlText) { Item item = new Item(text, htmlText); return new ClipData(label, MIMETYPES_TEXT_HTML, item); } /** * Create a new ClipData holding an Intent with MIME type * {@link ClipDescription#MIMETYPE_TEXT_INTENT}. Loading Loading @@ -574,6 +849,7 @@ public class ClipData implements Parcelable { for (int i=0; i<N; i++) { Item item = mItems.get(i); TextUtils.writeToParcel(item.mText, dest, flags); dest.writeString(item.mHtmlText); if (item.mIntent != null) { dest.writeInt(1); item.mIntent.writeToParcel(dest, flags); Loading @@ -600,9 +876,10 @@ public class ClipData implements Parcelable { final int N = in.readInt(); for (int i=0; i<N; i++) { CharSequence text = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); String htmlText = in.readString(); Intent intent = in.readInt() != 0 ? Intent.CREATOR.createFromParcel(in) : null; Uri uri = in.readInt() != 0 ? Uri.CREATOR.createFromParcel(in) : null; mItems.add(new Item(text, intent, uri)); mItems.add(new Item(text, htmlText, intent, uri)); } } Loading core/java/android/content/ClipDescription.java +5 −0 Original line number Diff line number Diff line Loading @@ -40,6 +40,11 @@ public class ClipDescription implements Parcelable { */ public static final String MIMETYPE_TEXT_PLAIN = "text/plain"; /** * The MIME type for a clip holding HTML text. */ public static final String MIMETYPE_TEXT_HTML = "text/html"; /** * The MIME type for a clip holding one or more URIs. This should be * used for URIs that are meaningful to a user (such as an http: URI). Loading core/java/android/content/ContentResolver.java +1 −1 Original line number Diff line number Diff line Loading @@ -248,7 +248,7 @@ public abstract class ContentResolver { * @param mimeTypeFilter The desired MIME type. This may be a pattern, * such as *\/*, to query for all available MIME types that match the * pattern. * @return Returns an array of MIME type strings for all availablle * @return Returns an array of MIME type strings for all available * data streams that match the given mimeTypeFilter. If there are none, * null is returned. */ Loading core/java/android/content/Intent.java +33 −3 Original line number Diff line number Diff line Loading @@ -954,7 +954,18 @@ public class Intent implements Parcelable, Cloneable { * using EXTRA_TEXT, the MIME type should be "text/plain"; otherwise it * should be the MIME type of the data in EXTRA_STREAM. Use {@literal *}/* * if the MIME type is unknown (this will only allow senders that can * handle generic data streams). * handle generic data streams). If using {@link #EXTRA_TEXT}, you can * also optionally supply {@link #EXTRA_HTML_TEXT} for clients to retrieve * your text with HTML formatting. * <p> * As of {@link android.os.Build.VERSION_CODES#JELLY_BEAN}, the data * being sent can be supplied through {@link #setClipData(ClipData)}. This * allows you to use {@link #FLAG_GRANT_READ_URI_PERMISSION} when sharing * content: URIs and other advanced features of {@link ClipData}. If * using this approach, you still must supply the same data through the * {@link #EXTRA_TEXT} or {@link #EXTRA_STREAM} fields described below * for compatibility with old applications. If you don't set a ClipData, * it will be copied there for you when calling {@link Context#startActivity(Intent)}. * <p> * Optional standard extras, which may be interpreted by some recipients as * appropriate, are: {@link #EXTRA_EMAIL}, {@link #EXTRA_CC}, Loading @@ -967,11 +978,13 @@ public class Intent implements Parcelable, Cloneable { /** * Activity Action: Deliver multiple data to someone else. * <p> * Like ACTION_SEND, except the data is multiple. * Like {@link #ACTION_SEND}, except the data is multiple. * <p> * Input: {@link #getType} is the MIME type of the data being sent. * get*ArrayListExtra can have either a {@link #EXTRA_TEXT} or {@link * #EXTRA_STREAM} field, containing the data to be sent. * #EXTRA_STREAM} field, containing the data to be sent. If using * {@link #EXTRA_TEXT}, you can also optionally supply {@link #EXTRA_HTML_TEXT} * for clients to retrieve your text with HTML formatting. * <p> * Multiple types are supported, and receivers should handle mixed types * whenever possible. The right way for the receiver to check them is to Loading @@ -983,6 +996,15 @@ public class Intent implements Parcelable, Cloneable { * be image/jpg, but if you are sending image/jpg and image/png, then the * intent's type should be image/*. * <p> * As of {@link android.os.Build.VERSION_CODES#JELLY_BEAN}, the data * being sent can be supplied through {@link #setClipData(ClipData)}. This * allows you to use {@link #FLAG_GRANT_READ_URI_PERMISSION} when sharing * content: URIs and other advanced features of {@link ClipData}. If * using this approach, you still must supply the same data through the * {@link #EXTRA_TEXT} or {@link #EXTRA_STREAM} fields described below * for compatibility with old applications. If you don't set a ClipData, * it will be copied there for you when calling {@link Context#startActivity(Intent)}. * <p> * Optional standard extras, which may be interpreted by some recipients as * appropriate, are: {@link #EXTRA_EMAIL}, {@link #EXTRA_CC}, * {@link #EXTRA_BCC}, {@link #EXTRA_SUBJECT}. Loading Loading @@ -2500,6 +2522,14 @@ public class Intent implements Parcelable, Cloneable { */ public static final String EXTRA_TEXT = "android.intent.extra.TEXT"; /** * A constant String that is associated with the Intent, used with * {@link #ACTION_SEND} to supply an alternative to {@link #EXTRA_TEXT} * as HTML formatted text. Note that you <em>must</em> also supply * {@link #EXTRA_TEXT}. */ public static final String EXTRA_HTML_TEXT = "android.intent.extra.HTML_TEXT"; /** * A content: URI holding a stream of data associated with the Intent, * used with {@link #ACTION_SEND} to supply the data being sent. Loading Loading
api/current.txt +9 −0 Original line number Diff line number Diff line Loading @@ -4833,6 +4833,7 @@ package android.content { method public android.content.ClipDescription getDescription(); method public android.content.ClipData.Item getItemAt(int); method public int getItemCount(); method public static android.content.ClipData newHtmlText(java.lang.CharSequence, java.lang.CharSequence, java.lang.String); method public static android.content.ClipData newIntent(java.lang.CharSequence, android.content.Intent); method public static android.content.ClipData newPlainText(java.lang.CharSequence, java.lang.CharSequence); method public static android.content.ClipData newRawUri(java.lang.CharSequence, android.net.Uri); Loading @@ -4843,10 +4844,15 @@ package android.content { public static class ClipData.Item { ctor public ClipData.Item(java.lang.CharSequence); ctor public ClipData.Item(java.lang.CharSequence, java.lang.String); ctor public ClipData.Item(android.content.Intent); ctor public ClipData.Item(android.net.Uri); ctor public ClipData.Item(java.lang.CharSequence, android.content.Intent, android.net.Uri); ctor public ClipData.Item(java.lang.CharSequence, java.lang.String, android.content.Intent, android.net.Uri); method public java.lang.String coerceToHtmlText(android.content.Context); method public java.lang.CharSequence coerceToStyledText(android.content.Context); method public java.lang.CharSequence coerceToText(android.content.Context); method public java.lang.String getHtmlText(); method public android.content.Intent getIntent(); method public java.lang.CharSequence getText(); method public android.net.Uri getUri(); Loading @@ -4864,6 +4870,7 @@ package android.content { method public boolean hasMimeType(java.lang.String); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator CREATOR; field public static final java.lang.String MIMETYPE_TEXT_HTML = "text/html"; field public static final java.lang.String MIMETYPE_TEXT_INTENT = "text/vnd.android.intent"; field public static final java.lang.String MIMETYPE_TEXT_PLAIN = "text/plain"; field public static final java.lang.String MIMETYPE_TEXT_URILIST = "text/uri-list"; Loading Loading @@ -5701,6 +5708,7 @@ package android.content { field public static final int EXTRA_DOCK_STATE_UNDOCKED = 0; // 0x0 field public static final java.lang.String EXTRA_DONT_KILL_APP = "android.intent.extra.DONT_KILL_APP"; field public static final java.lang.String EXTRA_EMAIL = "android.intent.extra.EMAIL"; field public static final java.lang.String EXTRA_HTML_TEXT = "android.intent.extra.HTML_TEXT"; field public static final java.lang.String EXTRA_INITIAL_INTENTS = "android.intent.extra.INITIAL_INTENTS"; field public static final java.lang.String EXTRA_INSTALLER_PACKAGE_NAME = "android.intent.extra.INSTALLER_PACKAGE_NAME"; field public static final java.lang.String EXTRA_INTENT = "android.intent.extra.INTENT"; Loading Loading @@ -20406,6 +20414,7 @@ package android.text { } public class Html { method public static java.lang.String escapeHtml(java.lang.CharSequence); method public static android.text.Spanned fromHtml(java.lang.String); method public static android.text.Spanned fromHtml(java.lang.String, android.text.Html.ImageGetter, android.text.Html.TagHandler); method public static java.lang.String toHtml(android.text.Spanned);
core/java/android/content/ClipData.java +288 −11 Original line number Diff line number Diff line Loading @@ -21,7 +21,12 @@ import android.graphics.Bitmap; import android.net.Uri; import android.os.Parcel; import android.os.Parcelable; import android.text.Html; import android.text.Spannable; import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.TextUtils; import android.text.style.URLSpan; import android.util.Log; import java.io.FileInputStream; Loading Loading @@ -144,6 +149,8 @@ import java.util.ArrayList; public class ClipData implements Parcelable { static final String[] MIMETYPES_TEXT_PLAIN = new String[] { ClipDescription.MIMETYPE_TEXT_PLAIN }; static final String[] MIMETYPES_TEXT_HTML = new String[] { ClipDescription.MIMETYPE_TEXT_HTML }; static final String[] MIMETYPES_TEXT_URILIST = new String[] { ClipDescription.MIMETYPE_TEXT_URILIST }; static final String[] MIMETYPES_TEXT_INTENT = new String[] { Loading Loading @@ -176,6 +183,7 @@ public class ClipData implements Parcelable { */ public static class Item { final CharSequence mText; final String mHtmlText; final Intent mIntent; final Uri mUri; Loading @@ -184,6 +192,20 @@ public class ClipData implements Parcelable { */ public Item(CharSequence text) { mText = text; mHtmlText = null; mIntent = null; mUri = null; } /** * Create an Item consisting of a single block of (possibly styled) text, * with an alternative HTML formatted representation. You <em>must</em> * supply a plain text representation in addition to HTML text; coercion * will not be done from HTML formated text into plain text. */ public Item(CharSequence text, String htmlText) { mText = text; mHtmlText = htmlText; mIntent = null; mUri = null; } Loading @@ -193,6 +215,7 @@ public class ClipData implements Parcelable { */ public Item(Intent intent) { mText = null; mHtmlText = null; mIntent = intent; mUri = null; } Loading @@ -202,16 +225,35 @@ public class ClipData implements Parcelable { */ public Item(Uri uri) { mText = null; mHtmlText = null; mIntent = null; mUri = uri; } /** * Create a complex Item, containing multiple representations of * text, intent, and/or URI. * text, Intent, and/or URI. */ public Item(CharSequence text, Intent intent, Uri uri) { mText = text; mHtmlText = null; mIntent = intent; mUri = uri; } /** * Create a complex Item, containing multiple representations of * text, HTML text, Intent, and/or URI. If providing HTML text, you * <em>must</em> supply a plain text representation as well; coercion * will not be done from HTML formated text into plain text. */ public Item(CharSequence text, String htmlText, Intent intent, Uri uri) { if (htmlText != null && text == null) { throw new IllegalArgumentException( "Plain text must be supplied if HTML text is supplied"); } mText = text; mHtmlText = htmlText; mIntent = intent; mUri = uri; } Loading @@ -223,6 +265,13 @@ public class ClipData implements Parcelable { return mText; } /** * Retrieve the raw HTML text contained in this Item. */ public String getHtmlText() { return mHtmlText; } /** * Retrieve the raw Intent contained in this Item. */ Loading Loading @@ -261,12 +310,14 @@ public class ClipData implements Parcelable { //BEGIN_INCLUDE(coerceToText) public CharSequence coerceToText(Context context) { // If this Item has an explicit textual value, simply return that. if (mText != null) { return mText; CharSequence text = getText(); if (text != null) { return text; } // If this Item has a URI value, try using that. if (mUri != null) { Uri uri = getUri(); if (uri != null) { // First see if the URI can be opened as a plain text stream // (of any sub-type). If so, this is the best textual Loading @@ -275,7 +326,7 @@ public class ClipData implements Parcelable { try { // Ask for a stream of the desired type. AssetFileDescriptor descr = context.getContentResolver() .openTypedAssetFileDescriptor(mUri, "text/*", null); .openTypedAssetFileDescriptor(uri, "text/*", null); stream = descr.createInputStream(); InputStreamReader reader = new InputStreamReader(stream, "UTF-8"); Loading Loading @@ -308,13 +359,14 @@ public class ClipData implements Parcelable { // If we couldn't open the URI as a stream, then the URI itself // probably serves fairly well as a textual representation. return mUri.toString(); return uri.toString(); } // Finally, if all we have is an Intent, then we can just turn that // into text. Not the most user-friendly thing, but it's something. if (mIntent != null) { return mIntent.toUri(Intent.URI_INTENT_SCHEME); Intent intent = getIntent(); if (intent != null) { return intent.toUri(Intent.URI_INTENT_SCHEME); } // Shouldn't get here, but just in case... Loading @@ -322,6 +374,210 @@ public class ClipData implements Parcelable { } //END_INCLUDE(coerceToText) /** * Like {@link #coerceToHtmlText(Context)}, but any text that would * be returned as HTML formatting will be returned as text with * style spans. * @param context The caller's Context, from which its ContentResolver * and other things can be retrieved. * @return Returns the item's textual representation. */ public CharSequence coerceToStyledText(Context context) { CharSequence text = getText(); if (text instanceof Spanned) { return text; } String htmlText = getHtmlText(); if (htmlText != null) { try { CharSequence newText = Html.fromHtml(htmlText); if (newText != null) { return newText; } } catch (RuntimeException e) { // If anything bad happens, we'll fall back on the plain text. } } if (text != null) { return text; } return coerceToHtmlOrStyledText(context, true); } /** * Turn this item into HTML text, regardless of the type of data it * actually contains. * * <p>The algorithm for deciding what text to return is: * <ul> * <li> If {@link #getHtmlText} is non-null, return that. * <li> If {@link #getText} is non-null, return that, converting to * valid HTML text. If this text contains style spans, * {@link Html#toHtml(Spanned) Html.toHtml(Spanned)} is used to * convert them to HTML formatting. * <li> If {@link #getUri} is non-null, try to retrieve its data * as a text stream from its content provider. If the provider can * supply text/html data, that will be preferred and returned as-is. * Otherwise, any text/* data will be returned and escaped to HTML. * If it is not a content: URI or the content provider does not supply * a text representation, HTML text containing a link to the URI * will be returned. * <li> If {@link #getIntent} is non-null, convert that to an intent: * URI and return as an HTML link. * <li> Otherwise, return an empty string. * </ul> * * @param context The caller's Context, from which its ContentResolver * and other things can be retrieved. * @return Returns the item's representation as HTML text. */ public String coerceToHtmlText(Context context) { // If the item has an explicit HTML value, simply return that. String htmlText = getHtmlText(); if (htmlText != null) { return htmlText; } // If this Item has a plain text value, return it as HTML. CharSequence text = getText(); if (text != null) { if (text instanceof Spanned) { return Html.toHtml((Spanned)text); } return Html.escapeHtml(text); } text = coerceToHtmlOrStyledText(context, false); return text != null ? text.toString() : null; } private CharSequence coerceToHtmlOrStyledText(Context context, boolean styled) { // If this Item has a URI value, try using that. if (mUri != null) { // Check to see what data representations the content // provider supports. We would like HTML text, but if that // is not possible we'll live with plan text. String[] types = context.getContentResolver().getStreamTypes(mUri, "text/*"); boolean hasHtml = false; boolean hasText = false; if (types != null) { for (String type : types) { if ("text/html".equals(type)) { hasHtml = true; } else if (type.startsWith("text/")) { hasText = true; } } } // If the provider can serve data we can use, open and load it. if (hasHtml || hasText) { FileInputStream stream = null; try { // Ask for a stream of the desired type. AssetFileDescriptor descr = context.getContentResolver() .openTypedAssetFileDescriptor(mUri, hasHtml ? "text/html" : "text/plain", null); stream = descr.createInputStream(); InputStreamReader reader = new InputStreamReader(stream, "UTF-8"); // Got it... copy the stream into a local string and return it. StringBuilder builder = new StringBuilder(128); char[] buffer = new char[8192]; int len; while ((len=reader.read(buffer)) > 0) { builder.append(buffer, 0, len); } String text = builder.toString(); if (hasHtml) { if (styled) { // We loaded HTML formatted text and the caller // want styled text, convert it. try { CharSequence newText = Html.fromHtml(text); return newText != null ? newText : text; } catch (RuntimeException e) { return text; } } else { // We loaded HTML formatted text and that is what // the caller wants, just return it. return text.toString(); } } if (styled) { // We loaded plain text and the caller wants styled // text, that is all we have so return it. return text; } else { // We loaded plain text and the caller wants HTML // text, escape it for HTML. return Html.escapeHtml(text); } } catch (FileNotFoundException e) { // Unable to open content URI as text... not really an // error, just something to ignore. } catch (IOException e) { // Something bad has happened. Log.w("ClippedData", "Failure loading text", e); return Html.escapeHtml(e.toString()); } finally { if (stream != null) { try { stream.close(); } catch (IOException e) { } } } } // If we couldn't open the URI as a stream, then we can build // some HTML text with the URI itself. // probably serves fairly well as a textual representation. if (styled) { return uriToStyledText(mUri.toString()); } else { return uriToHtml(mUri.toString()); } } // Finally, if all we have is an Intent, then we can just turn that // into text. Not the most user-friendly thing, but it's something. if (mIntent != null) { if (styled) { return uriToStyledText(mIntent.toUri(Intent.URI_INTENT_SCHEME)); } else { return uriToHtml(mIntent.toUri(Intent.URI_INTENT_SCHEME)); } } // Shouldn't get here, but just in case... return ""; } private String uriToHtml(String uri) { StringBuilder builder = new StringBuilder(256); builder.append("<a href=\""); builder.append(uri); builder.append("\">"); builder.append(Html.escapeHtml(uri)); builder.append("</a>"); return builder.toString(); } private CharSequence uriToStyledText(String uri) { SpannableStringBuilder builder = new SpannableStringBuilder(); builder.append(uri); builder.setSpan(new URLSpan(uri), 0, builder.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); return builder; } @Override public String toString() { StringBuilder b = new StringBuilder(128); Loading @@ -335,7 +591,10 @@ public class ClipData implements Parcelable { /** @hide */ public void toShortString(StringBuilder b) { if (mText != null) { if (mHtmlText != null) { b.append("H:"); b.append(mHtmlText); } else if (mText != null) { b.append("T:"); b.append(mText); } else if (mUri != null) { Loading Loading @@ -408,6 +667,22 @@ public class ClipData implements Parcelable { return new ClipData(label, MIMETYPES_TEXT_PLAIN, item); } /** * Create a new ClipData holding data of the type * {@link ClipDescription#MIMETYPE_TEXT_HTML}. * * @param label User-visible label for the clip data. * @param text The text of clip as plain text, for receivers that don't * handle HTML. This is required. * @param htmlText The actual HTML text in the clip. * @return Returns a new ClipData containing the specified data. */ static public ClipData newHtmlText(CharSequence label, CharSequence text, String htmlText) { Item item = new Item(text, htmlText); return new ClipData(label, MIMETYPES_TEXT_HTML, item); } /** * Create a new ClipData holding an Intent with MIME type * {@link ClipDescription#MIMETYPE_TEXT_INTENT}. Loading Loading @@ -574,6 +849,7 @@ public class ClipData implements Parcelable { for (int i=0; i<N; i++) { Item item = mItems.get(i); TextUtils.writeToParcel(item.mText, dest, flags); dest.writeString(item.mHtmlText); if (item.mIntent != null) { dest.writeInt(1); item.mIntent.writeToParcel(dest, flags); Loading @@ -600,9 +876,10 @@ public class ClipData implements Parcelable { final int N = in.readInt(); for (int i=0; i<N; i++) { CharSequence text = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); String htmlText = in.readString(); Intent intent = in.readInt() != 0 ? Intent.CREATOR.createFromParcel(in) : null; Uri uri = in.readInt() != 0 ? Uri.CREATOR.createFromParcel(in) : null; mItems.add(new Item(text, intent, uri)); mItems.add(new Item(text, htmlText, intent, uri)); } } Loading
core/java/android/content/ClipDescription.java +5 −0 Original line number Diff line number Diff line Loading @@ -40,6 +40,11 @@ public class ClipDescription implements Parcelable { */ public static final String MIMETYPE_TEXT_PLAIN = "text/plain"; /** * The MIME type for a clip holding HTML text. */ public static final String MIMETYPE_TEXT_HTML = "text/html"; /** * The MIME type for a clip holding one or more URIs. This should be * used for URIs that are meaningful to a user (such as an http: URI). Loading
core/java/android/content/ContentResolver.java +1 −1 Original line number Diff line number Diff line Loading @@ -248,7 +248,7 @@ public abstract class ContentResolver { * @param mimeTypeFilter The desired MIME type. This may be a pattern, * such as *\/*, to query for all available MIME types that match the * pattern. * @return Returns an array of MIME type strings for all availablle * @return Returns an array of MIME type strings for all available * data streams that match the given mimeTypeFilter. If there are none, * null is returned. */ Loading
core/java/android/content/Intent.java +33 −3 Original line number Diff line number Diff line Loading @@ -954,7 +954,18 @@ public class Intent implements Parcelable, Cloneable { * using EXTRA_TEXT, the MIME type should be "text/plain"; otherwise it * should be the MIME type of the data in EXTRA_STREAM. Use {@literal *}/* * if the MIME type is unknown (this will only allow senders that can * handle generic data streams). * handle generic data streams). If using {@link #EXTRA_TEXT}, you can * also optionally supply {@link #EXTRA_HTML_TEXT} for clients to retrieve * your text with HTML formatting. * <p> * As of {@link android.os.Build.VERSION_CODES#JELLY_BEAN}, the data * being sent can be supplied through {@link #setClipData(ClipData)}. This * allows you to use {@link #FLAG_GRANT_READ_URI_PERMISSION} when sharing * content: URIs and other advanced features of {@link ClipData}. If * using this approach, you still must supply the same data through the * {@link #EXTRA_TEXT} or {@link #EXTRA_STREAM} fields described below * for compatibility with old applications. If you don't set a ClipData, * it will be copied there for you when calling {@link Context#startActivity(Intent)}. * <p> * Optional standard extras, which may be interpreted by some recipients as * appropriate, are: {@link #EXTRA_EMAIL}, {@link #EXTRA_CC}, Loading @@ -967,11 +978,13 @@ public class Intent implements Parcelable, Cloneable { /** * Activity Action: Deliver multiple data to someone else. * <p> * Like ACTION_SEND, except the data is multiple. * Like {@link #ACTION_SEND}, except the data is multiple. * <p> * Input: {@link #getType} is the MIME type of the data being sent. * get*ArrayListExtra can have either a {@link #EXTRA_TEXT} or {@link * #EXTRA_STREAM} field, containing the data to be sent. * #EXTRA_STREAM} field, containing the data to be sent. If using * {@link #EXTRA_TEXT}, you can also optionally supply {@link #EXTRA_HTML_TEXT} * for clients to retrieve your text with HTML formatting. * <p> * Multiple types are supported, and receivers should handle mixed types * whenever possible. The right way for the receiver to check them is to Loading @@ -983,6 +996,15 @@ public class Intent implements Parcelable, Cloneable { * be image/jpg, but if you are sending image/jpg and image/png, then the * intent's type should be image/*. * <p> * As of {@link android.os.Build.VERSION_CODES#JELLY_BEAN}, the data * being sent can be supplied through {@link #setClipData(ClipData)}. This * allows you to use {@link #FLAG_GRANT_READ_URI_PERMISSION} when sharing * content: URIs and other advanced features of {@link ClipData}. If * using this approach, you still must supply the same data through the * {@link #EXTRA_TEXT} or {@link #EXTRA_STREAM} fields described below * for compatibility with old applications. If you don't set a ClipData, * it will be copied there for you when calling {@link Context#startActivity(Intent)}. * <p> * Optional standard extras, which may be interpreted by some recipients as * appropriate, are: {@link #EXTRA_EMAIL}, {@link #EXTRA_CC}, * {@link #EXTRA_BCC}, {@link #EXTRA_SUBJECT}. Loading Loading @@ -2500,6 +2522,14 @@ public class Intent implements Parcelable, Cloneable { */ public static final String EXTRA_TEXT = "android.intent.extra.TEXT"; /** * A constant String that is associated with the Intent, used with * {@link #ACTION_SEND} to supply an alternative to {@link #EXTRA_TEXT} * as HTML formatted text. Note that you <em>must</em> also supply * {@link #EXTRA_TEXT}. */ public static final String EXTRA_HTML_TEXT = "android.intent.extra.HTML_TEXT"; /** * A content: URI holding a stream of data associated with the Intent, * used with {@link #ACTION_SEND} to supply the data being sent. Loading