9

Ok, so I have a Android 3.1 tablet (Acer Iconia Tab, which is great by the way) which I can use with Android USB API to connect with a USB Mass Storage Device (a simple USB memory stick).

I use USB Host mode, find the device, get permission to connect to it (using BroadcastReceiver). All works great. The problem is that I don't know exactly what to do in order to copy a file from the External Storage Directory to the USB memory stick.

This is what I have so far:

final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        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) {

                    // Got to a point where I should set up connection
                    // I'm setting up a very simple connection, just want some file transfer

                    UsbInterface intf = device.getInterface(0);
                    UsbEndpoint endpoint = intf.getEndpoint(0);
                    UsbDeviceConnection connection = UsbManager.openDevice(device);

                    if (connection.claimInterface(intf, true)) {
                        UtilsAndDialogs.print(getApplicationContext(), "Connected to device");

                        // Copy file to USB...

                    } else
                        UtilsAndDialogs.print(getApplicationContext(), "Could not connect!");
                }
            } else {
                UtilsAndDialogs.print(getApplicationContext(), "Permission denied");
                Log.d(UtilsAndDialogs.LOG_TAG, "Permission denied for device " + device);
            }
        }
    } 
};

I read the documentation on the Android Dev Usb Host but it's not very explicit and I found a pretty good tutorial Android Usb Host Tutorial - AdbTest but it uses asynchronous communication.

I just want to know how should I set up the connection and use the endpoint (I didn't get the endpoint part, why they are needed) to just be able to create a new file on the USB storage device and copy contents of a different file in there, probably using bulkTransfer() method.

Any hints or pointers to more explicit documentation would be greatly appreciated.

Thank you

Shree
  • 354
  • 2
  • 21
Bandreid
  • 2,727
  • 28
  • 47

2 Answers2

5

The Android USB host APIs provide only raw USB access. To access files on a memory device, your app must itself implement USB Mass Storage Mode on top of the USB Apis, and then the code of a filesystem on top of that.

A few vendor-customized versions of Android will mount a USB mass storage device with a recognized file system at operation system level, but that is not currently part of standard android. It is also possible that if you have a rooted device you may be able to use that to convince the kernel to mount such a filesystem.

Chris Stratton
  • 39,853
  • 6
  • 84
  • 117
1

Your connection is set up, the end points are basically flags on the device with information on data transfer.

For your stick you need to do something like VV to figure out how many endpoints you have,

UsbInterface intf = device.getInterface(0);
// checks for 2 endpoints
if (intf.getEndpointCount() != 2) {
Toast toast = Toast.makeText(context, "could not find endpoint", duration);
toast.show();
return;
    }
UsbEndpoint ep = intf.getEndpoint(0);
if (ep.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {
if (ep.getDirection() == UsbConstants.USB_DIR_OUT) {

this will let you figure out if the endpoint you're interested in is a bulk (usb constants docs has other types) and if you can send data to or from the device at that endpoint (usb_dir_in to test for in). What endpoint you want is device specific, my example starts on 0, yours will be different

To resave the file you need to do something like

mConnection.bulkTransfer(mEndpointOut, bytes, 512, TIMEOUT);

I have been saving the buffer each time it fills with a file output stream, this is probably inefficient (as I assume bulktransfer is already saving somewhere) but documentation is scarce.

greg
  • 34
  • 2
  • Wow, thanks for answering. I lost hope of getting an answer. I will check it today and accept your answer if it works :). – Bandreid Jan 03 '12 at 09:34
  • 1
    @Bandreid I don't understand how you specify what you want to transfer. Where do you say, "send me file 'abc.txt' located in '/docs/alphabet/'? – Mike Ortiz Oct 16 '13 at 21:42
  • @Mike Ortiz - I did not add this part of code in my question. – Bandreid Feb 12 '14 at 15:03
  • I don't understand this answer. Where do you specify the folder name? Where's the file name? – AlikElzin-kilaka May 25 '14 at 08:36
  • 3
    @AlikElzin-kilaka - this answer is basically incomplete, as it fails to address the fact that **the android USB host apis support only raw access**. Filesystem-level access requires the application to itself implement USB mass storage mode and a filesystem on top of them. – Chris Stratton Oct 09 '14 at 18:04