diff --git a/docs/html/training/beam-files/index.jd b/docs/html/training/beam-files/index.jd new file mode 100644 index 0000000000000..71550924a8f8d --- /dev/null +++ b/docs/html/training/beam-files/index.jd @@ -0,0 +1,61 @@ +page.title=Sharing Files with NFC + +trainingnavtop=true +startpage=true + + +@jd:body + +
+ Android allows you to transfer large files between devices using the Android Beam file transfer + feature. This feature has a simple API and allows users to start the transfer process by simply + touching devices. In response, Android Beam file transfer automatically copies files from one + device to the other and notifies the user when it's finished. +
++ While the Android Beam file transfer API handles large amounts of data, the Android Beam NDEF + transfer API introduced in Android 4.0 (API level 14) handles small amounts of data such as + URIs or other small messages. In addition, Android Beam is only one of the features available + in the Android NFC framework, which allows you to read NDEF messages from NFC tags. To learn + more about Android Beam, see the topic + Beaming NDEF Messages to Other Devices. To learn more about the NFC framework, see the + Near Field Communication API guide. +
++ Android Beam file transfer copies files to a special directory on the receiving device. It also + scans the copied files using the Android Media Scanner and adds entries for media files to + the {@link android.provider.MediaStore} provider. This lesson shows you how to respond when the + file copy is complete, and how to locate the copied files on the receiving device. +
+
+ When Android Beam file transfer finishes copying files to the receiving device, it posts a
+ notification containing an {@link android.content.Intent} with the action
+ {@link android.content.Intent#ACTION_VIEW ACTION_VIEW}, the MIME type of the first file that
+ was transferred, and a URI that points to the first file. When the user clicks the notification,
+ this intent is sent out to the system. To have your app respond to this intent, add an
+ <intent-filter> element for the
+ <activity> element of the {@link android.app.Activity} that should respond.
+ In the <intent-filter> element, add the following child elements:
+
<action android:name="android.intent.action.VIEW" />
+ <category android:name="android.intent.category.CATEGORY_DEFAULT" />
+ <data android:mimeType="mime-type" />
+
+ For example, the following snippet shows you how to add an intent filter that
+ triggers the activity com.example.android.nfctransfer.ViewActivity:
+
+ <activity + android:name="com.example.android.nfctransfer.ViewActivity" + android:label="Android Beam Viewer" > + ... + <intent-filter> + <action android:name="android.intent.action.VIEW"/> + <category android:name="android.intent.category.DEFAULT"/> + ... + </intent-filter> + </activity> ++
+ Note: Android Beam file transfer is not the only source of an + {@link android.content.Intent#ACTION_VIEW ACTION_VIEW} intent. Other apps on the receiving + device can also send an {@link android.content.Intent} with this action. + Handling this situation is discussed in the section Get the directory from a content URI. +
++ To read files that Android Beam file transfer copies to the device, request the permission + {@link android.Manifest.permission#READ_EXTERNAL_STORAGE READ_EXTERNAL_STORAGE}. For example: +
++ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />+
+ If you want to copy transferred files to your app's own storage area, request the permission + {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE WRITE_EXTERNAL_STORAGE} instead. + {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE WRITE_EXTERNAL_STORAGE} includes + {@link android.Manifest.permission#READ_EXTERNAL_STORAGE READ_EXTERNAL_STORAGE}. +
++ Note: As of Android 4.2.2 (API level 17), the permission + {@link android.Manifest.permission#READ_EXTERNAL_STORAGE READ_EXTERNAL_STORAGE} is + only enforced if the user chooses to do so. Future versions of the platform may require this + permission in all cases. To ensure forward compatibility, request the permission now, before it + becomes required. +
++ Since your app has control over its internal storage area, you don't need to request + write permission to copy a transferred file to your internal storage area. +
++ Android Beam file transfer copies all the files in a single transfer to one directory + on the receiving device. The URI in the content {@link android.content.Intent} sent by the + Android Beam file transfer notification points to the first transferred file. However, your + app may also receive an {@link android.content.Intent#ACTION_VIEW ACTION_VIEW} intent from a + source other than Android Beam file transfer. To determine how you should handle the incoming + {@link android.content.Intent}, you need to examine its scheme and authority. +
++ To get the scheme for the URI, call {@link android.net.Uri#getScheme() Uri.getScheme()}. The + following code snippet shows you how to determine the scheme and handle the URI accordingly: +
+
+public class MainActivity extends Activity {
+ ...
+ // A File object containing the path to the transferred files
+ private File mParentPath;
+ // Incoming Intent
+ private Intent mIntent;
+ ...
+ /*
+ * Called from onNewIntent() for a SINGLE_TOP Activity
+ * or onCreate() for a new Activity. For onNewIntent(),
+ * remember to call setIntent() to store the most
+ * current Intent
+ *
+ */
+ private void handleViewIntent() {
+ ...
+ // Get the Intent action
+ mIntent = getIntent();
+ String action = mIntent.getAction();
+ /*
+ * For ACTION_VIEW, the Activity is being asked to display data.
+ * Get the URI.
+ */
+ if (TextUtils.equals(action, Intent.ACTION_VIEW)) {
+ // Get the URI from the Intent
+ Uri beamUri = mIntent.getData();
+ /*
+ * Test for the type of URI, by getting its scheme value
+ */
+ if (TextUtils.equals(beamUri.getScheme(), "file")) {
+ mParentPath = handleFileUri(beamUri);
+ } else if (TextUtils.equals(
+ beamUri.getScheme(), "content")) {
+ mParentPath = handleContentUri(beamUri);
+ }
+ }
+ ...
+ }
+ ...
+}
+
+
+ If the incoming {@link android.content.Intent} contains a file URI, the URI contains the
+ absolute file name of a file, including the full directory path and file name. For Android Beam
+ file transfer, the directory path points to the location of the other transferred files, if
+ any. To get the directory path, get the path part of the URI, which contains all of the URI
+ except the file: prefix. Create a {@link java.io.File} from the path part, then
+ get the parent path of the {@link java.io.File}:
+
+ ...
+ public String handleFileUri(Uri beamUri) {
+ // Get the path part of the URI
+ String fileName = beamUri.getPath();
+ // Create a File object for this filename
+ File copiedFile = new File(fileName);
+ // Get a string containing the file's parent directory
+ return copiedFile.getParent();
+ }
+ ...
+
+
++ If the incoming {@link android.content.Intent} contains a content URI, the URI may point to a + directory and file name stored in the {@link android.provider.MediaStore} content provider. You + can detect a content URI for {@link android.provider.MediaStore} by testing the URI's + authority value. A content URI for {@link android.provider.MediaStore} may come from + Android Beam file transfer or from another app, but in both cases you can retrieve a directory + and file name for the content URI. +
++ You can also receive an incoming {@link android.content.Intent#ACTION_VIEW ACTION_VIEW} + intent containing a content URI for a content provider other than + {@link android.provider.MediaStore}. In this case, the content URI doesn't contain the + {@link android.provider.MediaStore} authority value, and the content URI usually doesn't point + to a directory. +
++ Note: For Android Beam file transfer, you receive a content URI in the + {@link android.content.Intent#ACTION_VIEW ACTION_VIEW} intent if the first incoming file + has a MIME type of "audio/*", "image/*", or "video/*", indicating that the file is media- + related. Android Beam file transfer indexes the media files it transfers by running Media + Scanner on the directory where it stores transferred files. Media Scanner writes its results + to the {@link android.provider.MediaStore} content provider, then it passes a content URI + for the first file back to Android Beam file transfer. This content URI is the one you + receive in the notification {@link android.content.Intent}. To get the directory + of the first file, you retrieve it from {@link android.provider.MediaStore} using the content + URI. +
++ To determine if you can retrieve a file directory from the content URI, determine the + the content provider associated with the URI by calling + {@link android.net.Uri#getAuthority Uri.getAuthority()} to get the URI's authority. The + result has two possible values: +
++ To get the directory for a {@link android.provider.MediaStore} content URI, + run a query that specifies the incoming content URI for the {@link android.net.Uri} argument and + the column {@link android.provider.MediaStore.MediaColumns#DATA MediaColumns.DATA} for the + projection. The returned {@link android.database.Cursor} contains the full path and name for + the file represented by the URI. This path also contains all the other files that Android Beam + file transfer just copied to the device. +
++ The following snippet shows you how to test the authority of the content URI and retrieve the + the path and file name for the transferred file: +
+
+ ...
+ public String handleContentUri(Uri beamUri) {
+ // Position of the filename in the query Cursor
+ int filenameIndex;
+ // File object for the filename
+ File copiedFile;
+ // The filename stored in MediaStore
+ String fileName;
+ // Test the authority of the URI
+ if (!TextUtils.equals(beamUri.getAuthority(), MediaStore.AUTHORITY)) {
+ /*
+ * Handle content URIs for other content providers
+ */
+ // For a MediaStore content URI
+ } else {
+ // Get the column that contains the file name
+ String[] projection = { MediaStore.MediaColumns.DATA };
+ Cursor pathCursor =
+ getContentResolver().query(beamUri, projection,
+ null, null, null);
+ // Check for a valid cursor
+ if (pathCursor != null &&
+ pathCursor.moveToFirst()) {
+ // Get the column index in the Cursor
+ filenameIndex = pathCursor.getColumnIndex(
+ MediaStore.MediaColumns.DATA);
+ // Get the full file name including path
+ fileName = pathCursor.getString(filenameIndex);
+ // Create a File object for the filename
+ copiedFile = new File(fileName);
+ // Return the parent directory of the file
+ return new File(copiedFile.getParent());
+ } else {
+ // The query didn't work; return null
+ return null;
+ }
+ }
+ }
+ ...
+
++ To learn more about retrieving data from a content provider, see the section + Retrieving Data from the Provider. +
diff --git a/docs/html/training/beam-files/send-files.jd b/docs/html/training/beam-files/send-files.jd new file mode 100644 index 0000000000000..917b87f11594f --- /dev/null +++ b/docs/html/training/beam-files/send-files.jd @@ -0,0 +1,294 @@ +page.title=Sending Files to Another Device + +trainingnavtop=true +@jd:body + + ++ This lesson shows you how to design your app to send large files to another device using + Android Beam file transfer. To send files, you request permission to use NFC and external + storage, test to ensure your device supports NFC, and provide URIs to Android Beam file + transfer. +
++ The Android Beam file transfer feature has the following requirements: +
++ First, edit your app manifest to declare the permissions and features your app needs. +
++ To allow your app to use Android Beam file transfer to send files from external storage using + NFC, you must request the following permissions in your app manifest: +
+<manifest> element:
++ <uses-permission android:name="android.permission.NFC" /> ++
<manifest> element:
++ <uses-permission + android:name="android.permission.READ_EXTERNAL_STORAGE" /> ++
+ Note: As of Android 4.2.2 (API level 17), this permission is not + enforced. Future versions of the platform may require it for apps that want to read from + external storage. To ensure forward compatibility, request the permission now, before it + becomes required. +
+
+ Specify that your app uses NFC, by adding a
+ <uses-feature> element as a child
+ of the <manifest> element. Set the android:required attribute to
+ true to indicate that your app won't function unless NFC is present.
+
+ The following snippet shows you how to specify the
+ <uses-feature> element:
+
+<uses-feature + android:name="android.hardware.nfc" + android:required="true" />+
+ Note that if your app only uses NFC as an option, but still functions if NFC isn't present, you
+ should set android:required to false, and test for NFC in code.
+
+ Since Android Beam file transfer is only available in Android 4.1 (API level 16) and later,
+ if your app depends on Android Beam file transfer for a key part of its functionality you must
+ specify the <uses-sdk> element with the
+ android:minSdkVersion="16" attribute. Otherwise, you can set
+ android:minSdkVersion to another value as necessary, and test for the platform
+ version in code, as described in the following section.
+
+ To specify in your app manifest that NFC is optional, you use the following element: +
++<uses-feature android:name="android.hardware.nfc" android:required="false" />+
+ If you set the attribute
+ android:required="false", you must test for NFC support and Android Beam file
+ transfer support in code.
+
+ To test for Android Beam file transfer support in code, start by testing that the device + supports NFC by calling {@link android.content.pm.PackageManager#hasSystemFeature + PackageManager.hasSystemFeature()} with the argument + {@link android.content.pm.PackageManager#FEATURE_NFC FEATURE_NFC}. Next, check that the Android + version supports Android Beam file transfer by testing the value of + {@link android.os.Build.VERSION#SDK_INT}. If Android Beam file transfer is supported, get an + instance of the NFC controller, which allows you to communicate with the NFC hardware. + For example: +
+
+public class MainActivity extends Activity {
+ ...
+ NfcAdapter mNfcAdapter;
+ // Flag to indicate that Android Beam is available
+ boolean mAndroidBeamAvailable = false;
+ ...
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ ...
+ // NFC isn't available on the device
+ if (!PackageManager.hasSystemFeature(PackageManager.FEATURE_NFC)) {
+ /*
+ * Disable NFC features here.
+ * For example, disable menu items or buttons that activate
+ * NFC-related features
+ */
+ ...
+ // Android Beam file transfer isn't supported
+ } else if (Build.VERSION.SDK_INT <
+ Build.VERSION_CODES.JELLY_BEAN_MR1) {
+ // If Android Beam isn't available, don't continue.
+ mAndroidBeamAvailable = false;
+ /*
+ * Disable Android Beam file transfer features here.
+ */
+ ...
+ // Android Beam file transfer is available, continue
+ } else {
+ mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
+ ...
+ }
+ }
+ ...
+}
+
++ Once you've verified that the device supports Android Beam file transfer, add a callback + method that the system invokes when Android Beam file transfer detects that the user wants + to send files to another NFC-enabled device. In this callback method, return an array of + {@link android.net.Uri} objects. Android Beam file transfer copies the files represented by + these URIs to the receiving device. +
++ To add the callback method, implement the + {@link android.nfc.NfcAdapter.CreateBeamUrisCallback} interface and its method + {@link android.nfc.NfcAdapter.CreateBeamUrisCallback#createBeamUris createBeamUris()}. The + following snippet shows you how to do this: +
+
+public class MainActivity extends Activity {
+ ...
+ // List of URIs to provide to Android Beam
+ private Uri[] mFileUris = new Uri[10];
+ ...
+ /**
+ * Callback that Android Beam file transfer calls to get
+ * files to share
+ */
+ private class FileUriCallback implements
+ NfcAdapter.CreateBeamUrisCallback {
+ public FileUriCallback() {
+ }
+ /**
+ * Create content URIs as needed to share with another device
+ */
+ @Override
+ public Uri[] createBeamUris(NfcEvent event) {
+ return mFileUris;
+ }
+ }
+ ...
+}
+
++ Once you've implemented the interface, provide the callback to Android Beam file transfer by + calling {@link android.nfc.NfcAdapter#setBeamPushUrisCallback setBeamPushUrisCallback()}. The + following snippet shows you how to do this: +
+
+public class MainActivity extends Activity {
+ ...
+ // Instance that returns available files from this app
+ private FileUriCallback mFileUriCallback;
+ ...
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ ...
+ // Android Beam file transfer is available, continue
+ ...
+ mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
+ /*
+ * Instantiate a new FileUriCallback to handle requests for
+ * URIs
+ */
+ mFileUriCallback = new FileUriCallback();
+ // Set the dynamic callback for URI requests.
+ mNfcAdapter.setBeamPushUrisCallback(mFileUriCallback,this);
+ ...
+ }
+ ...
+}
+
++ Note: You can also provide the array of {@link android.net.Uri} objects + directly to the NFC framework through your app's {@link android.nfc.NfcAdapter} instance. Choose + this approach if you can define the URIs to transfer before the NFC touch event occurs. + To learn more about this approach, see {@link android.nfc.NfcAdapter#setBeamPushUris + NfcAdapter.setBeamPushUris()}. +
+
+ To transfer one or more files to another NFC-enabled device, get a file URI (a URI with a
+ file scheme) for each file and then add the URI to an array of
+ {@link android.net.Uri} objects. To transfer a file, you must also have permanent read access
+ for the file. For example, the following snippet shows you how to get a file URI from a file
+ name and then add the URI to the array:
+
+ /*
+ * Create a list of URIs, get a File,
+ * and set its permissions
+ */
+ private Uri[] mFileUris = new Uri[10];
+ String transferFile = "transferimage.jpg";
+ File extDir = getExternalFilesDir(null);
+ File requestFile = new File(extDir, transferFile);
+ requestFile.setReadable(true, false);
+ // Get a URI for the File and add it to the list of URIs
+ fileUri = Uri.fromFile(requestFile);
+ if (fileUri != null) {
+ mFileUris[0] = fileUri;
+ } else {
+ Log.e("My Activity", "No File URI available for file.");
+ }
+
diff --git a/docs/html/training/training_toc.cs b/docs/html/training/training_toc.cs
index 77ac235e88601..27e7004cadba7 100644
--- a/docs/html/training/training_toc.cs
+++ b/docs/html/training/training_toc.cs
@@ -423,7 +423,22 @@ include the action bar on devices running Android 2.1 or higher."
-
+