1096 lines
46 KiB
Plaintext
1096 lines
46 KiB
Plaintext
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("simple text","Hello, World!");
|
|
</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 = "content://com.example.contacts";
|
|
|
|
// Declares a path string for URIs that you use to copy data
|
|
private static final String COPY_PATH = "/copy";
|
|
|
|
// Declares the Uri to paste to the clipboard
|
|
Uri copyUri = Uri.parse(CONTACTS + COPY_PATH + "/" + 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 "URI", and its data is
|
|
// the Uri previously created.
|
|
ClipData clip = ClipData.newUri(getContentResolver(),"URI",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 "Intent" and its data is
|
|
// the Intent object created previously
|
|
ClipData clip = ClipData.newIntent("Intent",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 = "";
|
|
|
|
</pre>
|
|
</li>
|
|
<li>
|
|
Next, determine if you should enable or disable the "paste" 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 "paste" 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
|
|
"paste" 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 "paste"
|
|
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("Clipboard contains an invalid data type");
|
|
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 = "vnd.android.cursor.item/vnd.example.contact"
|
|
</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 "reference" (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>
|
|
"content://com.example.contacts"
|
|
</pre>
|
|
<p>
|
|
If you want to encode a name onto this URI, you would use the following snippet:
|
|
</p>
|
|
<pre>
|
|
String uriString = "content://com.example.contacts" + "/" + "Smith"
|
|
|
|
// 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>
|
|
"content://com.example.contacts"/people
|
|
"content://com.example.contacts"/people/detail
|
|
"content://com.example.contacts"/people/images
|
|
</pre>
|
|
<p>
|
|
You could add another path that is specific to copy URIs:
|
|
</p>
|
|
<pre>
|
|
"content://com.example.contacts/copying"
|
|
</pre>
|
|
<p>
|
|
You could then detect a "copy" 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 "copy" 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 "copy" path. Your application can then
|
|
create a "copy" 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 = "content://com.example.contacts";
|
|
|
|
// Declares a path string for URIs that you use to copy data
|
|
private static final String COPY_PATH = "/copy";
|
|
|
|
// Declares a MIME type for the copied data
|
|
public static final String MIME_TYPE_CONTACT = "vnd.android.cursor.item/vnd.example.contact"
|
|
</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 "lastName"
|
|
uriString = CONTACTS + COPY_PATH + "/" + 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(), "URI", 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
|
|
// "content://com.example.contacts/copy/*"
|
|
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 "Descriptor" 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>
|