8

I'm using FileProvider for my internal files to be exposed to the Gallery for example. To make it more uniform, I also put my my external files into the provider (via external-path) but for the files in removable sd card it doesn't work. Saying something like that folder is not authorized.

Any help will be greatly appreciated.

Thx

stdout
  • 2,471
  • 2
  • 31
  • 40

5 Answers5

27

i added this root-path as suggested by @Gubatron in my XML and it works.

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <external-path name="external_files" path="."/>
    <root-path name="external_files" path="/storage/" />
</paths>
Siddhesh Shirodkar
  • 891
  • 13
  • 16
7

Let's take a look at FileProvider code:

    private static PathStrategy parsePathStrategy(Context context, String authority)
        ...
        int type;
        while ((type = in.next()) != END_DOCUMENT) {
            if (type == START_TAG) {
                final String tag = in.getName();
                final String name = in.getAttributeValue(null, ATTR_NAME);
                String path = in.getAttributeValue(null, ATTR_PATH);
                File target = null;
                if (TAG_ROOT_PATH.equals(tag)) {
                    target = buildPath(DEVICE_ROOT, path);
                } else if (TAG_FILES_PATH.equals(tag)) {
                    target = buildPath(context.getFilesDir(), path);
                } else if (TAG_CACHE_PATH.equals(tag)) {
                    target = buildPath(context.getCacheDir(), path);
                } else if (TAG_EXTERNAL.equals(tag)) {
                    target = buildPath(Environment.getExternalStorageDirectory(), path);
                }
                if (target != null) {
                    strat.addRoot(name, target);
                }
            }
        }
        return strat;
    }

FileProvider accepted absolute pathes to directory with help of tag root-path (DEVICE_ROOT constant). So just add absolute path to your files folder in secondary external disc like below:

<root-path path="/storage/extSdCard/Android/data/com.edufii/files/image/" name="image-ext2" />
<root-path path="/storage/extSdCard/Android/data/com.edufii/files/video/" name="video-ext2" />
<root-path path="/storage/extSdCard/Android/data/com.edufii/files/datafile/" name="datafile-ext2" />
<root-path path="/storage/extSdCard/Android/data/com.edufii/files/audio/" name="audio-ext2" />

Note official documentation doesn't say anything about <root-path>, so it may changed in a future.

danik
  • 796
  • 9
  • 17
2

FileProvider does not support secondary external storage (like removable sd cards). This is even more an issue in Android 7 and above - because you can't use the file:// uris anymore.

I already issued a bug report here.

artkoenig
  • 7,117
  • 2
  • 40
  • 61
1

starting from android 4.4, normal applications are not allowed to access secondary external storage devices, i.e. sd card, except in their package-specific directories, even if you have requested WRITE_EXTERNAL_STORAGE permission.

The WRITE_EXTERNAL_STORAGE permission must only grant write access to the primary external storage on a device. Apps must not be allowed to write to secondary external storage devices, except in their package-specific directories as allowed by synthesized permissions. Restricting writes in this way ensures the system can clean up files when applications are uninstalled.

https://source.android.com/devices/storage/

Derek Fung
  • 8,171
  • 1
  • 25
  • 28
  • Thank you! But it seems to me a bit vouge though. See, in the docs it's said that external storage should be surfaced if it's semi-permanant like sd card slot in a battery compartment. But you're saying sd card is a secondary extarnal storage I guess and as of 4.4 it's not surfaced through the storage API. – stdout Sep 01 '15 at 14:30
  • Actually in android's term, both "internal memory" and "sd card" can be "external storage". Use old phone Motorola Defy as an example, it has only 1 "external storage", which is sd card, so the sd card is `primary external storage`. Moto G, or some Nexus phone, it has only got "internal memory" but no sd card, so "internal memory" is the `primary external storage` here. For samsung phones, they have both internal memory and sd card, this time, internal memory is the `primary external storage`, while `sd card` is the `secondary external storage`. – Derek Fung Sep 01 '15 at 14:34
  • 1
    To confuse the matter even more, it comes `internal storage`, the truth is all phone must have `internal MEMORY`, just large or not. Use the same example, Defy's internal MEMORY is small, and used only as `internal storage`, while new model usually have larger internal memory, so only part of it is assigned as `internal storage` – Derek Fung Sep 01 '15 at 14:38
  • Ok got it. One more... I come across a term sometimes which is "built-in external storage". I believe that's referring to the external storage inside internal storage then? – stdout Sep 01 '15 at 14:38
  • Yes, you are right. I would say it is external storage on `interal MEMORY` using my terms above. – Derek Fung Sep 01 '15 at 14:39
0

To access external sdcard . First call uri.getEncodedPath() to get the encoded path

" /external_files/3161-3330/WhatsApp/Media/WhatsApp%20Documents/All%20Currency.pdf "

Then use below logic to get file path of external storage

public String getFilePath(){
    if (isKitKat && DocumentsContract.isDocumentUri(mContext, uri)) {
                // ExternalStorageProvider
                if (com.android.externalstorage.documents.equals(uri.getAuthority())) {
                    final String docId = DocumentsContract.getDocumentId(uri);
                    final String[] split = docId.split(":");
                    final String type = split[0];
    
                    if ("primary".equalsIgnoreCase(type)) {
                        return Environment.getExternalStorageDirectory() + "/" + split[1];
                    } else {
                        return "/storage" + "/" + split[0] + "/" + split[1];
                    }
               }
    }
}

getFilePath() will give :

/storage/emulated/0/3161-3330/WhatsApp/Media/WhatsApp Documents/All Currency.pdf

where uri path starts with

/external_files/

and file path starts with

/storage/

Hence , we have to add below line

 <root-path name="external_files" path="/storage/" />

in

@xml/provider_paths.xml

Arst
  • 3,098
  • 1
  • 35
  • 42
adhi
  • 326
  • 4
  • 6