USB accessory mode allows users to connect USB host hardware specifically designed for Android-powered devices.
> Although the USB accessory APIs were introduced to the platform in Android 3.1, they are also available in Android 2.3.4 using the Google APIs add-on library. Because these APIs were backported using an external library, there are two packages that you can import to support USB accessory mode. Depending on what Android-powered devices you want to support, you might have to use one over the other:
1.com.android.future.usb(Android 2.3.4), Android 3.1 also supports importing and calling the classes within this namespace to support applications written with the add-on library.
2.android.hardware.usb,This namespace contains the classes that support USB accessory mode in Android 3.1. This package is included as part of the framework APIs, so Android 3.1 supports USB accessory mode without the use of an add-on library. Use this package if you only care about Android 3.1 or newer devices that have hardware support for USB accessory mode, which you can declare in your manifest file.
Note: There is, however, a minor usage difference between the add-on library and framework APIs that you should be aware of.
UsbManager manager = UsbManager.getInstance(this);
UsbAccessory accessory = UsbManager.getAccessory(intent);
UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);
UsbAccessory[] accessoryList = manager.getAcccessoryList();
UsbAccessory accessory = (UsbAccessory) intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
<manifest ...> <uses-feature android:name="android.hardware.usb.accessory" /> <uses-sdk android:minSdkVersion="<version>" /> ... <application> <uses-library android:name="com.android.future.usb.accessory" /> <activity ...> ... <intent-filter> <action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" /> </intent-filter> <meta-data android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" android:resource="@xml/accessory_filter" /> </activity> </application> </manifest>
<?xml version="1.0" encoding="utf-8"?> <resources> <usb-accessory model="DemoKit" manufacturer="Google" version="1.0"/> </resources>> The call to
requestPermission()
displays a dialog to the user asking for permission to connect to the accessory. The following sample code shows how to create the broadcast receiver:
private static final String ACTION_USB_PERMISSION = "com.android.example.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) { UsbAccessory accessory = (UsbAccessory) intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY); if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) { if(accessory != null){ //call method to set up accessory communication } } else { Log.d(TAG, "permission denied for accessory " + accessory); } } } } };
UsbManager mUsbManager = (UsbManager) getSystemService(Context.USB_SERVICE); private static final String ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION"; ... mPermissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0); IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION); registerReceiver(mUsbReceiver, filter);
> You should set up the communication between the device and accessory in another thread, so you don't lock the main UI thread. The following example shows how to open an accessory to communicate with:
UsbAccessory mAccessory; ParcelFileDescriptor mFileDescriptor; FileInputStream mInputStream; FileOutputStream mOutputStream; ... private void openAccessory() { Log.d(TAG, "openAccessory: " + accessory); mFileDescriptor = mUsbManager.openAccessory(mAccessory); if (mFileDescriptor != null) { FileDescriptor fd = mFileDescriptor.getFileDescriptor(); mInputStream = new FileInputStream(fd); mOutputStream = new FileOutputStream(fd); Thread thread = new Thread(null, this, "AccessoryThread"); thread.start(); } }In the thread's
run()
method, you can read and write to the accessory by using the
FileInputStream
or
FileOutputStream
objects. When reading data from an accessory with a
FileInputStream
object, ensure that the buffer that you use is big enough to store the USB packet data. The Android accessory protocol supports packet buffers up to 16384 bytes, so you can choose to always declare your buffer to be of this size for simplicity.
Note: At a lower level, the packets are 64 bytes for USB full-speed accessories and 512 bytes for USB high-speed accessories. The Android accessory protocol bundles the packets together for both speeds into one logical packet for simplicity.
Creating the broadcast receiver within the application, and not the manifest, allows your application to only handle detached events while it is running. This way, detached events are only sent to the application that is currently running and not broadcast to all applications.