7
7
import android .content .Intent ;
8
8
import android .content .pm .PackageManager ;
9
9
import android .content .pm .ResolveInfo ;
10
+ import android .database .Cursor ;
10
11
import android .net .Uri ;
11
12
import android .os .AsyncTask ;
12
13
import android .os .Build ;
13
14
import android .os .Bundle ;
14
15
import android .os .Environment ;
16
+ import android .provider .OpenableColumns ;
15
17
import android .support .annotation .NonNull ;
16
18
import android .support .v4 .app .ActivityCompat ;
17
19
import android .support .v4 .content .ContextCompat ;
20
+ import android .support .v4 .content .FileProvider ;
18
21
import android .support .v7 .app .ActionBar ;
19
22
import android .support .v7 .app .AlertDialog ;
20
23
import android .support .v7 .app .AppCompatActivity ;
30
33
import com .google .common .collect .ImmutableMap ;
31
34
32
35
import java .io .File ;
36
+ import java .io .FileInputStream ;
37
+ import java .io .FileNotFoundException ;
38
+ import java .io .IOException ;
39
+ import java .io .InputStream ;
33
40
import java .util .ArrayList ;
34
41
import java .util .List ;
35
42
import java .util .Map ;
@@ -162,8 +169,18 @@ public void onClick(View v)
162
169
DataFormat format = getSelectedFormat (R .id .importFileFormatSpinner );
163
170
File importFile = new File (sdcardDir , exportFilename + "." + format .extension ());
164
171
165
- Log .d (TAG , "Starting import from fixed location: " + importFile .getAbsolutePath ());
166
- startImport (importFile , format );
172
+ Uri uri = Uri .fromFile (importFile );
173
+ try
174
+ {
175
+ FileInputStream stream = new FileInputStream (importFile );
176
+ Log .d (TAG , "Starting import from fixed location: " + importFile .getAbsolutePath ());
177
+ startImport (format , stream , uri );
178
+ }
179
+ catch (FileNotFoundException e )
180
+ {
181
+ Log .e (TAG , "Could not import file " + importFile .getAbsolutePath (), e );
182
+ onImportComplete (false , uri );
183
+ }
167
184
}
168
185
});
169
186
}
@@ -176,26 +193,32 @@ private DataFormat getSelectedFormat(int id)
176
193
return format ;
177
194
}
178
195
179
- private void startImport (File target , DataFormat format )
196
+ private void startImport (DataFormat format , final InputStream target , final Uri targetUri )
180
197
{
181
198
ImportExportTask .TaskCompleteListener listener = new ImportExportTask .TaskCompleteListener ()
182
199
{
183
200
@ Override
184
- public void onTaskComplete (boolean success , File file )
201
+ public void onTaskComplete (boolean success )
185
202
{
186
- onImportComplete (success , file );
203
+ onImportComplete (success , targetUri );
187
204
}
188
205
};
189
206
190
- if (format == null )
207
+ String filename = fileNameFromUri (targetUri );
208
+ if (filename == null )
209
+ {
210
+ filename = targetUri .getPath ();
211
+ }
212
+
213
+ if (format == null && filename != null )
191
214
{
192
215
// Attempt to guess the data format based on the extension
193
- Log .d (TAG , "Attempting to determine file type for: " + target . getName () );
216
+ Log .d (TAG , "Attempting to determine file type for: " + filename );
194
217
195
218
for (Map .Entry <String , DataFormat > item : _fileFormatMap .entrySet ())
196
219
{
197
220
String key = item .getKey ();
198
- if (target . getName () .toLowerCase ().endsWith (key .toLowerCase ()))
221
+ if (filename .toLowerCase ().endsWith (key .toLowerCase ()))
199
222
{
200
223
format = item .getValue ();
201
224
break ;
@@ -205,34 +228,43 @@ public void onTaskComplete(boolean success, File file)
205
228
206
229
if (format != null )
207
230
{
208
- Log .d (TAG , "Starting import of file: " + target . getName () );
231
+ Log .d (TAG , "Starting import of file: " + filename );
209
232
importExporter = new ImportExportTask (ImportExportActivity .this ,
210
- true , format , target , listener );
233
+ format , target , listener );
211
234
importExporter .execute ();
212
235
}
213
236
else
214
237
{
215
238
// If format is still null, then we do not know what to import
216
- Log .w (TAG , "Could not import " + target .getAbsolutePath () + ", could not determine extension" );
217
- onImportComplete (false , target );
239
+ Log .w (TAG , "Could not import " + filename + ", could not determine extension" );
240
+ onImportComplete (false , targetUri );
241
+
242
+ try
243
+ {
244
+ target .close ();
245
+ }
246
+ catch (IOException e )
247
+ {
248
+ Log .w (TAG , "Failed to close stream during import" , e );
249
+ }
218
250
}
219
251
}
220
252
221
- private void startExport (DataFormat format )
253
+ private void startExport (final DataFormat format )
222
254
{
255
+ final File exportFile = new File (sdcardDir , exportFilename + "." + format .extension ());
256
+
223
257
ImportExportTask .TaskCompleteListener listener = new ImportExportTask .TaskCompleteListener ()
224
258
{
225
259
@ Override
226
- public void onTaskComplete (boolean success , File file )
260
+ public void onTaskComplete (boolean success )
227
261
{
228
- onExportComplete (success , file );
262
+ onExportComplete (success , exportFile , format );
229
263
}
230
264
};
231
265
232
- File exportFile = new File (sdcardDir , exportFilename + "." + format .extension ());
233
-
234
266
importExporter = new ImportExportTask (ImportExportActivity .this ,
235
- false , format , exportFile , listener );
267
+ format , exportFile , listener );
236
268
importExporter .execute ();
237
269
}
238
270
@@ -287,7 +319,34 @@ public boolean onOptionsItemSelected(MenuItem item)
287
319
return super .onOptionsItemSelected (item );
288
320
}
289
321
290
- private void onImportComplete (boolean success , File path )
322
+ private String fileNameFromUri (Uri uri )
323
+ {
324
+ if ("file" .equals (uri .getScheme ()))
325
+ {
326
+ return uri .getPath ();
327
+ }
328
+
329
+ Cursor returnCursor =
330
+ getContentResolver ().query (uri , null , null , null , null );
331
+ if (returnCursor == null )
332
+ {
333
+ return null ;
334
+ }
335
+
336
+ int nameIndex = returnCursor .getColumnIndex (OpenableColumns .DISPLAY_NAME );
337
+ if (returnCursor .moveToFirst () == false )
338
+ {
339
+ returnCursor .close ();
340
+ return null ;
341
+ }
342
+
343
+ String name = returnCursor .getString (nameIndex );
344
+ returnCursor .close ();
345
+
346
+ return name ;
347
+ }
348
+
349
+ private void onImportComplete (boolean success , Uri path )
291
350
{
292
351
AlertDialog .Builder builder = new AlertDialog .Builder (this );
293
352
@@ -303,7 +362,15 @@ private void onImportComplete(boolean success, File path)
303
362
int messageId = success ? R .string .importedFrom : R .string .importFailed ;
304
363
305
364
final String template = getResources ().getString (messageId );
306
- final String message = String .format (template , path .getAbsolutePath ());
365
+
366
+ // Get the filename of the file being imported
367
+ String filename = fileNameFromUri (path );
368
+ if (filename == null )
369
+ {
370
+ filename = "(unknown)" ;
371
+ }
372
+
373
+ final String message = String .format (template , filename );
307
374
builder .setMessage (message );
308
375
builder .setNeutralButton (R .string .ok , new DialogInterface .OnClickListener ()
309
376
{
@@ -317,7 +384,7 @@ public void onClick(DialogInterface dialog, int which)
317
384
builder .create ().show ();
318
385
}
319
386
320
- private void onExportComplete (boolean success , final File path )
387
+ private void onExportComplete (boolean success , final File path , final DataFormat format )
321
388
{
322
389
AlertDialog .Builder builder = new AlertDialog .Builder (this );
323
390
@@ -353,10 +420,13 @@ public void onClick(DialogInterface dialog, int which)
353
420
@ Override
354
421
public void onClick (DialogInterface dialog , int which )
355
422
{
356
- Uri outputUri = Uri . fromFile ( path );
423
+ Uri outputUri = FileProvider . getUriForFile ( ImportExportActivity . this , BuildConfig . APPLICATION_ID , path );
357
424
Intent sendIntent = new Intent (Intent .ACTION_SEND );
358
425
sendIntent .putExtra (Intent .EXTRA_STREAM , outputUri );
359
- sendIntent .setType ("text/plain" );
426
+ sendIntent .setType (format .mimetype ());
427
+
428
+ // set flag to give temporary permission to external app to use the FileProvider
429
+ sendIntent .setFlags (Intent .FLAG_GRANT_READ_URI_PERMISSION );
360
430
361
431
ImportExportActivity .this .startActivity (Intent .createChooser (sendIntent ,
362
432
sendLabel ));
@@ -411,34 +481,28 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data)
411
481
{
412
482
super .onActivityResult (requestCode , resultCode , data );
413
483
414
- if (resultCode == RESULT_OK && requestCode = = CHOOSE_EXPORT_FILE )
484
+ if (resultCode != RESULT_OK || requestCode ! = CHOOSE_EXPORT_FILE )
415
485
{
416
- String path = null ;
417
-
418
- Uri uri = data .getData ();
419
- if (uri != null && uri .toString ().startsWith ("/" ))
420
- {
421
- uri = Uri .parse ("file://" + uri .toString ());
422
- }
486
+ Log .w (TAG , "Failed onActivityResult(), result=" + resultCode );
487
+ return ;
488
+ }
423
489
424
- if (uri != null )
425
- {
426
- path = uri .getPath ();
427
- }
490
+ Uri uri = data .getData ();
491
+ if (uri == null )
492
+ {
493
+ Log .e (TAG , "Activity returned a NULL URI" );
494
+ return ;
495
+ }
428
496
429
- if (path != null )
430
- {
431
- Log .e (TAG , "Starting file import with: " + uri .toString ());
432
- startImport (new File (path ), null );
433
- }
434
- else
435
- {
436
- Log .e (TAG , "Fail to make sense of URI returned from activity: " + (uri != null ? uri .toString () : "null" ));
437
- }
497
+ try
498
+ {
499
+ InputStream reader = getContentResolver ().openInputStream (uri );
500
+ Log .e (TAG , "Starting file import with: " + uri .toString ());
501
+ startImport (null , reader , uri );
438
502
}
439
- else
503
+ catch ( FileNotFoundException e )
440
504
{
441
- Log .w (TAG , "Failed onActivityResult(), result= " + resultCode );
505
+ Log .e (TAG , "Failed to import file: " + uri . toString (), e );
442
506
}
443
507
}
444
508
}
0 commit comments