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
模式。