javaandroidandroid-sdcardsd-cardusb-otg

Get the list of paths of all the Storage Devices connected to an Android device


I want to get the list of all Storage Devices which are connected to the Android device.

For eg- Internal Storage(Storage in which all the folders such as Downloads, DCIM etc are present), SD Card and OTG device.

I Know there are a lot of StackOverflow posts which discuss this topic but none of them could serve my purpose as stated above.

I am able to get the Internal Storage by calling Environment.getExternalStorageDirectory().getPath() which return the path to the Internal Storage.

Any help on this would be really grateful as there is no standard AFAIK using which the list of all the connected Storage devices can be retrieved.

Also, many solutions do not work on different devices and Android version.


Solution

  • You can create one class EnvironmentSDCardCheck

    package com.example.storagecheck;
    
    import android.content.BroadcastReceiver;
    import android.content.Context;
    import android.content.Intent;
    import android.content.IntentFilter;
    import android.os.Build;
    import android.os.Environment;
    import android.os.storage.StorageManager;
    import android.support.v4.content.ContextCompat;
    import android.support.v4.os.EnvironmentCompat;
    import android.util.Log;
    
    import java.io.File;
    import java.io.IOException;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    import java.util.ArrayList;
    
    public class EnvironmentSDCardCheck {
        private static final String TAG = "EnvironmentSDCardCheck";
    
        public final static String TYPE_PRIMARY = "primär";
        public final static String TYPE_INTERNAL = "intern";
        public final static String TYPE_SD = "MicroSD";
        public final static String TYPE_USB = "USB";
        public final static String TYPE_UNKNOWN = "unbekannt";
    
        public final static String WRITE_NONE = "none";
        public final static String WRITE_READONLY = "readonly";
        public final static String WRITE_APPONLY = "apponly";
        public final static String WRITE_FULL = "readwrite";
    
        private static Device[] devices, externalstorage, storage;
        private static BroadcastReceiver receiver;
        private static boolean useReceiver = true;
        private static String userDir;
    
        public static Device[] getDevices(Context context) {
            if (devices == null) initDevices(context);
            return devices;
        }
    
        public static Device[] getExternalStorage(Context context) {
            if (devices == null) initDevices(context);
            return externalstorage;
        }
    
        public static Device[] getStorage(Context context) {
            if (devices == null) initDevices(context);
            return storage;
        }
    
        public static IntentFilter getRescanIntentFilter() {
            IntentFilter filter = new IntentFilter();
            filter.addAction(Intent.ACTION_MEDIA_BAD_REMOVAL); 
            filter.addAction(Intent.ACTION_MEDIA_MOUNTED); 
            filter.addAction(Intent.ACTION_MEDIA_REMOVED); 
            filter.addAction(Intent.ACTION_MEDIA_SHARED); 
            filter.addDataScheme("file");
            return filter;
        }
    
        public static void setUseReceiver(Context context, boolean use) {
            if (use && receiver == null) {
                receiver = new BroadcastReceiver() {
                    @Override
                    public void onReceive(Context context, Intent intent) {
                        Log.i(TAG, "Storage " + intent.getAction() + "-" + intent.getData());
                        initDevices(context);
                    }
                };
                context.registerReceiver(receiver, getRescanIntentFilter());
            } else if (!use && receiver != null) {
                context.unregisterReceiver(receiver);
                receiver = null;
            }
            useReceiver = use;
        }
    
        public static void initDevices(Context context) {
            if (userDir == null) userDir = "/Android/data/" + context.getPackageName();
            setUseReceiver(context, useReceiver);
            StorageManager sm = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
            Class c = sm.getClass();
            Object[] vols;
            try {
                Method m = c.getMethod("getVolumeList", null);
                vols = (Object[]) m.invoke(sm, null); // android.os.Storage.StorageVolume
                Device[] temp = new Device[vols.length];
                for (int i = 0; i < vols.length; i++) temp[i] = new Device(vols[i]);
                Device primary = null;
                for (Device d : temp) if (d.mPrimary) primary = d;
                if (primary == null) for (Device d : temp)
                    if (!d.mRemovable) {
                        d.mPrimary = true;
                        primary = d;
                        break;
                    }
                if (primary == null) {
                    primary = temp[0];
                    primary.mPrimary = true;
                }
    
                File[] files = ContextCompat.getExternalFilesDirs(context, null);
                File[] caches = ContextCompat.getExternalCacheDirs(context);
                for (Device d : temp) {
                    if (files != null) for (File f : files)
                        if (f != null && f.getAbsolutePath().startsWith(d.getAbsolutePath()))
                            d.mFiles = f;
                    if (caches != null) for (File f : caches)
                        if (f != null && f.getAbsolutePath().startsWith(d.getAbsolutePath()))
                            d.mCache = f;
                }
    
                ArrayList<Device> tempDev = new ArrayList<Device>(10);
                ArrayList<Device> tempStor = new ArrayList<Device>(10);
                ArrayList<Device> tempExt = new ArrayList<Device>(10);
                for (Device d : temp) {
                    tempDev.add(d);
                    if (d.isAvailable()) {
                        tempExt.add(d);
                        tempStor.add(d);
                    }
                }
    
                Device internal = new Device(context);
                tempStor.add(0, internal); // bei Storage-Alternativen immer
                if (!primary.mEmulated) tempDev.add(0, internal); // bei Devices nur wenn zusätzlich
    
                devices = tempDev.toArray(new Device[tempDev.size()]);
                storage = tempStor.toArray(new Device[tempStor.size()]);
                externalstorage = tempExt.toArray(new Device[tempExt.size()]);
            } catch (Exception e) {
                // Fallback auf normale Android-Funktionen
            }
    
        }
    
        public static class Device extends File {
            String mUserLabel, mUuid, mState, mWriteState, mType;
            boolean mPrimary, mRemovable, mEmulated, mAllowMassStorage;
            long mMaxFileSize;
            File mFiles, mCache;
    
            Device(Context context) {
                super(Environment.getDataDirectory().getAbsolutePath());
                mState = Environment.MEDIA_MOUNTED;
                mFiles = context.getFilesDir();
                mCache = context.getCacheDir();
                mType = TYPE_INTERNAL;
                mWriteState = WRITE_APPONLY;
            }
    
            @SuppressWarnings("NullArgumentToVariableArgMethod")
            Device(Object storage) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
                super((String) storage.getClass().getMethod("getPath", null).invoke(storage, null));
                for (Method m : storage.getClass().getMethods()) {
                    if (m.getName().equals("getUserLabel") && m.getParameterTypes().length == 0 && m.getReturnType() == String.class)
                        mUserLabel = (String) m.invoke(storage, null); // ab Android 4.4
                    if (m.getName().equals("getUuid") && m.getParameterTypes().length == 0 && m.getReturnType() == String.class)
                        mUuid = (String) m.invoke(storage, null); // ab Android 4.4
                    if (m.getName().equals("getState") && m.getParameterTypes().length == 0 && m.getReturnType() == String.class)
                        mState = (String) m.invoke(storage, null); // ab Android 4.4
                    if (m.getName().equals("isRemovable") && m.getParameterTypes().length == 0 && m.getReturnType() == boolean.class)
                        mRemovable = (Boolean) m.invoke(storage, null); // ab Android 4.0
                    if (m.getName().equals("isPrimary") && m.getParameterTypes().length == 0 && m.getReturnType() == boolean.class)
                        mPrimary = (Boolean) m.invoke(storage, null); // ab Android 4.2
                    if (m.getName().equals("isEmulated") && m.getParameterTypes().length == 0 && m.getReturnType() == boolean.class)
                        mEmulated = (Boolean) m.invoke(storage, null); // ab Android 4.0
                    if (m.getName().equals("allowMassStorage") && m.getParameterTypes().length == 0 && m.getReturnType() == boolean.class)
                        mAllowMassStorage = (Boolean) m.invoke(storage, null); // ab Android 4.0
                    if (m.getName().equals("getMaxFileSize") && m.getParameterTypes().length == 0 && m.getReturnType() == long.class)
                        mMaxFileSize = (Long) m.invoke(storage, null); // ab Android 4.0
                    // getDescription (ab 4.1 mit context) liefert keine sinnvollen Werte
                    // getPathFile (ab 4.2) liefert keine sinnvollen Werte
                    // getMtpReserveSpace (ab 4.0) für diese Zwecke unwichtig
                    // getStorageId (ab 4.0) für diese Zwecke unwichtig
                }
                if (mState == null) mState = getState();
    
                if (mPrimary)
                    mType = TYPE_PRIMARY;
                else {
                    String n = getAbsolutePath().toLowerCase();
                    if (n.indexOf("sd") > 0)
                        mType = TYPE_SD;
                    else if (n.indexOf("usb") > 0)
                        mType = TYPE_USB;
                    else
                        mType = TYPE_UNKNOWN + " " + getAbsolutePath();
                }
            }
    
            public String getType() {
                return mType;
            }
    
            public String getAccess() {
                if (mWriteState == null) {
                    try {
                        mWriteState = WRITE_NONE;
                        File[] root = listFiles();
                        if (root == null || root.length == 0)
                            throw new IOException("root empty/unreadable");
                        mWriteState = WRITE_READONLY;
                        File t = File.createTempFile("jow", null, getFilesDir());
                        //noinspection ResultOfMethodCallIgnored
                        t.delete();
                        mWriteState = WRITE_APPONLY;
                        t = File.createTempFile("jow", null, this);
                        //noinspection ResultOfMethodCallIgnored
                        t.delete();
                        mWriteState = WRITE_FULL;
                    } catch (IOException ignore) {
                        Log.v(TAG, "test " + getAbsolutePath() + " ->" + mWriteState + "<- " + ignore.getMessage());
                    }
                }
                return mWriteState;
            }
    
            public boolean isAvailable() {
                String s = getState();
                return (
                        Environment.MEDIA_MOUNTED.equals(s) ||
                                Environment.MEDIA_MOUNTED_READ_ONLY.equals(s)
                );
                // MEDIA_SHARED: als USB freigegeben; bitte Handy auf MTP umstellen
            }
    
            public String getState() {
                if (mRemovable || mState == null) {
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
                        // Android 5.0? Da gibts was neues
                        mState = Environment.getExternalStorageState(this);
                    else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
                        // Android 4.4? Dann dort nachfragen
                        mState = Environment.getStorageState(this);
                    else if (canRead() && getTotalSpace() > 0)
                        // lesbar und Größe vorhanden => gibt es
                        mState = Environment.MEDIA_MOUNTED;
                    else if (mState == null || Environment.MEDIA_MOUNTED.equals(mState))
                        // nicht lesbar, keine Größe aber noch MOUNTED || oder ungesetzt => UNKNOWN
                        mState = EnvironmentCompat.MEDIA_UNKNOWN;
                }
                return mState;
            }
    
            public File getFilesDir() {
                if (mFiles == null) {
                    mFiles = new File(this, userDir + "/files");
                    if (!mFiles.isDirectory())
                        //noinspection ResultOfMethodCallIgnored
                        mFiles.mkdirs();
                }
                return mFiles;
            }
    
            public File getCacheDir() {
                if (mCache == null) {
                    mCache = new File(this, userDir + "/cache");
                    if (!mCache.isDirectory())
                        //noinspection ResultOfMethodCallIgnored
                        mCache.mkdirs();
                }
                return mCache;
            }
    
            public boolean isPrimary() {
                return mPrimary;
            }
    
            public boolean isRemovable() {
                return mRemovable;
            }
            public boolean isEmulated() {
                return mEmulated;
            }
    
            public boolean isAllowMassStorage() {
                return mAllowMassStorage;
            }
    
            public long getMaxFileSize() {
                return mMaxFileSize;
            }
    
            public String getUserLabel() {
                return mUserLabel;
            }
    
            public String getUuid() {
                return mUuid;
            }
        }
    }
    

    and then you can use it to check sd card or Usb or unknown is presently connected or not with device

    This way you can get the connected sd card, usb, etc.

    private boolean checkSdCardPermission() {
        boolean flag = false;
        try {
            EnvironmentSDCard.Device[] devices = EnvironmentSDCard.getExternalStorage(MainActivity.this);
            for (EnvironmentSDCard.Device d : devices) {
                if (d.getType().equals(EnvironmentSDCard.TYPE_SD) || d.getType().contains(EnvironmentSDCard.TYPE_UNKNOWN) || d.getType().contains(EnvironmentSDCard.TYPE_USB)) {
                    flag = d.isAvailable();
                    if (flag)
                        break;
                }
            }
        } catch (Exception e) {
        }
        return flag;
    }