Android usb enumeration
The crash comes when you are trying to access the device with
connection = mManager.openDevice(device);
It crashes because it is throwing a SecurityException
because you haven't obtained permission from the user to use the device. It looks like you tried to obtain permission from the user in the line before this
mManager.requestPermission(device, mPermissionIntent);
But you need to understand that the call to requestPermission()
is asynchronous. It doesn't return immediately with the permission. What it does is that it shows the user a dialog and asks the user if he will grant permission to your application. Once the user grants or denies permission the dialog is dismissed and the PendingIntent
that you passed to requestPermission()
is used to broadcast an Intent indicating the permission was granted (or not). You need to listen for this in a registered BroadcastReceiver
and when the onReceive()
method is called you can then examine the extras in the received Intent
and decide how to proceed. Only if the user grants you permission can you move on to call openDevice()
.
This sounds kinda complicated, but that's the way it works.
Basically, you need to call
mManager.requestPermission(device, mPermissionIntent);
and then wait until permission has been granted before you try to access the device.
Comments
-
Britto almost 2 years
I am writing an android USB host application for which I am trying to enumerate the devices connected with tablet. I follow the code in the android USB host documentation in the developer site.
My code is as follows
AndroidUSBActivity
public class AndroidUSBActivity extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); USBClass usb = new USBClass(); ArrayList<String> deviceList = usb.GetUSBDevices(getBaseContext()); final CharSequence[] items = deviceList.toArray(new CharSequence[deviceList.size()]); AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle("Select a Reader"); builder.setSingleChoiceItems(items, -1, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int item) { String selectedDevice = (String) items[item]; dialog.dismiss(); TextView DeivceName = (TextView)findViewById(R.id.textView1); DeivceName.setText(selectedDevice); } }); AlertDialog alert = builder.create(); alert.show(); } }
USBClass
public class USBClass { private static UsbManager mManager = null; private static HashMap<String, UsbDevice> mdevices; private static PendingIntent mPermissionIntent; 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) { 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 Log.i("usb", "permission granted for device " + device); } } else { Log.i("usb", "permission denied for device " + device); } } } } }; public ArrayList<String> GetUSBDevices(Context context){ mManager = (UsbManager) context.getSystemService(Context.USB_SERVICE); mdevices = new HashMap<String, UsbDevice>(); ArrayList<String> deviceList = new ArrayList<String>(); mPermissionIntent = PendingIntent.getBroadcast(context, 0, new Intent("com.android.example.USB_PERMISSION"), 0); IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION); context.registerReceiver(mUsbReceiver, filter); // check for existing devices for (UsbDevice device : mManager.getDeviceList().values()) { String deviceName = null; UsbDeviceConnection connection = null; if(device.getVendorId() == 0x0123){ mManager.requestPermission(device, mPermissionIntent); connection = mManager.openDevice(device); byte rawBuf[] = new byte[255]; int len = connection.controlTransfer(0x80, 0x06, 0x0302, 0x0409, rawBuf, 0x00FF, 60); rawBuf = Arrays.copyOfRange(rawBuf, 2, len); deviceName = new String(rawBuf); deviceList.add(deviceName); mdevices.put(deviceName, device); } } context.unregisterReceiver(mUsbReceiver); return deviceList; } }
LOGCAT
06-13 10:13:54.556: D/dalvikvm(2219): Late-enabling CheckJNI 06-13 10:13:54.586: I/System.out(2219): Sending WAIT chunk 06-13 10:13:54.586: W/ActivityThread(2219): Application bri.sample is waiting for the debugger on port 8100... 06-13 10:13:54.596: I/dalvikvm(2219): Debugger is active 06-13 10:13:54.786: I/System.out(2219): Debugger has connected 06-13 10:13:54.786: I/System.out(2219): waiting for debugger to settle... 06-13 10:13:54.986: I/System.out(2219): waiting for debugger to settle... 06-13 10:13:55.186: I/System.out(2219): waiting for debugger to settle... 06-13 10:13:55.406: I/System.out(2219): waiting for debugger to settle... 06-13 10:13:55.596: I/System.out(2219): waiting for debugger to settle... 06-13 10:13:55.796: I/System.out(2219): waiting for debugger to settle... 06-13 10:13:55.996: I/System.out(2219): waiting for debugger to settle... 06-13 10:13:56.206: I/System.out(2219): waiting for debugger to settle... 06-13 10:13:56.406: I/System.out(2219): waiting for debugger to settle... 06-13 10:13:56.645: I/System.out(2219): waiting for debugger to settle... 06-13 10:13:56.846: I/System.out(2219): debugger has settled (1337) 06-13 10:13:57.116: E/UsbManager(2219): exception in UsbManager.openDevice 06-13 10:13:57.116: E/UsbManager(2219): java.lang.SecurityException: User has not given permission to device UsbDevice[mName=/dev/bus/usb/001/004,mVendorId=1254,mProductId=20758,mClass=0,mSubclass=0,mProtocol=0,mInterfaces=[Landroid.hardware.usb.UsbInterface;@41679100] 06-13 10:13:57.116: E/UsbManager(2219): at android.os.Parcel.readException(Parcel.java:1327) 06-13 10:13:57.116: E/UsbManager(2219): at android.os.Parcel.readException(Parcel.java:1281) 06-13 10:13:57.116: E/UsbManager(2219): at android.hardware.usb.IUsbManager$Stub$Proxy.openDevice(IUsbManager.java:340) 06-13 10:13:57.116: E/UsbManager(2219): at android.hardware.usb.UsbManager.openDevice(UsbManager.java:250) 06-13 10:13:57.116: E/UsbManager(2219): at bri.sample.USBClass.GetUSBDevices(USBClass.java:66) 06-13 10:13:57.116: E/UsbManager(2219): at bri.sample.AndroidUSBActivity.onCreate(AndroidUSBActivity.java:19) 06-13 10:13:57.116: E/UsbManager(2219): at android.app.Activity.performCreate(Activity.java:4465) 06-13 10:13:57.116: E/UsbManager(2219): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1049) 06-13 10:13:57.116: E/UsbManager(2219): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1920) 06-13 10:13:57.116: E/UsbManager(2219): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1981) 06-13 10:13:57.116: E/UsbManager(2219): at android.app.ActivityThread.access$600(ActivityThread.java:123) 06-13 10:13:57.116: E/UsbManager(2219): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1147) 06-13 10:13:57.116: E/UsbManager(2219): at android.os.Handler.dispatchMessage(Handler.java:99) 06-13 10:13:57.116: E/UsbManager(2219): at android.os.Looper.loop(Looper.java:137) 06-13 10:13:57.116: E/UsbManager(2219): at android.app.ActivityThread.main(ActivityThread.java:4424) 06-13 10:13:57.116: E/UsbManager(2219): at java.lang.reflect.Method.invokeNative(Native Method) 06-13 10:13:57.116: E/UsbManager(2219): at java.lang.reflect.Method.invoke(Method.java:511) 06-13 10:13:57.116: E/UsbManager(2219): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784) 06-13 10:13:57.116: E/UsbManager(2219): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551) 06-13 10:13:57.116: E/UsbManager(2219): at dalvik.system.NativeStart.main(Native Method) 06-13 10:13:57.566: D/dalvikvm(2219): threadid=1: still suspended after undo (sc=1 dc=1) 06-13 10:14:04.266: D/AndroidRuntime(2219): Shutting down VM 06-13 10:14:04.266: W/dalvikvm(2219): threadid=1: thread exiting with uncaught exception (group=0x40a531f8) 06-13 10:14:04.296: E/AndroidRuntime(2219): FATAL EXCEPTION: main 06-13 10:14:04.296: E/AndroidRuntime(2219): java.lang.RuntimeException: Unable to start activity ComponentInfo{bri.sample/bri.sample.AndroidUSBActivity}: java.lang.NullPointerException 06-13 10:14:04.296: E/AndroidRuntime(2219): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1956) 06-13 10:14:04.296: E/AndroidRuntime(2219): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1981) 06-13 10:14:04.296: E/AndroidRuntime(2219): at android.app.ActivityThread.access$600(ActivityThread.java:123) 06-13 10:14:04.296: E/AndroidRuntime(2219): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1147) 06-13 10:14:04.296: E/AndroidRuntime(2219): at android.os.Handler.dispatchMessage(Handler.java:99) 06-13 10:14:04.296: E/AndroidRuntime(2219): at android.os.Looper.loop(Looper.java:137) 06-13 10:14:04.296: E/AndroidRuntime(2219): at android.app.ActivityThread.main(ActivityThread.java:4424) 06-13 10:14:04.296: E/AndroidRuntime(2219): at java.lang.reflect.Method.invokeNative(Native Method) 06-13 10:14:04.296: E/AndroidRuntime(2219): at java.lang.reflect.Method.invoke(Method.java:511) 06-13 10:14:04.296: E/AndroidRuntime(2219): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784) 06-13 10:14:04.296: E/AndroidRuntime(2219): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551) 06-13 10:14:04.296: E/AndroidRuntime(2219): at dalvik.system.NativeStart.main(Native Method) 06-13 10:14:04.296: E/AndroidRuntime(2219): Caused by: java.lang.NullPointerException 06-13 10:14:04.296: E/AndroidRuntime(2219): at bri.sample.USBClass.GetUSBDevices(USBClass.java:68) 06-13 10:14:04.296: E/AndroidRuntime(2219): at bri.sample.AndroidUSBActivity.onCreate(AndroidUSBActivity.java:19) 06-13 10:14:04.296: E/AndroidRuntime(2219): at android.app.Activity.performCreate(Activity.java:4465) 06-13 10:14:04.296: E/AndroidRuntime(2219): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1049) 06-13 10:14:04.296: E/AndroidRuntime(2219): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1920) 06-13 10:14:04.296: E/AndroidRuntime(2219): ... 11 more
PROBLEM
I have the device plugged in and then I install the application. The first time when the application launches, it gets crashed.
-
Britto almost 12 yearsDear David i understand what u say. But what i require is that the usb functions are written as a jar library so that it can be included to build other applications. So an activity uses this usb library and provide calls to the usb apis in the library. Now that request permission being asynchronous i am unable to get the devices connected in the activity.
-
David Wasser almost 12 yearsSince this works asynchronously, you'll have build your library asynchronously. That means that you'll need to provide an API that the user can register a 'callback listener' on. Then, the user will need to request some access, and then, when the access is available, you'll have to call the user back on his callback listener. I hope that makes sense.
-
Richard Barraclough almost 4 yearsWhat is
mPermissionIntent
? Is it the activity you're in that's making the request? Or is it something else?