page.title=Sending Files to Another Device

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="#DeclareFeatures">Declare Features in the Manifest</a>
  <li><a href="#TestAndroidBeam">Test for Android Beam File Transfer Support</a></li>
  <li>
    <a href="#CreateCallback"
    >Create a Callback Method That Provides Files</a>
  </li>
  <li><a href="#ProvideUri">Specify the Files to Send</a>
</ol>

<h2>You should also read</h2>
<ul>
    <li><a href="{@docRoot}guide/topics/data/data-storage.html">Storage Options</a></li>
</ul>

</div>
</div>
<p>
    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.
</p>
<p>
    The Android Beam file transfer feature has the following requirements:
</p>
<ol>
    <li>
        Android Beam file transfer for large files is only available in Android 4.1 (API level 16)
        and higher.
    </li>
    <li>
        Files you want to transfer must reside in external storage. To learn more about using
        external storage, read <a href="{@docRoot}guide/topics/data/data-storage.html#filesExternal"
        >Using the External Storage</a>.
    </li>
    <li>
        Each file you want to transfer must be world-readable. You can set this permission by
        calling the method {@link java.io.File#setReadable File.setReadable(true,false)}.
    </li>
    <li>
        You must provide a file URI for the files you want to transfer. Android Beam file transfer
        is unable to handle content URIs generated by
        {@link android.support.v4.content.FileProvider#getUriForFile FileProvider.getUriForFile}.
    </li>
</ol>

<h2 id="DeclareFeatures">Declare Features in the Manifest</h2>
<p>
    First, edit your app manifest to declare the permissions and features your app needs.
</p>
<h3>Request Permissions</h3>
<p>
    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:
</p>
<dl>
    <dt>
        {@link android.Manifest.permission#NFC NFC}
    </dt>
    <dd>
        Allows your app to send data over NFC. To specify this permission, add the following element
        as a child of the <code><a href="{@docRoot}guide/topics/manifest/manifest-element.html"
        >&lt;manifest&gt;</a></code> element:
<pre>
    &lt;uses-permission android:name="android.permission.NFC" /&gt;
</pre>
    </dd>
    <dt>
        {@link android.Manifest.permission#READ_EXTERNAL_STORAGE READ_EXTERNAL_STORAGE}
    </dt>
    <dd>
        Allows your app to read from external storage. To specify this permission, add the following
        element as a child of the
        <code><a href="{@docRoot}guide/topics/manifest/manifest-element.html"
        >&lt;manifest&gt;</a></code> element:
<pre>
    &lt;uses-permission
            android:name="android.permission.READ_EXTERNAL_STORAGE" /&gt;
</pre>
    <p class="note">
        <strong>Note:</strong> 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.
    </p>
    </dd>
</dl>
<h3>Specify the NFC feature</h3>
<p>
    Specify that your app uses NFC, by adding a
    <code><a href="{@docRoot}guide/topics/manifest/uses-feature-element.html"
    >&lt;uses-feature&gt;</a></code> element as a child
    of the <code><a href="{@docRoot}guide/topics/manifest/manifest-element.html"
    >&lt;manifest&gt;</a></code> element. Set the <code>android:required</code> attribute to
    <code>true</code> to indicate that your app won't function unless NFC is present.
</p>
<p>
    The following snippet shows you how to specify the
    <code><a href="{@docRoot}guide/topics/manifest/uses-feature-element.html"
    >&lt;uses-feature&gt;</a></code> element:
</p>
<pre>
&lt;uses-feature
    android:name="android.hardware.nfc"
    android:required="true" /&gt;</pre>
<p>
    Note that if your app only uses NFC as an option, but still functions if NFC isn't present, you
    should set <code>android:required</code> to <code>false</code>, and test for NFC in code.
</p>
<h3>Specify Android Beam file transfer</h3>
<p>
    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 <code><a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html"
    >&lt;uses-sdk&gt;</a></code> element with the
    <code><a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min"
    >android:minSdkVersion</a>="16"</code> attribute. Otherwise, you can set
    <code><a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min"
    >android:minSdkVersion</a></code> to another value as necessary, and test for the platform
    version in code, as described in the following section.
</p>
<h2 id="TestAndroidBeam">Test for Android Beam File Transfer Support</h2>
<p>
    To specify in your app manifest that NFC is optional, you use the following element:
</p>
<pre>
&lt;uses-feature android:name="android.hardware.nfc" android:required="false" /&gt;</pre>
<p>
    If you set the attribute
    <code><a href="{@docRoot}guide/topics/manifest/uses-feature-element.html#required"
    >android:required</a>="false"</code>, you must test for NFC support and Android Beam file
    transfer support in code.
</p>
<p>
    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:
</p>
<pre>
public class MainActivity extends Activity {
    ...
    NfcAdapter mNfcAdapter;
    // Flag to indicate that Android Beam is available
    boolean mAndroidBeamAvailable  = false;
    ...
    &#64;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 &lt;
                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);
        ...
        }
    }
    ...
}</pre>

<h2 id="CreateCallback">
    Create a Callback Method that Provides Files
</h2>
<p>
    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.
</p>
<p>
    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:
</p>
<pre>
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
         */
        &#64;Override
        public Uri[] createBeamUris(NfcEvent event) {
            return mFileUris;
        }
    }
    ...
}
</pre>
<p>
    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:
</p>
<pre>
public class MainActivity extends Activity {
    ...
    // Instance that returns available files from this app
    private FileUriCallback mFileUriCallback;
    ...
    &#64;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);
        ...
    }
    ...
}
</pre>
<p class="note">
    <strong>Note:</strong> 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()}.
</p>
<h2 id="ProvideUri">Specify the Files to Send</h2>
<p>
    To transfer one or more files to another NFC-enabled device, get a file URI (a URI with a
    <code>file</code> 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:
</p>
<pre>
        /*
         * 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.");
        }
</pre>