blob: 8f898e445cb78c2d1cae452a533d635fca178309 [file] [log] [blame]
page.title=Copy and Paste
page.tags=clipboardmanager,clipdata,input
@jd:body
<div id="qv-wrapper">
<div id="qv">
<h2>Quickview</h2>
<ul>
<li>
A clipboard-based framework for copying and pasting data.
</li>
<li>
Supports both simple and complex data, including text strings, complex data
structures, text and binary stream data, and application assets.
</li>
<li>
Copies and pastes simple text directly to and from the clipboard.
</li>
<li>
Copies and pastes complex data using a content provider.
</li>
<li>
Requires API 11.
</li>
</ul>
<h2>In this document</h2>
<ol>
<li>
<a href="#Clipboard">The Clipboard Framework</a>
</li>
<li>
<a href="#ClipboardClasses">Clipboard Classes</a>
<ol>
<li>
<a href="#ClipboardManager">ClipboardManager</a>
</li>
<li>
<a href="#ClipClasses">
ClipData, ClipDescription, and ClipData.Item
</a>
</li>
<li>
<a href="#ClipDataMethods">ClipData convenience methods</a>
</li>
<li>
<a href="#CoerceToText">Coercing the clipboard data to text</a>
</li>
</ol>
</li>
<li>
<a href="#Copying">Copying to the Clipboard</a>
</li>
<li>
<a href="#Pasting">Pasting from the Clipboard</a>
<ol>
<li>
<a href="#PastePlainText">Pasting plain text</a>
</li>
<li>
<a href="#PasteContentUri">Pasting data from a content URI</a>
</li>
<li>
<a href="#PasteIntent">Pasting an Intent</a>
</li>
</ol>
</li>
<li>
<a href="#Provider">Using Content Providers to Copy Complex Data</a>
<ol>
<li>
<a href="#Encoding">Encoding an identifier on the URI</a>
</li>
<li>
<a href="#Records">Copying data structures</a>
</li>
<li>
<a href="#Streams">Copying data streams</a>
</li>
</ol>
</li>
<li>
<a href="#DataDesign">Designing Effective Copy/Paste Functionality</a>
</li>
</ol>
<h2>Key classes</h2>
<ol>
<li>
{@link android.content.ClipboardManager ClipboardManager}
</li>
<li>
{@link android.content.ClipData ClipData}
</li>
<li>
{@link android.content.ClipData.Item ClipData.Item}
</li>
<li>
{@link android.content.ClipDescription ClipDescription}
</li>
<li>
{@link android.net.Uri Uri}
</li>
<li>
{@link android.content.ContentProvider}
</li>
<li>
{@link android.content.Intent Intent}
</li>
</ol>
<h2>Related Samples</h2>
<ol>
<li>
<a href="{@docRoot}resources/samples/NotePad/index.html">
Note Pad sample application</a>
</li>
</ol>
<h2>See also</h2>
<ol>
<li>
<a href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a>
</li>
</ol>
</div>
</div>
<p>
Android provides a powerful clipboard-based framework for copying and pasting. It
supports both simple and complex data types, including text strings, complex data
structures, text and binary stream data, and even application assets. Simple text data is stored
directly in the clipboard, while complex data is stored as a reference that the pasting
application resolves with a content provider. Copying and pasting works both within an
application and between applications that implement the framework.
</p>
<p>
Since a part of the framework uses content providers, this topic assumes some
familiarity with the Android Content Provider API, which is described in the topic
<a href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a>.
</p>
<h2 id="Clipboard">The Clipboard Framework</h2>
<p>
When you use the clipboard framework, you put data into a clip object, and then
put the clip object on the system-wide clipboard. The clip object can take one of three forms:
</p>
<dl>
<dt>Text</dt>
<dd>
A text string. You put the string directly into the clip object, which you then put onto
the clipboard. To paste the string, you get the clip object from the clipboard and copy
the string to into your application's storage.
</dd>
<dt>URI</dt>
<dd>
A {@link android.net.Uri} object representing any form of URI. This is primarily for
copying complex data from a content provider. To copy data, you put a
{@link android.net.Uri} object into a clip object and put the clip object onto
the clipboard. To paste the data, you get the clip object, get the
{@link android.net.Uri} object, resolve it to a data source such as a content provider,
and copy the data from the source into your application's storage.
</dd>
<dt>Intent</dt>
<dd>
An {@link android.content.Intent}. This supports copying application shortcuts. To copy
data, you create an Intent, put it into a clip object, and put the clip object onto the
clipboard. To paste the data, you get the clip object and then copy the Intent object
into your application's memory area.
</dd>
</dl>
<p>
The clipboard holds only one clip object at a time. When an application puts a clip object on
the clipboard, the previous clip object disappears.
</p>
<p>
If you want to allow users to paste data into your application, you don't have to handle all
types of data. You can examine the data on the clipboard before you give users the option to
paste it. Besides having a certain data form, the clip object also contains metadata that tells
you what MIME type or types are available. This metadata helps you decide if your application
can do something useful with the clipboard data. For example, if you have an application that
primarily handles text you may want to ignore clip objects that contain a URI or Intent.
</p>
<p>
You may also want to allow users to paste text regardless of the form of data on the
clipboard. To do this, you can force the clipboard data into a text representation, and then
paste this text. This is described in the section <a href="#CoerceToText">Coercing the
clipboard to text</a>.
</p>
<h2 id="ClipboardClasses">Clipboard Classes</h2>
<p>
This section describes the classes used by the clipboard framework.
</p>
<h3 id="ClipboardManager">ClipboardManager</h3>
<p>
In the Android system, the system clipboard is represented by the global
{@link android.content.ClipboardManager} class. You do not instantiate this
class directly; instead, you get a reference to it by invoking
{@link android.content.Context#getSystemService(String) getSystemService(CLIPBOARD_SERVICE)}.
</p>
<h3 id="ClipClasses">ClipData, ClipData.Item, and ClipDescription</h3>
<p>
To add data to the clipboard, you create a {@link android.content.ClipData} object that
contains both a description of the data and the data itself. The clipboard holds only one
{@link android.content.ClipData} at a time. A {@link android.content.ClipData} contains a
{@link android.content.ClipDescription} object and one or more
{@link android.content.ClipData.Item} objects.
</p>
<p>
A {@link android.content.ClipDescription} object contains metadata about the clip. In
particular, it contains an array of available MIME types for the clip's data. When you put a
clip on the clipboard, this array is available to pasting applications, which can examine it to
see if they can handle any of available the MIME types.
</p>
<p>
A {@link android.content.ClipData.Item} object contains the text, URI, or Intent data:
</p>
<dl>
<dt>Text</dt>
<dd>
A {@link java.lang.CharSequence}.
</dd>
<dt>URI</dt>
<dd>
A {@link android.net.Uri}. This usually contains a content provider URI, although any
URI is allowed. The application that provides the data puts the URI on the clipboard.
Applications that want to paste the data get the URI from the clipboard and use it to
access the content provider (or other data source) and retrieve the data.
</dd>
<dt>Intent</dt>
<dd>
An {@link android.content.Intent}. This data type allows you to copy an application shortcut
to the clipboard. Users can then paste the shortcut into their applications for later use.
</dd>
</dl>
<p>
You can add more than one {@link android.content.ClipData.Item} object to a clip. This allows
users to copy and paste multiple selections as a single clip. For example, if you have a list
widget that allows the user to select more than one item at a time, you can copy all the items
to the clipboard at once. To do this, you create a separate
{@link android.content.ClipData.Item} for each list item, and then you add the
{@link android.content.ClipData.Item} objects to the {@link android.content.ClipData} object.
</p>
<h3 id="ClipDataMethods">ClipData convenience methods</h3>
<p>
The {@link android.content.ClipData} class provides static convenience methods for creating
a {@link android.content.ClipData} object with a single {@link android.content.ClipData.Item}
object and a simple {@link android.content.ClipDescription} object:
</p>
<dl>
<dt>
{@link android.content.ClipData#newPlainText(CharSequence,CharSequence) newPlainText(label, text)}
</dt>
<dd>
Returns a {@link android.content.ClipData} object whose single
{@link android.content.ClipData.Item} object contains a text string. The
{@link android.content.ClipDescription} object's label is set to <code>label</code>.
The single MIME type in {@link android.content.ClipDescription} is
{@link android.content.ClipDescription#MIMETYPE_TEXT_PLAIN}.
<p>
Use
{@link android.content.ClipData#newPlainText(CharSequence,CharSequence) newPlainText()}
to create a clip from a text string.
</dd>
<dt>
{@link android.content.ClipData#newUri(ContentResolver, CharSequence, Uri) newUri(resolver, label, URI)}
</dt>
<dd>
Returns a {@link android.content.ClipData} object whose single
{@link android.content.ClipData.Item} object contains a URI. The
{@link android.content.ClipDescription} object's label is set to <code>label</code>.
If the URI is a content URI ({@link android.net.Uri#getScheme() Uri.getScheme()} returns
<code>content:</code>), the method uses the {@link android.content.ContentResolver} object
provided in <code>resolver</code> to retrieve the available MIME types from the
content provider and store them in {@link android.content.ClipDescription}. For a URI that
is not a <code>content:</code> URI, the method sets the MIME type to
{@link android.content.ClipDescription#MIMETYPE_TEXT_URILIST}.
<p>
Use
{@link android.content.ClipData#newUri(ContentResolver, CharSequence, Uri) newUri()}
to create a clip from a URI, particularly a <code>content:</code> URI.
</p>
</dd>
<dt>
{@link android.content.ClipData#newIntent(CharSequence, Intent) newIntent(label, intent)}
</dt>
<dd>
Returns a {@link android.content.ClipData} object whose single
{@link android.content.ClipData.Item} object contains an {@link android.content.Intent}.
The {@link android.content.ClipDescription} object's label is set to <code>label</code>.
The MIME type is set to {@link android.content.ClipDescription#MIMETYPE_TEXT_INTENT}.
<p>
Use
{@link android.content.ClipData#newIntent(CharSequence, Intent) newIntent()}
to create a clip from an Intent object.
</dd>
</dl>
<h3 id="CoerceToText">Coercing the clipboard data to text</h3>
<p>
Even if your application only handles text, you can copy non-text data from the
clipboard by converting it with the method
{@link android.content.ClipData.Item#coerceToText(Context) ClipData.Item.coerceToText()}.
</p>
<p>
This method converts the data in {@link android.content.ClipData.Item} to text and
returns a {@link java.lang.CharSequence}. The value that
{@link android.content.ClipData.Item#coerceToText(Context) ClipData.Item.coerceToText()}
returns is based on the form of data in {@link android.content.ClipData.Item}:
</p>
<dl>
<dt><em>Text</em></dt>
<dd>
If {@link android.content.ClipData.Item} is text
({@link android.content.ClipData.Item#getText()} is not null),
{@link android.content.ClipData.Item#coerceToText(Context) coerceToText()} returns the
text.
</dd>
<dt><em>URI</em></dt>
<dd>
If {@link android.content.ClipData.Item} is a URI
({@link android.content.ClipData.Item#getUri()} is not null),
{@link android.content.ClipData.Item#coerceToText(Context) coerceToText()} tries to use
it as a content URI:
<ul>
<li>
If the URI is a content URI and the provider can return a text stream,
{@link android.content.ClipData.Item#coerceToText(Context) coerceToText()} returns
a text stream.
</li>
<li>
If the URI is a content URI but the provider does not offer a text stream,
{@link android.content.ClipData.Item#coerceToText(Context) coerceToText()} returns
a representation of the URI. The representation is the same as that returned by
{@link android.net.Uri#toString() Uri.toString()}.
</li>
<li>
If the URI is not a content URI,
{@link android.content.ClipData.Item#coerceToText(Context) coerceToText()} returns
a representation of the URI. The representation is the same as that returned by
{@link android.net.Uri#toString() Uri.toString()}.
</li>
</ul>
</dd>
<dt><em>Intent</em></dt>
<dd>
If {@link android.content.ClipData.Item} is an Intent
({@link android.content.ClipData.Item#getIntent()} is not null),
{@link android.content.ClipData.Item#coerceToText(Context) coerceToText()} converts it to
an Intent URI and returns it. The representation is the same as that returned by
{@link android.content.Intent#toUri(int) Intent.toUri(URI_INTENT_SCHEME)}.
</dd>
</dl>
<p>
The clipboard framework is summarized in Figure 1. To copy data, an application puts a
{@link android.content.ClipData} object on the {@link android.content.ClipboardManager} global
clipboard. The {@link android.content.ClipData} contains one or more
{@link android.content.ClipData.Item} objects and one
{@link android.content.ClipDescription} object. To paste data, an application gets the
{@link android.content.ClipData}, gets its MIME type from the
{@link android.content.ClipDescription}, and gets the data either from
the {@link android.content.ClipData.Item} or from the content provider referred to by
{@link android.content.ClipData.Item}.
</p>
<a name="framework"></a>
<img
src="{@docRoot}images/ui/clipboard/copy_paste_framework.png"
alt="A block diagram of the copy and paste framework" height="400px" id="figure1" />
<p class="img-caption">
<strong>Figure 1.</strong> The Android clipboard framework
</p>
<h2 id="Copying">Copying to the Clipboard</h2>
<p>
As described previously, to copy data to the clipboard you get a handle to the global
{@link android.content.ClipboardManager} object, create a {@link android.content.ClipData}
object, add a {@link android.content.ClipDescription} and one or more
{@link android.content.ClipData.Item} objects to it, and add the finished
{@link android.content.ClipData} object to the {@link android.content.ClipboardManager} object.
This is described in detail in the following procedure:
</p>
<ol>
<li>
If you are copying data using a content URI, set up a content
provider.
<p>
The <a href="{@docRoot}resources/samples/NotePad/index.html">
Note Pad</a> sample application is an example of using a content provider for
copying and pasting. The
<a href="{@docRoot}resources/samples/NotePad/src/com/example/android/notepad/NotePadProvider.html">
NotePadProvider</a> class implements the content provider. The
<a href="{@docRoot}resources/samples/NotePad/src/com/example/android/notepad/NotePad.html">
NotePad</a> class defines a contract between the provider and other applications,
including the supported MIME types.
</p>
</li>
<li>
Get the system clipboard:
<pre>
...
// if the user selects copy
case R.id.menu_copy:
// Gets a handle to the clipboard service.
ClipboardManager clipboard = (ClipboardManager)
getSystemService(Context.CLIPBOARD_SERVICE);
</pre>
</li>
<li>
<p>
Copy the data to a new {@link android.content.ClipData} object:
</p>
<ul>
<li>
<h4>For text</h4>
<pre>
// Creates a new text clip to put on the clipboard
ClipData clip = ClipData.newPlainText(&quot;simple text&quot;,&quot;Hello, World!&quot;);
</pre>
</li>
<li>
<h4>For a URI</h4>
<p>
This snippet constructs a URI by encoding a record ID onto the content URI
for the provider. This technique is covered in more detail
in the section <a href="#Encoding">Encoding an identifier on the URI</a>:
</p>
<pre>
// Creates a Uri based on a base Uri and a record ID based on the contact's last name
// Declares the base URI string
private static final String CONTACTS = &quot;content:&#47;&#47;com.example.contacts&quot;;
// Declares a path string for URIs that you use to copy data
private static final String COPY_PATH = &quot;/copy&quot;;
// Declares the Uri to paste to the clipboard
Uri copyUri = Uri.parse(CONTACTS + COPY_PATH + &quot;/&quot; + lastName);
...
// Creates a new URI clip object. The system uses the anonymous getContentResolver() object to
// get MIME types from provider. The clip object's label is &quot;URI&quot;, and its data is
// the Uri previously created.
ClipData clip = ClipData.newUri(getContentResolver(),&quot;URI&quot;,copyUri);
</pre>
</li>
<li>
<h4>For an Intent</h4>
<p>
This snippet constructs an Intent for an application
and then puts it in the clip object:
</p>
<pre>
// Creates the Intent
Intent appIntent = new Intent(this, com.example.demo.myapplication.class);
...
// Creates a clip object with the Intent in it. Its label is &quot;Intent&quot; and its data is
// the Intent object created previously
ClipData clip = ClipData.newIntent(&quot;Intent&quot;,appIntent);
</pre>
</li>
</ul>
</li>
<li>
Put the new clip object on the clipboard:
<pre>
// Set the clipboard's primary clip.
clipboard.setPrimaryClip(clip);
</pre>
</li>
</ol>
<h2 id="Pasting">Pasting from the Clipboard</h2>
<p>
As described previously, you paste data from the clipboard by getting the global clipboard
object, getting the clip object, looking at its data, and if possible copying the data from
the clip object to your own storage. This section describes in detail how to do this for
the three forms of clipboard data.
</p>
<h3 id="PastePlainText">Pasting plain text</h3>
<p>
To paste plain text, first get the global clipboard and verify that it can return plain text.
Then get the clip object and copy its text to your own storage using
{@link android.content.ClipData.Item#getText()}, as described in the following procedure:
</p>
<ol>
<li>
Get the global {@link android.content.ClipboardManager} object using
{@link android.content.Context#getSystemService(String) getSystemService(CLIPBOARD_SERVICE)}. Also
declare a global variable to contain the pasted text:
<pre>
ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
String pasteData = &quot;&quot;;
</pre>
</li>
<li>
Next, determine if you should enable or disable the &quot;paste&quot; option in the
current Activity. You should verify that the clipboard contains a clip and that you
can handle the type of data represented by the clip:
<pre>
// Gets the ID of the &quot;paste&quot; menu item
MenuItem mPasteItem = menu.findItem(R.id.menu_paste);
// If the clipboard doesn't contain data, disable the paste menu item.
// If it does contain data, decide if you can handle the data.
if (!(clipboard.hasPrimaryClip())) {
mPasteItem.setEnabled(false);
} else if (!(clipboard.getPrimaryClipDescription().hasMimeType(MIMETYPE_TEXT_PLAIN))) {
// This disables the paste menu item, since the clipboard has data but it is not plain text
mPasteItem.setEnabled(false);
} else {
// This enables the paste menu item, since the clipboard contains plain text.
mPasteItem.setEnabled(true);
}
}
</pre>
</li>
<li>
Copy the data from the clipboard. This point in the program is only reachable if the
&quot;paste&quot; menu item is enabled, so you can assume that the clipboard contains
plain text. You do not yet know if it contains a text string or a URI that points to plain
text. The following snippet tests this, but it only shows the code for handling plain text:
<pre>
// Responds to the user selecting &quot;paste&quot;
case R.id.menu_paste:
// Examines the item on the clipboard. If getText() does not return null, the clip item contains the
// text. Assumes that this application can only handle one item at a time.
ClipData.Item item = clipboard.getPrimaryClip().getItemAt(0);
// Gets the clipboard as text.
pasteData = item.getText();
// If the string contains data, then the paste operation is done
if (pasteData != null) {
return;
// The clipboard does not contain text. If it contains a URI, attempts to get data from it
} else {
Uri pasteUri = item.getUri();
// If the URI contains something, try to get text from it
if (pasteUri != null) {
// calls a routine to resolve the URI and get data from it. This routine is not
// presented here.
pasteData = resolveUri(Uri);
return;
} else {
// Something is wrong. The MIME type was plain text, but the clipboard does not contain either
// text or a Uri. Report an error.
Log.e(&quot;Clipboard contains an invalid data type&quot;);
return;
}
}
</pre>
</li>
</ol>
<h3 id="PasteContentUri">Pasting data from a content URI</h3>
<p>
If the {@link android.content.ClipData.Item} object contains a content URI and you
have determined that you can handle one of its MIME types, create a
{@link android.content.ContentResolver} and then call the appropriate content provider
method to retrieve the data.
</p>
<p>
The following procedure describes how to get data from a content provider based on a
content URI on the clipboard. It checks that a MIME type that the application can use
is available from the provider:
</p>
<ol>
<li>
Declare a global variable to contain the MIME type:
<pre>
// Declares a MIME type constant to match against the MIME types offered by the provider
public static final String MIME_TYPE_CONTACT = &quot;vnd.android.cursor.item/vnd.example.contact&quot;
</pre>
</li>
<li>
Get the global clipboard. Also get a content resolver so you can access the content
provider:
<pre>
// Gets a handle to the Clipboard Manager
ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
// Gets a content resolver instance
ContentResolver cr = getContentResolver();
</pre>
</li>
<li>
Get the primary clip from the clipboard, and get its contents as a URI:
<pre>
// Gets the clipboard data from the clipboard
ClipData clip = clipboard.getPrimaryClip();
if (clip != null) {
// Gets the first item from the clipboard data
ClipData.Item item = clip.getItemAt(0);
// Tries to get the item's contents as a URI
Uri pasteUri = item.getUri();
</pre>
</li>
<li>
Test to see if the URI is a content URI by calling
{@link android.content.ContentResolver#getType(Uri) getType(Uri)}. This method returns
null if <code>Uri</code> does not point to a valid content provider:
<pre>
// If the clipboard contains a URI reference
if (pasteUri != null) {
// Is this a content URI?
String uriMimeType = cr.getType(pasteUri);
</pre>
</li>
<li>
Test to see if the content provider supports a MIME type that the current application
understands. If it does, call
{@link android.content.ContentResolver#query(Uri, String[], String, String[], String)
ContentResolver.query()} to get the data. The return value is a
{@link android.database.Cursor}:
<pre>
// If the return value is not null, the Uri is a content Uri
if (uriMimeType != null) {
// Does the content provider offer a MIME type that the current application can use?
if (uriMimeType.equals(MIME_TYPE_CONTACT)) {
// Get the data from the content provider.
Cursor pasteCursor = cr.query(uri, null, null, null, null);
// If the Cursor contains data, move to the first record
if (pasteCursor != null) {
if (pasteCursor.moveToFirst()) {
// get the data from the Cursor here. The code will vary according to the
// format of the data model.
}
}
// close the Cursor
pasteCursor.close();
}
}
}
}
</pre>
</li>
</ol>
<h3 id="PasteIntent">Pasting an Intent</h3>
<p>
To paste an Intent, first get the global clipboard. Examine the
{@link android.content.ClipData.Item} object to see if it contains an Intent. Then call
{@link android.content.ClipData.Item#getIntent()} to copy the Intent to your own storage.
The following snippet demonstrates this:
</p>
<pre>
// Gets a handle to the Clipboard Manager
ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
// Checks to see if the clip item contains an Intent, by testing to see if getIntent() returns null
Intent pasteIntent = clipboard.getPrimaryClip().getItemAt(0).getIntent();
if (pasteIntent != null) {
// handle the Intent
} else {
// ignore the clipboard, or issue an error if your application was expecting an Intent to be
// on the clipboard
}
</pre>
<h2 id="Provider">Using Content Providers to Copy Complex Data</h2>
<p>
Content providers support copying complex data such as database records or file streams.
To copy the data, you put a content URI on the clipboard. Pasting applications then get this
URI from the clipboard and use it to retrieve database data or file stream descriptors.
</p>
<p>
Since the pasting application only has the content URI for your data, it needs to know which
piece of data to retrieve. You can provide this information by encoding an identifier for the
data on the URI itself, or you can provide a unique URI that will return the data you want to
copy. Which technique you choose depends on the organization of your data.
</p>
<p>
The following sections describe how to set up URIs, how to provide complex data, and how to
provide file streams. The descriptions assume that you are familiar with the general principles
of content provider design.
</p>
<h3 id="Encoding">Encoding an identifier on the URI</h3>
<p>
A useful technique for copying data to the clipboard with a URI is to encode an identifier for
the data on the URI itself. Your content provider can then get the identifier from the URI and
use it to retrieve the data. The pasting application doesn't have to know that the identifier
exists; all it has to do is get your &quot;reference&quot; (the URI plus the identifier) from
the clipboard, give it your content provider, and get back the data.
</p>
<p>
You usually encode an identifier onto a content URI by concatenating it to the end of the URI.
For example, suppose you define your provider URI as the following string:
</p>
<pre>
&quot;content://com.example.contacts&quot;
</pre>
<p>
If you want to encode a name onto this URI, you would use the following snippet:
</p>
<pre>
String uriString = &quot;content:&#47;&#47;com.example.contacts&quot; + &quot;/&quot; + &quot;Smith&quot;
// uriString now contains content://com.example.contacts/Smith.
// Generates a uri object from the string representation
Uri copyUri = Uri.parse(uriString);
</pre>
<p>
If you are already using a content provider, you may want to add a new URI path that indicates
the URI is for copying. For example, suppose you already have the following URI paths:
</p>
<pre>
&quot;content://com.example.contacts&quot;/people
&quot;content://com.example.contacts&quot;/people/detail
&quot;content://com.example.contacts&quot;/people/images
</pre>
<p>
You could add another path that is specific to copy URIs:
</p>
<pre>
&quot;content://com.example.contacts/copying&quot;
</pre>
<p>
You could then detect a &quot;copy&quot; URI by pattern-matching and handle it with code that
is specific for copying and pasting.
</p>
<p>
You normally use the encoding technique if you're already using a content provider, internal
database, or internal table to organize your data. In these cases, you have multiple pieces of
data you want to copy, and presumably a unique identifier for each piece. In response to a
query from the pasting application, you can look up the data by its identifier and return it.
</p>
<p>
If you don't have multiple pieces of data, then you probably don't need to encode an identifier.
You can simply use a URI that is unique to your provider. In response to a query, your provider
would return the data it currently contains.
</p>
<p>
Getting a single record by ID is used in the
<a href="{@docRoot}resources/samples/NotePad/index.html">Note Pad</a> sample application to
open a note from the notes list. The sample uses the <code>_id</code> field from an SQL
database, but you can have any numeric or character identifier you want.
</p>
<h3 id="Records">Copying data structures</h3>
<p>
You set up a content provider for copying and pasting complex data as a subclass of the
{@link android.content.ContentProvider} component. You should also encode the URI you put on
the clipboard so that it points to the exact record you want to provide. In addition, you
have to consider the existing state of your application:
</p>
<ul>
<li>
If you already have a content provider, you can add to its functionality. You may only
need to modify its
{@link android.content.ContentResolver#query(Uri, String[], String, String[], String) query()}
method to handle URIs coming from applications that want to paste data. You will
probably want to modify the method to handle a &quot;copy&quot; URI pattern.
</li>
<li>
If your application maintains an internal database, you may
want to move this database into a content provider to facilitate copying from it.
</li>
<li>
If you are not currently using a database, you can implement a simple content provider
whose sole purpose is to offer data to applications that are pasting from the
clipboard.
</li>
</ul>
<p>
In the content provider, you will want to override at least the following methods:
</p>
<dl>
<dt>
{@link android.content.ContentResolver#query(Uri, String[], String, String[], String) query()}
</dt>
<dd>
Pasting applications will assume that they can get your data by using this method with
the URI you put on the clipboard. To support copying, you should have this method
detect URIs that contain a special &quot;copy&quot; path. Your application can then
create a &quot;copy&quot; URI to put on the clipboard, containing the copy path and
a pointer to the exact record you want to copy.
</dd>
<dt>
{@link android.content.ContentProvider#getType(Uri) getType()}
</dt>
<dd>
This method should return the MIME type or types for the data you intend to copy. The method
{@link android.content.ClipData#newUri(ContentResolver, CharSequence, Uri) newUri()} calls
{@link android.content.ContentProvider#getType(Uri) getType()} in order to put the MIME
types into the new {@link android.content.ClipData} object.
<p>
MIME types for complex data are described in the topic
<a href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a>.
</p>
</dd>
</dl>
<p>
Notice that you don't have to have any of the other content provider methods such as
{@link android.content.ContentProvider#insert(Uri, ContentValues) insert()} or
{@link android.content.ContentProvider#update(Uri, ContentValues, String, String[]) update()}.
A pasting application only needs to get your supported MIME types and copy data from your
provider. If you already have these methods, they won't interfere with copy operations.
</p>
<p>
The following snippets demonsrate how to set up your application to copy complex data:
</p>
<ol>
<li>
<p>
In the global constants for your application,
declare a base URI string and a path that identifies URI strings you are
using to copy data. Also declare a MIME type for the copied data:
</p>
<pre>
// Declares the base URI string
private static final String CONTACTS = &quot;content:&#47;&#47;com.example.contacts&quot;;
// Declares a path string for URIs that you use to copy data
private static final String COPY_PATH = &quot;/copy&quot;;
// Declares a MIME type for the copied data
public static final String MIME_TYPE_CONTACT = &quot;vnd.android.cursor.item/vnd.example.contact&quot;
</pre>
</li>
<li>
In the Activity from which users copy data,
set up the code to copy data to the clipboard. In response to a copy request, put
the URI on the clipboard:
<pre>
public class MyCopyActivity extends Activity {
...
// The user has selected a name and is requesting a copy.
case R.id.menu_copy:
// Appends the last name to the base URI
// The name is stored in &quot;lastName&quot;
uriString = CONTACTS + COPY_PATH + &quot;/&quot; + lastName;
// Parses the string into a URI
Uri copyUri = Uri.parse(uriString);
// Gets a handle to the clipboard service.
ClipboardManager clipboard = (ClipboardManager)
getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clip = ClipData.newUri(getContentResolver(), &quot;URI&quot;, copyUri);
// Set the clipboard's primary clip.
clipboard.setPrimaryClip(clip);
</pre>
</li>
<li>
<p>
In the global scope of your content provider, create a URI matcher and add a URI
pattern that will match URIs you put on the clipboard:
</p>
<pre>
public class MyCopyProvider extends ContentProvider {
...
// A Uri Match object that simplifies matching content URIs to patterns.
private static final UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH);
// An integer to use in switching based on the incoming URI pattern
private static final int GET_SINGLE_CONTACT = 0;
...
// Adds a matcher for the content URI. It matches
// &quot;content://com.example.contacts/copy/*&quot;
sUriMatcher.addURI(CONTACTS, "names/*", GET_SINGLE_CONTACT);
</pre>
</li>
<li>
<p>
Set up the
{@link android.content.ContentProvider#query(Uri, String[], String, String[], String) query()}
method. This method can handle different URI patterns, depending on how you code it, but
only the pattern for the clipboard copying operation is shown:
</p>
<pre>
// Sets up your provider's query() method.
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
String sortOrder) {
...
// Switch based on the incoming content URI
switch (sUriMatcher.match(uri)) {
case GET_SINGLE_CONTACT:
// query and return the contact for the requested name. Here you would decode
// the incoming URI, query the data model based on the last name, and return the result
// as a Cursor.
...
}
</pre>
</li>
<li>
<p>
Set up the {@link android.content.ContentProvider#getType(Uri) getType()} method to
return an appropriate MIME type for copied data:
</p>
<pre>
// Sets up your provider's getType() method.
public String getType(Uri uri) {
...
switch (sUriMatcher.match(uri)) {
case GET_SINGLE_CONTACT:
return (MIME_TYPE_CONTACT);
</pre>
</li>
</ol>
<p>
The section <a href="#PasteContentUri">Pasting data from a content URI</a>
describes how to get a content URI from the clipboard and use it to get and paste data.
</p>
<h3 id="Streams">Copying data streams</h3>
<p>
You can copy and paste large amounts of text and binary data as streams. The data can have
forms such as the following:
</p>
<ul>
<li>
Files stored on the actual device.
</li>
<li>
Streams from sockets.
</li>
<li>
Large amounts of data stored in a provider's underlying database system.
</li>
</ul>
<p>
A content provider for data streams provides access to its data with a file descriptor object
such as {@link android.content.res.AssetFileDescriptor} instead of a
{@link android.database.Cursor} object. The pasting application reads the data stream using
this file descriptor.
</p>
<p>
To set up your application to copy a data stream with a provider, follow these steps:
</p>
<ol>
<li>
Set up a content URI for the data stream you are putting on the clipboard. Options
for doing this include the following:
<ul>
<li>
Encode an identifier for the data stream onto the URI,
as described in the section
<a href="#Encoding">Encoding an identifier on the URI</a>, and then maintain a
table in your provider that contains identifiers and the corresponding stream name.
</li>
<li>
Encode the stream name directly on the URI.
</li>
<li>
Use a unique URI that always returns the current stream from the provider. If you
use this option, you have to remember to update your provider to point to a
different stream whenever you copy the stream to the clipboard via the URI.
</li>
</ul>
</li>
<li>
Provide a MIME type for each type of data stream you plan to offer. Pasting applications
need this information to determine if they can paste the data on the clipboard.
</li>
<li>
Implement one of the {@link android.content.ContentProvider} methods that returns
a file descriptor for a stream. If you encode identifiers on the content URI, use this
method to determine which stream to open.
</li>
<li>
To copy the data stream to the clipboard, construct the content URI and place it
on the clipboard.
</li>
</ol>
<p>
To paste a data stream, an application gets the clip from the clipboard, gets the URI, and
uses it in a call to a {@link android.content.ContentResolver} file descriptor method that
opens the stream. The {@link android.content.ContentResolver} method calls the corresponding
{@link android.content.ContentProvider} method, passing it the content URI. Your provider
returns the file descriptor to {@link android.content.ContentResolver} method. The pasting
application then has the responsibility to read the data from the stream.
</p>
<p>
The following list shows the most important file descriptor methods for a content provider.
Each of these has a corresponding {@link android.content.ContentResolver} method with the
string &quot;Descriptor&quot; appended to the method name; for example, the
{@link android.content.ContentResolver} analog of
{@link android.content.ContentProvider#openAssetFile(Uri, String) openAssetFile()} is
{@link android.content.ContentResolver#openAssetFileDescriptor(Uri, String) openAssetFileDescriptor()}:
</p>
<dl>
<dt>
{@link android.content.ContentProvider#openTypedAssetFile(Uri,String,Bundle) openTypedAssetFile()}
</dt>
<dd>
This method should return an asset file descriptor, but only if the provided MIME type is
supported by the provider. The caller (the application doing the pasting) provides a MIME
type pattern. The content provider (of the application that has copied a URI to the
clipboard) returns an {@link android.content.res.AssetFileDescriptor} file handle if it
can provide that MIME type, or throws an exception if it can not.
<p>
This method handles subsections of files. You can use it to read assets that the
content provider has copied to the clipboard.
</p>
</dd>
<dt>
{@link android.content.ContentProvider#openAssetFile(Uri, String) openAssetFile()}
</dt>
<dd>
This method is a more general form of
{@link android.content.ContentProvider#openTypedAssetFile(Uri,String,Bundle) openTypedAssetFile()}.
It does not filter for allowed MIME types, but it can read subsections of files.
</dd>
<dt>
{@link android.content.ContentProvider#openFile(Uri, String) openFile()}
</dt>
<dd>
This is a more general form of
{@link android.content.ContentProvider#openAssetFile(Uri, String) openAssetFile()}. It can't
read subsections of files.
</dd>
</dl>
<p>
You can optionally use the
{@link android.content.ContentProvider#openPipeHelper(Uri, String, Bundle, T, ContentProvider.PipeDataWriter) openPipeHelper()}
method with your file descriptor method. This allows the pasting application to read the
stream data in a background thread using a pipe. To use this method, you need to implement the
{@link android.content.ContentProvider.PipeDataWriter} interface. An example of doing this is
given in the <a href="{@docRoot}resources/samples/NotePad/index.html">Note Pad</a> sample
application, in the <code>openTypedAssetFile()</code> method of
<code>NotePadProvider.java</code>.
</p>
<h2 id="DataDesign">Designing Effective Copy/Paste Functionality</h2>
<p>
To design effective copy and paste functionality for your application, remember these
points:
</p>
<ul>
<li>
At any time, there is only one clip on the clipboard. A new copy operation by
any application in the system overwrites the previous clip. Since the user may
navigate away from your application and do a copy before returning, you can't assume
that the clipboard contains the clip that the user previously copied in <em>your</em>
application.
</li>
<li>
The intended purpose of multiple {@link android.content.ClipData.Item}
objects per clip is to support copying and pasting of multiple selections rather than
different forms of reference to a single selection. You usually want all of the
{@link android.content.ClipData.Item} objects in a clip to have the same form, that is,
they should all be simple text, content URI, or {@link android.content.Intent}, but not
a mixture.
</li>
<li>
When you provide data, you can offer different MIME representations. Add the MIME types
you support to the {@link android.content.ClipDescription}, and then
implement the MIME types in your content provider.
</li>
<li>
When you get data from the clipboard, your application is responsible for checking the
available MIME types and then deciding which one, if any, to use. Even if there is a
clip on the clipboard and the user requests a paste, your application is not required
to do the paste. You <em>should</em> do the paste if the MIME type is compatible. You
may choose to coerce the data on the clipboard to text using
{@link android.content.ClipData.Item#coerceToText(Context) coerceToText()} if you
choose. If your application supports more than one of the available MIME types, you can
allow the user to choose which one to use.
</li>
</ul>