I need to import / export some data from / to a usb stick.
Is there a way to get the path of the mounted usb devices?
My code looks something like this:
UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);
HashMap<String, UsbDevice> deviceList = manager.getDeviceList();
Iterator<UsbDevice> deviceIterator = deviceList.values().iterator();
while(deviceIterator.hasNext()){
UsbDevice device = deviceIterator.next();
UsbInterface deviceInterface = device.getInterface(0);
if(deviceInterface != null && deviceInterface.getInterfaceClass() == UsbConstants.USB_CLASS_MASS_STORAGE){
// check if path "mnt/usb_storage/*" exist
}
}
I can search if the path "mnt/usb_storage/*" exists when the device is a mass storage.
This works fine if only one usb mass storage is attached or the app is in foreground when a second usb mass storaged is attached.
If you wonder, yes there are Android devices with multiple usb ports.
Is there no way to get the path when I have the UsbManager/UsbDevice/UsbInterface?
Is the path on all devices like "mnt/usb_storage/*"?
Update 1:
Target Android Version 5.1
Requirement: "Filechooser" has to be integrated inside the app, filter for folders, file names und file types have to be applied.
Update 2:
As suggested by #greenapps I gave "ACTION_OPEN_DOCUMENT_TREE" a try:
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
intent.putExtra("android.content.extra.SHOW_ADVANCED", true);
intent.putExtra("android.content.extra.FANCY", true);
intent.putExtra("android.content.extra.SHOW_FILESIZE", true);
startActivityForResult(intent, OPEN_DOCUMENT_TREE_REQUEST_CODE);
This does not show the usb stick neither was I able to filter the files and folders.
Same device: es-datei explorer is able to display the usb device.
My requirements are to display a custom file chooser where the user can select files from a customer specific cloud, internal storage or usb devices similar to the es datei explorer.
My solution with searching if the path: "mnt/usb_storage/*" exists works as required I am just wondering if there is a better way.
So I have searched quite a number of SO questions to get the path of a USB devices. I have not quite found an answer yet, but since this is top of the Google search and a fairly recent question, I will post what I have found.
Attempt (fleshed out)
So initially I tried (with my own implementation) as the question contains:
public static String getUSBProblematic(Context context){
UsbManager usbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
if (usbManager == null) {
Log.e(TAG, "Unable to get USB_SERVICE");
return "";
}
UsbAccessory[] accessoryList = usbManager.getAccessoryList();
if (accessoryList != null) {
for (UsbAccessory usbAccessory : accessoryList) {
// here we check the vendor
Log.d(TAG, "getUSBProblematic: " + usbAccessory.toString());
}
}
HashMap<String, UsbDevice> deviceList = usbManager.getDeviceList();
if(deviceList != null) {
List<UsbDevice> usbDeviceList = new ArrayList<>(deviceList.values());
for (Iterator<UsbDevice> iterator = usbDeviceList.iterator(); iterator.hasNext();) {
UsbDevice next = iterator.next();
boolean isMassStorage = false;
for (int i = 0; i < next.getInterfaceCount(); i++) {
// Check USB interface type is mass storage
UsbInterface usbInterface = next.getInterface(i);
if(usbInterface.getInterfaceClass() == UsbConstants.USB_CLASS_MASS_STORAGE && usbInterface.getEndpointCount() == 2) {
// Check endpoints support bulk transfer
for (int j = 0; j < usbInterface.getEndpointCount(); j++) {
UsbEndpoint endpoint = usbInterface.getEndpoint(j);
if(endpoint != null) {
if(endpoint.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK){
// Valid mass storage
isMassStorage = true;
}
}
}
}
}
if(!isMassStorage) {
iterator.remove();
}
}
for (UsbDevice usbDevice : usbDeviceList) {
Log.d(TAG, "getUSBProblematic: Device Name" + usbDevice.getDeviceName());
Log.d(TAG, "getUSBProblematic: Device Desc" + usbDevice.toString());
}
}
return "";
}
So the best I can get out of this is something like /dev/bus/usb/003, but nothing more than that.
So looking over my mounts file in /proc/mounts (found on the device, see Device File Explorer in Android Studio, I saw that USB specific storage devices are mounted at /mnt/media_rw/. But browsing to /storage, I saw the USB devices I expected or was looking for.
I am not sure if this is a good strategy or device specific (I use a Huawei Mate 10 Pro), but I am using
Possible Solution
public static String getUSB(){
File storageDirectory = new File("/storage");
if(!storageDirectory.exists()) {
Log.e(TAG, "getUSB: '/storage' does not exist on this device");
return "";
}
File[] files = storageDirectory.listFiles();
if(files == null) {
Log.e(TAG, "getUSB: Null when requesting directories inside '/storage'");
return "";
}
List<String> possibleUSBStorageMounts = new ArrayList<>();
for (File file : files) {
String path = file.getPath();
if (path.contains("emulated") ||
path.contains("sdcard") ||
path.contains("self")) {
Log.d(TAG, "getUSB: Found '" + path + "' - not USB");
} else {
possibleUSBStorageMounts.add(path);
}
}
if (possibleUSBStorageMounts.size() == 0) {
Log.e(TAG, "getUSB: Did not find any possible USB mounts");
return "";
}
if(possibleUSBStorageMounts.size() > 1) {
Log.d(TAG, "getUSB: Found multiple possible USB mount points, choosing the first one");
}
return possibleUSBStorageMounts.get(0);
}
EDIT 1
This may also be useful (search for USB)
There mostly is no path on modern Android systems. Nowadays you will try to get a document tree scheme.
There are several options.
You could have a look at the second or third item returned by getExternalFilesDirs(). (Will give a path. But writing not possible.)
For Android 6+ use Intent.ACTION_OPEN_DOCUMENT_TREE to let the user choose the drive. This will give you a content sheme. No file path.
For Android 7+ have a look at Storage Volumes.
Related
I'm trying to connect Android and Arduino UNO using the Android USB Host API.
I discover the device using an intent-filter.
I obtain the appropriate UsbInterface and UsbEndpoint. Everything seems fine until I try opening the UsbDeviceConnection, which always fails despite permissions are granted.
What's the reason?
Snippet below:
#Override
protected void onResume() {
super.onResume();
usbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
Intent intent = getIntent();
String action = intent.getAction();
if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) {
device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
}
}
public boolean connect(UsbDevice device){
[...] // search for appropriate interfaces/endpoints
Log.i(TAG, "usbInEndpoint = " + usbInEndpoint.toString());
Log.i(TAG, "usbOutEndpoint = " + usbOutEndpoint.toString());
Log.i(TAG, "usbInterface = " + usbInterface.toString());
Log.i(TAG, "permission = " + usbManager.hasPermission(device));
usbDeviceConnection = usbManager.openDevice(device);
Log.i(TAG, "usbDeviceConnection = " + usbDeviceConnection));
[...]
}
Logcat extract below:
usbInEndpoint = UsbEndpoint[mAddress=131,mAttributes=2,mMaxPacketSize=64,mInterval=1]
usbOutEndpoint = UsbEndpoint[mAddress=4,mAttributes=2,mMaxPacketSize=64,mInterval=1]
usbInterface = UsbInterface[mId=1,mAlternateSetting=0,mName=null,mClass=10,mSubclass=0,mProtocol=0,mEndpoints=[
UsbEndpoint[mAddress=4,mAttributes=2,mMaxPacketSize=64,mInterval=1]
UsbEndpoint[mAddress=131,mAttributes=2,mMaxPacketSize=64,mInterval=1]]
permission = true
D/UsbService: openDevice(/dev/bus/usb/001/002) : HostAPI is restricted
usbDeviceConnection = null
EDIT
I edited the question and the Logcat extract because I noticed UsbService logs that "Host API is restricted" after I call opendevice, so I guess is kind of device security setting. How to check that? I'm using Samsung A8
I answer my own question hoping this would be helpful for others with same issue. This was due to my mobile being managed by a MDM.
I have a an android Setup Box in which 2gb internal Memory available and 8 gb external memory available and device has slots for connect USB device. I wanted to get Memory information of connected USB Device. Suppose i have connected more then one USB Device. I am getting connection Disconnection event using Broadcast Receiver. But if i wanted to get Memory information that i am unable to get. I am only able to get inbuilt external memory information Please Guide me.
I am very new to android development. I have tried this way
private void sizeInfo(){
File path = Environment.getDataDirectory();
StatFs stat2 = new StatFs(path.getPath());
long blockSize = stat2.getBlockSize();
long availableBlocks = stat2.getAvailableBlocks();
String format = Formatter.formatFileSize(this, availableBlocks * blockSize);
// Log.d("space","Path : "+ path +"\n");
Log.d("space","Available Space in GB : "+ format);
String str = Environment.getExternalStorageState();
//Log.d("Checking","Media "+Environment.isExternalStorageEmulated());
}
I am getting list of attached device by following
private void updateDeviceList() {
Log.d("Checking","updateDeviceList function");
int DivCount =0;
HashMap<String, UsbDevice> connectedDevices = mUsbManager.getDeviceList();
if (connectedDevices.isEmpty()) {
usbDevice = null;
Log.d("Checking", "No Currently Device Conneted");
} else {
for (UsbDevice device : connectedDevices.values()) {
DivCount++;
Log.d("Device Info","DeviceId " +device.getDeviceId()+"\n");
Log.d("Device Info","ProductId "+device.getProductId()+"\n");
Log.d("Device Info","DeviceName "+device.getDeviceName()+"\n");
Log.d("Device Info","DeviceClass "+device.getDeviceClass());
String str = Build.MANUFACTURER;
Log.d("Device Info","Model "+str);
usbDevice =device;
sizeInfo();
}
}
}
I am able to get attached device list but not able to getting memory information of removable usb
I need your help, I'm trying to read some directory and trying to copy it to another place.
Now I can connect to usb host and read the usb specifications but i canĀ“t read the information on the usb to copy it.
this is my code
if (ACTION_USB_PERMISSION.equals(action)) {
synchronized (this) {
UsbDevice device = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
if (device != null) {
//call method to set up device communication
byte[] bytes = new byte[0];
int TIMEOUT = 0;
boolean forceClaim = true;
intf = device.getInterface(0);
UsbEndpoint endpoint = intf.getEndpoint(0);
connection = manager.openDevice(device);
connection.claimInterface(intf, forceClaim);
bytes=connection.getRawDescriptors();
Toast.makeText(context,"PERMISO CONCEDIDO",Toast.LENGTH_SHORT).show();
ArrayList<String>directorios=new ArrayList<>();
directorios=ObtnerDirectorios("/storage/UsbDriveA");
String dir="";
for(int i=0; i<directorios.size();i++){
dir+=directorios.get(i)+"\n";
}
infotext.setText(dir);
}
} else {
Toast.makeText(context,"PERMISO DENEGADO",Toast.LENGTH_SHORT).show();
}
}
}
I read the google documentation and I think t have to use a bulktransfer and control transfer but I'm not sure.
Could you help me?
Thanks
I have been trying to follow this tutorial to read data output from my arduino using my android phone, they are connected via OTG.
https://code.google.com/p/usb-serial-for-android/
I am able to print the result in a text view, however the output is 0. This is the code snippet I am using:
// Get UsbManager from Android.
UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);
// Find the first available driver.
UsbSerialDriver driver = UsbSerialProber.acquire(manager);
if (driver != null) {
driver.open();
try {
driver.setBaudRate(115200);
byte buffer[] = new byte[16];
int numBytesRead = driver.read(buffer, 1000);
Log.d(TAG, "Read " + numBytesRead + " bytes.");
} catch (IOException e) {
// Deal with error.
} finally {
driver.close();
}
}
My error might be relating to driver.read, can't find much documentation on it. Any thoughts on how the data get's pulled from the Arduino through serial in this method? If not, better ways to do it?
Thanks!
Arun
I am trying to make application for reading external storage file system connected using OTG cable to XOOM with ICS.
i am using this code to determine IN and OUT endpoint for communication with flash device
final UsbDeviceConnection connection = manager.openDevice(device);
UsbInterface inf = device.getInterface(0);
if (!connection.claimInterface(inf, true)) {
Log.v("USB", "failed to claim interface");
}
UsbEndpoint epOut = null;
UsbEndpoint epIn = null;
// look for our bulk endpoints
for (int i = 0; i < inf.getEndpointCount(); i++) {
UsbEndpoint ep = inf.getEndpoint(i);
if (ep.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {
if (ep.getDirection() == UsbConstants.USB_DIR_OUT) {
epOut = ep;
} else {
epIn = ep;
}
}
}
if (epOut == null || epIn == null) {
throw new IllegalArgumentException("not all endpoints found");
}
final UsbEndpoint inEndPoint = epIn;
it works normal.
then i am trying to read first 512 bytes to get FAT32 boot sector
ByteBuffer arg1 = ByteBuffer.allocate(512);
UsbRequest request = new UsbRequest();
request.initialize(connection, inEndPoint);
request.queue(arg1, inEndPoint.getMaxPacketSize());
UsbRequest result = connection.requestWait(); // halt here
connection.releaseInterface(inf);
connection.close();
but it does not read any data from connected device.
all this code run on separate thread after granding permission on device
PendingIntent mPermissionIntent = PendingIntent.getBroadcast(USBHostSampleActivity.this, 0, new Intent(ACTION_USB_PERMISSION), 0);
IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
registerReceiver(mUsbReceiver, filter);
manager.requestPermission(lDevices.get(position),mPermissionIntent);
in Broadcast receiver i just start new thread with previous code;
i also tried to make call to
USBDeviceConnection.controlTransfer
byte[] b = new byte[0x10];
int cTransfer = connection.controlTransfer(128, 6, 16, 0,b, 12, 0);
like in libusb sample to get f0 data and/or hwstats but it always return -1
also i tried replace async request using USBRequst to sync bulkTransfers but result is the same.
Have anyone worked with this part of Android SDK?
Thanks!
It appears you are missing a whole protocol layer; you can't just read 512 bytes from the device. What should it send back? How could it know you want to start to read at the beginning of the disk?
How you actually read a memory location from USB-MSC device depends on the device sub class type and the supported transport protocol.
It is likely that an ordinary flash disk uses the SCSI transparent command set in conjunction with the USB Mass Storage Class Bulk-Only (BBB) Transport.
You have to examine the device descriptor to find out what your device supports. See also the MSC device class overview for all possible values and references to their documentation.
I wrote a library for that called libaums: https://github.com/mjdev/libaums
The library takes care of low level USB communication and implements the FAT32 file system. It also includes an example app. Listing a directory would work as follows:
UsbMassStorageDevice[] devices = UsbMassStorageDevice.getMassStorageDevices(this);
device.init();
// we only use the first device
device = devices[0];
// we always use the first partition of the device
FileSystem fs = device.getPartitions().get(0).getFileSystem();
Log.d(TAG, "Capacity: " + fs.getCapacity());
Log.d(TAG, "Occupied Space: " + fs.getOccupiedSpace());
Log.d(TAG, "Free Space: " + fs.getFreeSpace());
UsbFile root = fs.getRootDirectory();
for(UsbFile f : root.listFiles())
Log.d(TAG, f.getName())