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