Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a documented way, in Android 2.x, to inspect multiple sd cards for content?

Some Android 2.x tablets such as the HTC Flyer and Samsung Galaxy Tab support both internal tablet storage and an external SD card. For example on my Flyer, /sdcard and /sdcard2 are separate, with the former representing the tablet's "internal storage."

If I use Environment.getExternalStorageDirectory(), there doesn't seem to be any set rule on which of those storage locations will be returned. In using getExternalStorageDirectory(), my concern is that I'll only find media stored on one of the two storage locations.

One solution is to just hard-code scanning /sdcard* into the application, but this makes an assumption that all devices will use that as a naming scheme, and I don't consider that a safe assumption.

Is there a documented way to scan and use multiple sd card/storage locations on Android 2.x?

My goal is actually to find all audiobooks on the tablet, so I'd like to find and use all /sdcard*/Audiobooks in some documented way.

like image 288
Ken Kinder Avatar asked Oct 10 '22 22:10

Ken Kinder


2 Answers

Normally second sdcard is mounted within the first one.

Here is what I mean:

  • First sdcard is mounted at /mnt/sdcard.

  • The second sdcard is mounted into /mnt/sdcard/external_sd

So whenever you receive /mnt/sdcard as path for external storage and start scanning the tree, you won't miss the second sdcard (if it was also mounted).

This is not documented behavior. But Galaxy Tab behaves exactly this way. I assume this is because there is no official Android API support (i.e. no special function in Environment class) for multiple external storages.

like image 153
inazaruk Avatar answered Oct 13 '22 11:10

inazaruk


You may use the code bellow to get paths to all SD-CARDs in system. This works on all Android versions and return paths to all storages (include emulated).

Works correctly on all my devices.

private static final Pattern DIR_SEPORATOR = Pattern.compile("/");

/**
 * Raturns all available SD-Cards in the system (include emulated)
 *
 * Warning: Hack! Based on Android source code of version 4.3 (API 18)
 * Because there is no standart way to get it.
 * TODO: Test on future Android versions 4.4+
 *
 * @return paths to all available SD-Cards in the system (include emulated)
 */
public static String[] getStorageDirectories()
{
    // Final set of paths
    final Set<String> rv = new HashSet<String>();
    // Primary physical SD-CARD (not emulated)
    final String rawExternalStorage = System.getenv("EXTERNAL_STORAGE");
    // All Secondary SD-CARDs (all exclude primary) separated by ":"
    final String rawSecondaryStoragesStr = System.getenv("SECONDARY_STORAGE");
    // Primary emulated SD-CARD
    final String rawEmulatedStorageTarget = System.getenv("EMULATED_STORAGE_TARGET");
    if(TextUtils.isEmpty(rawEmulatedStorageTarget))
    {
        // Device has physical external storage; use plain paths.
        if(TextUtils.isEmpty(rawExternalStorage))
        {
            // EXTERNAL_STORAGE undefined; falling back to default.
            rv.add("/storage/sdcard0");
        }
        else
        {
            rv.add(rawExternalStorage);
        }
    }
    else
    {
        // Device has emulated storage; external storage paths should have
        // userId burned into them.
        final String rawUserId;
        if(Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1)
        {
            rawUserId = "";
        }
        else
        {
            final String path = Environment.getExternalStorageDirectory().getAbsolutePath();
            final String[] folders = DIR_SEPORATOR.split(path);
            final String lastFolder = folders[folders.length - 1];
            boolean isDigit = false;
            try
            {
                Integer.valueOf(lastFolder);
                isDigit = true;
            }
            catch(NumberFormatException ignored)
            {
            }
            rawUserId = isDigit ? lastFolder : "";
        }
        // /storage/emulated/0[1,2,...]
        if(TextUtils.isEmpty(rawUserId))
        {
            rv.add(rawEmulatedStorageTarget);
        }
        else
        {
            rv.add(rawEmulatedStorageTarget + File.separator + rawUserId);
        }
    }
    // Add all secondary storages
    if(!TextUtils.isEmpty(rawSecondaryStoragesStr))
    {
        // All Secondary SD-CARDs splited into array
        final String[] rawSecondaryStorages = rawSecondaryStoragesStr.split(File.pathSeparator);
        Collections.addAll(rv, rawSecondaryStorages);
    }
    return rv.toArray(new String[rv.size()]);
}
like image 34
Dmitriy Lozenko Avatar answered Oct 13 '22 12:10

Dmitriy Lozenko