Accessing USB Pendrive from android tablet - android

We have a usb port in our android tablet(version 4.0.3).
How do we find out any PenDrive connected on that port or not.
How do we access the files in the USB Pendrive which connected on that port through programmatically in android.
We have a /mnt contained Folder as
asec
extsd
obb
sdcard
secure
usbhost1
How to programmatically identify which one is Internal Memory Path, External SD Card Path and USB Path.
What is the purpose for used this folder asec, obb and secure.
Thanks in advance.
Regards
Bala

I guess to use the external sdcard you need to use this:
new File("/mnt/external_sd/")
OR
new File("/mnt/extSdCard/")
OR
new File("/mnt/usb_storage")
in replace of Environment.getExternalStorageDirectory()
Works for me. You should check whats in the directory mnt first and work from there..
You should use some type of selection method to choose which sdcard to use:
File storageDir = new File("/mnt/");
if(storageDir.isDirectory()){
String[] dirList = storageDir.list();
//TODO some type of selecton method?
}
The "pen drive" is located in /mnt/ (just like all other storage devices in 4.0>)
It will probably be different for some devices, for the Acer Iconia A500 running 4.0.3 usb storage is under /mnt/usb_storage/

How do we find out any PenDrive connected on that port or not.
There is no documented and supported means to do that in the Android SDK. You would need to speak with your device manufacturer and get their recommendations for how to do this for their specific device.
How do we access the files in the USB Pendrive which connected on that port through programmatically in android.
See above.

*Using this you can find path and asses the file in USB*
public String getStoragepath() {
try {
Runtime runtime = Runtime.getRuntime();
Process proc = runtime.exec("mount");
InputStream is = proc.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
String line;
String[] patharray = new String[10];
int i = 0;
int available = 0;
BufferedReader br = new BufferedReader(isr);
while ((line = br.readLine()) != null) {
String mount = new String();
if (line.contains("secure"))
continue;
if (line.contains("asec"))
continue;
if (line.contains("fat")) {// TF card
String columns[] = line.split(" ");
if (columns != null && columns.length > 1) {
mount = mount.concat(columns[1] + "/requiredfiles");
patharray[i] = mount;
i++;
// check directory is exist or not
File dir = new File(mount);
if (dir.exists() && dir.isDirectory()) {
// do something here
// t1.show();
available = 1;
finalpath = mount;
break;
} else {
}
}
}
}
if (available == 1) {
} else if (available == 0) {
finalpath = patharray[0];
}
} catch (Exception e) {
}
return finalpath;
}

Related

Get the public/root directory of a secondary external storage device in Android?

In android I am able to get my phone's removable external storage by use of:
for (File f : context.getExternalFilesDirs("/"))
if (Environment.isExternalStorageRemovable(f))
Log.println(Log.DEBUG, "#", f.getAbsolutePath());
However, this returns /storage/8E6A-06FF/Android/data/test.application/files which isn't what I want as I simply want the removable's root path /storage/8E6A-06FF/. How can I can get the root path of my phone's removable storage?
You can try this one it is works perfectly for me.It works like a charm with all Os's version.I didn't found any issue so far with this function.
public static String getSDPath() {
String filepath = "";
String[] strPath = {"/storage/sdcard1", "/storage/extsdcard",
"/storage/sdcard0/external_sdcard", "/mnt/extsdcard",
"/mnt/sdcard/external_sd", "/mnt/external_sd",
"/mnt/media_rw/sdcard1", "/removable/microsd", "/mnt/emmc",
"/storage/external_SD", "/storage/ext_sd",
"/storage/removable/sdcard1", "/data/sdext", "/data/sdext2",
"/data/sdext3", "/data/sdext4", "/emmc", "/sdcard/sd",
"/mnt/sdcard/bpemmctest", "/mnt/sdcard/_ExternalSD",
"/mnt/sdcard-ext", "/mnt/Removable/MicroSD",
"/Removable/MicroSD", "/mnt/external1", "/mnt/extSdCard",
"/mnt/extsd", "/mnt/usb_storage", "/mnt/extSdCard",
"/mnt/UsbDriveA", "/mnt/UsbDriveB"};
for (String value : strPath) {
File f = null;
f = new File(value);
if (f.exists() && f.isDirectory()) {
filepath = value;
break;
}
}
return filepath;
}
Try this:
for (File f : context.getExternalFilesDirs("/"))
if (Environment.isExternalStorageRemovable(f))
Log.println(Log.DEBUG, "#", f.getParentFile().getParentFile().getParentFile().getParent());
context.getExternalFilesDirs() will always returns application-specific directory. But the good thing is that application-specific directories are always 4 level deep from the root folder of the storage device. So calling getParentFile() four times on the File f instead of f.getAbsolutePath() will get you the root path of your phone's removable storage.
Maybe just split it at Android?
I tested it, and it works after I request for permission - WRITE_EXTERNAL_STORAGE.
fun getBaseDir(dir: File): String {
val absPath = dir.absolutePath
return if (absPath.contains("/Android")) {
absPath.split("/Android")[0]
} else {
absPath
}
}
This will loop through files on sdcard root directory. If you want primary storage, just change [1] to [0].
getExternalFilesDirs returns paths to your app directory on primary and secondary storage. After splitting the second path by "Android", the first string will contain path to your secondary storage root. for example in my case it was "/storage/B242-37B2/". Working with minSdkVersion 19+.
String sdCardRoot = ContextCompat.getExternalFilesDirs(getApplicationContext(), null)[1].getAbsolutePath().split("Android")[0];
File f = new File(sdCardRoot);
File[] files = f.listFiles();
for (File inFile : files){
Log.d("Files", inFile.getName());
}
Try this one if it helps you. For more information refer this link.
public static HashSet<String> getExternalMounts() {
final HashSet<String> out = new HashSet<String>();
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);
}
}
}
}
return out;
}
Here is another approach for the same. Source from here.
Environment.getExternalStorageState() returns path to internal SD
mount point like "/mnt/sdcard"
But the question is about external SD. How to get a path like "/mnt/sdcard/external_sd" (it may differ from device to device)?
Android has no concept of "external SD", aside from external storage, as described above.
If a device manufacturer has elected to have external storage be on-board flash and also has an SD card, you will need to contact that manufacturer to determine whether or not you can use the SD card (not guaranteed) and what the rules are for using it, such as what path to use for it.

Sd Card Path of Android Phone

I am trying to make a file browser app. So I want to begin with displaying something like this.
But I can not reach my SD card's path. I used this method
String path = Environment.getExternalStorageDirectory();
In the documentation here It says:
Note: don't be confused by the word "external" here. This directory can better be thought as media/shared storage. It is a filesystem that can hold a relatively large amount of data and that is shared across all applications (does not enforce permissions). Traditionally this is an SD card, but it may also be implemented as built-in storage in a device that is distinct from the protected internal storage and can be mounted as a filesystem on a computer.
The problem is I can reach to the device storage but I can't reach to my SD card's path. Does anyone know how to get that path?
// Access the built-in SD card
private String getInnerSDCardPath() {
return Environment.getExternalStorageDirectory().getPath();
}
// Access to external SD card
private List<String> getExtSDCardPath() {
List<String> pathList = new ArrayList<String>();
try {
Runtime runtime = Runtime.getRuntime();
Process proc = runtime.exec("mount");
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(proc.getInputStream()));
String line;
while ((line = bufferedReader.readLine()) != null) {
if (line.contains("extSdCard")) {
String[] arr = line.split(" ");
String path = arr[1];
File file = new File(path);
if (file.isDirectory()) {
pathList.add(path);
}
}
}
bufferedReader.close();
} catch (Exception e) {
e.printStackTrace();
}
return pathList;
}
I hope it can help you.

Getting sd card directory in Android device

Below is the code written for retrieving the sd card directory.
I have been using execution of command and changed into reading the /proc/mounts.
My Question is whether it is the right code ?
Not an expert on Linux OS. Will the /proc/mounts path be same for all the devices ?
I think this code will be also free of any command injection possiblities.
// Process process = new ProcessBuilder().command("mount").start();
// process.waitFor();
reader = new BufferedReader(new FileReader("/proc/mounts"));
String line;
while ((line = reader.readLine()) != null) {
// Output the line of output from the mount command
logger.debug(" {}", line);
if (line.startsWith("/dev/block/vold/")) {
String[] tokens = line.split(" ");
if (tokens.length >= 3 && (tokens[2].equals("vfat") || tokens[2].equals("exfat"))) {
String path = tokens[1];
File file = new File(path);
if (file.exists() && file.isDirectory()) {
logger.debug("Detected SD card at {}", file.getPath());
if (!file.canWrite()) {
logger.warn("The SD card path {} is reporting that it is not writable", file.getPath());
}
return path;
}
}
}
}
cheers,
Saurav
On Android you can get the sd card's directory on any device through
Environment.getExternalStorageDirectory();
http://developer.android.com/reference/android/os/Environment.html#getExternalStorageDirectory()
Please use
Environment.getExternalStorageDirectory(); to get the path to SD card.
Also, use Environment.getExternalStorageState() against attribute Environment.MEDIA_MOUNTED etc, to check if the SD card is Readable, Mounted etc. :)

how to differentiate between internal and external SD card path in android

In android application I need to do:
If(removable SdCard is present){
String path=get the path of removable Sdcard() ;
//using this path we will create some files in sdcard
} else{
//display error message
}
To achieve this we used the code as:
If (Environment.getExternalStorageState().equalsIgnoreCase(Environment.MEDIA_MOUNTED)){
String path= Environment.getExternalStorageDirectory().getPath();
}
The above code fails in some of latest android mobiles. Please help us on this.
Below are the details of what we have tried:
In android mobiles having OS of ICS and JellyBean, the exact path of the removable sdcard varies because of device manufacturer.
See the table below
Tested Devices OS version removable sdcard path internal sd path
Samsung galaxy s2 4.0.4 /mnt/sdcard/external_sd /mnt/sdcard
Samsung S Advance 4.1.2 /storage/extSdCard /storage/sdcard0
Samsung Galaxy s3 4.0.4 /mnt/extSdCard /mnt/sdcard
Samsung Galaxy Note 4.0.4 /mnt/sdcard/external_sd /mnt/sdcard
When running the above code in these devices we got:
The android API Environment.getExternalStorageDirectory().getPath() returns only the internal sd path
Also the the API Environment.getExternalStorageState() return Environment.MEDIA_MOUNTED in above devices even though sdcard is removed.
Further the API Environment.isExternalStorageRemovable() always returns false for above devices whether removable sdcard is present or not.
We searched in google and tried some functions they given.It gives only list of storage paths that are mounted to the device.But it doesnot indicate whether the removale sdcard is present or not.
The function i tried to get the storage path:
private static String getMountedPaths(){
String sdcardPath = "";
Runtime runtime = Runtime.getRuntime();
Process proc = null;
try {
proc = runtime.exec("mount");
} catch (IOException e1) {
e1.printStackTrace();
}
InputStream is = proc.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
String line;
BufferedReader br = new BufferedReader(isr);
try {
while ((line = br.readLine()) != null) {
if (line.contains("secure")) continue;
if (line.contains("asec")) continue;
if (line.contains("fat")) {//TF card
String columns[] = line.split(" ");
if (columns != null && columns.length > 1) {
mount.add(columns[1]);
sdcardPath=columns[1];
}
} else if (line.contains("fuse")) {//internal storage
String columns[] = line.split(" ");
if (columns != null && columns.length > 1) {
mount.add(columns[1]);
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
return sdcardPath;
}
Is there any other function better than above to get the list of storage paths in android ?
also help to solve the above problem .
To get internal SD card
String internalStorage = System.getenv("EXTERNAL_STORAGE");
File f_exts = new File(internalStorage );
To get external SD card
String externalStorage = System.getenv("SECONDARY_STORAGE");
File f_secs = new File(externalStorage );

How can I get the external SD card path for Android 4.0+?

Samsung Galaxy S3 has an external SD card slot, which is mounted to /mnt/extSdCard.
How can I get this path by something like Environment.getExternalStorageDirectory()?
This will return mnt/sdcard, and I can't find the API for the external SD card. (Or removable USB storage on some tablets.)
I have a variation on a solution I found here
public static HashSet<String> getExternalMounts() {
final HashSet<String> out = new HashSet<String>();
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);
}
}
}
}
return out;
}
The original method was tested and worked with
Huawei X3 (stock)
Galaxy S2 (stock)
Galaxy S3 (stock)
I'm not certain which android version these were on when they were tested.
I've tested my modified version with
Moto Xoom 4.1.2 (stock)
Galaxy Nexus (cyanogenmod 10) using an otg cable
HTC Incredible (cyanogenmod 7.2) this returned both the internal and external. This device is kinda an oddball in that its internal largely goes unused as getExternalStorage() returns a path to the sdcard instead.
and some single storage devices that use an sdcard as their main storage
HTC G1 (cyanogenmod 6.1)
HTC G1 (stock)
HTC Vision/G2 (stock)
Excepting the Incredible all these devices only returned their removable storage. There are probably some extra checks I should be doing, but this is at least a bit better than any solution I've found thus far.
I found more reliable way 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.
P.S.: Based on source code of Environment class.
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()]);
}
I guess to use the external sdcard you need to use this:
new File("/mnt/external_sd/")
OR
new File("/mnt/extSdCard/")
in your case...
in replace of Environment.getExternalStorageDirectory()
Works for me. You should check whats in the directory mnt first and work from there..
You should use some type of selection method to choose which sdcard to use:
File storageDir = new File("/mnt/");
if(storageDir.isDirectory()){
String[] dirList = storageDir.list();
//TODO some type of selecton method?
}
I was using Dmitriy Lozenko's solution until i checked on an Asus Zenfone2, Marshmallow 6.0.1 and the solution is not working. The solution failed when getting EMULATED_STORAGE_TARGET, specifically for microSD path, i.e: /storage/F99C-10F4/. I edited the code to get the emulated root paths directly from emulated application paths with context.getExternalFilesDirs(null); and add more known phone-model-specific physical paths.
To make our life easier, I made a library here. You can use it via gradle, maven, sbt, and leiningen build system.
If you like the old-fashioned way, you can also copy paste the file directly from here, but you will not know if there is an update in the future without checking it manually.
If you have any question or suggestion, please let me know
In order to retrieve all the External Storages (whether they are SD cards or internal non-removable storages), you can use the following code:
final String state = Environment.getExternalStorageState();
if ( Environment.MEDIA_MOUNTED.equals(state) || Environment.MEDIA_MOUNTED_READ_ONLY.equals(state) ) { // we can read the External Storage...
//Retrieve the primary External Storage:
final File primaryExternalStorage = Environment.getExternalStorageDirectory();
//Retrieve the External Storages root directory:
final String externalStorageRootDir;
if ( (externalStorageRootDir = primaryExternalStorage.getParent()) == null ) { // no parent...
Log.d(TAG, "External Storage: " + primaryExternalStorage + "\n");
}
else {
final File externalStorageRoot = new File( externalStorageRootDir );
final File[] files = externalStorageRoot.listFiles();
for ( final File file : files ) {
if ( file.isDirectory() && file.canRead() && (file.listFiles().length > 0) ) { // it is a real directory (not a USB drive)...
Log.d(TAG, "External Storage: " + file.getAbsolutePath() + "\n");
}
}
}
}
Alternatively, you might use System.getenv("EXTERNAL_STORAGE") to retrieve the primary External Storage directory (e.g. "/storage/sdcard0") and System.getenv("SECONDARY_STORAGE") to retieve the list of all the secondary directories (e.g. "/storage/extSdCard:/storage/UsbDriveA:/storage/UsbDriveB"). Remember that, also in this case, you might want to filter the list of secondary directories in order to exclude the USB drives.
In any case, please note that using hard-coded paths is always a bad approach (expecially when every manufacturer may change it as pleased).
Good news! In KitKat there's now a public API for interacting with these secondary shared storage devices.
The new Context.getExternalFilesDirs() and Context.getExternalCacheDirs() methods can return multiple paths, including both primary and secondary devices. You can then iterate over them and check Environment.getStorageState() and File.getFreeSpace() to determine the best place to store your files. These methods are also available on ContextCompat in the support-v4 library.
Also note that if you're only interested in using the directories returned by Context, you no longer need the READ_ or WRITE_EXTERNAL_STORAGE permissions. Going forward, you'll always have read/write access to these directories with no additional permissions required.
Apps can also continue working on older devices by end-of-lifing their permission request like this:
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="18" />
I did the following to get acces to all the external sd cards.
With:
File primaryExtSd=Environment.getExternalStorageDirectory();
you get the path to the primary external SD
Then with:
File parentDir=new File(primaryExtSd.getParent());
you get the parent dir of the primary external storage, and it is also the parent of all the external sd.
Now, you can list all the storage and select the one that you want.
Hope it is usefull.
Found a new way that is more official starting from Android N (if before, you can try what I've written above) and especially from Android R, using StorageManager (based on a solution I wrote here) :
class MainActivity : AppCompatActivity() {
#RequiresApi(Build.VERSION_CODES.N)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
getSdCardPaths(this, true)?.forEach { volumePath ->
Log.d("AppLog", "volumePath:$volumePath")
}
}
/**
* returns a list of all available sd cards paths, or null if not found.
*
* #param includePrimaryExternalStorage set to true if you wish to also include the path of the primary external storage
*/
fun getSdCardPaths(context: Context, includePrimaryExternalStorage: Boolean): List<String>? {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
val storageManager = context.getSystemService(Context.STORAGE_SERVICE) as StorageManager
val storageVolumes = storageManager.storageVolumes
if (!storageVolumes.isNullOrEmpty()) {
val primaryVolume = storageManager.primaryStorageVolume
val result = ArrayList<String>(storageVolumes.size)
for (storageVolume in storageVolumes) {
val volumePath = getVolumePath(storageVolume) ?: continue
if (storageVolume.uuid == primaryVolume.uuid || storageVolume.isPrimary) {
if (includePrimaryExternalStorage)
result.add(volumePath)
continue
}
result.add(volumePath)
}
return if (result.isEmpty()) null else result
}
}
val externalCacheDirs = ContextCompat.getExternalCacheDirs(context)
if (externalCacheDirs.isEmpty())
return null
if (externalCacheDirs.size == 1) {
if (externalCacheDirs[0] == null)
return null
val storageState = EnvironmentCompat.getStorageState(externalCacheDirs[0])
if (Environment.MEDIA_MOUNTED != storageState)
return null
if (!includePrimaryExternalStorage && Environment.isExternalStorageEmulated())
return null
}
val result = ArrayList<String>()
if (externalCacheDirs[0] != null && (includePrimaryExternalStorage || externalCacheDirs.size == 1))
result.add(getRootOfInnerSdCardFolder(context, externalCacheDirs[0]))
for (i in 1 until externalCacheDirs.size) {
val file = externalCacheDirs[i] ?: continue
val storageState = EnvironmentCompat.getStorageState(file)
if (Environment.MEDIA_MOUNTED == storageState)
result.add(getRootOfInnerSdCardFolder(context, externalCacheDirs[i]))
}
return if (result.isEmpty()) null else result
}
fun getRootOfInnerSdCardFolder(context: Context, inputFile: File): String {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
val storageManager = context.getSystemService(Context.STORAGE_SERVICE) as StorageManager
storageManager.getStorageVolume(inputFile)?.let {
val result = getVolumePath(it)
if (result != null)
return result
}
}
var file: File = inputFile
val totalSpace = file.totalSpace
while (true) {
val parentFile = file.parentFile
if (parentFile == null || parentFile.totalSpace != totalSpace || !parentFile.canRead())
return file.absolutePath
file = parentFile
}
}
#RequiresApi(Build.VERSION_CODES.N)
fun getVolumePath(storageVolume: StorageVolume): String? {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R)
return storageVolume.directory?.absolutePath
try {
val storageVolumeClazz = StorageVolume::class.java
val getPath = storageVolumeClazz.getMethod("getPath")
return getPath.invoke(storageVolume) as String
} catch (e: Exception) {
e.printStackTrace()
}
return null
}
}
Thanks for the clues provided by you guys, especially #SmartLemon, I got the solution. In case someone else need it, I put my final solution here( to find the first listed external SD card ):
public File getExternalSDCardDirectory()
{
File innerDir = Environment.getExternalStorageDirectory();
File rootDir = innerDir.getParentFile();
File firstExtSdCard = innerDir ;
File[] files = rootDir.listFiles();
for (File file : files) {
if (file.compareTo(innerDir) != 0) {
firstExtSdCard = file;
break;
}
}
//Log.i("2", firstExtSdCard.getAbsolutePath().toString());
return firstExtSdCard;
}
If no external SD card there, then it returns the on board storage. I will use it if the sdcard is not exist, you may need to change it.
refer to my code, hope helpful for you:
Runtime runtime = Runtime.getRuntime();
Process proc = runtime.exec("mount");
InputStream is = proc.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
String line;
String mount = new String();
BufferedReader br = new BufferedReader(isr);
while ((line = br.readLine()) != null) {
if (line.contains("secure")) continue;
if (line.contains("asec")) continue;
if (line.contains("fat")) {//TF card
String columns[] = line.split(" ");
if (columns != null && columns.length > 1) {
mount = mount.concat("*" + columns[1] + "\n");
}
} else if (line.contains("fuse")) {//internal storage
String columns[] = line.split(" ");
if (columns != null && columns.length > 1) {
mount = mount.concat(columns[1] + "\n");
}
}
}
txtView.setText(mount);
This solution (assembled from other answers to this question) handles the fact (as mentioned by #ono) that System.getenv("SECONDARY_STORAGE") is of no use with Marshmallow.
Tested and working on:
Samsung Galaxy Tab 2 (Android 4.1.1 - Stock)
Samsung Galaxy Note 8.0 (Android 4.2.2 - Stock)
Samsung Galaxy S4 (Android 4.4 - Stock)
Samsung Galaxy S4 (Android 5.1.1 - Cyanogenmod)
Samsung Galaxy Tab A (Android 6.0.1 - Stock)
/**
* Returns all available external SD-Card roots in the system.
*
* #return paths to all available external SD-Card roots in the system.
*/
public static String[] getStorageDirectories() {
String [] storageDirectories;
String rawSecondaryStoragesStr = System.getenv("SECONDARY_STORAGE");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
List<String> results = new ArrayList<String>();
File[] externalDirs = applicationContext.getExternalFilesDirs(null);
for (File file : externalDirs) {
String path = file.getPath().split("/Android")[0];
if((Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && Environment.isExternalStorageRemovable(file))
|| rawSecondaryStoragesStr != null && rawSecondaryStoragesStr.contains(path)){
results.add(path);
}
}
storageDirectories = results.toArray(new String[0]);
}else{
final Set<String> rv = new HashSet<String>();
if (!TextUtils.isEmpty(rawSecondaryStoragesStr)) {
final String[] rawSecondaryStorages = rawSecondaryStoragesStr.split(File.pathSeparator);
Collections.addAll(rv, rawSecondaryStorages);
}
storageDirectories = rv.toArray(new String[rv.size()]);
}
return storageDirectories;
}
Actually in some devices the external sdcard default name is showing as extSdCard and for other it is sdcard1.
This code snippet helps to find out that exact path and helps to retrieve you the path of external device.
String sdpath,sd1path,usbdiskpath,sd0path;
if(new File("/storage/extSdCard/").exists())
{
sdpath="/storage/extSdCard/";
Log.i("Sd Cardext Path",sdpath);
}
if(new File("/storage/sdcard1/").exists())
{
sd1path="/storage/sdcard1/";
Log.i("Sd Card1 Path",sd1path);
}
if(new File("/storage/usbcard1/").exists())
{
usbdiskpath="/storage/usbcard1/";
Log.i("USB Path",usbdiskpath);
}
if(new File("/storage/sdcard0/").exists())
{
sd0path="/storage/sdcard0/";
Log.i("Sd Card0 Path",sd0path);
}
Yes. Different manufacturer use different SDcard name like in Samsung Tab 3 its extsd, and other samsung devices use sdcard like this different manufacturer use different names.
I had the same requirement as you. so i have created a sample example for you from my project goto this link Android Directory chooser example which uses the androi-dirchooser library. This example detect the SDcard and list all the subfolders and it also detects if the device has morethan one SDcard.
Part of the code looks like this For full example goto the link Android Directory Chooser
/**
* Returns the path to internal storage ex:- /storage/emulated/0
*
* #return
*/
private String getInternalDirectoryPath() {
return Environment.getExternalStorageDirectory().getAbsolutePath();
}
/**
* Returns the SDcard storage path for samsung ex:- /storage/extSdCard
*
* #return
*/
private String getSDcardDirectoryPath() {
return System.getenv("SECONDARY_STORAGE");
}
mSdcardLayout.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view) {
String sdCardPath;
/***
* Null check because user may click on already selected buton before selecting the folder
* And mSelectedDir may contain some wrong path like when user confirm dialog and swith back again
*/
if (mSelectedDir != null && !mSelectedDir.getAbsolutePath().contains(System.getenv("SECONDARY_STORAGE"))) {
mCurrentInternalPath = mSelectedDir.getAbsolutePath();
} else {
mCurrentInternalPath = getInternalDirectoryPath();
}
if (mCurrentSDcardPath != null) {
sdCardPath = mCurrentSDcardPath;
} else {
sdCardPath = getSDcardDirectoryPath();
}
//When there is only one SDcard
if (sdCardPath != null) {
if (!sdCardPath.contains(":")) {
updateButtonColor(STORAGE_EXTERNAL);
File dir = new File(sdCardPath);
changeDirectory(dir);
} else if (sdCardPath.contains(":")) {
//Multiple Sdcards show root folder and remove the Internal storage from that.
updateButtonColor(STORAGE_EXTERNAL);
File dir = new File("/storage");
changeDirectory(dir);
}
} else {
//In some unknown scenario at least we can list the root folder
updateButtonColor(STORAGE_EXTERNAL);
File dir = new File("/storage");
changeDirectory(dir);
}
}
});
On some devices (for example samsung galaxy sII )internal memory card mabe be in vfat. In this case use refer last code, we obtain path internal memory card (/mnt/sdcad) but no external card. Code refer below solve this problem.
static String getExternalStorage(){
String exts = Environment.getExternalStorageDirectory().getPath();
try {
FileReader fr = new FileReader(new File("/proc/mounts"));
BufferedReader br = new BufferedReader(fr);
String sdCard=null;
String line;
while((line = br.readLine())!=null){
if(line.contains("secure") || line.contains("asec")) continue;
if(line.contains("fat")){
String[] pars = line.split("\\s");
if(pars.length<2) continue;
if(pars[1].equals(exts)) continue;
sdCard =pars[1];
break;
}
}
fr.close();
br.close();
return sdCard;
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
File[] files = null;
File file = new File("/storage");// /storage/emulated
if (file.exists()) {
files = file.listFiles();
}
if (null != files)
for (int j = 0; j < files.length; j++) {
Log.e(TAG, "" + files[j]);
Log.e(TAG, "//--//--// " + files[j].exists());
if (files[j].toString().replaceAll("_", "")
.toLowerCase().contains("extsdcard")) {
external_path = files[j].toString();
break;
} else if (files[j].toString().replaceAll("_", "")
.toLowerCase()
.contains("sdcard".concat(Integer.toString(j)))) {
// external_path = files[j].toString();
}
Log.e(TAG, "--///--///-- " + external_path);
}
System.getenv("SECONDARY_STORAGE") returns null for Marshmallow. This is another way of finding all the externals dirs. You can check if it's removable which determines if internal/external
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
File[] externalCacheDirs = context.getExternalCacheDirs();
for (File file : externalCacheDirs) {
if (Environment.isExternalStorageRemovable(file)) {
// It's a removable storage
}
}
}
I am sure this code will surely resolve your issues...This is working fine for me...\
try {
File mountFile = new File("/proc/mounts");
usbFoundCount=0;
sdcardFoundCount=0;
if(mountFile.exists())
{
Scanner usbscanner = new Scanner(mountFile);
while (usbscanner.hasNext()) {
String line = usbscanner.nextLine();
if (line.startsWith("/dev/fuse /storage/usbcard1")) {
usbFoundCount=1;
Log.i("-----USB--------","USB Connected and properly mounted---/dev/fuse /storage/usbcard1" );
}
}
}
if(mountFile.exists()){
Scanner sdcardscanner = new Scanner(mountFile);
while (sdcardscanner.hasNext()) {
String line = sdcardscanner.nextLine();
if (line.startsWith("/dev/fuse /storage/sdcard1")) {
sdcardFoundCount=1;
Log.i("-----USB--------","USB Connected and properly mounted---/dev/fuse /storage/sdcard1" );
}
}
}
if(usbFoundCount==1)
{
Toast.makeText(context,"USB Connected and properly mounted", 7000).show();
Log.i("-----USB--------","USB Connected and properly mounted" );
}
else
{
Toast.makeText(context,"USB not found!!!!", 7000).show();
Log.i("-----USB--------","USB not found!!!!" );
}
if(sdcardFoundCount==1)
{
Toast.makeText(context,"SDCard Connected and properly mounted", 7000).show();
Log.i("-----SDCard--------","SDCard Connected and properly mounted" );
}
else
{
Toast.makeText(context,"SDCard not found!!!!", 7000).show();
Log.i("-----SDCard--------","SDCard not found!!!!" );
}
}catch (Exception e) {
e.printStackTrace();
}
String path = Environment.getExternalStorageDirectory()
+ File.separator + Environment.DIRECTORY_PICTURES;
File dir = new File(path);
You can use something like - Context.getExternalCacheDirs() or Context.getExternalFilesDirs() or Context.getObbDirs(). They give application specific directories in all external storage devices where the application can store its files.
So something like this - Context.getExternalCacheDirs()[i].getParentFile().getParentFile().getParentFile().getParent() can get you the root path of external storage devices.
I know these commands are for a different purpose but other answers didn't work for me.
This link gave me good pointers - https://possiblemobile.com/2014/03/android-external-storage/
I have tried the solutions provided by Dmitriy Lozenko and Gnathonic on my Samsung Galaxy Tab S2 (Model: T819Y) but none helped me retrieve path to an external SD Card directory. mount command execution contained the required path to external SD Card directory (i.e. /Storage/A5F9-15F4) but it did not match the regular expression hence it was not returned. I don't get the directory naming mechanism followed by Samsung. Why they deviate from standards (i.e. extsdcard) and come up with something really fishy like in my case (i.e. /Storage/A5F9-15F4). Is there anything I am missing? Anyways, following changes in regular expression of Gnathonic's solution helped me get valid sdcard directory:
final HashSet<String> out = new HashSet<String>();
String reg = "(?i).*(vold|media_rw).*(sdcard|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);
}
}
}
}
return out;
I am not sure if this is a valid solution and if it will give results for other Samsung tablets but it has fixed my problem for now. Following is another method to retrieve removable SD Card path in Android (v6.0). I have tested the method with android marshmallow and it works. Approach used in it is very basic and will surely work for other versions too but testing is mandatory. Some insight into it will be helpful:
public static String getSDCardDirPathForAndroidMarshmallow() {
File rootDir = null;
try {
// Getting external storage directory file
File innerDir = Environment.getExternalStorageDirectory();
// Temporarily saving retrieved external storage directory as root
// directory
rootDir = innerDir;
// Splitting path for external storage directory to get its root
// directory
String externalStorageDirPath = innerDir.getAbsolutePath();
if (externalStorageDirPath != null
&& externalStorageDirPath.length() > 1
&& externalStorageDirPath.startsWith("/")) {
externalStorageDirPath = externalStorageDirPath.substring(1,
externalStorageDirPath.length());
}
if (externalStorageDirPath != null
&& externalStorageDirPath.endsWith("/")) {
externalStorageDirPath = externalStorageDirPath.substring(0,
externalStorageDirPath.length() - 1);
}
String[] pathElements = externalStorageDirPath.split("/");
for (int i = 0; i < pathElements.length - 1; i++) {
rootDir = rootDir.getParentFile();
}
File[] files = rootDir.listFiles();
for (File file : files) {
if (file.exists() && file.compareTo(innerDir) != 0) {
// Try-catch is implemented to prevent from any IO exception
try {
if (Environment.isExternalStorageRemovable(file)) {
return file.getAbsolutePath();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
Kindly share if you have any other approach to handle this issue. Thanks
String secStore = System.getenv("SECONDARY_STORAGE");
File externalsdpath = new File(secStore);
This will get the path of external sd secondary storage.
//manifest file outside the application tag
//please give permission write this
//<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
File file = new File("/mnt");
String[] fileNameList = file.list(); //file names list inside the mnr folder
String all_names = ""; //for the log information
String foundedFullNameOfExtCard = ""; // full name of ext card will come here
boolean isExtCardFounded = false;
for (String name : fileNameList) {
if (!isExtCardFounded) {
isExtCardFounded = name.contains("ext");
foundedFullNameOfExtCard = name;
}
all_names += name + "\n"; // for log
}
Log.d("dialog", all_names + foundedFullNameOfExtCard);
To access files in my SD card, on my HTC One X (Android), I use this path:
file:///storage/sdcard0/folder/filename.jpg
Note the tripple "/" !
On Galaxy S3 Android 4.3 the path I use is ./storage/extSdCard/Card/ and it does the job. Hope it helps,
that's not true. /mnt/sdcard/external_sd can exist even if the SD card is not mounted. your application will crash when you try to write to /mnt/sdcard/external_sd when it's not mounted.
you need to check if the SD card is mounted first using:
boolean isSDPresent = Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);
The following steps worked for me. You just need to write this lines:
String sdf = new String(Environment.getExternalStorageDirectory().getName());
String sddir = new String(Environment.getExternalStorageDirectory().getPath().replace(sdf,""));
The first line will give the name of sd directory, and you just need to use it in the replace method for the second string. The second string will contain the path for the internal and removable sd(/storage/ in my case). I just needed this path for my app but you can go further if you need it.

Categories

Resources