1page.title=Receiving Files from Another Device 2 3trainingnavtop=true 4@jd:body 5 6<div id="tb-wrapper"> 7<div id="tb"> 8 9<h2>This lesson teaches you to</h2> 10<ol> 11 <li><a href="#IntentFilter">Respond to a Request to Display Data</a></li> 12 <li><a href="#RequestPermissions">Request File Permissions</a></li> 13 <li><a href="#GetFilePath">Get the Directory for Copied Files</a></li> 14</ol> 15<h2>You should also read</h2> 16<ul> 17 <li> 18 <a href="{@docRoot}guide/topics/providers/content-provider-basics.html#ContentURIs" 19 >Content URIs</a> 20 </li> 21 <li> 22 <a href="{@docRoot}guide/components/intents-filters.html">Intents and Intent Filters</a> 23 </li> 24 <li> 25 <a href="{@docRoot}guide/topics/ui/notifiers/notifications.html">Notifications</a> 26 </li> 27 <li> 28 <a href="{@docRoot}guide/topics/data/data-storage.html#filesExternal" 29 >Using the External Storage</a> 30 </li> 31</ul> 32 33</div> 34</div> 35 36<p> 37 Android Beam file transfer copies files to a special directory on the receiving device. It also 38 scans the copied files using the Android Media Scanner and adds entries for media files to 39 the {@link android.provider.MediaStore} provider. This lesson shows you how to respond when the 40 file copy is complete, and how to locate the copied files on the receiving device. 41</p> 42<h2 id="IntentFilter">Respond to a Request to Display Data</h2> 43<p> 44 When Android Beam file transfer finishes copying files to the receiving device, it posts a 45 notification containing an {@link android.content.Intent} with the action 46 {@link android.content.Intent#ACTION_VIEW ACTION_VIEW}, the MIME type of the first file that 47 was transferred, and a URI that points to the first file. When the user clicks the notification, 48 this intent is sent out to the system. To have your app respond to this intent, add an 49 <code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html" 50 ><intent-filter></a></code> element for the 51 <code><a href="{@docRoot}guide/topics/manifest/activity-element.html" 52 ><activity></a></code> element of the {@link android.app.Activity} that should respond. 53 In the <code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html" 54 ><intent-filter></a></code> element, add the following child elements: 55</p> 56<dl> 57 <dt> 58 <code><a href="{@docRoot}guide/topics/manifest/action-element.html" 59 ><action android:name="android.intent.action.VIEW" /></a></code> 60 </dt> 61 <dd> 62 Matches the {@link android.content.Intent#ACTION_VIEW ACTION_VIEW} intent sent from the 63 notification. 64 </dd> 65 <dt> 66 <code><a href="{@docRoot}guide/topics/manifest/category-element.html" 67 ><category android:name="android.intent.category.CATEGORY_DEFAULT" /></a></code> 68 </dt> 69 <dd> 70 Matches an {@link android.content.Intent} that doesn't have an explicit category. 71 </dd> 72 <dt> 73 <code><a href="{@docRoot}guide/topics/manifest/data-element.html" 74 ><data android:mimeType="<i>mime-type</i>" /></a></code> 75 </dt> 76 <dd> 77 Matches a MIME type. Specify only those MIME types that your app can handle. 78 </dd> 79</dl> 80<p> 81 For example, the following snippet shows you how to add an intent filter that 82 triggers the activity <code>com.example.android.nfctransfer.ViewActivity</code>: 83</p> 84<pre> 85 <activity 86 android:name="com.example.android.nfctransfer.ViewActivity" 87 android:label="Android Beam Viewer" > 88 ... 89 <intent-filter> 90 <action android:name="android.intent.action.VIEW"/> 91 <category android:name="android.intent.category.DEFAULT"/> 92 ... 93 </intent-filter> 94 </activity> 95</pre> 96<p class="note"> 97 <strong>Note:</strong> Android Beam file transfer is not the only source of an 98 {@link android.content.Intent#ACTION_VIEW ACTION_VIEW} intent. Other apps on the receiving 99 device can also send an {@link android.content.Intent} with this action. 100 Handling this situation is discussed in the section <a href="#GetDirectory" 101 >Get the directory from a content URI</a>. 102</p> 103<h2 id="RequestPermissions">Request File Permissions</h2> 104<p> 105 To read files that Android Beam file transfer copies to the device, request the permission 106 {@link android.Manifest.permission#READ_EXTERNAL_STORAGE READ_EXTERNAL_STORAGE}. For example: 107</p> 108<pre> 109 <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /></pre> 110<p> 111 If you want to copy transferred files to your app's own storage area, request the permission 112 {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE WRITE_EXTERNAL_STORAGE} instead. 113 {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE WRITE_EXTERNAL_STORAGE} includes 114 {@link android.Manifest.permission#READ_EXTERNAL_STORAGE READ_EXTERNAL_STORAGE}. 115</p> 116<p class="note"> 117 <strong>Note:</strong> As of Android 4.2.2 (API level 17), the permission 118 {@link android.Manifest.permission#READ_EXTERNAL_STORAGE READ_EXTERNAL_STORAGE} is 119 only enforced if the user chooses to do so. Future versions of the platform may require this 120 permission in all cases. To ensure forward compatibility, request the permission now, before it 121 becomes required. 122</p> 123<p> 124 Since your app has control over its internal storage area, you don't need to request 125 write permission to copy a transferred file to your internal storage area. 126</p> 127<h2 id="GetFilePath">Get the Directory for Copied Files</h2> 128<p> 129 Android Beam file transfer copies all the files in a single transfer to one directory 130 on the receiving device. The URI in the content {@link android.content.Intent} sent by the 131 Android Beam file transfer notification points to the first transferred file. However, your 132 app may also receive an {@link android.content.Intent#ACTION_VIEW ACTION_VIEW} intent from a 133 source other than Android Beam file transfer. To determine how you should handle the incoming 134 {@link android.content.Intent}, you need to examine its scheme and authority. 135</p> 136<p> 137 To get the scheme for the URI, call {@link android.net.Uri#getScheme() Uri.getScheme()}. The 138 following code snippet shows you how to determine the scheme and handle the URI accordingly: 139</p> 140<pre> 141public class MainActivity extends Activity { 142 ... 143 // A File object containing the path to the transferred files 144 private File mParentPath; 145 // Incoming Intent 146 private Intent mIntent; 147 ... 148 /* 149 * Called from onNewIntent() for a SINGLE_TOP Activity 150 * or onCreate() for a new Activity. For onNewIntent(), 151 * remember to call setIntent() to store the most 152 * current Intent 153 * 154 */ 155 private void handleViewIntent() { 156 ... 157 // Get the Intent action 158 mIntent = getIntent(); 159 String action = mIntent.getAction(); 160 /* 161 * For ACTION_VIEW, the Activity is being asked to display data. 162 * Get the URI. 163 */ 164 if (TextUtils.equals(action, Intent.ACTION_VIEW)) { 165 // Get the URI from the Intent 166 Uri beamUri = mIntent.getData(); 167 /* 168 * Test for the type of URI, by getting its scheme value 169 */ 170 if (TextUtils.equals(beamUri.getScheme(), "file")) { 171 mParentPath = handleFileUri(beamUri); 172 } else if (TextUtils.equals( 173 beamUri.getScheme(), "content")) { 174 mParentPath = handleContentUri(beamUri); 175 } 176 } 177 ... 178 } 179 ... 180} 181</pre> 182<h3>Get the directory from a file URI</h3> 183<p> 184 If the incoming {@link android.content.Intent} contains a file URI, the URI contains the 185 absolute file name of a file, including the full directory path and file name. For Android Beam 186 file transfer, the directory path points to the location of the other transferred files, if 187 any. To get the directory path, get the path part of the URI, which contains all of the URI 188 except the <code>file:</code> prefix. Create a {@link java.io.File} from the path part, then 189 get the parent path of the {@link java.io.File}: 190</p> 191<pre> 192 ... 193 public String handleFileUri(Uri beamUri) { 194 // Get the path part of the URI 195 String fileName = beamUri.getPath(); 196 // Create a File object for this filename 197 File copiedFile = new File(fileName); 198 // Get a string containing the file's parent directory 199 return copiedFile.getParent(); 200 } 201 ... 202</pre> 203 204<h3 id="GetDirectory">Get the directory from a content URI</h3> 205<p> 206 If the incoming {@link android.content.Intent} contains a content URI, the URI may point to a 207 directory and file name stored in the {@link android.provider.MediaStore} content provider. You 208 can detect a content URI for {@link android.provider.MediaStore} by testing the URI's 209 authority value. A content URI for {@link android.provider.MediaStore} may come from 210 Android Beam file transfer or from another app, but in both cases you can retrieve a directory 211 and file name for the content URI. 212</p> 213<p> 214 You can also receive an incoming {@link android.content.Intent#ACTION_VIEW ACTION_VIEW} 215 intent containing a content URI for a content provider other than 216 {@link android.provider.MediaStore}. In this case, the content URI doesn't contain the 217 {@link android.provider.MediaStore} authority value, and the content URI usually doesn't point 218 to a directory. 219</p> 220<p class="note"> 221 <strong>Note:</strong> For Android Beam file transfer, you receive a content URI in the 222 {@link android.content.Intent#ACTION_VIEW ACTION_VIEW} intent if the first incoming file 223 has a MIME type of "audio/*", "image/*", or "video/*", indicating that the file is media- 224 related. Android Beam file transfer indexes the media files it transfers by running Media 225 Scanner on the directory where it stores transferred files. Media Scanner writes its results 226 to the {@link android.provider.MediaStore} content provider, then it passes a content URI 227 for the first file back to Android Beam file transfer. This content URI is the one you 228 receive in the notification {@link android.content.Intent}. To get the directory 229 of the first file, you retrieve it from {@link android.provider.MediaStore} using the content 230 URI. 231</p> 232<h3>Determine the content provider</h3> 233<p> 234 To determine if you can retrieve a file directory from the content URI, determine the 235 the content provider associated with the URI by calling 236 {@link android.net.Uri#getAuthority Uri.getAuthority()} to get the URI's authority. The 237 result has two possible values: 238</p> 239<dl> 240 <dt> 241 {@link android.provider.MediaStore#AUTHORITY MediaStore.AUTHORITY} 242 </dt> 243 <dd> 244 The URI is for a file or files tracked by {@link android.provider.MediaStore}. Retrieve the 245 full file name from {@link android.provider.MediaStore}, and get directory from the file 246 name. 247 </dd> 248 <dt> 249 Any other authority value 250 </dt> 251 <dd> 252 A content URI from another content provider. Display the data associated with the content 253 URI, but don't get the file directory. 254 </dd> 255</dl> 256<p> 257 To get the directory for a {@link android.provider.MediaStore} content URI, 258 run a query that specifies the incoming content URI for the {@link android.net.Uri} argument and 259 the column {@link android.provider.MediaStore.MediaColumns#DATA MediaColumns.DATA} for the 260 projection. The returned {@link android.database.Cursor} contains the full path and name for 261 the file represented by the URI. This path also contains all the other files that Android Beam 262 file transfer just copied to the device. 263</p> 264<p> 265 The following snippet shows you how to test the authority of the content URI and retrieve the 266 the path and file name for the transferred file: 267</p> 268<pre> 269 ... 270 public String handleContentUri(Uri beamUri) { 271 // Position of the filename in the query Cursor 272 int filenameIndex; 273 // File object for the filename 274 File copiedFile; 275 // The filename stored in MediaStore 276 String fileName; 277 // Test the authority of the URI 278 if (!TextUtils.equals(beamUri.getAuthority(), MediaStore.AUTHORITY)) { 279 /* 280 * Handle content URIs for other content providers 281 */ 282 // For a MediaStore content URI 283 } else { 284 // Get the column that contains the file name 285 String[] projection = { MediaStore.MediaColumns.DATA }; 286 Cursor pathCursor = 287 getContentResolver().query(beamUri, projection, 288 null, null, null); 289 // Check for a valid cursor 290 if (pathCursor != null && 291 pathCursor.moveToFirst()) { 292 // Get the column index in the Cursor 293 filenameIndex = pathCursor.getColumnIndex( 294 MediaStore.MediaColumns.DATA); 295 // Get the full file name including path 296 fileName = pathCursor.getString(filenameIndex); 297 // Create a File object for the filename 298 copiedFile = new File(fileName); 299 // Return the parent directory of the file 300 return new File(copiedFile.getParent()); 301 } else { 302 // The query didn't work; return null 303 return null; 304 } 305 } 306 } 307 ... 308</pre> 309<p> 310 To learn more about retrieving data from a content provider, see the section 311 <a href="{@docRoot}guide/topics/providers/content-provider-basics.html#SimpleQuery" 312 >Retrieving Data from the Provider</a>. 313</p> 314