4

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. Select Document Tree

Same device: es-datei explorer is able to display the usb device.

ES Datei explorer

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.

eugstman
  • 978
  • 2
  • 15
  • 18

2 Answers2

5

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)

CybeX
  • 2,060
  • 3
  • 48
  • 115
  • I also tried to play around with `StorageManager` (https://developer.android.com/reference/android/os/storage/StorageManager), but some most functionality only appeared API +24, which is a bit later than what I also need to support – CybeX Dec 18 '19 at 15:02
  • Yes the name is device dependent on my device it was "mnt/usb_storage" – eugstman Jan 15 '20 at 16:07
2

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.

greenapps
  • 11,154
  • 2
  • 16
  • 19
  • The used devices have Android 5.1, getExternalFileDirs does not return the usb mass storage. According to the requirement I have the "Filechooser" has to be integrated inside the app therefore opening another app is not an option. As i explicitly request permissions for a specific device when it is plugged in I have read and write access I only don't know the exact path. – eugstman Aug 16 '18 at 08:45
  • If you use ACTION_OPEN_DOCUMENT_TREE you wil have write permision too. Why are you not even commenting on this possibility? And why are you talking about another app? Which app? – greenapps Aug 16 '18 at 09:16
  • ACTION_OPEN_DOCUMENT_TREE opens another app if there are multiple to support this intent right? Also does it not support usb devices in the test I did. I have Android 5 so it isn't possible anyway according to you. – eugstman Aug 16 '18 at 15:10
  • No that does not open another app. And Android 5 supports it. – greenapps Aug 16 '18 at 16:51
  • You wrote "Android 6+ use Intent.ACTION_OPEN_DOCUMENT_TREE". In this case I give this a try and come back to you. – eugstman Aug 16 '18 at 18:04
  • 1
    I tested ACTION_OPEN_DOCUMENT_TREE, the usb device is not displayed neither can I fulfill my requirements with this. See my update of the question. thanks for your support anyway. – eugstman Aug 17 '18 at 14:40
  • Does it show the micro SD card either.? If you are not familiar with the gui of it you might forget to enable showing all drives. – greenapps Aug 17 '18 at 16:04
  • You should inform us if a micro SD card is inserted or not. Because if yes then it should show the card if you checked that option in the menu. Only then you would be sure that it should show the usb drive. – greenapps Aug 23 '18 at 16:53
  • There is no sd card inserted. – eugstman Aug 27 '18 at 17:56