diff options
| author | 2010-08-26 22:11:06 -0700 | |
|---|---|---|
| committer | 2010-08-27 11:06:01 -0700 | |
| commit | 1040dc465cbf5ca8f834a87c949e476abefa3f76 (patch) | |
| tree | 98841629e182d19c19bc68835d7a4b2e426b883a | |
| parent | 59024f1697e09ea50d4349e9813d0c101411292b (diff) | |
Improve clipboard API.
- Rename ClippedData to ClipData.
- Introudce ClipDescription subclass.
- Add convenience APIs for creating a ClipData.
- Add ClipboardManager API to get just the ClipDescription.
- Define MIME types associated with a clip.
Change-Id: If97ef91aa99a4dd0ec74ccaea504345c9ef12b5c
| -rw-r--r-- | CleanSpec.mk | 1 | ||||
| -rw-r--r-- | api/current.xml | 413 | ||||
| -rw-r--r-- | core/java/android/content/ClipData.aidl (renamed from core/java/android/content/ClippedData.aidl) | 2 | ||||
| -rw-r--r-- | core/java/android/content/ClipData.java (renamed from core/java/android/content/ClippedData.java) | 148 | ||||
| -rw-r--r-- | core/java/android/content/ClipDescription.aidl | 19 | ||||
| -rw-r--r-- | core/java/android/content/ClipDescription.java | 206 | ||||
| -rw-r--r-- | core/java/android/content/ClipboardManager.java | 24 | ||||
| -rw-r--r-- | core/java/android/content/ContentProvider.java | 34 | ||||
| -rw-r--r-- | core/java/android/content/IClipboard.aidl | 8 | ||||
| -rw-r--r-- | core/java/android/widget/TextView.java | 23 | ||||
| -rw-r--r-- | services/java/com/android/server/ClipboardService.java | 15 |
11 files changed, 713 insertions, 180 deletions
diff --git a/CleanSpec.mk b/CleanSpec.mk index a9f4d195faa1..e961a5a06cb3 100644 --- a/CleanSpec.mk +++ b/CleanSpec.mk @@ -77,6 +77,7 @@ $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/lib/libhwui.so) $(call add-clean-step, rm -rf $(PRODUCT_OUT)/symbols/system/lib/libhwui.so) $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/libhwui.so) $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/os/storage/*) +$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/content/IClipboard.P) # ************************************************ # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST diff --git a/api/current.xml b/api/current.xml index b8871bb17b77..ad4fb2204def 100644 --- a/api/current.xml +++ b/api/current.xml @@ -39293,15 +39293,31 @@ </parameter> </method> </class> -<class name="ClipboardManager" - extends="android.text.ClipboardManager" +<class name="ClipData" + extends="android.content.ClipDescription" abstract="false" static="false" final="false" deprecated="not deprecated" visibility="public" > -<method name="addPrimaryClipChangedListener" +<constructor name="ClipData" + type="android.content.ClipData" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="label" type="java.lang.CharSequence"> +</parameter> +<parameter name="mimeTypes" type="java.lang.String[]"> +</parameter> +<parameter name="icon" type="android.graphics.Bitmap"> +</parameter> +<parameter name="item" type="android.content.ClipData.Item"> +</parameter> +</constructor> +<method name="addItem" return="void" abstract="false" native="false" @@ -39311,11 +39327,11 @@ deprecated="not deprecated" visibility="public" > -<parameter name="what" type="android.content.ClipboardManager.OnPrimaryClipChangedListener"> +<parameter name="item" type="android.content.ClipData.Item"> </parameter> </method> -<method name="getPrimaryClip" - return="android.content.ClippedData" +<method name="getIcon" + return="android.graphics.Bitmap" abstract="false" native="false" synchronized="false" @@ -39325,19 +39341,21 @@ visibility="public" > </method> -<method name="getText" - return="java.lang.CharSequence" +<method name="getItem" + return="android.content.ClipData.Item" abstract="false" native="false" synchronized="false" static="false" final="false" - deprecated="deprecated" + deprecated="not deprecated" visibility="public" > +<parameter name="index" type="int"> +</parameter> </method> -<method name="hasPrimaryClip" - return="boolean" +<method name="getItemCount" + return="int" abstract="false" native="false" synchronized="false" @@ -39347,67 +39365,142 @@ visibility="public" > </method> -<method name="hasText" - return="boolean" +<method name="newIntent" + return="android.content.ClipData" abstract="false" native="false" synchronized="false" - static="false" + static="true" final="false" - deprecated="deprecated" + deprecated="not deprecated" visibility="public" > +<parameter name="label" type="java.lang.CharSequence"> +</parameter> +<parameter name="icon" type="android.graphics.Bitmap"> +</parameter> +<parameter name="intent" type="android.content.Intent"> +</parameter> </method> -<method name="removePrimaryClipChangedListener" - return="void" +<method name="newPlainText" + return="android.content.ClipData" abstract="false" native="false" synchronized="false" - static="false" + static="true" final="false" deprecated="not deprecated" visibility="public" > -<parameter name="what" type="android.content.ClipboardManager.OnPrimaryClipChangedListener"> +<parameter name="label" type="java.lang.CharSequence"> +</parameter> +<parameter name="icon" type="android.graphics.Bitmap"> +</parameter> +<parameter name="text" type="java.lang.CharSequence"> </parameter> </method> -<method name="setPrimaryClip" - return="void" +<method name="newRawUri" + return="android.content.ClipData" abstract="false" native="false" synchronized="false" - static="false" + static="true" final="false" deprecated="not deprecated" visibility="public" > -<parameter name="clip" type="android.content.ClippedData"> +<parameter name="label" type="java.lang.CharSequence"> +</parameter> +<parameter name="icon" type="android.graphics.Bitmap"> +</parameter> +<parameter name="uri" type="android.net.Uri"> </parameter> </method> -<method name="setText" - return="void" +<method name="newUri" + return="android.content.ClipData" abstract="false" native="false" synchronized="false" - static="false" + static="true" final="false" - deprecated="deprecated" + deprecated="not deprecated" visibility="public" > -<parameter name="text" type="java.lang.CharSequence"> +<parameter name="resolver" type="android.content.ContentResolver"> +</parameter> +<parameter name="label" type="java.lang.CharSequence"> +</parameter> +<parameter name="icon" type="android.graphics.Bitmap"> +</parameter> +<parameter name="uri" type="android.net.Uri"> </parameter> </method> +<field name="CREATOR" + type="android.os.Parcelable.Creator" + transient="false" + volatile="false" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> </class> -<interface name="ClipboardManager.OnPrimaryClipChangedListener" - abstract="true" +<class name="ClipData.Item" + extends="java.lang.Object" + abstract="false" static="true" final="false" deprecated="not deprecated" visibility="public" > -<method name="onPrimaryClipChanged" - return="void" - abstract="true" +<constructor name="ClipData.Item" + type="android.content.ClipData.Item" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="text" type="java.lang.CharSequence"> +</parameter> +</constructor> +<constructor name="ClipData.Item" + type="android.content.ClipData.Item" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="intent" type="android.content.Intent"> +</parameter> +</constructor> +<constructor name="ClipData.Item" + type="android.content.ClipData.Item" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="uri" type="android.net.Uri"> +</parameter> +</constructor> +<constructor name="ClipData.Item" + type="android.content.ClipData.Item" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="text" type="java.lang.CharSequence"> +</parameter> +<parameter name="intent" type="android.content.Intent"> +</parameter> +<parameter name="uri" type="android.net.Uri"> +</parameter> +</constructor> +<method name="coerceToText" + return="java.lang.CharSequence" + abstract="false" native="false" synchronized="false" static="false" @@ -39415,9 +39508,44 @@ deprecated="not deprecated" visibility="public" > +<parameter name="context" type="android.content.Context"> +</parameter> </method> -</interface> -<class name="ClippedData" +<method name="getIntent" + return="android.content.Intent" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="getText" + return="java.lang.CharSequence" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="getUri" + return="android.net.Uri" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +</class> +<class name="ClipDescription" extends="java.lang.Object" abstract="false" static="false" @@ -39427,8 +39555,8 @@ > <implements name="android.os.Parcelable"> </implements> -<constructor name="ClippedData" - type="android.content.ClippedData" +<constructor name="ClipDescription" + type="android.content.ClipDescription" static="false" final="false" deprecated="not deprecated" @@ -39436,22 +39564,32 @@ > <parameter name="label" type="java.lang.CharSequence"> </parameter> -<parameter name="icon" type="android.graphics.Bitmap"> +<parameter name="mimeTypes" type="java.lang.String[]"> </parameter> -<parameter name="item" type="android.content.ClippedData.Item"> +</constructor> +<constructor name="ClipDescription" + type="android.content.ClipDescription" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="o" type="android.content.ClipDescription"> </parameter> </constructor> -<method name="addItem" - return="void" +<method name="compareMimeTypes" + return="boolean" abstract="false" native="false" synchronized="false" - static="false" + static="true" final="false" deprecated="not deprecated" visibility="public" > -<parameter name="item" type="android.content.ClippedData.Item"> +<parameter name="concreteType" type="java.lang.String"> +</parameter> +<parameter name="desiredType" type="java.lang.String"> </parameter> </method> <method name="describeContents" @@ -39465,8 +39603,8 @@ visibility="public" > </method> -<method name="getIcon" - return="android.graphics.Bitmap" +<method name="filterMimeTypes" + return="java.lang.String[]" abstract="false" native="false" synchronized="false" @@ -39475,9 +39613,22 @@ deprecated="not deprecated" visibility="public" > +<parameter name="mimeType" type="java.lang.String"> +</parameter> </method> -<method name="getItem" - return="android.content.ClippedData.Item" +<method name="getLabel" + return="java.lang.CharSequence" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="getMimeType" + return="java.lang.String" abstract="false" native="false" synchronized="false" @@ -39489,7 +39640,7 @@ <parameter name="index" type="int"> </parameter> </method> -<method name="getItemCount" +<method name="getMimeTypeCount" return="int" abstract="false" native="false" @@ -39500,8 +39651,8 @@ visibility="public" > </method> -<method name="getLabel" - return="java.lang.CharSequence" +<method name="hasMimeType" + return="boolean" abstract="false" native="false" synchronized="false" @@ -39510,6 +39661,8 @@ deprecated="not deprecated" visibility="public" > +<parameter name="mimeType" type="java.lang.String"> +</parameter> </method> <method name="writeToParcel" return="void" @@ -39536,74 +39689,96 @@ visibility="public" > </field> -</class> -<class name="ClippedData.Item" - extends="java.lang.Object" - abstract="false" +<field name="MIMETYPE_TEXT_INTENT" + type="java.lang.String" + transient="false" + volatile="false" + value=""text/vnd.android.intent"" static="true" - final="false" + final="true" deprecated="not deprecated" visibility="public" > -<constructor name="ClippedData.Item" - type="android.content.ClippedData.Item" +</field> +<field name="MIMETYPE_TEXT_PLAIN" + type="java.lang.String" + transient="false" + volatile="false" + value=""text/plain"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="MIMETYPE_TEXT_URILIST" + type="java.lang.String" + transient="false" + volatile="false" + value=""text/uri-list"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +</class> +<class name="ClipboardManager" + extends="android.text.ClipboardManager" + abstract="false" static="false" final="false" deprecated="not deprecated" visibility="public" > -<parameter name="text" type="java.lang.CharSequence"> -</parameter> -</constructor> -<constructor name="ClippedData.Item" - type="android.content.ClippedData.Item" +<method name="addPrimaryClipChangedListener" + return="void" + abstract="false" + native="false" + synchronized="false" static="false" final="false" deprecated="not deprecated" visibility="public" > -<parameter name="intent" type="android.content.Intent"> +<parameter name="what" type="android.content.ClipboardManager.OnPrimaryClipChangedListener"> </parameter> -</constructor> -<constructor name="ClippedData.Item" - type="android.content.ClippedData.Item" +</method> +<method name="getPrimaryClip" + return="android.content.ClipData" + abstract="false" + native="false" + synchronized="false" static="false" final="false" deprecated="not deprecated" visibility="public" > -<parameter name="uri" type="android.net.Uri"> -</parameter> -</constructor> -<constructor name="ClippedData.Item" - type="android.content.ClippedData.Item" +</method> +<method name="getPrimaryClipDescription" + return="android.content.ClipDescription" + abstract="false" + native="false" + synchronized="false" static="false" final="false" deprecated="not deprecated" visibility="public" > -<parameter name="text" type="java.lang.CharSequence"> -</parameter> -<parameter name="intent" type="android.content.Intent"> -</parameter> -<parameter name="uri" type="android.net.Uri"> -</parameter> -</constructor> -<method name="coerceToText" +</method> +<method name="getText" return="java.lang.CharSequence" abstract="false" native="false" synchronized="false" static="false" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > -<parameter name="context" type="android.content.Context"> -</parameter> </method> -<method name="getIntent" - return="android.content.Intent" +<method name="hasPrimaryClip" + return="boolean" abstract="false" native="false" synchronized="false" @@ -39613,8 +39788,19 @@ visibility="public" > </method> -<method name="getText" - return="java.lang.CharSequence" +<method name="hasText" + return="boolean" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="deprecated" + visibility="public" +> +</method> +<method name="removePrimaryClipChangedListener" + return="void" abstract="false" native="false" synchronized="false" @@ -39623,9 +39809,11 @@ deprecated="not deprecated" visibility="public" > +<parameter name="what" type="android.content.ClipboardManager.OnPrimaryClipChangedListener"> +</parameter> </method> -<method name="getUri" - return="android.net.Uri" +<method name="setPrimaryClip" + return="void" abstract="false" native="false" synchronized="false" @@ -39634,8 +39822,42 @@ deprecated="not deprecated" visibility="public" > +<parameter name="clip" type="android.content.ClipData"> +</parameter> +</method> +<method name="setText" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="deprecated" + visibility="public" +> +<parameter name="text" type="java.lang.CharSequence"> +</parameter> </method> </class> +<interface name="ClipboardManager.OnPrimaryClipChangedListener" + abstract="true" + static="true" + final="false" + deprecated="not deprecated" + visibility="public" +> +<method name="onPrimaryClipChanged" + return="void" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +</interface> <interface name="ComponentCallbacks" abstract="true" static="false" @@ -39959,21 +40181,6 @@ <parameter name="values" type="android.content.ContentValues[]"> </parameter> </method> -<method name="compareMimeTypes" - return="boolean" - abstract="false" - native="false" - synchronized="false" - static="true" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="concreteType" type="java.lang.String"> -</parameter> -<parameter name="desiredType" type="java.lang.String"> -</parameter> -</method> <method name="delete" return="int" abstract="true" diff --git a/core/java/android/content/ClippedData.aidl b/core/java/android/content/ClipData.aidl index 52465268764e..5fc12ce1fe7e 100644 --- a/core/java/android/content/ClippedData.aidl +++ b/core/java/android/content/ClipData.aidl @@ -16,4 +16,4 @@ package android.content; -parcelable ClippedData; +parcelable ClipData; diff --git a/core/java/android/content/ClippedData.java b/core/java/android/content/ClipData.java index c3f0237eb36d..0c0c0ec1177c 100644 --- a/core/java/android/content/ClippedData.java +++ b/core/java/android/content/ClipData.java @@ -37,6 +37,14 @@ import java.util.ArrayList; * each of which can hold one or more representations of an item of data. * For display to the user, it also has a label and iconic representation.</p> * + * <p>A ClipData is a sub-class of {@link ClipDescription}, which describes + * important meta-data about the clip. In particular, its {@link #getMimeType(int)} + * must return correct MIME type(s) describing the data in the clip. For help + * in correctly constructing a clip with the correct MIME type, use + * {@link #newPlainText(CharSequence, Bitmap, CharSequence)}, + * {@link #newUri(ContentResolver, CharSequence, Bitmap, Uri)}, and + * {@link #newIntent(CharSequence, Bitmap, Intent)}. + * * <p>Each Item instance can be one of three main classes of data: a simple * CharSequence of text, a single Intent object, or a Uri. See {@link Item} * for more details. @@ -53,11 +61,16 @@ import java.util.ArrayList; * * <p>If all you want is the textual representation of the clipped data, you * can use the convenience method {@link Item#coerceToText Item.coerceToText}. + * In this case there is generally no need to worry about the MIME types + * reported by {@link #getMimeType(int)}, since any clip item an always be + * converted to a string. * * <p>More complicated exchanges will be done through URIs, in particular * "content:" URIs. A content URI allows the recipient of a ClippedData item * to interact closely with the ContentProvider holding the data in order to - * negotiate the transfer of that data. + * negotiate the transfer of that data. The clip must also be filled in with + * the available MIME types; {@link #newUri(ContentResolver, CharSequence, Bitmap, Uri)} + * will take care of correctly doing this. * * <p>For example, here is the paste function of a simple NotePad application. * When retrieving the data from the clipboard, it can do either two things: @@ -120,9 +133,12 @@ import java.util.ArrayList; * into an editor), then {@link Item#coerceToText(Context)} will ask the content * provider for the clip URI as text and successfully paste the entire note. */ -public class ClippedData implements Parcelable { - CharSequence mLabel; - Bitmap mIcon; +public class ClipData extends ClipDescription { + static final String[] MIMETYPES_TEXT_PLAIN = new String[] { MIMETYPE_TEXT_PLAIN }; + static final String[] MIMETYPES_TEXT_URILIST = new String[] { MIMETYPE_TEXT_URILIST }; + static final String[] MIMETYPES_TEXT_INTENT = new String[] { MIMETYPE_TEXT_INTENT }; + + final Bitmap mIcon; final ArrayList<Item> mItems = new ArrayList<Item>(); @@ -146,28 +162,34 @@ public class ClippedData implements Parcelable { * </ul> */ public static class Item { - CharSequence mText; - Intent mIntent; - Uri mUri; + final CharSequence mText; + final Intent mIntent; + final Uri mUri; /** * Create an Item consisting of a single block of (possibly styled) text. */ public Item(CharSequence text) { mText = text; + mIntent = null; + mUri = null; } /** * Create an Item consisting of an arbitrary Intent. */ public Item(Intent intent) { + mText = null; mIntent = intent; + mUri = null; } /** * Create an Item consisting of an arbitrary URI. */ public Item(Uri uri) { + mText = null; + mIntent = null; mUri = uri; } @@ -292,19 +314,103 @@ public class ClippedData implements Parcelable { * Create a new clip. * * @param label Label to show to the user describing this clip. + * @param mimeTypes An array of MIME types this data is available as. * @param icon Bitmap providing the user with an iconing representation of * the clip. * @param item The contents of the first item in the clip. */ - public ClippedData(CharSequence label, Bitmap icon, Item item) { + public ClipData(CharSequence label, String[] mimeTypes, Bitmap icon, Item item) { + super(label, mimeTypes); if (item == null) { throw new NullPointerException("item is null"); } - mLabel = label; mIcon = icon; mItems.add(item); } + /** + * Create a new ClipData holding data of the type {@link #MIMETYPE_TEXT_PLAIN}. + * + * @param label User-visible label for the clip data. + * @param icon Iconic representation of the clip data. + * @param text The actual text in the clip. + * @return Returns a new ClipData containing the specified data. + */ + static public ClipData newPlainText(CharSequence label, Bitmap icon, CharSequence text) { + Item item = new Item(text); + return new ClipData(label, MIMETYPES_TEXT_PLAIN, icon, item); + } + + /** + * Create a new ClipData holding an Intent with MIME type {@link #MIMETYPE_TEXT_INTENT}. + * + * @param label User-visible label for the clip data. + * @param icon Iconic representation of the clip data. + * @param intent The actual Intent in the clip. + * @return Returns a new ClipData containing the specified data. + */ + static public ClipData newIntent(CharSequence label, Bitmap icon, Intent intent) { + Item item = new Item(intent); + return new ClipData(label, MIMETYPES_TEXT_INTENT, icon, item); + } + + /** + * Create a new ClipData holding a URI. If the URI is a content: URI, + * this will query the content provider for the MIME type of its data and + * use that as the MIME type. Otherwise, it will use the MIME type + * {@link #MIMETYPE_TEXT_URILIST}. + * + * @param resolver ContentResolver used to get information about the URI. + * @param label User-visible label for the clip data. + * @param icon Iconic representation of the clip data. + * @param uri The URI in the clip. + * @return Returns a new ClipData containing the specified data. + */ + static public ClipData newUri(ContentResolver resolver, CharSequence label, + Bitmap icon, Uri uri) { + Item item = new Item(uri); + String[] mimeTypes = null; + if ("content".equals(uri.getScheme())) { + String realType = resolver.getType(uri); + mimeTypes = resolver.getStreamTypes(uri, "*/*"); + if (mimeTypes == null) { + if (realType != null) { + mimeTypes = new String[] { realType, MIMETYPE_TEXT_URILIST }; + } + } else { + String[] tmp = new String[mimeTypes.length + (realType != null ? 2 : 1)]; + int i = 0; + if (realType != null) { + tmp[0] = realType; + i++; + } + System.arraycopy(mimeTypes, 0, tmp, i, mimeTypes.length); + tmp[i + mimeTypes.length] = MIMETYPE_TEXT_URILIST; + mimeTypes = tmp; + } + } + if (mimeTypes == null) { + mimeTypes = MIMETYPES_TEXT_URILIST; + } + return new ClipData(label, mimeTypes, icon, item); + } + + /** + * Create a new ClipData holding an URI with MIME type {@link #MIMETYPE_TEXT_URILIST}. + * Unlike {@link #newUri(ContentResolver, CharSequence, Bitmap, Uri)}, nothing + * is inferred about the URI -- if it is a content: URI holding a bitmap, + * the reported type will still be uri-list. Use this with care! + * + * @param label User-visible label for the clip data. + * @param icon Iconic representation of the clip data. + * @param uri The URI in the clip. + * @return Returns a new ClipData containing the specified data. + */ + static public ClipData newRawUri(CharSequence label, Bitmap icon, Uri uri) { + Item item = new Item(uri); + return new ClipData(label, MIMETYPES_TEXT_URILIST, icon, item); + } + public void addItem(Item item) { if (item == null) { throw new NullPointerException("item is null"); @@ -312,10 +418,6 @@ public class ClippedData implements Parcelable { mItems.add(item); } - public CharSequence getLabel() { - return mLabel; - } - public Bitmap getIcon() { return mIcon; } @@ -335,7 +437,7 @@ public class ClippedData implements Parcelable { @Override public void writeToParcel(Parcel dest, int flags) { - TextUtils.writeToParcel(mLabel, dest, flags); + super.writeToParcel(dest, flags); if (mIcon != null) { dest.writeInt(1); mIcon.writeToParcel(dest, flags); @@ -362,10 +464,12 @@ public class ClippedData implements Parcelable { } } - ClippedData(Parcel in) { - mLabel = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); + ClipData(Parcel in) { + super(in); if (in.readInt() != 0) { mIcon = Bitmap.CREATOR.createFromParcel(in); + } else { + mIcon = null; } final int N = in.readInt(); for (int i=0; i<N; i++) { @@ -376,15 +480,15 @@ public class ClippedData implements Parcelable { } } - public static final Parcelable.Creator<ClippedData> CREATOR = - new Parcelable.Creator<ClippedData>() { + public static final Parcelable.Creator<ClipData> CREATOR = + new Parcelable.Creator<ClipData>() { - public ClippedData createFromParcel(Parcel source) { - return new ClippedData(source); + public ClipData createFromParcel(Parcel source) { + return new ClipData(source); } - public ClippedData[] newArray(int size) { - return new ClippedData[size]; + public ClipData[] newArray(int size) { + return new ClipData[size]; } }; } diff --git a/core/java/android/content/ClipDescription.aidl b/core/java/android/content/ClipDescription.aidl new file mode 100644 index 000000000000..391fd5a086d6 --- /dev/null +++ b/core/java/android/content/ClipDescription.aidl @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2010, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content; + +parcelable ClipDescription; diff --git a/core/java/android/content/ClipDescription.java b/core/java/android/content/ClipDescription.java new file mode 100644 index 000000000000..3229f0f9a211 --- /dev/null +++ b/core/java/android/content/ClipDescription.java @@ -0,0 +1,206 @@ +/** + * Copyright (c) 2010, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content; + +import android.os.Parcel; +import android.os.Parcelable; +import android.text.TextUtils; + +import java.util.ArrayList; + +/** + * Meta-data describing the contents of a {@link #ClipData}. Provides enough + * information to know if you can handle the ClipData, but not the data + * itself. + */ +public class ClipDescription implements Parcelable { + /** + * The MIME type for a clip holding plain text. + */ + public static final String MIMETYPE_TEXT_PLAIN = "text/plain"; + + /** + * 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). + * It should <em>not</em> be used for a content: URI that references some + * other piece of data; in that case the MIME type should be the type + * of the referenced data. + */ + public static final String MIMETYPE_TEXT_URILIST = "text/uri-list"; + + /** + * The MIME type for a clip holding an Intent. + */ + public static final String MIMETYPE_TEXT_INTENT = "text/vnd.android.intent"; + + final CharSequence mLabel; + final String[] mMimeTypes; + + /** + * Create a new clip. + * + * @param label Label to show to the user describing this clip. + * @param mimeTypes An array of MIME types this data is available as. + */ + public ClipDescription(CharSequence label, String[] mimeTypes) { + if (mimeTypes == null) { + throw new NullPointerException("mimeTypes is null"); + } + mLabel = label; + mMimeTypes = mimeTypes; + } + + /** + * Create a copy of a ClipDescription. + */ + public ClipDescription(ClipDescription o) { + mLabel = o.mLabel; + mMimeTypes = o.mMimeTypes; + } + + /** + * Helper to compare two MIME types, where one may be a pattern. + * @param concreteType A fully-specified MIME type. + * @param desiredType A desired MIME type that may be a pattern such as *\/*. + * @return Returns true if the two MIME types match. + */ + public static boolean compareMimeTypes(String concreteType, String desiredType) { + final int typeLength = desiredType.length(); + if (typeLength == 3 && desiredType.equals("*/*")) { + return true; + } + + final int slashpos = desiredType.indexOf('/'); + if (slashpos > 0) { + if (typeLength == slashpos+2 && desiredType.charAt(slashpos+1) == '*') { + if (desiredType.regionMatches(0, concreteType, 0, slashpos+1)) { + return true; + } + } else if (desiredType.equals(concreteType)) { + return true; + } + } + + return false; + } + + /** + * Return the label for this clip. + */ + public CharSequence getLabel() { + return mLabel; + } + + /** + * Check whether the clip description contains the given MIME type. + * + * @param mimeType The desired MIME type. May be a pattern. + * @return Returns true if one of the MIME types in the clip description + * matches the desired MIME type, else false. + */ + public boolean hasMimeType(String mimeType) { + for (int i=0; i<mMimeTypes.length; i++) { + if (compareMimeTypes(mMimeTypes[i], mimeType)) { + return true; + } + } + return false; + } + + /** + * Filter the clip description MIME types by the given MIME type. Returns + * all MIME types in the clip that match the given MIME type. + * + * @param mimeType The desired MIME type. May be a pattern. + * @return Returns an array of all matching MIME types. If there are no + * matching MIME types, null is returned. + */ + public String[] filterMimeTypes(String mimeType) { + ArrayList<String> array = null; + for (int i=0; i<mMimeTypes.length; i++) { + if (compareMimeTypes(mMimeTypes[i], mimeType)) { + if (array == null) { + array = new ArrayList<String>(); + } + array.add(mMimeTypes[i]); + } + } + if (array == null) { + return null; + } + String[] rawArray = new String[array.size()]; + array.toArray(rawArray); + return rawArray; + } + + /** + * Return the number of MIME types the clip is available in. + */ + public int getMimeTypeCount() { + return mMimeTypes.length; + } + + /** + * Return one of the possible clip MIME types. + */ + public String getMimeType(int index) { + return mMimeTypes[index]; + } + + /** @hide */ + public void validate() { + if (mMimeTypes == null) { + throw new NullPointerException("null mime types"); + } + if (mMimeTypes.length <= 0) { + throw new IllegalArgumentException("must have at least 1 mime type"); + } + for (int i=0; i<mMimeTypes.length; i++) { + if (mMimeTypes[i] == null) { + throw new NullPointerException("mime type at " + i + " is null"); + } + } + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + TextUtils.writeToParcel(mLabel, dest, flags); + dest.writeStringArray(mMimeTypes); + } + + ClipDescription(Parcel in) { + mLabel = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); + mMimeTypes = in.createStringArray(); + } + + public static final Parcelable.Creator<ClipDescription> CREATOR = + new Parcelable.Creator<ClipDescription>() { + + public ClipDescription createFromParcel(Parcel source) { + return new ClipDescription(source); + } + + public ClipDescription[] newArray(int size) { + return new ClipDescription[size]; + } + }; +} diff --git a/core/java/android/content/ClipboardManager.java b/core/java/android/content/ClipboardManager.java index d685cf37dde5..0ea06482dbe4 100644 --- a/core/java/android/content/ClipboardManager.java +++ b/core/java/android/content/ClipboardManager.java @@ -37,7 +37,7 @@ import java.util.ArrayList; * <p> * The ClipboardManager API itself is very simple: it consists of methods * to atomically get and set the current primary clipboard data. That data - * is expressed as a {@link ClippedData} object, which defines the protocol + * is expressed as a {@link ClipData} object, which defines the protocol * for data exchange between applications. * * @see android.content.Context#getSystemService @@ -96,7 +96,7 @@ public class ClipboardManager extends android.text.ClipboardManager { * * @param clip The clipped data item to set. */ - public void setPrimaryClip(ClippedData clip) { + public void setPrimaryClip(ClipData clip) { try { getService().setPrimaryClip(clip); } catch (RemoteException e) { @@ -106,7 +106,7 @@ public class ClipboardManager extends android.text.ClipboardManager { /** * Returns the current primary clip on the clipboard. */ - public ClippedData getPrimaryClip() { + public ClipData getPrimaryClip() { try { return getService().getPrimaryClip(); } catch (RemoteException e) { @@ -115,6 +115,18 @@ public class ClipboardManager extends android.text.ClipboardManager { } /** + * Returns a description of the current primary clip on the clipboard + * but not a copy of its data. + */ + public ClipDescription getPrimaryClipDescription() { + try { + return getService().getPrimaryClipDescription(); + } catch (RemoteException e) { + return null; + } + } + + /** * Returns true if there is currently a primary clip on the clipboard. */ public boolean hasPrimaryClip() { @@ -156,7 +168,7 @@ public class ClipboardManager extends android.text.ClipboardManager { * the primary clip and tries to coerce it to a string. */ public CharSequence getText() { - ClippedData clip = getPrimaryClip(); + ClipData clip = getPrimaryClip(); if (clip != null && clip.getItemCount() > 0) { return clip.getItem(0).coerceToText(mContext); } @@ -164,12 +176,12 @@ public class ClipboardManager extends android.text.ClipboardManager { } /** - * @deprecated Use {@link #setPrimaryClip(ClippedData)} instead. This + * @deprecated Use {@link #setPrimaryClip(ClipData)} instead. This * creates a ClippedItem holding the given text and sets it as the * primary clip. It has no label or icon. */ public void setText(CharSequence text) { - setPrimaryClip(new ClippedData(null, null, new ClippedData.Item(text))); + setPrimaryClip(ClipData.newPlainText(null, null, text)); } /** diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java index 88e012397083..d3c1b4e567e9 100644 --- a/core/java/android/content/ContentProvider.java +++ b/core/java/android/content/ContentProvider.java @@ -767,32 +767,6 @@ public abstract class ContentProvider implements ComponentCallbacks { } /** - * Helper to compare two MIME types, where one may be a pattern. - * @param concreteType A fully-specified MIME type. - * @param desiredType A desired MIME type that may be a pattern such as *\/*. - * @return Returns true if the two MIME types match. - */ - public static boolean compareMimeTypes(String concreteType, String desiredType) { - final int typeLength = desiredType.length(); - if (typeLength == 3 && desiredType.equals("*/*")) { - return true; - } - - final int slashpos = desiredType.indexOf('/'); - if (slashpos > 0) { - if (typeLength == slashpos+2 && desiredType.charAt(slashpos+1) == '*') { - if (desiredType.regionMatches(0, concreteType, 0, slashpos+1)) { - return true; - } - } else if (desiredType.equals(concreteType)) { - return true; - } - } - - return false; - } - - /** * Called by a client to determine the types of data streams that this * content provider supports for the given URI. The default implementation * returns null, meaning no types. If your content provider stores data @@ -809,7 +783,7 @@ public abstract class ContentProvider implements ComponentCallbacks { * * @see #getType(Uri) * @see #openTypedAssetFile(Uri, String, Bundle) - * @see #compareMimeTypes(String, String) + * @see ClipDescription#compareMimeTypes(String, String) */ public String[] getStreamTypes(Uri uri, String mimeTypeFilter) { return null; @@ -825,7 +799,7 @@ public abstract class ContentProvider implements ComponentCallbacks { * result of {@link #getType(Uri)} and, if the match, simple calls * {@link #openAssetFile(Uri, String)}. * - * <p>See {@link ClippedData} for examples of the use and implementation + * <p>See {@link ClipData} for examples of the use and implementation * of this method. * * @param uri The data in the content provider being queried. @@ -848,7 +822,7 @@ public abstract class ContentProvider implements ComponentCallbacks { * * @see #getStreamTypes(Uri, String) * @see #openAssetFile(Uri, String) - * @see #compareMimeTypes(String, String) + * @see ClipDescription#compareMimeTypes(String, String) */ public AssetFileDescriptor openTypedAssetFile(Uri uri, String mimeTypeFilter, Bundle opts) throws FileNotFoundException { @@ -857,7 +831,7 @@ public abstract class ContentProvider implements ComponentCallbacks { return openAssetFile(uri, "r"); } String baseType = getType(uri); - if (baseType != null && compareMimeTypes(baseType, mimeTypeFilter)) { + if (baseType != null && ClipDescription.compareMimeTypes(baseType, mimeTypeFilter)) { // Use old untyped open call if this provider has a type for this // URI and it matches the request. return openAssetFile(uri, "r"); diff --git a/core/java/android/content/IClipboard.aidl b/core/java/android/content/IClipboard.aidl index b4534a94b676..3e1fe55f8b95 100644 --- a/core/java/android/content/IClipboard.aidl +++ b/core/java/android/content/IClipboard.aidl @@ -16,7 +16,8 @@ package android.content; -import android.content.ClippedData; +import android.content.ClipData; +import android.content.ClipDescription; import android.content.IOnPrimaryClipChangedListener; /** @@ -25,8 +26,9 @@ import android.content.IOnPrimaryClipChangedListener; * {@hide} */ interface IClipboard { - void setPrimaryClip(in ClippedData clip); - ClippedData getPrimaryClip(); + void setPrimaryClip(in ClipData clip); + ClipData getPrimaryClip(); + ClipDescription getPrimaryClipDescription(); boolean hasPrimaryClip(); void addPrimaryClipChangedListener(in IOnPrimaryClipChangedListener listener); void removePrimaryClipChangedListener(in IOnPrimaryClipChangedListener listener); diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 6db5b9c2ff1b..961c7821894c 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -22,7 +22,7 @@ import com.android.internal.widget.EditableInputConnection; import org.xmlpull.v1.XmlPullParserException; import android.content.ClipboardManager; -import android.content.ClippedData; +import android.content.ClipData; import android.content.Context; import android.content.pm.PackageManager; import android.content.res.ColorStateList; @@ -7330,17 +7330,18 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener URLSpan[] urls = ((Spanned) mText).getSpans(min, max, URLSpan.class); if (urls.length >= 1) { - ClippedData clip = null; + ClipData clip = null; for (int i=0; i<urls.length; i++) { Uri uri = Uri.parse(urls[0].getURL()); - ClippedData.Item item = new ClippedData.Item(uri); if (clip == null) { - clip = new ClippedData(null, null, item); + clip = ClipData.newRawUri(null, null, uri); } else { - clip.addItem(item); + clip.addItem(new ClipData.Item(uri)); } } - clipboard.setPrimaryClip(clip); + if (clip != null) { + clipboard.setPrimaryClip(clip); + } } return true; @@ -7536,7 +7537,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener switch (item.getItemId()) { case ID_PASTE: - ClippedData clip = clipboard.getPrimaryClip(); + ClipData clip = clipboard.getPrimaryClip(); if (clip != null) { boolean didfirst = false; for (int i=0; i<clip.getItemCount(); i++) { @@ -7557,15 +7558,15 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return true; case ID_CUT: - clipboard.setPrimaryClip(new ClippedData(null, null, - new ClippedData.Item(mTransformed.subSequence(min, max)))); + clipboard.setPrimaryClip(ClipData.newPlainText(null, null, + mTransformed.subSequence(min, max))); ((Editable) mText).delete(min, max); stopSelectionActionMode(); return true; case ID_COPY: - clipboard.setPrimaryClip(new ClippedData(null, null, - new ClippedData.Item(mTransformed.subSequence(min, max)))); + clipboard.setPrimaryClip(ClipData.newPlainText(null, null, + mTransformed.subSequence(min, max))); stopSelectionActionMode(); return true; } diff --git a/services/java/com/android/server/ClipboardService.java b/services/java/com/android/server/ClipboardService.java index 4e4fc0cbeb58..308c9c0c8c23 100644 --- a/services/java/com/android/server/ClipboardService.java +++ b/services/java/com/android/server/ClipboardService.java @@ -16,7 +16,8 @@ package com.android.server; -import android.content.ClippedData; +import android.content.ClipData; +import android.content.ClipDescription; import android.content.IClipboard; import android.content.IOnPrimaryClipChangedListener; import android.content.Context; @@ -27,7 +28,7 @@ import android.os.RemoteException; * Implementation of the clipboard for copy and paste. */ public class ClipboardService extends IClipboard.Stub { - private ClippedData mPrimaryClip; + private ClipData mPrimaryClip; private final RemoteCallbackList<IOnPrimaryClipChangedListener> mPrimaryClipListeners = new RemoteCallbackList<IOnPrimaryClipChangedListener>(); @@ -36,7 +37,7 @@ public class ClipboardService extends IClipboard.Stub { */ public ClipboardService(Context context) { } - public void setPrimaryClip(ClippedData clip) { + public void setPrimaryClip(ClipData clip) { synchronized (this) { if (clip != null && clip.getItemCount() <= 0) { throw new IllegalArgumentException("No items"); @@ -56,12 +57,18 @@ public class ClipboardService extends IClipboard.Stub { } } - public ClippedData getPrimaryClip() { + public ClipData getPrimaryClip() { synchronized (this) { return mPrimaryClip; } } + public ClipDescription getPrimaryClipDescription() { + synchronized (this) { + return new ClipDescription(mPrimaryClip); + } + } + public boolean hasPrimaryClip() { synchronized (this) { return mPrimaryClip != null; |