-2

The issue I have, is that i can't extract the file exetension from files choosen on a smartphone with Android 9. The problem doesn't appear on devices with Android 8 or less.

When the user has choosen any kind of file the onActivityResult gets called. In this method I call getPath from FileUtils class, so I can extract the file extension.

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    Uri uri = new Uri.Builder().build();
    if (resultCode == RESULT_OK) {
        switch (requestCode) {
            case PICKFILE_REQUEST_CODE: {
                String path = new File(data.getData().getPath()).getAbsolutePath();

                if (path != null) {
                    uri = data.getData();
                    path = FileUtils.getPath(getApplicationContext().getContentResolver(), uri);
                    name = path.substring(path.lastIndexOf("."));
                    extension = path.substring(path.lastIndexOf(".") + 1);
                }
                break;
            }
        }
    }

getPath() from FileUtils class (from this repo) evaluates the file via URI which kind of file it is, but responsible for that case is following part:

public static String getPath(final ContentResolver cr, final Uri uri) {
    if (isDownloadsDocument(uri)) {
        final String id = DocumentsContract.getDocumentId(uri);

        final List<Uri> uris = new ArrayList<>();
        uris.add(ContentUris.withAppendedId(
                 Uri.parse("content://downloads/public_downloads"), Long.valueOf(id)));
        uris.add(ContentUris.withAppendedId(
                 Uri.parse("content://downloads/my_downloads"), Long.valueOf(id)));
        uris.add(ContentUris.withAppendedId(
                 Uri.parse("content://downloads/all_downloads"), Long.valueOf(id)));

        String res;
        for (int i = 0; i < uris.size(); i++) {
            res = getDataColumn(cr, uris.get(i), null, null);
            if (res != null) return res;
        }
    }
}

getDataColumn() queries the column of the file in which the physical path of the file is saved:

public static String getDataColumn(ContentResolver cr,
                                   Uri uri, String selection,
                                   String[] selectionArgs) {
    Cursor cursor = null;
    final String[] projection = {"_data"};
    String col = "";

    try {
        cursor = cr.query(uri, projection, selection, selectionArgs,null);
        if (cursor != null && cursor.moveToFirst()) {
            final int column_index = cursor.getColumnIndexOrThrow("_data");
            col = cursor.getString(column_index);
        }
    }finally{ if (cursor != null) cursor.close();}
    return col;
}

When I'm testing the it the path I get looks for example like: E/AddItemActivity: result, path: /storage/emulated/0/Download/SampleVideo_176x144_1mb.3gp. But with Android 9 the path is always empty.

Zoe
  • 27,060
  • 21
  • 118
  • 148
Marcel Hofgesang
  • 951
  • 1
  • 15
  • 36

2 Answers2

9

For the solution I am using the MediaStore to extract the name and extension of a choosen file. So I replace code in onActivityResult with following code:

String path = new File(data.getData().getPath()).getAbsolutePath();

if(path != null){
  uri = data.getData();

  String filename;
  Cursor cursor = getContentResolver().query(uri,null,null,null,null);
  
  if(cursor == null) filename=uri.getPath();
  else{
    cursor.moveToFirst();
    int idx = cursor.getColumnIndex(MediaStore.Files.FileColumns.DISPLAY_NAME);
    filename = cursor.getString(idx);
    cursor.close();
  }

  String name = filename.substring(0,filename.lastIndexOf("."));
  String extension = filename.substring(filename.lastIndexOf(".")+1);
}

So with MediaStore.File.FileColumns.DISPLAY_NAME it's possible to get the file name and extension from any file choosen with a file chooser.

zBugi
  • 13
  • 5
Marcel Hofgesang
  • 951
  • 1
  • 15
  • 36
  • 1
    This will fail when the file was downloaded from another application. a `Uri` does not necessarily have to provide a file name or an extension. – KRK Aug 28 '19 at 10:15
  • Actually it does not fail using a filechooser to get the Uri from the Intent ```data```. – Marcel Hofgesang Sep 01 '20 at 07:12
2
fun Uri.getFileNameWithExtension(context: Context): String? {
    val name = this.path?.let { path -> File(path).name }.orEmpty()
    val extension = MimeTypeMap.getSingleton()
        .getExtensionFromMimeType(getMimeType(context)).orEmpty()
    
    return if (name.isNotEmpty() && extension.isNotEmpty()) "$name.$extension" else null
}

fun Uri.getMimeType(context: Context): String? {
    return when (scheme) {
        ContentResolver.SCHEME_CONTENT -> context.contentResolver.getType(this)
        ContentResolver.SCHEME_FILE -> MimeTypeMap.getSingleton().getMimeTypeFromExtension(
            MimeTypeMap.getFileExtensionFromUrl(toString()).toLowerCase(Locale.US)
        )
        else -> null
    }
}
kulikovman
  • 333
  • 4
  • 8