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