android 手機通過usb資料線與OTG裝置通訊
阿新 • • 發佈:2018-12-12
1.首先在AndroidManifest.xml檔案中新增所需要的許可權
<uses-feature android:name="android.hardware.usb.host" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
2.然後在AndroidManifest.xml檔案中的activity下新增以下程式碼
<activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> <!--加上這句程式碼,手機與OTG裝置連線就會啟動該APP,並跳轉到該activity--> <intent-filter> <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" /> </intent-filter> <!--在res資料夾下面新建一個 xml的資料夾,然後新建device_filter.xml--> <meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" android:resource="@xml/device_filter" /> </activity>
3.新建device_filter.xml資料夾
<?xml version="1.0" encoding="utf-8"?> <resources> <usb-device <!--這兩個id由製造提供的--> product-id="123" vendor-id="1234" /> </resources>
4.在onCreate方法中初始化連線裝置的一些配置,註冊廣播接收裝置斷開與連線的廣播
public static final String ACTION_USB_PERMISSION = "com.test.otg.USB_PERMISSION"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //獲取 USB 管理器 usbManager = (UsbManager) getSystemService(Context.USB_SERVICE); pendingIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0); registerBrasdcast(); initUsb(); initView(); }
//初始化裝置
private void initUsb() { try { //取連線到裝置上的 USB 裝置集合 HashMap<String, UsbDevice> map = usbManager.getDeviceList(); //遍歷集合取指定的 USB 裝置 for (UsbDevice device : map.values()) { Log.i("device", "vid:" + device.getVendorId() + " pid:" + device.getProductId() + " " + device.getDeviceName()); if (1234== device.getVendorId() && 123== device.getProductId()) { usbDevice = device; if (usbManager.hasPermission(usbDevice)) { usbManager.requestPermission(device, pendingIntent); } getDeviceInterface();//獲取介面 assignEndpoint(Interface2);// 分配端點 openDevice(Interface2);//開啟裝置 } } if (usbDevice == null) { Log.e("TAG", "沒有獲取到裝置"); return; } } catch (Exception e) { e.printStackTrace(); toast("裝置獲取異常"); } }
// 尋找裝置介面 private void getDeviceInterface() { if (usbDevice != null) { Log.i("TAG", "interfaceCounts : " + usbDevice.getInterfaceCount()); for (int i = 0; i < usbDevice.getInterfaceCount(); i++) { UsbInterface intf = usbDevice.getInterface(i); if (i == 0) { Interface1 = intf; // 儲存裝置介面 Log.i("TAG", "成功獲得裝置介面:" + Interface1.getId()); } if (i == 1) { Interface2 = intf; Log.i("TAG", "成功獲得裝置介面:" + Interface2.getId()); } } } else { Log.e("TAG", "未連線裝置!"); } }
// 分配端點,IN /OUT,即輸入輸出; private UsbEndpoint assignEndpoint(UsbInterface mInterface) { for (int i = 0; i < mInterface.getEndpointCount(); i++) { UsbEndpoint ep = mInterface.getEndpoint(i); if (ep.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) { if (ep.getDirection() == UsbConstants.USB_DIR_OUT) { epBulkOut = ep; } else { epBulkIn = ep; } } if (ep.getType() == UsbConstants.USB_ENDPOINT_XFER_CONTROL) { epControl = ep; } if (ep.getType() == UsbConstants.USB_ENDPOINT_XFER_INT) { if (ep.getDirection() == UsbConstants.USB_DIR_OUT) { epIntEndpointOut = ep; } if (ep.getDirection() == UsbConstants.USB_DIR_IN) { epIntEndpointIn = ep; } } } if (epBulkOut == null && epBulkIn == null && epControl == null && epIntEndpointOut == null && epIntEndpointIn == null) { throw new IllegalArgumentException("not endpoint is founded!"); } return epIntEndpointIn; }
// 開啟裝置 public void openDevice(UsbInterface mInterface) { if (mInterface != null) { UsbDeviceConnection conn = null; // 在open前判斷是否有連線許可權;對於連線許可權可以靜態分配,也可以動態分配許可權 if (usbManager.hasPermission(usbDevice)) { conn = usbManager.openDevice(usbDevice); } else { usbManager.requestPermission(usbDevice, pendingIntent); } if (conn == null) { return; } if (conn.claimInterface(mInterface, true)) { myDeviceConnection = conn; // 到此你的android裝置已經連上otg裝置 if (myDeviceConnection != null) System.out.println("開啟裝置成功!"); } else { System.out.println("無法開啟連線通道。"); conn.close(); } } }
//廣播註冊 private void registerBrasdcast() { //註冊許可權廣播 IntentFilter usbFilter = new IntentFilter(ACTION_USB_PERMISSION); //usb 插入廣播 usbFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED); //usb 拔出廣播 usbFilter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED); registerReceiver(mUsbReceiver, usbFilter); }
//廣播接收 private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { Log.e("TAG", intent.getAction()); switch (intent.getAction()) { case UsbManager.ACTION_USB_DEVICE_ATTACHED: toast("裝置插入"); initUsb();//初始化裝置 break; case UsbManager.ACTION_USB_DEVICE_DETACHED: toast("裝置斷開"); break; case ACTION_USB_PERMISSION: synchronized (this) { UsbDevice device = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) { if (device != null) { openDevice(Interface2); } } else { Toast.makeText(MainActivity.this, "使用者拒絕了USB的許可權!", Toast.LENGTH_LONG).show(); return; } } break; } } };
5.傳送與接收資料
//傳送資料 @Override public void onClick(View v) { switch (v.getId()) { if (myDeviceConnection == null) { toast("裝置未連線或未授權!"); return; } // 傳送準備命令 int reto = myDeviceConnection.bulkTransfer(epBulkOut, openDate, openDate.length, 5000); if (reto != -1) { Log.i("TAG", "已經發送資料" + reto); Message openMsg = Message.obtain(); openMsg.what = SEND_DAT; mHandler.sendMessage(openMsg); } } }
//接收資料 private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case SEND_DATA: byte[] receiverDate= new byte[20]; int rets = myDeviceConnection.bulkTransfer(epBulkIn, receiverDate, 20, 5000); if(rets!=-1){ //處理收到的receiverDate陣列,16進位制的 } } } };
6.解除廣播
@Override protected void onDestroy() { super.onDestroy(); unregisterReceiver(mUsbReceiver); }
AndroidManifest.xml的activity中沒有加上這段程式碼,連線時總是會彈出允許裝置的視窗,點預設也沒有用。
<intent-filter> <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" /> </intent-filter>
網上說可以改原始碼,我對原始碼進行修改後也不起作用,暫時不知道怎麼去掉USB的許可權允許窗。