3

My app receives files from other apps. So, I receive the URI but... how to access to the file name and data?

Now, I'm doing something like this:

if ("file".equals(dataUri.getScheme())){
    File file = new File(dataUri.getPath));
    // I do needed operations with the file here
}
else if ("content".equals(dataUri.getScheme())){
    Cursor cursor = getContentResolver().query(dataUri, new String[]{MediaStore.MediaColumns.DISPLAY_NAME}, null, null, null);
    if (cursor.moveToFirst() && (nameIndex = cursor.getColumnIndex(cursor.getColumnNames()[0])) >= 0){
        String fileName = cursor.getString(nameIndex);
        InputStream inputStream = getContentResolver().openInputStream(dataUri);
        // I do needed operations with the file here
    }
}

Is this enough for handle every case?

Sergio Viudes
  • 2,714
  • 5
  • 26
  • 44
  • That seems enough to handle any local file url, is that what you need? – Nanoc Oct 08 '15 at 10:34
  • Yes, I need to handle any local file, but I don't know if I there are any other uri types I'm not considering, and I don't know if this code will work on all Android versions. – Sergio Viudes Oct 08 '15 at 11:35
  • As far as i know there is no other schema to refer to local files and its a URL not an Android exclusive thing, it should be universal. – Nanoc Oct 08 '15 at 11:38

1 Answers1

2

You don't need to handle file and content differently, both can be handled by calling getContentResolver().openInputStream(uri).

http://developer.android.com/reference/android/content/ContentResolver.html#openInputStream(android.net.Uri)

From the rest of the documentation on that page, you can see that ContentResolver has references to three schemes and that method handles them all.

  • SCHEME_ANDROID_RESOURCE
  • SCHEME_CONTENT
  • SCHEME_FILE

If you dig deeper, there is more detailed information about opening documents here: http://developer.android.com/guide/topics/providers/document-provider.html#client

Although it is generally talking about a newer option available in API 19, the following sections are applicable to older versions as well.

Examine Document Metadata

public void dumpImageMetaData(Uri uri) {

    // The query, since it only applies to a single document, will only return
    // one row. There's no need to filter, sort, or select fields, since we want
    // all fields for one document.
    Cursor cursor = getActivity().getContentResolver()
            .query(uri, null, null, null, null, null);

    try {
        // moveToFirst() returns false if the cursor has 0 rows.  Very handy for
        // "if there's anything to look at, look at it" conditionals.
        if (cursor != null && cursor.moveToFirst()) {

            // Note it's called "Display Name".  This is
            // provider-specific, and might not necessarily be the file name.
            String displayName = cursor.getString(
                    cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
            Log.i(TAG, "Display Name: " + displayName);

            int sizeIndex = cursor.getColumnIndex(OpenableColumns.SIZE);
            // If the size is unknown, the value stored is null.  But since an
            // int can't be null in Java, the behavior is implementation-specific,
            // which is just a fancy term for "unpredictable".  So as
            // a rule, check if it's null before assigning to an int.  This will
            // happen often:  The storage API allows for remote files, whose
            // size might not be locally known.
            String size = null;
            if (!cursor.isNull(sizeIndex)) {
                // Technically the column stores an int, but cursor.getString()
                // will do the conversion automatically.
                size = cursor.getString(sizeIndex);
            } else {
                size = "Unknown";
            }
            Log.i(TAG, "Size: " + size);
        }
    } finally {
        cursor.close();
    }
}

Open A Document

Bitmap

private Bitmap getBitmapFromUri(Uri uri) throws IOException {
    ParcelFileDescriptor parcelFileDescriptor = getContentResolver().openFileDescriptor(uri, "r");
    FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
    Bitmap image = BitmapFactory.decodeFileDescriptor(fileDescriptor);
    parcelFileDescriptor.close();
    return image;
}

Input Stream

private String readTextFromUri(Uri uri) throws IOException {
    InputStream inputStream = getContentResolver().openInputStream(uri);
    BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
    StringBuilder stringBuilder = new StringBuilder();
    String line;
    while ((line = reader.readLine()) != null) {
        stringBuilder.append(line);
    }
    inputStream.close();
    return stringBuilder.toString();
}
mpkuth
  • 6,994
  • 2
  • 27
  • 44
  • Thanks for your detailed explanation. So, there is no need to get real path like this answer says, right?: http://stackoverflow.com/questions/27602986/how-to-convert-the-file-path-into-to-uri-in-android#answer-27603104 I'll try if using getContentResolver().openInputStream(uri) I'm able to handle all cases – Sergio Viudes Oct 14 '15 at 15:32
  • That is correct. There is no need to get the path to access the file/content data. You should only need the Uri object. – mpkuth Oct 14 '15 at 17:14
  • 1
    Thanks, Solved! I would like to link this good article here, that is related to that question: https://commonsware.com/blog/2014/07/04/uri-not-necessarily-file.html – Sergio Viudes Oct 15 '15 at 10:09