How to Monitor USB Events on Android

Comparing to iOS, one of my favorite Android features is that Android supports USB peripherals. It’s fairly convenient to connect USB devices to Android smartphones via OTG cables. Therefore, no matter whether your Android phones, which probably only have 16G built-in storage, have SD card slot or not, it’s still capable of extending storage spaces with the power of accessing USB flash drive on Android operating system. In this post, I’d like to share what I’ve learned from Android developer website about how to monitor the events of attaching and detaching USB devices.

usb_devices

Android USB Host

Create an Android project, and add the following line to AndroidManifest.xml:

<uses-feature android:name="android.hardware.usb.host" />

Use broadcast receivers to register the events of attaching and detaching USB devices:

BroadcastReceiver mUsbAttachReceiver = new BroadcastReceiver() {
	    public void onReceive(Context context, Intent intent) {
	        String action = intent.getAction(); 

	      if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) {
	    	  showDevices();
	      }
	    }
	};

BroadcastReceiver mUsbDetachReceiver = new BroadcastReceiver() {
	    public void onReceive(Context context, Intent intent) {
	        String action = intent.getAction(); 

	      if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) {
	            UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
	            if (device != null) {
	                // call your method that cleans up and closes communication with the device
	            	UsbDataBinder binder = mHashMap.get(device);
	            	if (binder != null) {
	            		binder.onDestroy();
		            	mHashMap.remove(device);
	            	}
	            }
	        }
	    }
	};

Bind corresponding intent filters with broadcast receivers when application is created:

IntentFilter filter = new IntentFilter(UsbManager.ACTION_USB_DEVICE_ATTACHED);
		registerReceiver(mUsbAttachReceiver , filter);
filter = new IntentFilter(UsbManager.ACTION_USB_DEVICE_DETACHED);
		registerReceiver(mUsbDetachReceiver , filter);

Remember to unbind broadcast receivers when application is destroyed:

unregisterReceiver(mUsbDetachReceiver);
unregisterReceiver(mUsbAttachReceiver);

Once USB devices connected to Android system, all available information could be displayed by enumerating:

        HashMap<String, UsbDevice> deviceList = mUsbManager.getDeviceList();
		Iterator<UsbDevice> deviceIterator = deviceList.values().iterator();
		while(deviceIterator.hasNext()){
		    UsbDevice device = deviceIterator.next();
		    mLogger.log("usb", "name: " + device.getDeviceName() + ", " +
		    		"ID: " + device.getDeviceId());
		    mInfo.append(device.getDeviceName() + "\n");
		    mInfo.append(device.getDeviceId() + "\n");
		    mInfo.append(device.getDeviceProtocol() + "\n");
		    mInfo.append(device.getProductId() + "\n");
		    mInfo.append(device.getVendorId() + "\n");
		}

If you want to communicate with USB devices, you need to obtain the permission via broadcast receiver:

private static final String ACTION_USB_PERMISSION = "com.dynamsoft.USB_PERMISSION";
	private 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) {
							// call method to set up device communication
							 UsbDataBinder binder = new UsbDataBinder(mUsbManager, device);
							 mHashMap.put(device, binder);
						}
					} else {
						// Log.d(TAG, "permission denied for device " + device);
					}
				}
			}
		}
	};

The broadcast receiver will be triggered after calling requestPermission ():

mPermissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0);
mUsbManager.requestPermission(device, mPermissionIntent);

Finally, the connection will be built successfully:

         mUsbManager = manager;
		mDevice = device;
		mIntf = mDevice.getInterface(0);
		mEndpoint = mIntf.getEndpoint(0);
		mConnection = mUsbManager.openDevice(mDevice);

So far, we have made a basic Android USB application. What’s next step? If you are a document imaging developer, perhaps you would like to develop a more sophisticated Android app to communicate with a variety of USB devices, such as scanner, Webcam and etc.

References

USB Host and Accessory

Source Code

https://github.com/yushulx/android-usb-monitor

  • Daniel Tybora

    This example works for devices like usb-stick, camera, etc, but does not show connected active usb hub.

  • Matias

    For me it seems that the USB_DEVICE_DETACHED broadcast is not working in 5.0.1. Right?

  • http://www.dynamsoft.com Desmond Shaw

    I tested it on Android 4.4.4, including scanner, Webcam and flash drive via OTG

  • Robert

    Have you tested the code? The connect event does not work for me on android 4.1.2. The disconnect event works.