I'm trying to copy the files of my camera who use PTP to my tablet. I have use the android API MTPDevice
(https://developer.android.com/reference/android/mtp/MtpDevice.html#importFile%28int,%20java.lang.String%29) , I have request necessary permission(android.mtp.MtpClient.action.USB_PERMISSION).
I have open the device, the function return true, and open the USBConnection (Connexion OK).
I try to import all files of the camera in a temp Folder on my tablet (/mnt/sdcard/tmpFolder). The path exist on my tablet, but when i give it to the importFiles function I have the error :
[LOGCAT]
MtpDevice: readObject: /mnt/sdcard/tmpFolder
MtpDevice: open failed for /mnt/sdcard/tmpFolder
Debug: File import KO
I have try with a path doesn't exist I have the message :
[LOGCAT]
MtpDevice: readObject: /mnt/sdcard/tptp
MtpDevice: readResponse failed
Debug: File import KO
Someone can help me ?
Thanks
#Background
#DebugLog
public void getMTPDevice() {
HashMap<String, UsbDevice> deviceList = manager.getDeviceList();
Iterator<UsbDevice> deviceIterator = deviceList.values().iterator();
if (deviceIterator.hasNext()) {
UsbDevice usbDevice = deviceIterator.next();
device = openDeviceLocked(usbDevice);
if(device!=null){
File folder = returnTempFolderCamera();
if(folder.exists()){
Log.d("Debug", "Folder exist /mnt/sdcard/tmpFolder");
if(device.importFile(0,folder.getPath()))
{
Toast.makeText(this, "File import OK", Toast.LENGTH_LONG).show();
Log.d("Debug", "Files import OK");
}else {
Toast.makeText(this, "File import KO", Toast.LENGTH_LONG).show();
Log.d("Debug", "Files import KO");
}
}
}
}
}/**
* Opens the {#link android.hardware.usb.UsbDevice} for an MTP or PTP device
* and return an {#link android.mtp.MtpDevice} for it.
*
* #param usbDevice
* the device to open
* #return an MtpDevice for the device.
*/
#DebugLog
private MtpDevice openDeviceLocked(UsbDevice usbDevice) {
String deviceName = usbDevice.getDeviceName();
byte[] data = new byte[128];
int TIMEOUT = 0;
boolean forceClaim = true;
// don't try to open devices that we have decided to ignore
// or are currently asking permission for
if (isCamera(usbDevice)
&& !mRequestPermissionDevices.contains(deviceName)) {
if (!manager.hasPermission(usbDevice)) {
manager.requestPermission(usbDevice, mPermissionIntent);
mRequestPermissionDevices.add(deviceName);
} else {
UsbInterface intf = usbDevice.getInterface(0);
UsbEndpoint endpoint = intf.getEndpoint(0);
UsbDeviceConnection connection = manager.openDevice(usbDevice);
connection.claimInterface(intf, forceClaim);
connection.bulkTransfer(endpoint, data, data.length, TIMEOUT);
if (connection != null) {
MtpDevice mtpDevice = new MtpDevice(usbDevice);
if (mtpDevice.open(connection)) {
mDevices.put(usbDevice.getDeviceName(), mtpDevice);
return mtpDevice;
}
}
}
}
return null;
}
private File returnTempFolder(){
File tmp = new File(Environment.getExternalStorageDirectory().getAbsolutePath()+"/tmpFolder");
return tmp;
}
For people who have the same problem :
Solution is (Found on github) :
MtpClient (https://android.googlesource.com/platform/packages/apps/Gallery2/+/jb-dev/src/com/android/gallery3d/data/MtpClient.java)
#Background
#DebugLog
public void importFiles() {
MtpClient mtpClient = new MtpClient(this);
mtpClient.getDeviceList();
for (int i = 0; i < mtpClient.getDeviceList().size(); i++) {
int[] tab = mtpClient.getDeviceList().get(i).getObjectHandles(mtpClient.getDeviceList().get(i).getStorageIds()[0], 0, 0);
for (int j = 0; j < tab.length; j++) {
File dest = Environment.getExternalStorageDirectory();
// NAME_IMPORTED_FOLDER = tmpFolder
dest = new File(dest, NAME_IMPORTED_FOLDER);
dest.mkdirs();
MtpObjectInfo objInfo = mtpClient.getDeviceList().get(i).getObjectInfo(tab[j]);
if (objInfo != null) {
String destPath = new File(dest, objInfo.getName()).getAbsolutePath();
int objectId = objInfo.getObjectHandle();
// Succes !!
boolean result = mtpClient.getDeviceList().get(i).importFile(objectId, destPath);
}
}
}
mtpClient.close();
}
Regarding above post,
I downloaded the github gallery3d project ,
and look into code of MtpClient.java,
then I find the difference,
The code section from github
String destPath = new File(dest,objInfo.getName()).getAbsolutePath();
int objectId = objInfo.getObjectHandle();
boolean result = mtpClient.getDeviceList().get(i).importFile(objectId, destPath);
The point is 2nd parameter of importFile(objectId, destPath ) "destPath", need to include folder path + filename, then filename should not be changed original filename
But in the origianl question author, you just set folder path
in 2nd parameter
Related
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.
These two answers are what I merged to get it working.
How to get SD_Card path in android6.0 programmatically
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.
I used to get all the files in USB/SD Card from "/storage/external_storage" like so
File = new File("/storage/external_storage");
file.listFiles()
and show the files and folders in my own Fragment and it worked great until API 23. Where now I am unable to get the file list from the path.
I know in Android Marshmallow (23) there were permission changes and some USB Connection behavior changes.
If your app supports user interactions with the device over a USB port, take into consideration that the interaction must be explicitly enabled.
Does not explain how or when user can enable interactions explicitly.
My question is whether or not it is possible to Access USB files and Folders list.
If there is how can we achieve this?
EDIT : I opened Android Device Monitor and I couldn't find external_storage in /storage/external_storage.
It is true the doc is not very clear about that....but it seems you have to ask the system to mount the media device for you. Can you try to use
Environment.getExternalStorageState() to see what it returns you?
Otherwise, you can also try to access the SD/External USB by using this class:
public class ExternalStorage {
public static final String SD_CARD = "sdCard";
public static final String EXTERNAL_SD_CARD = "externalSdCard";
/**
* #return True if the external storage is available. False otherwise.
*/
public static boolean isAvailable() {
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state) || Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
return true;
}
return false;
}
public static String getSdCardPath() {
return Environment.getExternalStorageDirectory().getPath() + "/";
}
/**
* #return True if the external storage is writable. False otherwise.
*/
public static boolean isWritable() {
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
return true;
}
return false;
}
/**
* #return A map of all storage locations available
*/
public static Map<String, File> getAllStorageLocations() {
Map<String, File> map = new HashMap<String, File>(10);
List<String> mMounts = new ArrayList<String>(10);
List<String> mVold = new ArrayList<String>(10);
mMounts.add("/mnt/sdcard");
mVold.add("/mnt/sdcard");
try {
File mountFile = new File("/proc/mounts");
if(mountFile.exists()){
Scanner scanner = new Scanner(mountFile);
while (scanner.hasNext()) {
String line = scanner.nextLine();
if (line.startsWith("/dev/block/vold/")) {
String[] lineElements = line.split(" ");
String element = lineElements[1];
// don't add the default mount path
// it's already in the list.
if (!element.equals("/mnt/sdcard"))
mMounts.add(element);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
try {
File voldFile = new File("/system/etc/vold.fstab");
if(voldFile.exists()){
Scanner scanner = new Scanner(voldFile);
while (scanner.hasNext()) {
String line = scanner.nextLine();
if (line.startsWith("dev_mount")) {
String[] lineElements = line.split(" ");
String element = lineElements[2];
if (element.contains(":"))
element = element.substring(0, element.indexOf(":"));
if (!element.equals("/mnt/sdcard"))
mVold.add(element);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
for (int i = 0; i < mMounts.size(); i++) {
String mount = mMounts.get(i);
if (!mVold.contains(mount))
mMounts.remove(i--);
}
mVold.clear();
List<String> mountHash = new ArrayList<String>(10);
for(String mount : mMounts){
File root = new File(mount);
if (root.exists() && root.isDirectory() && root.canWrite()) {
File[] list = root.listFiles();
String hash = "[";
if(list!=null){
for(File f : list){
hash += f.getName().hashCode()+":"+f.length()+", ";
}
}
hash += "]";
if(!mountHash.contains(hash)){
String key = SD_CARD + "_" + map.size();
if (map.size() == 0) {
key = SD_CARD;
} else if (map.size() == 1) {
key = EXTERNAL_SD_CARD;
}
mountHash.add(hash);
map.put(key, root);
}
}
}
mMounts.clear();
if(map.isEmpty()){
map.put(SD_CARD, Environment.getExternalStorageDirectory());
}
return map;
}
}
The use is like this:
Map<String, File> externalLocations = ExternalStorage.getAllStorageLocations();
File sdCard = externalLocations.get(ExternalStorage.SD_CARD);
File externalSdCard = externalLocations.get(ExternalStorage.EXTERNAL_SD_CARD);
Source here: Find an external SD card location
Have a look at getExternalFilesDirs().
If a micro SD card is inserted the second entry will point to the card.
If you then attach a USB OTG drive the third entry will point to the drive.
With Intent.ACTION_OPEN_DOCUMENT_TREE you can let the user choose from all drives and then use Storage Access Framework.
I am trying to check whether device having external storage or not by using external storage path like this given below
if (new File("/ext_card/").exists()) {
specialPath = "/ext_card/";
} else if (new File("/mnt/sdcard/external_sd/").exists()) {
specialPath = "/mnt/sdcard/external_sd/";
} else if (new File("/storage/extSdCard/").exists()) {
specialPath = "/storage/extSdCard/";
} else if (new File("/mnt/extSdCard/").exists()) {
specialPath = "/mnt/extSdCard/";
} else if (new File("/mnt/sdcard/external_sd/").exists()) {
specialPath = "/mnt/sdcard/external_sd/";
} else if (new File("storage/sdcard1/").exists()) {
specialPath = "storage/sdcard1/";
}
But in marshmallow I con't find this path and while checking using ES FILEMANAGER, they give like storage/3263-3131 in Moto G 3rd generation. While check in other marshmallow devices that numbers getting differ. Please help me to check that marshmallow device have external storage or not? and if storage found means how to get the path of that external storage?
Note:- I gave permission for storage in my application and also enabled storage permission in settings for my app.
Thanks in advance and did you find any mistake in my question please crt it. thank you again.
Here's my solution, which is guaranteed to work till Android 7.0 Nougat:
/* returns external storage paths (directory of external memory card) as array of Strings */
public String[] getExternalStorageDirectories() {
List<String> results = new ArrayList<>();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { //Method 1 for KitKat & above
File[] externalDirs = getExternalFilesDirs(null);
String internalRoot = Environment.getExternalStorageDirectory().getAbsolutePath().toLowerCase();
for (File file : externalDirs) {
if(file==null) //solved NPE on some Lollipop devices
continue;
String path = file.getPath().split("/Android")[0];
if(path.toLowerCase().startsWith(internalRoot))
continue;
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
// better variation of: http://stackoverflow.com/a/40123073/5002496
String output = "";
try {
final Process process = new ProcessBuilder().command("mount | grep /dev/block/vold")
.redirectErrorStream(true).start();
process.waitFor();
final InputStream is = process.getInputStream();
final byte[] buffer = new byte[1024];
while (is.read(buffer) != -1) {
output = output + new String(buffer);
}
is.close();
} catch (final Exception e) {
e.printStackTrace();
}
if(!output.trim().isEmpty()) {
String devicePoints[] = output.split("\n");
for(String voldPoint: devicePoints) {
results.add(voldPoint.split(" ")[2]);
}
}
}
//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(LOG_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(LOG_TAG, results.get(i)+" might not be extSDcard");
results.remove(i--);
}
}
}
String[] storageDirectories = new String[results.size()];
for(int i=0; i<results.size(); ++i) storageDirectories[i] = results.get(i);
return storageDirectories;
}
I found the solution for this over here https://stackoverflow.com/a/13648873/842607
The code is -
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 other one is the hack which I found from the same page -
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()]);
}
This library solve my problem.
https://github.com/hendrawd/StorageUtil
What i did is:
private File directory;
String[] allPath;
allPath = StorageUtil.getStorageDirectories(this);
for (String path: allPath){
directory = new File(path);
Methods.update_Directory_Files(directory);
}
Methods.update_Directory_Files()
// Retrieving files from memory
public static void update_Directory_Files(File directory) {
//Get all file in storage
File[] fileList = directory.listFiles();
//check storage is empty or not
if(fileList != null && fileList.length > 0)
{
for (int i=0; i<fileList.length; i++)
{
boolean restricted_directory = false;
//check file is directory or other file
if(fileList[i].isDirectory())
{
for (String path : Constant.removePath){
if (path.equals(fileList[i].getPath())) {
restricted_directory = true;
break;
}
}
if (!restricted_directory)
update_Directory_Files(fileList[i]);
}
else
{
String name = fileList[i].getName().toLowerCase();
for (String ext : Constant.videoExtensions){
//Check the type of file
if(name.endsWith(ext))
{
//first getVideoDuration
String videoDuration = Methods.getVideoDuration(fileList[i]);
long playbackPosition;
long percentage = C.TIME_UNSET;
FilesInfo.fileState state;
/*First check video already played or not. If not then state is NEW
* else load playback position and calculate percentage of it and assign it*/
//check it if already exist or not if yes then start from there else start from start position
int existIndex = -1;
for (int j = 0; j < Constant.filesPlaybackHistory.size(); j++) {
String fListName = fileList[i].getName();
String fPlaybackHisName = Constant.filesPlaybackHistory.get(j).getFileName();
if (fListName.equals(fPlaybackHisName)) {
existIndex = j;
break;
}
}
try {
if (existIndex != -1) {
//if true that means file is not new
state = FilesInfo.fileState.NOT_NEW;
//set playbackPercentage not playbackPosition
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
retriever.setDataSource(fileList[i].getPath());
String time = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
retriever.release();
int duration = Integer.parseInt(time);
playbackPosition = Constant.filesPlaybackHistory.get(existIndex).getPlaybackPosition();
if (duration > 0)
percentage = 1000L * playbackPosition / duration;
else
percentage = C.TIME_UNSET;
}
else
state = FilesInfo.fileState.NEW;
//playbackPosition have value in percentage
Constant.allMemoryVideoList.add(new FilesInfo(fileList[i],
directory,videoDuration, state, percentage));
//directory portion
currentDirectory = directory.getPath();
unique_directory = true;
for(int j=0; j<directoryList.size(); j++)
{
if((directoryList.get(j).toString()).equals(currentDirectory)){
unique_directory = false;
}
}
if(unique_directory){
directoryList.add(directory);
}
//When we found extension from videoExtension array we will break it.
break;
}catch (Exception e){
e.printStackTrace();
Constant.allMemoryVideoList.add(new FilesInfo(fileList[i],
directory,videoDuration, FilesInfo.fileState.NOT_NEW, C.TIME_UNSET));
}
}
}
}
}
}
Constant.directoryList = directoryList;
}
in this i have redmi note prime 2.and i have no memory card.so when i found path and File[] externalDirs = getExternalFilesDirs(null); give null second postion value of file[].
}
I met a strange question, /storage/udisk/sda4/ and /mnt/media_rw/udisk/sda4/ should mean the same folder in android, but with the code below:
File sdcard = new File("/mnt/media_rw/udisk/sda4");
Log.d(LOG_TAG, "sdcard: " + sdcard
+ ", exists: " + sdcard.exists()); // return false
sdcard = new File("/storage/udisk/sda4");
Log.d(LOG_TAG, "sdcard: " + sdcard
+ ", exists: " + sdcard.exists()); // return true
I get different result, why is this?
ll /mnt/media_rw/udisk/ return drwxrwx--- media_rw media_rw 1970-01-01 00:00 sda4
ll /storage/udisk return drwxrwx--x root sdcard_r 1970-01-01 00:00 sda4
/mnt/media_rw/udisk/sda4 is mounted storage device. and it has more permission for access(permission-771)
/storage/udisk/sda4 is soft storage(permission-751)
use /mnt/media_rw/udisk/sda4 for better access
can you try this code, i hope this working
import java.io.File;
import java.util.ArrayList;
import java.util.Scanner;
import android.os.Build;
import android.os.Environment;
import android.util.Log;
public class StorageOptions {
private static ArrayList<String> mMounts = new ArrayList<String>();
private static ArrayList<String> mVold = new ArrayList<String>();
public static String[] labels;
public static String[] paths;
public static int count = 0;
private static final String TAG = StorageOptions.class.getSimpleName();
public static void determineStorageOptions() {
readMountsFile();
readVoldFile();
compareMountsWithVold();
testAndCleanMountsList();
setProperties();
}
private static void readMountsFile() {
/*
* Scan the /proc/mounts file and look for lines like this:
* /dev/block/vold/179:1 /mnt/sdcard vfat
* rw,dirsync,nosuid,nodev,noexec,
* relatime,uid=1000,gid=1015,fmask=0602,dmask
* =0602,allow_utime=0020,codepage
* =cp437,iocharset=iso8859-1,shortname=mixed,utf8,errors=remount-ro 0 0
*
* When one is found, split it into its elements and then pull out the
* path to the that mount point and add it to the arraylist
*/
// some mount files don't list the default
// path first, so we add it here to
// ensure that it is first in our list
mMounts.add("/mnt/sdcard");
try {
Scanner scanner = new Scanner(new File("/proc/mounts"));
while (scanner.hasNext()) {
String line = scanner.nextLine();
if (line.startsWith("/dev/block/vold/")) {
String[] lineElements = line.split(" ");
String element = lineElements[1];
// don't add the default mount path
// it's already in the list.
if (!element.equals("/mnt/sdcard"))
mMounts.add(element);
}
}
} catch (Exception e) {
// Auto-generated catch block
e.printStackTrace();
}
for(String p:mMounts)
{
Log.i("storage", p);
}
}
private static void readVoldFile() {
/*
* Scan the /system/etc/vold.fstab file and look for lines like this:
* dev_mount sdcard /mnt/sdcard 1
* /devices/platform/s3c-sdhci.0/mmc_host/mmc0
*
* When one is found, split it into its elements and then pull out the
* path to the that mount point and add it to the arraylist
*/
// some devices are missing the vold file entirely
// so we add a path here to make sure the list always
// includes the path to the first sdcard, whether real
// or emulated.
mVold.add("/mnt/sdcard");
try {
Scanner scanner = new Scanner(new File("/system/etc/vold.fstab"));
while (scanner.hasNext()) {
String line = scanner.nextLine();
if (line.startsWith("dev_mount")) {
String[] lineElements = line.split(" ");
String element = lineElements[2];
if (element.contains(":"))
element = element.substring(0, element.indexOf(":"));
// don't add the default vold path
// it's already in the list.
if (!element.equals("/mnt/sdcard"))
mVold.add(element);
}
}
} catch (Exception e) {
// Auto-generated catch block
e.printStackTrace();
}
}
private static void compareMountsWithVold() {
/*
* Sometimes the two lists of mount points will be different. We only
* want those mount points that are in both list.
*
* Compare the two lists together and remove items that are not in both
* lists.
*/
for (int i = 0; i < mMounts.size(); i++) {
String mount = mMounts.get(i);
if (!mVold.contains(mount))
mMounts.remove(i--);
}
// don't need this anymore, clear the vold list to reduce memory
// use and to prepare it for the next time it's needed.
mVold.clear();
}
private static void testAndCleanMountsList() {
/*
* Now that we have a cleaned list of mount paths Test each one to make
* sure it's a valid and available path. If it is not, remove it from
* the list.
*/
for (int i = 0; i < mMounts.size(); i++) {
String mount = mMounts.get(i);
File root = new File(mount);
if (!root.exists() || !root.isDirectory() || !root.canWrite())
mMounts.remove(i--);
}
}
#SuppressWarnings("unchecked")
private static void setProperties() {
/*
* At this point all the paths in the list should be valid. Build the
* public properties.
*/
Constants.mMounts = new ArrayList<String>();
ArrayList<String> mLabels = new ArrayList<String>();
int j = 0;
if (mMounts.size() > 0) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.GINGERBREAD)
mLabels.add("Auto");
else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
if (Environment.isExternalStorageRemovable()) {
mLabels.add("External SD Card 1");
j = 1;
} else
mLabels.add("Internal Storage");
} else {
if (!Environment.isExternalStorageRemovable()
|| Environment.isExternalStorageEmulated())
mLabels.add("Internal Storage");
else {
mLabels.add("External SD Card 1");
j = 1;
}
}
if (mMounts.size() > 1) {
for (int i = 1; i < mMounts.size(); i++) {
mLabels.add("External SD Card " + (i + j));
}
}
}
labels = new String[mLabels.size()];
mLabels.toArray(labels);
paths = new String[mMounts.size()];
mMounts.toArray(paths);
Constants.mMounts = (ArrayList<String>) mMounts.clone();
Constants.mLabels = (ArrayList<String>) mLabels.clone();
count = Math.min(labels.length, paths.length);
// don't need this anymore, clear the mounts list to reduce memory
// use and to prepare it for the next time it's needed.
mMounts.clear();
}
}
this code help you to find all sdcard and external storage paths
i got the paths of my Samsung phone
Is it true that the file path to external SDCard on Android devices are always "/storage/extSdCard"? If not, how many variations are there?
I need it for my App to test the availability of external SDCard.
I am using Titanium, it has a method Titanium.Filesystem.isExternalStoragePresent( )
but it always return true even external SDCard is not mounted.
I think it detect SDCard at local storage thus return true. But what I really want is detect whether physical SDCard is mounted or not.
Can I do this by detecting the existence of file "/storage/extSdCard" alone?
Thanks.
Is it true that the file path to external SDCard on Android devices are always "/storage/extSdCard"? If not, how many variations are there?
Sadly the path to the external storage is not always the same according to manufacturer. Using Environment.getExternalStorageDirectory() will return you the normal path for SD card which is mnt/sdcard/. But for Samsung devices for example, the SD card path is either under mnt/extSdCard/ or under mnt/external_sd/.
So one way to proceed would be to check the existence of external directory according to the path used by each manufacturer. With something like this:
mExternalDirectory = Environment.getExternalStorageDirectory()
.getAbsolutePath();
if (android.os.Build.DEVICE.contains("samsung")
|| android.os.Build.MANUFACTURER.contains("samsung")) {
File f = new File(Environment.getExternalStorageDirectory()
.getParent() + "/extSdCard" + "/myDirectory");
if (f.exists() && f.isDirectory()) {
mExternalDirectory = Environment.getExternalStorageDirectory()
.getParent() + "/extSdCard";
} else {
f = new File(Environment.getExternalStorageDirectory()
.getAbsolutePath() + "/external_sd" + "/myDirectory");
if (f.exists() && f.isDirectory()) {
mExternalDirectory = Environment
.getExternalStorageDirectory().getAbsolutePath()
+ "/external_sd";
}
}
}
But what I really want is detect whether physical SDCard is mounted or not.
I didn't try the code yet, but the approach of Dmitriy Lozenko in this answer is much more interesting. His method returns the path of all mounted SD cards on sytem regardless of the manufacturer.
This is how I finally got sdcard path using :
public String getExternalStoragePath() {
String internalPath = Environment.getExternalStorageDirectory().getAbsolutePath();
String[] paths = internalPath.split("/");
String parentPath = "/";
for (String s : paths) {
if (s.trim().length() > 0) {
parentPath = parentPath.concat(s);
break;
}
}
File parent = new File(parentPath);
if (parent.exists()) {
File[] files = parent.listFiles();
for (File file : files) {
String filePath = file.getAbsolutePath();
Log.d(TAG, filePath);
if (filePath.equals(internalPath)) {
continue;
} else if (filePath.toLowerCase().contains("sdcard")) {
return filePath;
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
try {
if (Environment.isExternalStorageRemovable(file)) {
return filePath;
}
} catch (RuntimeException e) {
Log.e(TAG, "RuntimeException: " + e);
}
}
}
}
return null;
}
I hope it will be useful for you :)
import android.os.Environment;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
public class MemoryStorage {
private MemoryStorage() {}
public static final String SD_CARD = "sdCard";
public static final String EXTERNAL_SD_CARD = "externalSdCard";
/**
* #return True if the external storage is available. False otherwise.
*/
public static boolean isAvailable() {
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state) || Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
return true;
}
return false;
}
public static String getSdCardPath() {
return Environment.getExternalStorageDirectory().getPath() + "/";
}
/**
* #return True if the external storage is writable. False otherwise.
*/
public static boolean isWritable() {
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
return true;
}
return false;
}
/**
* #return A map of all storage locations available
*/
public static Map<String, File> getAllStorageLocations() {
Map<String, File> map = new HashMap<String, File>(10);
List<String> mMounts = new ArrayList<String>(10);
List<String> mVold = new ArrayList<String>(10);
mMounts.add("/mnt/sdcard");
mVold.add("/mnt/sdcard");
try {
File mountFile = new File("/proc/mounts");
if (mountFile.exists()) {
Scanner scanner = new Scanner(mountFile);
while (scanner.hasNext()) {
String line = scanner.nextLine();
if (line.startsWith("/dev/block/vold/")) {
String[] lineElements = line.split(" ");
String element = lineElements[1];
// don't add the default mount path
// it's already in the list.
if (!element.equals("/mnt/sdcard"))
mMounts.add(element);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
try {
File voldFile = new File("/system/etc/vold.fstab");
if (voldFile.exists()) {
Scanner scanner = new Scanner(voldFile);
while (scanner.hasNext()) {
String line = scanner.nextLine();
if (line.startsWith("dev_mount")) {
String[] lineElements = line.split(" ");
String element = lineElements[2];
if (element.contains(":"))
element = element.substring(0, element.indexOf(":"));
if (!element.equals("/mnt/sdcard"))
mVold.add(element);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
for (int i = 0; i < mMounts.size(); i++) {
String mount = mMounts.get(i);
if (!mVold.contains(mount))
mMounts.remove(i--);
}
mVold.clear();
List<String> mountHash = new ArrayList<String>(10);
for (String mount : mMounts) {
File root = new File(mount);
if (root.exists() && root.isDirectory() && root.canWrite()) {
File[] list = root.listFiles();
String hash = "[";
if (list != null) {
for (File f : list) {
hash += f.getName().hashCode() + ":" + f.length() + ", ";
}
}
hash += "]";
if (!mountHash.contains(hash)) {
String key = SD_CARD + "_" + map.size();
if (map.size() == 0) {
key = SD_CARD;
} else if (map.size() == 1) {
key = EXTERNAL_SD_CARD;
}
mountHash.add(hash);
map.put(key, root);
}
}
}
mMounts.clear();
if (map.isEmpty()) {
map.put(SD_CARD, Environment.getExternalStorageDirectory());
}
return map;
}
}
I just figured out something. At least for my Android Emulator, I 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 my android emulator!
String removableStoragePath;
File fileList[] = new File("/storage/").listFiles();
for (File file : fileList)
{ if(!file.getAbsolutePath().equalsIgnoreCase(Environment.getExternalStorageDirectory().getAbsolutePath()) && file.isDirectory() && file.canRead())
removableStoragePath = file.getAbsolutePath(); }
//If there is an SD Card, removableStoragePath will have it's path. If there isn't it will be an empty string.
If there is an SD Card, removableStoragePath will have it's path. If there isn't it will be an empty string.
I have got solution on this after 4 days, Please note following points while giving path to File class in Android(Java):
Use path for internal storage String
path="/storage/sdcard0/myfile.txt";
use path for external storage
path="/storage/sdcard1/myfile.txt";
mention permissions in Manifest file.
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
First check file length for confirmation.
Check paths in ES File Explorer regarding sdcard0 & sdcard1 is
this same or else...
e.g.:
File file = new File(path);
long = file.length();//in Bytes