summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Dianne Hackborn <hackbod@google.com> 2010-08-26 22:11:06 -0700
committer Dianne Hackborn <hackbod@google.com> 2010-08-27 11:06:01 -0700
commit1040dc465cbf5ca8f834a87c949e476abefa3f76 (patch)
tree98841629e182d19c19bc68835d7a4b2e426b883a
parent59024f1697e09ea50d4349e9813d0c101411292b (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.mk1
-rw-r--r--api/current.xml413
-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.aidl19
-rw-r--r--core/java/android/content/ClipDescription.java206
-rw-r--r--core/java/android/content/ClipboardManager.java24
-rw-r--r--core/java/android/content/ContentProvider.java34
-rw-r--r--core/java/android/content/IClipboard.aidl8
-rw-r--r--core/java/android/widget/TextView.java23
-rw-r--r--services/java/com/android/server/ClipboardService.java15
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="&quot;text/vnd.android.intent&quot;"
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="&quot;text/plain&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="MIMETYPE_TEXT_URILIST"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;text/uri-list&quot;"
+ 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;