-
-
Save PauloLuan/4bcecc086095bce28e22 to your computer and use it in GitHub Desktop.
public static String getExternalSdCardPath() { | |
String path = null; | |
File sdCardFile = null; | |
List<String> sdCardPossiblePath = Arrays.asList("external_sd", "ext_sd", "external", "extSdCard"); | |
for (String sdPath : sdCardPossiblePath) { | |
File file = new File("/mnt/", sdPath); | |
if (file.isDirectory() && file.canWrite()) { | |
path = file.getAbsolutePath(); | |
String timeStamp = new SimpleDateFormat("ddMMyyyy_HHmmss").format(new Date()); | |
File testWritable = new File(path, "test_" + timeStamp); | |
if (testWritable.mkdirs()) { | |
testWritable.delete(); | |
} | |
else { | |
path = null; | |
} | |
} | |
} | |
if (path != null) { | |
sdCardFile = new File(path); | |
} | |
else { | |
sdCardFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath()); | |
} | |
return sdCardFile.getAbsolutePath(); | |
} |
paresh996 you are absolutely correct. I have tested your code on my device(Gionee) and it worked . But i heard that samsung manufacturer put the removable storage in mnt/extSdCard/ .Did you tested this on samsung as well?
Greate code PauloLuan ! Really saved Me , Looking for this from 10 days of searching everysite.....
/**
* Get external sd card path using reflection
* @param mContext
* @param is_removable is external storage removable
* @return
*/
private static String getExternalStoragePath(Context mContext, boolean is_removable) {
StorageManager mStorageManager = (StorageManager) mContext.getSystemService(Context.STORAGE_SERVICE);
Class<?> storageVolumeClazz = null;
try {
storageVolumeClazz = Class.forName("android.os.storage.StorageVolume");
Method getVolumeList = mStorageManager.getClass().getMethod("getVolumeList");
Method getPath = storageVolumeClazz.getMethod("getPath");
Method isRemovable = storageVolumeClazz.getMethod("isRemovable");
Object result = getVolumeList.invoke(mStorageManager);
final int length = Array.getLength(result);
for (int i = 0; i < length; i++) {
Object storageVolumeElement = Array.get(result, i);
String path = (String) getPath.invoke(storageVolumeElement);
boolean removable = (Boolean) isRemovable.invoke(storageVolumeElement);
if (is_removable == removable) {
return path;
}
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
Kotlin version:
private fun getExternalCardDirectory(): File? {
val storageManager = getSystemService(Context.STORAGE_SERVICE)
try {
val storageVolumeClazz = Class.forName("android.os.storage.StorageVolume")
val getVolumeList = storageManager.javaClass.getMethod("getVolumeList")
val getPath = storageVolumeClazz.getMethod("getPath")
val isRemovable = storageVolumeClazz.getMethod("isRemovable")
val result = getVolumeList.invoke(storageManager) as Array<StorageVolume>
result.forEach {
if (isRemovable.invoke(it) as Boolean) {
return File(getPath.invoke(it) as String)
}
}
} catch (e: Throwable) {
e.printStackTrace()
}
return null
}
lovelyelfpop's version works great, thank you!
@lovelyelfpop Great, it works
@lovelyelfpop God bless you, seems this is the only working solution on internet currently. Thanks a bunch!!
In Samsung external card location has changed as:
/storage/0000-0000/
Thanks, @lovelyelfpop this worked on my Samsung SM-T320 running Android version 4.4.2.
- I followed get Context in non-Activity class [duplicate] to get the context into my Util class from the MainActivity.
- Here's some things I imported. there might have been a couple more.
import android.os.storage.StorageManager;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
Thanks again. This worked like a champ
@lovelyelfpop Thank you, very much
Hi,
After Android Q, the method getPath cannot be called through reflection.
For me, the following code works. Tested on around 6-7 devices, ranging from Android 4.3 up to Android 12.
private fun getExternalCardDirectory(): String {
val storageManager = context.getSystemService(Context.STORAGE_SERVICE)
try {
val storageVolumeClassReflection = Class.forName("android.os.storage.StorageVolume")
val getVolumeList = storageManager.javaClass.getMethod("getVolumeList")
val getPath = if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
storageVolumeClassReflection.getMethod("getDirectory")
} else {
storageVolumeClassReflection.getMethod("getPath")
}
val isRemovable = storageVolumeClassReflection.getMethod("isRemovable")
val result = getVolumeList.invoke(storageManager) as Array<StorageVolume>
result.forEach {
if (isRemovable.invoke(it) as Boolean) {
return when(val invokeResult = getPath.invoke(it)) {
is File -> invokeResult.absolutePath
is String -> invokeResult
else -> DEFAULT_VALUE.also {
log.debug { "Reflection unsupported type; Invoke result: $invokeResult" }
}
}
}
}
} catch (e: Throwable) {
log.debug { "Could not get SD card path; Exception: $e" }
}
return DEFAULT_VALUE
}
With DEFAULT_VALUE = "N/A"
Credit @lovelyelfpop
I just figured out something. At least for every phone I came across today and even my Android Emulator had the SD Card Path like ' /storage/????-???? ' where every ? is a capital letter or a digit.
So, if /storage/ directory has a directory which is readable and that is not the internal storage directory, it must be the SD Card.
My code worked on all phones I tested and even on my android emulator!
If there is an SD Card, removableStoragePath will have it's path. If there isn't it will be an empty string.