Android 获取USB OTG插入状置的资讯

Android 获取USB OTG插入状置的资讯

至从Android支援USB Host(Android USB OTG)之后,陆续的支援很多USB接外设备,例如:Audio、USB Stick、Keyboard、Mouse…等周边,有些插入后就自动支援,有些可能不支援内建的驱动,但可以经过UsbDeviceConnection进行USB控制硬体也能达到效果,但该周边功能仅能给自建的APP使用。

USB Manager

先取得USB Manager物件的控制:

//-----------start-----------
UsbManager mUsbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
//------------end------------

之后可以利用它来取得已知的USB讯息,利如列出已有的USB周边:

//-----------start-----------
        HashMap<String, UsbDevice> deviceList = mUsbManager.getDeviceList();
        Log.d(TAG, deviceList.size()+" USB device(s) found");
        Iterator<UsbDevice> deviceIterator = deviceList.values().iterator();
        while(deviceIterator.hasNext()){
            UsbDevice device = deviceIterator.next();
            Log.d("1",device);
        }
//------------end------------

将上面的程式直接至放于onCreate并且预先插入USB周边再启动APP后就能得到USB装置的讯息。

//-----------start-----------
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        UsbManager mUsbManager = (UsbManager) getSystemService(Context.USB_SERVICE);

        HashMap<String, UsbDevice> deviceList = mUsbManager.getDeviceList();
        Log.d("1", deviceList.size()+" USB device(s) found");
        Iterator<UsbDevice> deviceIterator = deviceList.values().iterator();
        while(deviceIterator.hasNext()){
            UsbDevice device = deviceIterator.next();
            Log.d("1","" + device);
        }

    }
//------------end------------

输出结果:

1 USB device(s) found
UsbDevice[mName=/dev/bus/usb/001/002,mVendorId=2965,mProductId=5920,mClass=2,mSubclass=0,mProtocol=0,mInterfaces=[Landroid.os.Parcelable;@41818b98]


USB Plug 讯息接收

拔除装置

USB 周边在插入(attached)与拔除(deattached)时必需要经过插入装置的IntentFilter设定过滤资讯并注册Receiver来取得当前的资讯,拔除时要过滤的action为UsbManager.ACTION_USB_ACCESSORY_DETACHED,程式如下:

//-----------start-----------

IntentFilter filterAttached_and_Detached = null; filterAttached_and_Detached = new IntentFilter(UsbManager.ACTION_USB_ACCESSORY_DETACHED); // private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (ACTION_USB_DEVICE_DETACHED.equals(action)) { synchronized (this) { UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); if(device != null){ Log.d("1","DEATTCHED-" + device); } } } }; // registerReceiver(mUsbReceiver, filterAttached_and_Detached); //------------end------------

插入装置

插入装置的IntentFilter过滤名称为UsbManager.ACTION_USB_DEVICE_ATTACHED,并且当BroadcastReceiver广播通知启动时也会连带的将滤名称填入Intent物件中,其中BroadcastReceiver功能本章不做介绍,还未了解的请至官网了解。

//-----------start-----------
IntentFilter filterAttached_and_Detached = null;
filterAttached_and_Detached = new IntentFilter(UsbManager.ACTION_USB_DEVICE_ATTACHED);
//
    private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {

        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (ACTION_USB_DEVICE_ATTACHED.equals(action)) {
                synchronized (this) {
                    UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);

                    if(device != null){

                        Log.d("1","ATTACHED-" + device);
                      }
                }
            }
    };
//
registerReceiver(mUsbReceiver, filterAttached_and_Detached);
//------------end------------

USB 权限请求

当你插入USB装置时会引发UsbManager.ACTION_USB_DEVICE_ATTACHED后必需要检查权限是否同意被使用,至于权限会包在Intent之中并于BroadcastReceiver中取得,所以在插入USB通知时必需要先取得包在Intent资讯中的UsbManager.EXTRA_PERMISSION_GRANTED检查布林值:

//-----------start-----------

if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) { : //false 不需要请求 : } //------------end------------

如果需要权限请求时可以使用USB Manager的requestPermission

//-----------start-----------
PendingIntent mPermissionIntent;
mPermissionIntent = PendingIntent.getBroadcast(MainActivity.this, 0, 
new Intent(ACTION_USB_PERMISSION), PendingIntent.FLAG_ONE_SHOT);
//
mUsbManager.requestPermission(device, mPermissionIntent);
//------------end------------

请求过程结束后会依照PendingIntent指定的action内容ACTION_USB_PERMISSION发播广通知,所以收到播广通知后判断是否为ACTION_USB_PERMISSION就能知道权限的请求状态,程式内容会改成:

//-----------start-----------
            if (ACTION_USB_DEVICE_ATTACHED.equals(action)) {
                synchronized (this) {
                    UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
                    if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {

                        if(device != null){
                          //

                            Log.d("1","ATTACHED-" + device);
                       }
                    }
                    else {
                        PendingIntent mPermissionIntent;
                        mPermissionIntent = PendingIntent.getBroadcast(MainActivity.this, 0, new Intent(ACTION_USB_PERMISSION), PendingIntent.FLAG_ONE_SHOT);
                        mUsbManager.requestPermission(device, mPermissionIntent);

                    }

                }
            }
//------------end------------

ACTION_USB_PERMISSION的内容可以自订,但内容必需要唯一值,例子中使用的内容为:

//-----------start-----------
private static final String ACTION_USB_PERMISSION = "tw.g35gtwcms.android.test.list_usb_otg.USB_PERMISSION";
//------------end------------

当需要权限请求设定的对话框出现后,

完成选择时会依照宣告Intent的action发广播通知,所以接收广播通知的程式要另外加入:

//-----------start-----------
            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){
                          //
                            Log.d("1","PERMISSION-" + device);
                       }
                    }
                }
            }
//------------end------------

权限请求完成后,收到通知并且确认不需要权限请求时就将接上USB的装置资讯印出,像下面的输出结果:

PERMISSION-UsbDevice[mName=/dev/bus/usb/001/010,mVendorId=2965,mProductId=5920,mClass=2,mSubclass=0,mProtocol=0,mInterfaces=[Landroid.os.Parcelable;@4182b720]

范例程式

此次范例程式使用前必要注意一点,USB会因为装置占用而无法使用USB传轮线来取得LogCat的内容,所以在这之前必需要将你的除错模式的输出改为tcpip的方式,也就是经由网路输出,要何操作请参考站内文章ADB使用WiFi进行除错 – ADB Over WiFi

以上都完成后就可以执行范例程式,执行后再接上你的OTG线并且插入USB装置并且观察LogCat的变化,输出结果如下:

输出结果文字版:

PERMISSION-UsbDevice[mName=/dev/bus/usb/001/010,mVendorId=2965,mProductId=5920,mClass=2,mSubclass=0,mProtocol=0,mInterfaces=[Landroid.os.Parcelable;@4182b720]

DETACHED-UsbDevice[mName=/dev/bus/usb/001/010,mVendorId=2965,mProductId=5920,mClass=2,mSubclass=0,mProtocol=0,mInterfaces=[Landroid.os.Parcelable;@4182d7c8]

DETACHED-UsbDevice[mName=/dev/bus/usb/001/010,mVendorId=2965,mProductId=5920,mClass=2,mSubclass=0,mProtocol=0,mInterfaces=[Landroid.os.Parcelable;@4182e5a8]

DETACHED-UsbDevice[mName=/dev/bus/usb/001/001,mVendorId=7531,mProductId=2,mClass=9,mSubclass=0,mProtocol=1,mInterfaces=[Landroid.os.Parcelable;@4182f340]


测试完成后如果不使用请务必再将除错模式更改为usb模式。

范例程式

参考资讯

UsbManager

UsbDevice