2

I've been trying to get access to Internal and External SD Card in android. I've tried many codes available in StackOverFlow but doesn't work on most or all Android versions. Then, I found two solutions. One which works on Kitkat & above, another one which works on lower than Kitkat. I tried to merge both of them and it works!

If anyone has better solution than this, please share.

OneCricketeer
  • 179,855
  • 19
  • 132
  • 245
Farhan Farooqui
  • 918
  • 1
  • 9
  • 17
  • Sharing this to help others who wants to get the path of External SD Card – Farhan Farooqui Jan 15 '17 at 11:10
  • Your question should contain merged code. Your question is "what is the alternative way". Also, you need manifest permissions – OneCricketeer Jan 15 '17 at 11:18
  • @cricket_007 I forgot about adding the manifest permissions in the answer. And I put the merged code in the answers because it works, since StackOverFlow has an option to answer your own questions I thought it would be best. – Farhan Farooqui Jan 15 '17 at 11:22
  • Sure, your first linked answer below is for marshmallow, anyways, not kitkat. Marshmallow needs runtime permission checks – OneCricketeer Jan 15 '17 at 11:23
  • @cricket_007 I gave this solution only to get path of the External Storages, anyone who'll be using the solution should check for permissions beforehand :) – Farhan Farooqui Jan 15 '17 at 11:31

1 Answers1

0

These two answers are what I merged to get it working.

  1. How to get SD_Card path in android6.0 programmatically

  2. Find an external SD card location

Here's the solution,

Add this line of code in AndroidManifest.xml to get permission from Android to read external storages.

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

Now, add this class to your project.

public class StoragePath {
File[] getExternalFilesDirs;

/**
 * Constructor for KitKat & above
 * @param getExternalFilesDirs
 */
public StoragePath(File[] getExternalFilesDirs) {
    this.getExternalFilesDirs = getExternalFilesDirs;
}

/**
 * Constructor for lower than Kitkat
 *
 */
public StoragePath() {

}

public String[] getDeviceStorages() {
    List<String> results = new ArrayList<>();

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { //Method 1 for KitKat & above
        File[] externalDirs = getExternalFilesDirs;

        for (File file : externalDirs) {
            String path = file.getPath().split("/Android")[0];

            boolean addPath = false;

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                addPath = Environment.isExternalStorageRemovable(file);
            } else {
                addPath = Environment.MEDIA_MOUNTED.equals(EnvironmentCompat.getStorageState(file));
            }

            if (addPath) {
                results.add(path);
            }
        }
    }

    if (results.isEmpty()) { //Method 2 for all versions
        final List<String> out = new ArrayList<>();
        String reg = "(?i).*vold.*(vfat|ntfs|exfat|fat32|ext3|ext4).*rw.*";
        String s = "";
        try {
            final Process process = new ProcessBuilder().command("mount")
                    .redirectErrorStream(true).start();
            process.waitFor();
            final InputStream is = process.getInputStream();
            final byte[] buffer = new byte[1024];
            while (is.read(buffer) != -1) {
                s = s + new String(buffer);
            }
            is.close();
        } catch (final Exception e) {
            e.printStackTrace();
        }

        // parse output
        final String[] lines = s.split("\n");
        for (String line : lines) {
            if (!line.toLowerCase(Locale.US).contains("asec")) {
                if (line.matches(reg)) {
                    String[] parts = line.split(" ");
                    for (String part : parts) {
                        if (part.startsWith("/"))
                            if (!part.toLowerCase(Locale.US).contains("vold"))
                                out.add(part);
                    }
                }
            }
        }
        results.addAll(out);
    }

    //Below few lines is to remove paths which may not be external memory card, like OTG (feel free to comment them out)
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        for (int i = 0; i < results.size(); i++) {
            if (!results.get(i).toLowerCase().matches(".*[0-9a-f]{4}[-][0-9a-f]{4}")) {
                Log.d("Tag", results.get(i) + " might not be extSDcard");
                results.remove(i--);
            }
        }
    } else {
        for (int i = 0; i < results.size(); i++) {
            if (!results.get(i).toLowerCase().contains("ext") && !results.get(i).toLowerCase().contains("sdcard")) {
                Log.d("Tag", results.get(i) + " might not be extSDcard");
                results.remove(i--);
            }
        }
    }

    //Get path to the Internal Storage aka ExternalStorageDirectory
    final String internalStoragePath = Environment.getExternalStorageDirectory().getAbsolutePath();
    results.add(0, internalStoragePath);

    String[] storageDirectories = new String[results.size()];
    for (int i = 0; i < results.size(); ++i) storageDirectories[i] = results.get(i);

    return storageDirectories;

}
}

Now to use this class,

StoragePath storagePath;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
        storagePath = new StoragePath(getExternalFilesDirs(null));
}else {
        storagePath = new StoragePath();
}

String[] storages;
storages = storagePath.getDeviceStorages();

String array storages now contains the path of the storages.

Community
  • 1
  • 1
Farhan Farooqui
  • 918
  • 1
  • 9
  • 17
  • If you really have to downvote then at least comment why so :) What problem did you face? What was wrong in the answer? Maybe then I can improve what's lacking – Farhan Farooqui Jan 15 '17 at 13:07