安卓USB枚举

5

我正在编写一个 Android USB 主机应用程序,我试图枚举连接到平板电脑的设备。我遵循了开发者网站上 Android USB 主机文档中的代码。

我的代码如下:

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

问题

我把设备插上后安装了应用程序。当我首次启动应用程序时,它崩溃了。


这是与下面链接中类似的问题。请帮忙,我不理解解决方案。http://stackoverflow.com/questions/10450473/broadcastreceiver-fires-after-the-activity-is-already-created/10450627#10450627 - Britto
Logcat打印出了什么吗? - Turbo J
我也遇到了同样的问题,只有第一次会出现。当我拔掉设备后再重新插入时,它就正常工作了。甚至不需要重新启动Activity。 - milosmns
1个回答

16

当您尝试访问设备时,会出现崩溃。

connection = mManager.openDevice(device);

这个程序崩溃了,因为它抛出了一个 SecurityException 异常,这是因为你没有得到用户使用设备的权限。看起来你尝试在这行代码之前获取了用户的权限。

mManager.requestPermission(device, mPermissionIntent);
但是您需要了解,调用requestPermission()是异步的。它不会立即返回权限。它做的是显示一个对话框并询问用户是否授予您的应用程序权限。一旦用户授予或拒绝权限,对话框将被关闭,并使用传递给requestPermission()PendingIntent广播一个指示权限已被授予(或未被授予)的Intent。 您需要在注册的BroadcastReceiver中监听此内容,当调用onReceive()方法时,您可以检查接收到的Intent中的附加信息,然后决定如何继续操作。只有在用户授予您权限后,您才能继续调用openDevice()
这听起来有点复杂,但这就是它的工作原理。
基本上,您需要调用
mManager.requestPermission(device, mPermissionIntent);

在尝试访问设备之前,请等待获得许可。


亲爱的David,我明白你所说的。但是我需要的是将USB功能编写为JAR库,以便可以将其包含到其他应用程序中构建。因此,一个活动使用此USB库并提供对库中USB API的调用。由于请求权限是异步的,因此我无法在活动中获取连接的设备。 - Britto
1
由于这是异步工作的,因此您需要异步构建库。这意味着您需要提供一个API,用户可以在其上注册“回调侦听器”。然后,用户将需要请求某些访问权限,当访问权限可用时,您将不得不在其回调侦听器上回调用户。我希望这有意义。 - David Wasser
mPermissionIntent是什么?它是当前活动发出请求的吗?还是其他什么东西? - Richard Barraclough

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接