1

I used to get all the files in USB/SD Card from "/storage/external_storage" like so

File = new File("/storage/external_storage");
file.listFiles()

and show the files and folders in my own Fragment and it worked great until API 23. Where now I am unable to get the file list from the path.

I know in Android Marshmallow (23) there were permission changes and some USB Connection behavior changes.

If your app supports user interactions with the device over a USB port, take into consideration that the interaction must be explicitly enabled.

Does not explain how or when user can enable interactions explicitly.

My question is whether or not it is possible to Access USB files and Folders list. If there is how can we achieve this?

EDIT : I opened Android Device Monitor and I couldn't find external_storage in /storage/external_storage.

Abbas
  • 3,529
  • 5
  • 36
  • 64
  • You need to implement run time permissions or set target api ver 22. – phnmnn Dec 07 '16 at 08:13
  • On side note, don't hard code the path, instead use [getExternalStorageDirectory()](https://developer.android.com/reference/android/os/Environment.html#getExternalStorageDirectory()) – Mudassir Dec 07 '16 at 08:17
  • @phnmnn Thanks for you reply. I need to target api 23. However I already have the write permission. Unless there is some new USB/SD card permission required? – Abbas Dec 07 '16 at 08:18
  • @Mudassir Yes but that also gives local file path for when there is no usb connected or Default external storage is set to local. I only want to show files when USB is connected. – Abbas Dec 07 '16 at 08:21
  • Probably your problem comes cause of Runtime Permissions from API 23, try this: https://developer.android.com/training/permissions/requesting.html – zapotec Dec 07 '16 at 08:29
  • @zapotec I considered that but which permission do I need to access USB/SD Card file and folders. If you know any such permission that please leave in comment. – Abbas Dec 07 '16 at 08:31
  • Try these two ones: – zapotec Dec 07 '16 at 08:33
  • @zapotec I tried the permissions didn't work and I checked in Android Device Monitor and there is no `external_storage` folder their. (Check my updated question). – Abbas Dec 07 '16 at 08:42
  • `to access USB/SD Card file and folders`. Those are two things. You are unclear what you want to access. A removable micro SD card or a connected USB OTG drive. You also did not tell for which Android version you compile. – greenapps Dec 07 '16 at 13:25
  • @greenapps don't both link to the same folder? Like `"storage/external_storage"`? – Abbas Dec 08 '16 at 08:55
  • Imagine that both a micro SD card and OTG drive are available.... how could that be one folder? The folder you mention does not exist on most devices. In fact i have never seen a device that has a folder with that name. Your subject is completely wrong. – greenapps Dec 08 '16 at 12:12
  • @greenapps you are right about multiple removable media attached at the same time. It does create a seperate folder. But I have successfully used "sotrage/" folder on a number of occasions, however they are not applicable on all devices. I will update question's subject accordingly. – Abbas Dec 08 '16 at 12:22
  • @greenapps Is there a way to only retrieve the folders that are removable? i.e. all the usb/sd card folders? – Abbas Dec 08 '16 at 12:56
  • @greenapps oops my bad, I got engaged elsewhere. Updated the question. – Abbas Dec 08 '16 at 13:57

2 Answers2

1

It is true the doc is not very clear about that....but it seems you have to ask the system to mount the media device for you. Can you try to use Environment.getExternalStorageState() to see what it returns you?

Otherwise, you can also try to access the SD/External USB by using this class:

public class ExternalStorage {

public static final String SD_CARD = "sdCard";
public static final String EXTERNAL_SD_CARD = "externalSdCard";

/**
 * @return True if the external storage is available. False otherwise.
 */
public static boolean isAvailable() {
    String state = Environment.getExternalStorageState();
    if (Environment.MEDIA_MOUNTED.equals(state) || Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
        return true;
    }
    return false;
}

public static String getSdCardPath() {
    return Environment.getExternalStorageDirectory().getPath() + "/";
}

/**
 * @return True if the external storage is writable. False otherwise.
 */
public static boolean isWritable() {
    String state = Environment.getExternalStorageState();
    if (Environment.MEDIA_MOUNTED.equals(state)) {
        return true;
    }
    return false;

}

/**
 * @return A map of all storage locations available
 */
public static Map<String, File> getAllStorageLocations() {
    Map<String, File> map = new HashMap<String, File>(10);

    List<String> mMounts = new ArrayList<String>(10);
    List<String> mVold = new ArrayList<String>(10);
    mMounts.add("/mnt/sdcard");
    mVold.add("/mnt/sdcard");

    try {
        File mountFile = new File("/proc/mounts");
        if(mountFile.exists()){
            Scanner scanner = new Scanner(mountFile);
            while (scanner.hasNext()) {
                String line = scanner.nextLine();
                if (line.startsWith("/dev/block/vold/")) {
                    String[] lineElements = line.split(" ");
                    String element = lineElements[1];

                    // don't add the default mount path
                    // it's already in the list.
                    if (!element.equals("/mnt/sdcard"))
                        mMounts.add(element);
                }
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    }

    try {
        File voldFile = new File("/system/etc/vold.fstab");
        if(voldFile.exists()){
            Scanner scanner = new Scanner(voldFile);
            while (scanner.hasNext()) {
                String line = scanner.nextLine();
                if (line.startsWith("dev_mount")) {
                    String[] lineElements = line.split(" ");
                    String element = lineElements[2];

                    if (element.contains(":"))
                        element = element.substring(0, element.indexOf(":"));
                    if (!element.equals("/mnt/sdcard"))
                        mVold.add(element);
                }
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    }


    for (int i = 0; i < mMounts.size(); i++) {
        String mount = mMounts.get(i);
        if (!mVold.contains(mount))
            mMounts.remove(i--);
    }
    mVold.clear();

    List<String> mountHash = new ArrayList<String>(10);

    for(String mount : mMounts){
        File root = new File(mount);
        if (root.exists() && root.isDirectory() && root.canWrite()) {
            File[] list = root.listFiles();
            String hash = "[";
            if(list!=null){
                for(File f : list){
                    hash += f.getName().hashCode()+":"+f.length()+", ";
                }
            }
            hash += "]";
            if(!mountHash.contains(hash)){
                String key = SD_CARD + "_" + map.size();
                if (map.size() == 0) {
                    key = SD_CARD;
                } else if (map.size() == 1) {
                    key = EXTERNAL_SD_CARD;
                }
                mountHash.add(hash);
                map.put(key, root);
            }
        }
    }

    mMounts.clear();

    if(map.isEmpty()){
             map.put(SD_CARD, Environment.getExternalStorageDirectory());
    }
    return map;
}
}

The use is like this:

Map<String, File> externalLocations = ExternalStorage.getAllStorageLocations();
File sdCard = externalLocations.get(ExternalStorage.SD_CARD);
File externalSdCard = externalLocations.get(ExternalStorage.EXTERNAL_SD_CARD);

Source here: Find an external SD card location

Community
  • 1
  • 1
zapotec
  • 2,628
  • 4
  • 31
  • 53
  • `Environment.getExternalStorageState()` returns "mounted", which I suppose is what I should get while the USB is connected. However in `Environment.getExternalStorageDirectory()` I get the local shared directory path. I will give `ExternalStorage` a shot and get back to you. – Abbas Dec 07 '16 at 09:43
  • I tried your code but It doesn't work. I get path to "mnt/sdcard" which is a shared location. – Abbas Dec 07 '16 at 10:01
0

Have a look at getExternalFilesDirs(). If a micro SD card is inserted the second entry will point to the card. If you then attach a USB OTG drive the third entry will point to the drive.

With Intent.ACTION_OPEN_DOCUMENT_TREE you can let the user choose from all drives and then use Storage Access Framework.

greenapps
  • 11,154
  • 2
  • 16
  • 19