diff options
-rw-r--r-- | docs/html/training/basics/intents/filters.jd | 5 | ||||
-rw-r--r-- | docs/html/training/basics/intents/index.jd | 7 | ||||
-rw-r--r-- | docs/html/training/basics/intents/result.jd | 5 | ||||
-rw-r--r-- | docs/html/training/basics/intents/sending.jd | 4 | ||||
-rw-r--r-- | docs/html/training/building-content-sharing.jd | 8 | ||||
-rw-r--r-- | docs/html/training/secure-file-sharing/index.jd | 80 | ||||
-rw-r--r-- | docs/html/training/secure-file-sharing/request-file.jd | 147 | ||||
-rw-r--r-- | docs/html/training/secure-file-sharing/retrieve-info.jd | 110 | ||||
-rw-r--r-- | docs/html/training/secure-file-sharing/setup-sharing.jd | 136 | ||||
-rw-r--r-- | docs/html/training/secure-file-sharing/share-file.jd | 298 | ||||
-rw-r--r-- | docs/html/training/sharing/index.jd | 30 | ||||
-rw-r--r-- | docs/html/training/sharing/receive.jd | 48 | ||||
-rw-r--r-- | docs/html/training/sharing/send.jd | 66 | ||||
-rw-r--r-- | docs/html/training/sharing/shareaction.jd | 58 | ||||
-rw-r--r-- | docs/html/training/training_toc.cs | 120 |
15 files changed, 979 insertions, 143 deletions
diff --git a/docs/html/training/basics/intents/filters.jd b/docs/html/training/basics/intents/filters.jd index 0090c98..9b6a111 100644 --- a/docs/html/training/basics/intents/filters.jd +++ b/docs/html/training/basics/intents/filters.jd @@ -20,7 +20,8 @@ previous.link=result.html <h2>You should also read</h2> <ul> - <li><a href="{@docRoot}training/sharing/index.html">Sharing Content</a></li> + <li><a href="{@docRoot}training/sharing/index.html">Sharing Simple Data</a></li> + <li><a href="{@docRoot}training/secure-file-sharing/index.html">Sharing Files</a> </ul> </div> </div> @@ -152,7 +153,7 @@ implicit intents will resolve to your activity.</p> <p>For more information about sending and receiving {@link android.content.Intent#ACTION_SEND} intents that perform social sharing behaviors, see the lesson about <a -href="{@docRoot}training/sharing/receive.html">Receiving Content from Other Apps</a>.</p> +href="{@docRoot}training/sharing/receive.html">Receiving Simple Data from Other Apps</a>.</p> <h2 id="HandleIntent">Handle the Intent in Your Activity</h2> diff --git a/docs/html/training/basics/intents/index.jd b/docs/html/training/basics/intents/index.jd index 8876a33..59ba11f 100644 --- a/docs/html/training/basics/intents/index.jd +++ b/docs/html/training/basics/intents/index.jd @@ -19,7 +19,8 @@ Lifecycle</a>)</li> <h2>You should also read</h2> <ul> - <li><a href="{@docRoot}training/sharing/index.html">Sharing Content</a></li> + <li><a href="{@docRoot}training/sharing/index.html">Sharing Simple Data</a></li> + <li><a href="{@docRoot}training/secure-file-sharing/index.html">Sharing Files</a> <li><a href="http://android-developers.blogspot.com/2009/11/integrating-application-with-intents.html"> Integrating Application with Intents (blog post)</a></li> @@ -49,7 +50,7 @@ interactions with other apps, such as start another app, receive a result from t make your app able to respond to intents from other apps.</p> <h2>Lessons</h2> - + <dl> <dt><b><a href="sending.html">Sending the User to Another App</a></b></dt> <dd>Shows how you can create implicit intents to launch other apps that can perform an @@ -59,5 +60,5 @@ action.</dd> <dt><b><a href="filters.html">Allowing Other Apps to Start Your Activity</a></b></dt> <dd>Shows how to make activities in your app open for use by other apps by defining intent filters that declare the implicit intents your app accepts.</dd> -</dl> +</dl> diff --git a/docs/html/training/basics/intents/result.jd b/docs/html/training/basics/intents/result.jd index 24ecc46..64fbb8b 100644 --- a/docs/html/training/basics/intents/result.jd +++ b/docs/html/training/basics/intents/result.jd @@ -21,7 +21,8 @@ next.link=filters.html <h2>You should also read</h2> <ul> - <li><a href="{@docRoot}training/sharing/index.html">Sharing Content</a></li> + <li><a href="{@docRoot}training/sharing/index.html">Sharing Simple Data</a></li> + <li><a href="{@docRoot}training/secure-file-sharing/index.html">Sharing Files</a> </ul> </div> @@ -71,7 +72,7 @@ private void pickContact() { <h2 id="ReceiveResult">Receive the Result</h2> -<p>When the user is done with the subsequent activity and returns, the system calls your activity's +<p>When the user is done with the subsequent activity and returns, the system calls your activity's {@link android.app.Activity#onActivityResult onActivityResult()} method. This method includes three arguments:</p> diff --git a/docs/html/training/basics/intents/sending.jd b/docs/html/training/basics/intents/sending.jd index aba3896..79c017b 100644 --- a/docs/html/training/basics/intents/sending.jd +++ b/docs/html/training/basics/intents/sending.jd @@ -22,7 +22,7 @@ next.link=result.html <h2>You should also read</h2> <ul> - <li><a href="{@docRoot}training/sharing/index.html">Sharing Content</a></li> + <li><a href="{@docRoot}training/sharing/index.html">Sharing Simple Data</a></li> </ul> </div> @@ -200,7 +200,7 @@ Intent mapIntent = new Intent(Intent.ACTION_VIEW, location); PackageManager packageManager = {@link android.content.Context#getPackageManager()}; List<ResolveInfo> activities = packageManager.queryIntentActivities(mapIntent, 0); boolean isIntentSafe = activities.size() > 0; - + // Start an activity if it's safe if (isIntentSafe) { startActivity(mapIntent); diff --git a/docs/html/training/building-content-sharing.jd b/docs/html/training/building-content-sharing.jd new file mode 100644 index 0000000..52298c3 --- /dev/null +++ b/docs/html/training/building-content-sharing.jd @@ -0,0 +1,8 @@ +page.title=Building Apps with Content Sharing +page.trainingcourse=true + +@jd:body + + + +<p>These classes teach you how to create apps that share data between apps and devices.</p> diff --git a/docs/html/training/secure-file-sharing/index.jd b/docs/html/training/secure-file-sharing/index.jd new file mode 100644 index 0000000..19a1042 --- /dev/null +++ b/docs/html/training/secure-file-sharing/index.jd @@ -0,0 +1,80 @@ +page.title=Sharing Files + +trainingnavtop=true +startpage=true + + +@jd:body + +<div id="tb-wrapper"> +<div id="tb"> + +<h2>Dependencies and prerequisites</h2> +<ul> + <li>Android 1.6 (API Level 4) or higher</li> + <li>Familiarity with file operations such as opening, reading, and writing files</li> +</ul> + +<h2>You should also read</h2> +<ul> + <li><a href="{@docRoot}guide/topics/data/data-storage.html">Storage Options</a></li> + <li><a href="{@docRoot}training/basics/data-storage/files.html">Saving Files</a> + <li><a href="{@docRoot}training/sharing/index.html">Sharing Simple Data</a></li> +</ul> + +</div> +</div> + +<p> + Apps often have a need to offer one or more of their files to another app. For example, an image + gallery may want to offer files to image editors, or a file management app may want to allow + users to copy and paste files between areas in external storage. One way a sending app can + share a file is to respond to a request from the receiving app. +</p> +<p> + In all cases, the only secure way to offer a file from your app to another app is to send the + receiving app the file's content URI and grant temporary access permissions to that URI. + Content URIs with temporary URI access permissions are secure because they apply only to the + app that receives the URI, and they expire automatically. The Android + {@link android.support.v4.content.FileProvider} component provides the method + {@link android.support.v4.content.FileProvider#getUriForFile getUriForFile()} for + generating a file's content URI. +</p> +<p> + If you want to share small amounts of text or numeric data between apps, you should send an + {@link android.content.Intent} that contains the data. To learn how to send simple data with an + {@link android.content.Intent}, see the training class + <a href="{@docRoot}training/sharing/index.html">Sharing Simple Data</a>. +</p> +<p> + This class explains how to securely share files from your app to another app using content URIs + generated by the Android {@link android.support.v4.content.FileProvider} component and + temporary permissions that you grant to the receiving app for the content URI. +</p> +<h2>Lessons</h2> +<dl> + <dt><b><a href="setup-sharing.html">Setting Up File Sharing</a></b></dt> + <dd> + Learn how to set up your app to share files. + </dd> + <dt><b><a href="share-file.html">Sharing a File</a></b></dt> + <dd> + Learn how to offer a file to another app by generating a content URI for the file, + granting access permissions to the URI, and sending the URI to the app. + </dd> + <dt><b><a href="request-file.html">Requesting a Shared File</a></b></dt> + <dd> + Learn how to request a file shared by another app, receive the content URI for the file, + and use the content URI to open the file. + </dd> + <dt> + <b><a href="retrieve-info.html">Retrieving File Information</a></b> + </dt> + <dd> + Learn how an app can use a content URI generated by a + {@link android.support.v4.content.FileProvider} to retrieve file information including + MIME type and file size. + </dd> +</dl> + + diff --git a/docs/html/training/secure-file-sharing/request-file.jd b/docs/html/training/secure-file-sharing/request-file.jd new file mode 100644 index 0000000..116701d --- /dev/null +++ b/docs/html/training/secure-file-sharing/request-file.jd @@ -0,0 +1,147 @@ +page.title=Requesting a Shared File + +trainingnavtop=true +@jd:body + + +<div id="tb-wrapper"> +<div id="tb"> + +<h2>This lesson teaches you to</h2> +<ol> + <li><a href="#SendRequest">Send a Request for the File</a></li> + <li><a href="#OpenFile">Access the Requested File</a> +</ol> + +<h2>You should also read</h2> +<ul> + <li> + <a href="{@docRoot}guide/components/intents-filters.html">Intents and Intent Filters</a> + </li> + <li> + <a href="{@docRoot}guide/topics/providers/content-provider-basics.html#SimpleQuery" + >Retrieving Data from the Provider</a> + </li> +</ul> + +</div> +</div> + +<p> + When an app wants to access a file shared by another app, the requesting app (the client) + usually sends a request to the app sharing the files (the server). In most cases, the request + starts an {@link android.app.Activity} in the server app that displays the files it can share. + The user picks a file, after which the server app returns the file's content URI to the + client app. +</p> +<p> + This lesson shows you how a client app requests a file from a server app, receives the file's + content URI from the server app, and opens the file using the content URI. +</p> + +<h2 id="SendRequest">Send a Request for the File</h2> +<p> + To request a file from the server app, the client app calls + {@link android.app.Activity#startActivityForResult startActivityForResult} with an + {@link android.content.Intent} containing the action such as + {@link android.content.Intent#ACTION_PICK ACTION_PICK} and a MIME type that the client app + can handle. +</p> +<p> + For example, the following code snippet demonstrates how to send an + {@link android.content.Intent} to a server app in order to start the + {@link android.app.Activity} described in <a href="share-file.html#SendURI" + >Sharing a File</a>: +</p> +<pre> +public class MainActivity extends Activity { + private Intent mRequestFileIntent; + private ParcelFileDescriptor mInputPFD; + ... + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + mRequestFileIntent = new Intent(Intent.ACTION_PICK); + mRequestFileIntent.setType("image/jpg"); + ... + } + ... + protected void requestFile() { + /** + * When the user requests a file, send an Intent to the + * server app. + * files. + */ + startActivityForResult(mRequestFileIntent, 0); + ... + } + ... +} +</pre> +<h2 id="OpenFile">Access the Requested File</h2> +<p> + The server app sends the file's content URI back to the client app in an + {@link android.content.Intent}. This {@link android.content.Intent} is passed to the client + app in its override of {@link android.app.Activity#onActivityResult onActivityResult()}. Once + the client app has the file's content URI, it can access the file by getting its + {@link java.io.FileDescriptor}. +</p> +<p> +<p> + File security is preserved in this process because the content URI is the only piece of data + that the client app receives. Since this URI doesn't contain a directory path, the client app + can't discover and open any other files in the server app. Only the client app gets access to + the file, and only for the permissions granted by the server app. The permissions are temporary, + so once the client app's task stack is finished, the file is no longer accessible outside the + server app. +</p> +<p> + The next snippet demonstrates how the client app handles the + {@link android.content.Intent} sent from the server app, and how the client app gets the + {@link java.io.FileDescriptor} using the content URI: +</p> +<pre> + /* + * When the Activity of the app that hosts files sets a result and calls + * finish(), this method is invoked. The returned Intent contains the + * content URI of a selected file. The result code indicates if the + * selection worked or not. + */ + @Override + public void onActivityResult(int requestCode, int resultCode, + Intent returnIntent) { + // If the selection didn't work + if (resultCode != RESULT_OK) { + // Exit without doing anything else + return; + } else { + // Get the file's content URI from the incoming Intent + Uri returnUri = returnIntent.getData(); + /* + * Try to open the file for "read" access using the + * returned URI. If the file isn't found, write to the + * error log and return. + */ + try { + /* + * Get the content resolver instance for this context, and use it + * to get a ParcelFileDescriptor for the file. + */ + mInputPFD = getContentResolver().openFileDescriptor(returnUri, "r"); + } catch (FileNotFoundException e) { + e.printStackTrace(); + Log.e("MainActivity", "File not found."); + return; + } + // Get a regular file descriptor for the file + FileDescriptor fd = mInputPFD.getFileDescriptor(); + ... + } + } +</pre> +<p> + The method {@link android.content.ContentResolver#openFileDescriptor openFileDescriptor()} + returns a {@link android.os.ParcelFileDescriptor} for the file. From this object, the client + app gets a {@link java.io.FileDescriptor} object, which it can then use to read the file. +</p> diff --git a/docs/html/training/secure-file-sharing/retrieve-info.jd b/docs/html/training/secure-file-sharing/retrieve-info.jd new file mode 100644 index 0000000..4a2b7d8 --- /dev/null +++ b/docs/html/training/secure-file-sharing/retrieve-info.jd @@ -0,0 +1,110 @@ +page.title=Retrieving File Information + +trainingnavtop=true +@jd:body + + +<div id="tb-wrapper"> +<div id="tb"> + +<!-- table of contents --> +<h2>This lesson teaches you to</h2> +<ol> + <li><a href="#RetrieveMimeType">Retrieve a File's MIME Type</a></li> + <li><a href="#RetrieveFileInfo">Retrieve a File's Name and Size</a></li> +</ol> + +<!-- other docs (NOT javadocs) --> +<h2>You should also read</h2> +<ul> + <li><a href="{@docRoot}guide/topics/providers/content-provider-basics.html#SimpleQuery" + >Retrieving Data from the Provider</a></li> +</ul> + +</div> +</div> +<p> + Before a client app tries to work with a file for which it has a content URI, the app can + request information about the file from the server app, including the file's data type and + file size. The data type helps the client app to determine if it can handle the file, and the + file size helps the client app set up buffering and caching for the file. +</p> +<p> + This lesson demonstrates how to query the server app's + {@link android.support.v4.content.FileProvider} to retrieve a file's MIME type and size. +</p> +<h2 id="RetrieveMimeType">Retrieve a File's MIME Type</h2> +<p> + A file's data type indicates to the client app how it should handle the file's contents. To get + the data type of a shared file given its content URI, the client app calls + {@link android.content.ContentResolver#getType ContentResolver.getType()}. This method returns + the file's MIME type. By default, a + {@link android.support.v4.content.FileProvider} determines the file's MIME type from its + filename extension. +</p> +<p> + The following code snippet demonstrates how a client app retrieves the MIME type of a file once + the server app has returned the content URI to the client: +</p> +<pre> + ... + /* + * Get the file's content URI from the incoming Intent, then + * get the file's MIME type + */ + Uri returnUri = returnIntent.getData(); + String mimeType = getContentResolver().getType(returnUri); + ... +</pre> +<h2 id="RetrieveFileInfo">Retrieve a File's Name and Size</h2> +<p> + The {@link android.support.v4.content.FileProvider} class has a default implementation of the + {@link android.support.v4.content.FileProvider#query query()} method that returns the + name and size of the file associated with a content URI in a + {@link android.database.Cursor}. The default implementation returns two columns: +</p> +<dl> + <dt>{@link android.provider.OpenableColumns#DISPLAY_NAME DISPLAY_NAME}</dt> + <dd> + The file's name, as a {@link java.lang.String}. This value is the same as the value returned + by {@link java.io.File#getName File.getName()}. + </dd> + <dt>{@link android.provider.OpenableColumns#SIZE SIZE}</dt> + <dd> + The size of the file in bytes, as a {@code long} This value is the same as the value + returned by {@link java.io.File#length File.length()} + </dd> +</dl> +<p> + The client app can get both the {@link android.provider.OpenableColumns#DISPLAY_NAME + DISPLAY_NAME} and {@link android.provider.OpenableColumns#SIZE SIZE} for a file by setting all + of the arguments of {@link android.support.v4.content.FileProvider#query query()} to + {@code null} except for the content URI. For example, this code snippet retrieves a file's + {@link android.provider.OpenableColumns#DISPLAY_NAME DISPLAY_NAME} and + {@link android.provider.OpenableColumns#SIZE SIZE} and displays each one in separate + {@link android.widget.TextView}: +</p> +<pre> + ... + /* + * Get the file's content URI from the incoming Intent, + * then query the server app to get the file's display name + * and size. + */ + Uri returnUri = returnIntent.getData(); + Cursor returnCursor = + getContentResolver().query(returnUri, null, null, null, null); + /* + * Get the column indexes of the data in the Cursor, + * move to the first row in the Cursor, get the data, + * and display it. + */ + int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME); + int sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE); + returnCursor.moveToFirst(); + TextView nameView = (TextView) findViewById(R.id.filename_text); + TextView sizeView = (TextView) findViewById(R.id.filesize_text); + nameView.setText(returnCursor.getString(nameIndex)); + sizeView.setText(Long.toString(returnCursor.getLong(sizeIndex))); + ... +</pre> diff --git a/docs/html/training/secure-file-sharing/setup-sharing.jd b/docs/html/training/secure-file-sharing/setup-sharing.jd new file mode 100644 index 0000000..d1ab993 --- /dev/null +++ b/docs/html/training/secure-file-sharing/setup-sharing.jd @@ -0,0 +1,136 @@ +page.title=Setting Up File Sharing +trainingnavtop=true +@jd:body + + +<div id="tb-wrapper"> +<div id="tb"> + +<!-- table of contents --> +<h2>This lesson teaches you to</h2> +<ol> + <li><a href="#DefineProvider">Specify the FileProvider</a></li> + <li><a href="#DefineMetaData">Specify Sharable Directories</a></li> +</ol> + +<h2>You should also read</h2> +<ul> + <li><a href="{@docRoot}guide/topics/data/data-storage.html">Storage Options</a></li> + <li><a href="{@docRoot}training/basics/data-storage/files.html">Saving Files</a> +</ul> + +</div> +</div> + +<p> + To securely offer a file from your app to another app, you need to configure your app to offer + a secure handle to the file, in the form of a content URI. The Android + {@link android.support.v4.content.FileProvider} component generates content URIs for + files, based on specifications you provide in XML. This lesson shows you how to add the default + implementation of {@link android.support.v4.content.FileProvider} to your app, and how to + specify the files you want to offer to other apps. +</p> +<h2 id="DefineProvider">Specify the FileProvider</h2> +<p> + Defining a {@link android.support.v4.content.FileProvider} for your app requires an entry in + your manifest. This entry specifies the authority to use in generating content URIs, as well as + the name of an XML file that specifies the directories your app can share. +</p> +<p> + The following snippet shows you how to add to your manifest the + <code><a href="{@docRoot}guide/topics/manifest/provider-element.html" + ><provider></a></code> element that specifies the + {@link android.support.v4.content.FileProvider} class, the authority, and the + XML file name: +</p> +<pre> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.example.myapp"> + <application + ...> + <provider + android:name="android.support.v4.content.FileProvider" + android:authorities="com.example.myapp.fileprovider" + android:grantUriPermissions="true" + android:exported="false"> + <meta-data + android:name="android.support.FILE_PROVIDER_PATHS" + android:resource="@xml/filepaths" /> + </provider> + ... + </application> +</manifest></pre> +<p> + In this example, the <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#auth" + >android:authorities</a></code> attribute specifies the URI authority + that you want to use for content URIs generated by the + {@link android.support.v4.content.FileProvider}. + In the example, the authority is <code>com.example.myapp.fileprovider</code>. For your own + app, specify an authority consisting of the app's + <code><a href="{@docRoot}guide/topics/manifest/manifest-element.html#package" + >android:package</a></code> value with the string "fileprovider" appended to it. To learn more + about the authority value, see the topic + <a href="{@docRoot}guide/topics/providers/content-provider-basics.html#ContentURIs" + >Content URIs</a> and the documentation for the + <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#auth" + >android:authorities</a></code> attribute. +</p> +<p> + The <code><a href="{@docRoot}guide/topics/manifest/meta-data-element.html" + ><meta-data></a></code> child element of the + <code><a href="{@docRoot}guide/topics/manifest/provider-element.html" + ><provider></a></code> points to an XML file that specifies the directories you want to + share. The <code>android:resource</code> attribute is the path and name of the file, without + the <code>.xml</code> extension.The contents of this file are described in the next section. +</p> +<h2 id="DefineMetaData">Specify Sharable Directories</h2> +<p> + Once you have added the {@link android.support.v4.content.FileProvider} to your app manifest, + you need to specify the directories that contain the files you want to share. To specify the + directories, start by creating the file <code>filepaths.xml</code> in the <code>res/xml/</code> + subdirectory of your project. In this file, specify the directories by adding an XML element for + each directory. The following snippet shows you an example of the contents of + <code>res/xml/filepaths.xml</code>. The snippet also demonstrates how to share a subdirectory + of the <code>files/</code> directory in your internal storage area: +</p> +<pre> +<paths> + <files-path path="images/" name="myimages" /> +</paths></pre> +<p> + In this example, the <code><files-path></code> tag shares directories within the + <code>files/</code> directory of your app's internal storage. The <code>path</code> attribute + shares the <code>images/</code> subdirectory of <code>files/</code>. The <code>name</code> + attribute tells the {@link android.support.v4.content.FileProvider} to add the path segment + <code>myimages</code> to content URIs for files in the <code>files/images/</code> subdirectory. +</p> +<p> + The <code><paths></code> element can have multiple children, each specifying a different + directory to share. In addition to the <code><files-path></code> element, you can + use the <code><external-path></code> element to share directories in external storage, and + the <code><cache-path></code> element to share directories in your internal cache + directory. To learn more about the child elements that specify shared directories, see the + {@link android.support.v4.content.FileProvider} reference documentation. +</p> +<p class="note"> + <strong>Note:</strong> The XML file is the only way you can specify the directories you want to + share; you can't programmatically add a directory. +</p> +<p> + You now have a complete specification of a {@link android.support.v4.content.FileProvider} + that generates content URIs for files in the <code>files/</code> directory of your app's + internal storage or for files in subdirectories of <code>files/</code>. When your app generates + a content URI for a file, it contains the authority specified in the + <code><a href="{@docRoot}guide/topics/manifest/provider-element.html" + ><provider></a></code> element (<code>com.example.myapp.fileprovider</code>), + the path <code>myimages/</code>, and the name of the file. +</p> +<p> + For example, if you define a {@link android.support.v4.content.FileProvider} according to the + snippets in this lesson, and you request a content URI for the file + <code>default_image.jpg</code>, {@link android.support.v4.content.FileProvider} returns the + following URI: +</p> +<pre> +content://com.example.myapp.fileprovider/myimages/default_image.jpg</pre> + diff --git a/docs/html/training/secure-file-sharing/share-file.jd b/docs/html/training/secure-file-sharing/share-file.jd new file mode 100644 index 0000000..6c52770 --- /dev/null +++ b/docs/html/training/secure-file-sharing/share-file.jd @@ -0,0 +1,298 @@ +page.title=Sharing a File + +trainingnavtop=true +@jd:body + + +<div id="tb-wrapper"> +<div id="tb"> + +<h2>This lesson teaches you to</h2> +<ol> + <li><a href="#ReceiveRequests">Receive File Requests</a></li> + <li><a href="#CreateFileSelection">Create a File Selection Activity</a></li> + <li><a href="#RespondToRequest">Respond to a File Selection</a></li> + <li><a href="#GrantPermissions">Grant Permissions for the File</a></li> + <li><a href="#ShareFile">Share the File with the Requesting App</a> +</ol> + +<h2>You should also read</h2> +<ul> + <li> + <a href="{@docRoot}guide/topics/providers/content-provider-creating.html#ContentURI" + >Designing Content URIs</a> + </li> + <li> + <a href="{@docRoot}guide/topics/providers/content-provider-creating.html#Permissions" + >Implementing Content Provider Permissions</a> + </li> + <li> + <a href="{@docRoot}guide/topics/security/permissions.html">Permissions</a> + </li> + <li> + <a href="{@docRoot}guide/components/intents-filters.html">Intents and Intent Filters</a> + </li> +</ul> + +</div> +</div> +<p> + Once you have set up your app to share files using content URIs, you can respond to other apps' + requests for those files. One way to respond to these requests is to provide a file selection + interface from the server app that other applications can invoke. This approach allows a client + application to let users select a file from the server app and then receive the selected file's + content URI. +</p> +<p> + This lesson shows you how to create a file selection {@link android.app.Activity} in your app + that responds to requests for files. +</p> +<h2 id="ReceiveRequests">Receive File Requests</h2> +<p> + To receive requests for files from client apps and respond with a content URI, your app should + provide a file selection {@link android.app.Activity}. Client apps start this + {@link android.app.Activity} by calling {@link android.app.Activity#startActivityForResult + startActivityForResult()} with an {@link android.content.Intent} containing the action + {@link android.content.Intent#ACTION_PICK ACTION_PICK}. When the client app calls + {@link android.app.Activity#startActivityForResult startActivityForResult()}, your app can + return a result to the client app, in the form of a content URI for the file the user selected. +</p> +<p> + To learn how to implement a request for a file in a client app, see the lesson + <a href="request-file.html">Requesting a Shared File</a>. +</p> +<h2 id="CreateFileSelection">Create a File Selection Activity</h2> +<p> + To set up the file selection {@link android.app.Activity}, start by specifying the + {@link android.app.Activity} in your manifest, along with an intent filter + that matches the action {@link android.content.Intent#ACTION_PICK ACTION_PICK} and the + categories {@link android.content.Intent#CATEGORY_DEFAULT CATEGORY_DEFAULT} and + {@link android.content.Intent#CATEGORY_OPENABLE CATEGORY_OPENABLE}. Also add MIME type filters + for the files your app serves to other apps. The following snippet shows you how to specify the + new {@link android.app.Activity} and intent filter: +</p> +<pre> +<manifest xmlns:android="http://schemas.android.com/apk/res/android"> + ... + <application> + ... + <activity + android:name=".FileSelectActivity" + android:label="@"File Selector" > + <intent-filter> + <action + android:name="android.intent.action.PICK"/> + <category + android:name="android.intent.category.DEFAULT"/> + <category + android:name="android.intent.category.OPENABLE"/> + <data android:mimeType="text/plain"/> + <data android:mimeType="image/*"/> + </intent-filter> + </activity></pre> +<h3>Define the file selection Activity in code</h3> +<p> + Next, define an {@link android.app.Activity} subclass that displays the files available from + your app's <code>files/images/</code> directory in internal storage and allows the user to pick + the desired file. The following snippet demonstrates how to define this + {@link android.app.Activity} and respond to the user's selection: +</p> +<pre> +public class MainActivity extends Activity { + // The path to the root of this app's internal storage + private File mPrivateRootDir; + // The path to the "images" subdirectory + private File mImagesDir; + // Array of files in the images subdirectory + File[] mImageFiles; + // Array of filenames corresponding to mImageFiles + String[] mImageFilenames; + // Initialize the Activity + @Override + protected void onCreate(Bundle savedInstanceState) { + ... + // Set up an Intent to send back to apps that request a file + mResultIntent = + new Intent("com.example.myapp.ACTION_RETURN_FILE"); + // Get the files/ subdirectory of internal storage + mPrivateRootDir = getFilesDir(); + // Get the files/images subdirectory; + mImagesDir = new File(mPrivateRootDir, "images"); + // Get the files in the images subdirectory + mImageFiles = mImagesDir.listFiles(); + // Set the Activity's result to null to begin with + setResult(Activity.RESULT_CANCELED, null); + /* + * Display the file names in the ListView mFileListView. + * Back the ListView with the array mImageFilenames, which + * you can create by iterating through mImageFiles and + * calling File.getAbsolutePath() for each File + */ + ... + } + ... +}</pre> +<h2 id="RespondToRequest">Respond to a File Selection</h2> +<p> + Once a user selects a shared file, your application must determine what file was selected and + then generate a content URI for the file. Since the {@link android.app.Activity} displays the + list of available files in a {@link android.widget.ListView}, when the user clicks a file name + the system calls the method {@link android.widget.AdapterView.OnItemClickListener#onItemClick + onItemClick()}, in which you can get the selected file. +</p> +<p> + In {@link android.widget.AdapterView.OnItemClickListener#onItemClick onItemClick()}, get a + {@link java.io.File} object for the file name of the selected file and pass it as an argument to + {@link android.support.v4.content.FileProvider#getUriForFile getUriForFile()}, along with the + authority that you specified in the + <code><a href="{@docRoot}guide/topics/manifest/provider-element.html" + ><provider></a></code> element for the {@link android.support.v4.content.FileProvider}. + The resulting content URI contains the authority, a path segment corresponding to the file's + directory (as specified in the XML meta-data), and the name of the file including its + extension. How {@link android.support.v4.content.FileProvider} maps directories to path + segments based on XML meta-data is described in the section + <a href="setup-sharing.html#DefineMetaData">Specify Sharable Directories</a>. +</p> +<p> + The following snippet shows you how to detect the selected file and get a content URI for it: +</p> +<pre> + protected void onCreate(Bundle savedInstanceState) { + ... + // Define a listener that responds to clicks on a file in the ListView + mFileListView.setOnItemClickListener( + new AdapterView.OnItemClickListener() { + @Override + /* + * When a filename in the ListView is clicked, get its + * content URI and send it to the requesting app + */ + public void onItemClick(AdapterView<?> adapterView, + View view, + int position, + long rowId) { + /* + * Get a File for the selected file name. + * Assume that the file names are in the + * mImageFilename array. + */ + File requestFile = new File(mImageFilename[position]); + /* + * Most file-related method calls need to be in + * try-catch blocks. + */ + // Use the FileProvider to get a content URI + try { + fileUri = FileProvider.getUriForFile( + MainActivity.this, + "com.example.myapp.fileprovider", + requestFile); + } catch (IllegalArgumentException e) { + Log.e("File Selector", + "The selected file can't be shared: " + + clickedFilename); + } + ... + } + }); + ... + }</pre> +<p> + Remember that you can only generate content URIs for files that reside in a directory + you've specified in the meta-data file that contains the <code><paths></code> element, as + described in the section <a href="setup-sharing.html#DefineMetaData" + >Specify Sharable Directories</a>. If you call + {@link android.support.v4.content.FileProvider#getUriForFile getUriForFile()} for a + {@link java.io.File} in a path that you haven't specified, you receive an + {@link java.lang.IllegalArgumentException}. +</p> +<h2 id="GrantPermissions">Grant Permissions for the File</h2> +<p> + Now that you have a content URI for the file you want to share with another app, you need to + allow the client app to access the file. To allow access, grant permissions to the client app by + adding the content URI to an {@link android.content.Intent} and then setting permission flags on + the {@link android.content.Intent}. The permissions you grant are temporary and expire + automatically when the receiving app's task stack is finished. +</p> +<p> + The following code snippet shows you how to set read permission for the file: +</p> +<pre> + protected void onCreate(Bundle savedInstanceState) { + ... + // Define a listener that responds to clicks in the ListView + mFileListView.setOnItemClickListener( + new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView<?> adapterView, + View view, + int position, + long rowId) { + ... + if (fileUri != null) { + // Grant temporary read permission to the content URI + mResultIntent.addFlags( + Intent.FLAG_GRANT_READ_URI_PERMISSION); + } + ... + } + ... + }); + ... + }</pre> +<p class="caution"> + <strong>Caution:</strong> Calling {@link android.content.Intent#setFlags setFlags()} is the only + way to securely grant access to your files using temporary access permissions. Avoid calling + {@link android.content.Context#grantUriPermission Context.grantUriPermission()} method for a + file's content URI, since this method grants access that you can only revoke by + calling {@link android.content.Context#revokeUriPermission Context.revokeUriPermission()}. +</p> +<h2 id="ShareFile">Share the File with the Requesting App</h2> +<p> + To share the file with the app that requested it, pass the {@link android.content.Intent} + containing the content URI and permissions to {@link android.app.Activity#setResult + setResult()}. When the {@link android.app.Activity} you have just defined is finished, the + system sends the {@link android.content.Intent} containing the content URI to the client app. + The following code snippet shows you how to do this: +</p> +<pre> + protected void onCreate(Bundle savedInstanceState) { + ... + // Define a listener that responds to clicks on a file in the ListView + mFileListView.setOnItemClickListener( + new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView<?> adapterView, + View view, + int position, + long rowId) { + ... + if (fileUri != null) { + ... + // Put the Uri and MIME type in the result Intent + mResultIntent.setDataAndType( + fileUri, + getContentResolver().getType(fileUri)); + // Set the result + MainActivity.this.setResult(Activity.RESULT_OK, + mResultIntent); + } else { + mResultIntent.setDataAndType(null, ""); + MainActivity.this.setResult(RESULT_CANCELED, + mResultIntent); + } + } + });</pre> +<p> + Provide users with an way to return immediately to the client app once they have chosen a file. + One way to do this is to provide a checkmark or <b>Done</b> button. Associate a method with + the button using the button's + <code><a href="{@docRoot}reference/android/view/View.html#attr_android:onClick" + >android:onClick</a></code> attribute. In the method, call + {@link android.app.Activity#finish finish()}. For example: +</p> +<pre> + public void onDoneClick(View v) { + // Associate a method with the Done button + finish(); + }</pre> diff --git a/docs/html/training/sharing/index.jd b/docs/html/training/sharing/index.jd index 2aa22b6..06d42fc 100644 --- a/docs/html/training/sharing/index.jd +++ b/docs/html/training/sharing/index.jd @@ -1,4 +1,4 @@ -page.title=Sharing Content +page.title=Sharing Simple Data page.tags="intents","share" trainingnavtop=true @@ -20,26 +20,26 @@ Intent Filters</a></li> </div> </div> - + <p>One of the great things about Android applications is their ability to communicate and integrate with each other. Why reinvent functionality that isn't core to your application when it -already exists in another application?</p> +already exists in another application?</p> -<p>This class covers some common ways you can send and receive content between +<p>This class covers some common ways you can send and receive simple data between applications using {@link android.content.Intent} APIs and the {@link android.view.ActionProvider} object.</p> <h2>Lessons</h2> - -<dl> - <dt><b><a href="send.html">Sending Content to Other Apps</a></b></dt> + +<dl> + <dt><b><a href="send.html">Sending Simple Data to Other Apps</a></b></dt> <dd>Learn how to set up your application to be able to send text and binary data to other -applications with intents.</dd> - - <dt><b><a href="receive.html">Receiving Content from Other Apps</a></b></dt> - <dd>Learn how to set up your application to receive text and binary data from intents.</dd> - - <dt><b><a href="shareaction.html">Adding an Easy Share Action</a></b></dt> - <dd>Learn how to add a "share" action item to your action bar.</dd> -</dl> +applications with intents.</dd> + + <dt><b><a href="receive.html">Receiving Simple Data from Other Apps</a></b></dt> + <dd>Learn how to set up your application to receive text and binary data from intents.</dd> + + <dt><b><a href="shareaction.html">Adding an Easy Share Action</a></b></dt> + <dd>Learn how to add a "share" action item to your action bar.</dd> +</dl> diff --git a/docs/html/training/sharing/receive.jd b/docs/html/training/sharing/receive.jd index 7ec3def..8c5f862 100644 --- a/docs/html/training/sharing/receive.jd +++ b/docs/html/training/sharing/receive.jd @@ -1,5 +1,5 @@ -page.title=Receiving Content from Other Apps -parent.title=Sharing Content +page.title=Receiving Simple Data from Other Apps +parent.title=Sharing Simple Data parent.link=index.html trainingnavtop=true @@ -30,26 +30,26 @@ Intent Filters</a></li> </div> </div> -<p>Just as your application can send data to other applications, so too can it easily receive data -from applications. Think about how users interact with your application, and what data types you -want to receive from other applications. For example, a social networking application would likely -be interested in receiving text content, like an interesting web URL, from another app. The +<p>Just as your application can send data to other applications, so too can it easily receive data +from applications. Think about how users interact with your application, and what data types you +want to receive from other applications. For example, a social networking application would likely +be interested in receiving text content, like an interesting web URL, from another app. The <a href="https://play.google.com/store/apps/details?id=com.google.android.apps.plus">Google+ Android -application</a> -accepts both text <em>and</em> single or multiple images. With this app, a user can easily start a +application</a> +accepts both text <em>and</em> single or multiple images. With this app, a user can easily start a new Google+ post with photos from the Android Gallery app.</p> <h2 id="update-manifest">Update Your Manifest</h2> -<p>Intent filters inform the system what intents an application component is willing to accept. -Similar to how you constructed an intent with action {@link android.content.Intent#ACTION_SEND} in -the <a href="{@docRoot}training/sharing/send.html">Send Content to Other Apps Using Intents</a> -lesson, you create intent filters in order to be able to receive intents with this action. You -define an intent filter in your manifest, using the +<p>Intent filters inform the system what intents an application component is willing to accept. +Similar to how you constructed an intent with action {@link android.content.Intent#ACTION_SEND} in +the <a href="{@docRoot}training/sharing/send.html">Sending Simple Data to Other Apps</a> +lesson, you create intent filters in order to be able to receive intents with this action. You +define an intent filter in your manifest, using the <code><a -href="{@docRoot}guide/components/intents-filters.html#ifs"><intent-filter></a></code> -element. For example, if your application handles receiving text content, a single image of any +href="{@docRoot}guide/components/intents-filters.html#ifs"><intent-filter></a></code> +element. For example, if your application handles receiving text content, a single image of any type, or multiple images of any type, your manifest would look like:</p> <pre> @@ -72,24 +72,24 @@ type, or multiple images of any type, your manifest would look like:</p> </activity> </pre> -<p class="note"><strong>Note:</strong> For more information on intent filters and intent resolution +<p class="note"><strong>Note:</strong> For more information on intent filters and intent resolution please read <a href="{@docRoot}guide/components/intents-filters.html#ifs">Intents and Intent Filters</a></p> <p>When another application tries to share any of these things by constructing an intent and passing it to {@link android.content.Context#startActivity(android.content.Intent) startActivity()}, your -application will be listed as an option in the intent chooser. If the user selects your application, -the corresponding activity (<code>.ui.MyActivity</code> in the example above) will be started. It +application will be listed as an option in the intent chooser. If the user selects your application, +the corresponding activity (<code>.ui.MyActivity</code> in the example above) will be started. It is then up to you to handle the content appropriately within your code and UI.</p> <h2 id="handling-content">Handle the Incoming Content</h2> <p>To handle the content delivered by an {@link android.content.Intent}, start by calling {@link -android.content.Intent#getIntent(String) getIntent()} -to get {@link android.content.Intent} object. Once you have the object, you can examine its -contents to determine what to do next. Keep in mind that if this activity can be started from other -parts of the system, such as the launcher, then you will need to take this into consideration when +android.content.Intent#getIntent(String) getIntent()} +to get {@link android.content.Intent} object. Once you have the object, you can examine its +contents to determine what to do next. Keep in mind that if this activity can be started from other +parts of the system, such as the launcher, then you will need to take this into consideration when examining the intent.</p> <pre> @@ -143,7 +143,7 @@ know what some other application may send you. For example, the wrong MIME type image being sent might be extremely large. Also, remember to process binary data in a separate thread rather than the main ("UI") thread.</p> -<p>Updating the UI can be as simple as populating an {@link android.widget.EditText}, or it can -be more complicated like applying an interesting photo filter to an image. It's really specific +<p>Updating the UI can be as simple as populating an {@link android.widget.EditText}, or it can +be more complicated like applying an interesting photo filter to an image. It's really specific to your application what happens next.</p> diff --git a/docs/html/training/sharing/send.jd b/docs/html/training/sharing/send.jd index ed9e12e..f5da68f 100644 --- a/docs/html/training/sharing/send.jd +++ b/docs/html/training/sharing/send.jd @@ -1,9 +1,9 @@ -page.title=Sending Content to Other Apps -parent.title=Sharing Content +page.title=Sending Simple Data to Other Apps +parent.title=Sharing Simple Data parent.link=index.html trainingnavtop=true -next.title=Receiving Content from Other Apps +next.title=Receiving Simple Data from Other Apps next.link=receive.html @jd:body @@ -29,22 +29,22 @@ Intent Filters</a></li> </div> </div> -<p>When you construct an intent, you must specify the action you want the intent to "trigger." -Android defines several actions, including {@link android.content.Intent#ACTION_SEND} which, as -you can probably guess, indicates that the intent is sending data from one activity to another, -even across process boundaries. To send data to another activity, all you need to do is specify -the data and its type, the system will identify compatible receiving activities and display them -to the user (if there are multiple options) or immediately start the activity (if there is only -one option). Similarly, you can advertise the data types that your activities support receiving +<p>When you construct an intent, you must specify the action you want the intent to "trigger." +Android defines several actions, including {@link android.content.Intent#ACTION_SEND} which, as +you can probably guess, indicates that the intent is sending data from one activity to another, +even across process boundaries. To send data to another activity, all you need to do is specify +the data and its type, the system will identify compatible receiving activities and display them +to the user (if there are multiple options) or immediately start the activity (if there is only +one option). Similarly, you can advertise the data types that your activities support receiving from other applications by specifying them in your manifest.</p> -<p>Sending and receiving data between applications with intents is most commonly used for social -sharing of content. Intents allow users to share information quickly and easily, using their +<p>Sending and receiving data between applications with intents is most commonly used for social +sharing of content. Intents allow users to share information quickly and easily, using their favorite applications.</p> -<p><strong>Note:</strong> The best way to add a share action item to an -{@link android.app.ActionBar} is to use {@link android.widget.ShareActionProvider}, which became -available in API level 14. {@link android.widget.ShareActionProvider} is discussed in the lesson +<p><strong>Note:</strong> The best way to add a share action item to an +{@link android.app.ActionBar} is to use {@link android.widget.ShareActionProvider}, which became +available in API level 14. {@link android.widget.ShareActionProvider} is discussed in the lesson about <a href="shareaction.html">Adding an Easy Share Action</a>.</p> @@ -58,10 +58,10 @@ on a handset. </p> </div> -<p>The most straightforward and common use of the {@link android.content.Intent#ACTION_SEND} -action is sending text content from one activity to another. For example, the built-in Browser -app can share the URL of the currently-displayed page as text with any application. This is useful -for sharing an article or website with friends via email or social networking. Here is the code to +<p>The most straightforward and common use of the {@link android.content.Intent#ACTION_SEND} +action is sending text content from one activity to another. For example, the built-in Browser +app can share the URL of the currently-displayed page as text with any application. This is useful +for sharing an article or website with friends via email or social networking. Here is the code to implement this type of sharing:</p> <pre> @@ -72,12 +72,12 @@ sendIntent.setType("text/plain"); startActivity(sendIntent); </pre> -<p>If there's an installed application with a filter that matches -{@link android.content.Intent#ACTION_SEND} and MIME type text/plain, the Android system will run -it; if more than one application matches, the system displays a disambiguation dialog (a "chooser") -that allows the user to choose an app. If you call +<p>If there's an installed application with a filter that matches +{@link android.content.Intent#ACTION_SEND} and MIME type text/plain, the Android system will run +it; if more than one application matches, the system displays a disambiguation dialog (a "chooser") +that allows the user to choose an app. If you call {@link android.content.Intent#createChooser(android.content.Intent, CharSequence) -Intent.createChooser()} +Intent.createChooser()} for the intent, Android will <strong>always</strong> display the chooser. This has some advantages:</p> @@ -100,17 +100,17 @@ startActivity(<strong>Intent.createChooser(sendIntent, getResources().getText(R. <p>The resulting dialog is shown in figure 1.</p> -<p>Optionally, you can set some standard extras for the intent: -{@link android.content.Intent#EXTRA_EMAIL}, {@link android.content.Intent#EXTRA_CC}, -{@link android.content.Intent#EXTRA_BCC}, {@link android.content.Intent#EXTRA_SUBJECT}. However, -if the receiving application is not designed to use them, nothing will happen. You can use -custom extras as well, but there's no effect unless the receiving application understands them. +<p>Optionally, you can set some standard extras for the intent: +{@link android.content.Intent#EXTRA_EMAIL}, {@link android.content.Intent#EXTRA_CC}, +{@link android.content.Intent#EXTRA_BCC}, {@link android.content.Intent#EXTRA_SUBJECT}. However, +if the receiving application is not designed to use them, nothing will happen. You can use +custom extras as well, but there's no effect unless the receiving application understands them. Typically, you'd use custom extras defined by the receiving application itself.</p> -<p class="note"><strong>Note:</strong> Some e-mail applications, such as Gmail, expect a -{@link java.lang.String String[]} for extras like {@link android.content.Intent#EXTRA_EMAIL} and -{@link android.content.Intent#EXTRA_CC}, use -{@link android.content.Intent#putExtra(String,String[]) putExtra(String, String[])} to add these +<p class="note"><strong>Note:</strong> Some e-mail applications, such as Gmail, expect a +{@link java.lang.String String[]} for extras like {@link android.content.Intent#EXTRA_EMAIL} and +{@link android.content.Intent#EXTRA_CC}, use +{@link android.content.Intent#putExtra(String,String[]) putExtra(String, String[])} to add these to your intent.</p> diff --git a/docs/html/training/sharing/shareaction.jd b/docs/html/training/sharing/shareaction.jd index 873f614..ee811da 100644 --- a/docs/html/training/sharing/shareaction.jd +++ b/docs/html/training/sharing/shareaction.jd @@ -3,7 +3,7 @@ parent.title=Sharing Content parent.link=index.html trainingnavtop=true -previous.title=Receiving Content from Other Apps +previous.title=Receiving Simple Data from Other Apps previous.link=receive.html @jd:body @@ -28,7 +28,7 @@ previous.link=receive.html </div> -<p>Implementing an effective and user friendly share action in your {@link android.app.ActionBar} +<p>Implementing an effective and user friendly share action in your {@link android.app.ActionBar} is made even easier with the introduction of {@link android.view.ActionProvider} in Android 4.0 (API Level 14). An {@link android.view.ActionProvider}, once attached to a menu item in the action bar, handles both the appearance and behavior of that item. In the case of {@link @@ -47,36 +47,48 @@ starting with API Level 14 and higher.</p> <h2 id="update-menus">Update Menu Declarations</h2> -<p>To get started with {@link android.widget.ShareActionProvider ShareActionProviders}, define the <code>android:actionProviderClass</code> attribute for the corresponding <code><item></code> in your <a href="{@docRoot}guide/topics/resources/menu-resource.html">menu resource</a> file:</p> +<p> + To get started with {@link android.widget.ShareActionProvider ShareActionProviders}, + define the <code>android:actionProviderClass</code> attribute for the corresponding + <code><item></code> in your <a href="{@docRoot}guide/topics/resources/menu-resource.html" + >menu resource</a> file:</p> <pre> <menu xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:id="@+id/menu_item_share" - android:showAsAction="ifRoom" - android:title="Share" - <strong>android:actionProviderClass="android.widget.ShareActionProvider"</strong> /> + <item + android:id="@+id/menu_item_share" + android:showAsAction="ifRoom" + android:title="Share" + <b>android:actionProviderClass= + "android.widget.ShareActionProvider"</b> /> ... </menu> </pre> -<p>This delegates responsibility for the item's appearance and function to -{@link android.widget.ShareActionProvider}. However, you will need to tell the provider what you -would like to share.</p> +<p> + This delegates responsibility for the item's appearance and function to + {@link android.widget.ShareActionProvider}. However, you will need to tell the provider what you + would like to share. +</p> <h2 id="set-share-intent">Set the Share Intent</h2> -<p>In order for {@link android.widget.ShareActionProvider} to function, you must provide it a share -intent. This share intent should be the same as described in the <a -href="{@docRoot}training/sharing/send.html">Sending Content to Other Apps</a> -lesson, with action {@link android.content.Intent#ACTION_SEND} and additional data set via extras -like {@link android.content.Intent#EXTRA_TEXT} and {@link android.content.Intent#EXTRA_STREAM}. To -assign a share intent, first find the corresponding {@link android.view.MenuItem} while inflating -your menu resource in your {@link android.app.Activity} or {@link android.app.Fragment}. Next, call -{@link android.view.MenuItem#getActionProvider() MenuItem.getActionProvider()} to retreive an -instance of {@link android.widget.ShareActionProvider}. Use {@link -android.widget.ShareActionProvider#setShareIntent(android.content.Intent) setShareIntent()} to -update the share intent associated with that action item. Here's an example:</p> +<p> + In order for {@link android.widget.ShareActionProvider} to function, you must provide it a share + intent. This share intent should be the same as described in the + <a href="{@docRoot}training/sharing/send.html">Sending Simple Data to Other Apps</a> lesson, + with action {@link android.content.Intent#ACTION_SEND} and additional data set via extras + like {@link android.content.Intent#EXTRA_TEXT} and {@link android.content.Intent#EXTRA_STREAM}. + To assign a share intent, first find the corresponding {@link android.view.MenuItem} while + inflating your menu resource in your {@link android.app.Activity} or + {@link android.app.Fragment}. Next, call {@link android.view.MenuItem#getActionProvider + MenuItem.getActionProvider()} to retrieve an instance of + {@link android.widget.ShareActionProvider}. Use + {@link android.widget.ShareActionProvider#setShareIntent(android.content.Intent) + setShareIntent()} to update the share intent associated with that action item. Here's an + example: +</p> <pre> private ShareActionProvider mShareActionProvider; @@ -105,8 +117,8 @@ private void setShareIntent(Intent shareIntent) { } </pre> -<p>You may only need to set the share intent once during the creation of your menus, or you may -want to set it and then update it as the UI changes. For example, when you view photos full screen +<p>You may only need to set the share intent once during the creation of your menus, or you may +want to set it and then update it as the UI changes. For example, when you view photos full screen in the Gallery app, the sharing intent changes as you flip between photos.</p> <p>For further discussion about the {@link android.widget.ShareActionProvider} object, see the <a diff --git a/docs/html/training/training_toc.cs b/docs/html/training/training_toc.cs index 27e7004..a66b773 100644 --- a/docs/html/training/training_toc.cs +++ b/docs/html/training/training_toc.cs @@ -192,33 +192,91 @@ include the action bar on devices running Android 2.1 or higher." </ul> </li> - <li class="nav-section"> + </ul> + </li><!-- end getting started --> + <li class="nav-section"> <div class="nav-section-header"> - <a href="<?cs var:toroot ?>training/sharing/index.html" - description= - "How to take your app interaction to the next level by sharing - information with other apps, receive information back, and provide a simple and - scalable way to perform Share actions with user content." - >Sharing Content</a> + <a href="<?cs var:toroot ?>training/building-content-sharing.html"> + <span class="small">Building Apps with</span><br/>Content Sharing + </a> </div> <ul> - <li><a href="<?cs var:toroot ?>training/sharing/send.html"> - Sending Content to Other Apps - </a> - </li> - <li><a href="<?cs var:toroot ?>training/sharing/receive.html"> - Receiving Content from Other Apps - </a> - </li> - <li><a href="<?cs var:toroot ?>training/sharing/shareaction.html"> - Adding an Easy Share Action - </a> - </li> + <li class="nav-section"> + <div class="nav-section-header"> + <a href="<?cs var:toroot ?>training/sharing/index.html" + description= + "How to take your app interaction to the next level by sharing + information with other apps, receive information back, and provide a simple and + scalable way to perform Share actions with user content." + >Sharing Simple Data</a> + </div> + <ul> + <li> + <a href="<?cs var:toroot ?>training/sharing/send.html"> + Sending Simple Data to Other Apps + </a> + </li> + <li> + <a href="<?cs var:toroot ?>training/sharing/receive.html"> + Receiving Simple Data from Other Apps + </a> + </li> + <li> + <a href="<?cs var:toroot ?>training/sharing/shareaction.html"> + Adding an Easy Share Action + </a> + </li> + </ul> + </li> + <li class="nav-section"> + <div class="nav-section-header"> + <a href="<?cs var:toroot?>training/secure-file-sharing/index.html" + description= + "How to provide secure access to a file associated with your app using a content + URI and temporary access permissions." + >Sharing Files</a> + </div> + <ul> + <li> + <a href="<?cs var:toroot ?>training/secure-file-sharing/setup-sharing.html"> + Setting Up File Sharing + </a> + </li> + <li> + <a href="<?cs var:toroot ?>training/secure-file-sharing/share-file.html"> + Sharing a File + </a> + </li> + <li> + <a href="<?cs var:toroot ?>training/secure-file-sharing/request-file.html"> + Requesting a Shared File + </a> + </li> + <li> + <a href="<?cs var:toroot ?>training/secure-file-sharing/retrieve-info.html"> + Retrieving File Information + </a> + </li> + </ul> + </li> + <li class="nav-section"> + <div class="nav-section-header"> + <a href="<?cs var:toroot ?>training/beam-files/index.html" + description= + "How to transfer files between devices using the NFC Android Beam feature." + >Sharing Files with NFC</a> + </div> + <ul> + <li> + <a href="<?cs var:toroot ?>training/beam-files/send-files.html" + >Sending Files to Another Device</a> + </li> + <li><a href="<?cs var:toroot ?>training/beam-files/receive-files.html" + >Receiving Files from Another Device</a></li> + </ul> + </li> </ul> - </li> - </ul> - </li><!-- end getting started --> - + </li> @@ -423,22 +481,6 @@ include the action bar on devices running Android 2.1 or higher." </li> </ul> </li> - <li class="nav-section"> - <div class="nav-section-header"> - <a href="<?cs var:toroot ?>training/beam-files/index.html" - description= - "How to transfer files between devices using the NFC Android Beam feature." - >Sharing Files with NFC</a> - </div> - <ul> - <li> - <a href="<?cs var:toroot ?>training/beam-files/send-files.html" - >Sending Files to Another Device</a> - </li> - <li><a href="<?cs var:toroot ?>training/beam-files/receive-files.html" - >Receiving Files from Another Device</a></li> - </ul> - </li> <li class="nav-section"> <div class="nav-section-header"> <a href="<?cs var:toroot ?>training/basics/network-ops/index.html" |