1.Android通过两种模式支持各种USB设备
USB host 和USB accessory (Android3.1 API 12以上)
USB Host Mode 主机模式:Android设备充当主设备,并为总线供电
USB Accessory Mode 附件模式:外部硬件充当USB主设备,本机为附件
2.Android sdk中与usb相关的API
UsbManager
获取连接的USB设备并与之通信
UsbManager.ACTION_USB_ACCESSORY_ATTACHED 设备插入
UsbManager.ACTION_USB_ACCESSORY_DETACHED 设备拔出
UsbDevice
代表一个连接的USB 设备,包含一系列方法获取自身信息,包括interfaces,endpoints
UsbInterface
代表USB 设备上定义的一系列功能接口,一个usb设备可以有一个或多个接口
UsbEndpoint
代表一个interface通信频道,一个interface可以有一个或多个endpoints,一般含有输入输出两个端点来支持双工通信
UsbDeviceConnection
代表设备连接的一个链路,将数据传输到端点上,这个类允许你同步或异步的来回发送数据
UsbRequest
代表一个异步请求,通过UsbDeviceConnection来跟设备通信
UsbConstants
定义了linux内核文件linux/usb/ch9.h中的常量
3.android Host与accessory模式之间是通过AOA协议进行通讯
所有的通道均在USB端点0进行
3.1配件发送序号51的USB请求报文,手机收到后查询自己的AOA版本协议,发送响应报文给配件
3.2配件校验协议版本号,目前为1或2,其他的均为不支持
3.2配件发送序号52的USB请求报文,通过Index字段携带配件自身信息,包括制造商、型号、版本、设备描述、序 列号URI等。手机根据这些信息启动响应的APP
3.4配件发送序号53的USB请求报文,切换USB模式,主要是根据切换的vendorID和productID
3.5重新枚举USB设备,准备建立AOA数据通道
4.Android Host模式相关代码
4.1 AndroidManifest文件设置(一定要加)
uses-feature 声明这个软件需要使用USB功能,申明这个Google Play会把不满足的设备过滤掉
usb对api级别有要求,必须是12或者更高,目前市面上的api都已达标这里不做过多处理
配置好清单文件以后,当用户连接与您的设备过滤器匹配的设备时,系统会向他们显示一个对话框,询问是否允许USB权限,如果用户接受,则应用程序将自动具有访问设备的权限,直到设备断开连接。
4.1 android中关于usb连接的成功与失败,是通过系统广播的方式来获取的
这里需要自定义两个广播来监听usb设备的连接与断开
/** * 用来监听系统下发的usb设备连接成功的广播 */ public class OpenDevicesReceiver extends BroadcastReceiver { private OpenDevicesListener mOpenDevicesListener;//usb设备连接的回调接口 public OpenDevicesReceiver(OpenDevicesListener openDevicesListener) { mOpenDevicesListener = openDevicesListener; } private CommunicationListener listener;//sdk中用户打开usb连接成功的回调 public void setCommunicationListener(CommunicationListener listener) {//设置usb设备连接成功的回调 this.listener = listener; } @Override public void onReceive(Context context, Intent intent) { UsbDevice usbDevice = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);//获取附件设备 if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {//判断设备是都有usb if (usbDevice != null) { mOpenDevicesListener.openAccessoryModel(usbDevice); listener.onSuccess(CommunicationCode.USB_OPEN_SUCCESS,"USB权限开启成功"); Toast.makeText(context, "USB权限开启成功", Toast.LENGTH_SHORT).show(); } else { mOpenDevicesListener.openDevicesError(); listener.onFaild("USB设备连接异常"); } } else { //打开权限失败 mOpenDevicesListener.openDevicesError(); listener.onFaild("用户未授权USB权限"); } } public interface OpenDevicesListener { /** * 打开Accessory模式 * * @param usbDevice */ void openAccessoryModel(UsbDevice usbDevice); /** * 打开设备(手机)失败 */ void openDevicesError(); } }
/** * 用来监听系统下发的usb设备断开连接的广播 */ public class UsbDetachedReceiver extends BroadcastReceiver { private UsbDetachedListener mUsbDetachedListener; //usb连接断开的回调 /** * 构造方法中添加回调参数 * @param usbDetachedListener */ public UsbDetachedReceiver(UsbDetachedListener usbDetachedListener) { mUsbDetachedListener = usbDetachedListener; } @Override public void onReceive(Context context, Intent intent) { mUsbDetachedListener.usbDetached(); } public interface UsbDetachedListener { /** * usb断开连接 */ void usbDetached(); } }
4.2对应用户操控usb的四个状态: 开启usb 、关闭usb、发送数据、接收数据
定义接口基类
public interface BaseCommunication { /** * 开启通讯接口 * @return 200 表示成功开启 */ public void openCommunication(CommunicationListener listener); /** * 关闭通讯接口 */ public void closeCommunication(); /** * 发送byte[]类型数据 */ public void sendMessage(byte[] bytes, SendMessageListener listener); /** * 接收byte[]类型数据 */ public void receiveMessage(ReciverMessageListener listener); }
4.3关于基类中的三个回调:开启usb成功的回调、发送数据成功的回调、接受数据成功的回调,关闭usb连接时只需要把相关的资源注销掉即可
/** * usb连接开启成功或失败的回调 */ public interface CommunicationListener { void onSuccess(int code, String msg); void onFaild(String msg); }
/** * usb接受数据成功或失败的回调 */ public interface ReciverMessageListener { void onSuccess(byte[] bytes); void onFaild(String msg); }
/** * usb发送数据成功或失败的回调 */ public interface SendMessageListener { void onSuccess(); void onFaild(String msg); }
4.4 编写基类实现UsbCommunication
public class UsbCommunication implements BaseCommunication, UsbDetachedReceiver.UsbDetachedListener, OpenDevicesReceiver.OpenDevicesListener { //usb设备连接广播 private OpenDevicesReceiver mOpenDevicesReceiver; //usb连接断开广播 private UsbDetachedReceiver mUsbDetachedReceiver; //需要使用context初始化相关usb资源 private Context mContext; //usb设备管理器 private UsbManager mUsbManager; //自定义usb权限action private static final String USB_ACTION = "com.wiseasy.communication.usb.hostchart"; /** * Handler相关判断的变量,对应:usb连接初始化成功、失败,usb连接接收消息成功、失败,usb连接发送消息成功、失败 */ private static final int RECEIVER_MESSAGE_SUCCESS = 1; private static final int SEND_MESSAGE_SUCCESS = 2; private static final int RECEIVER_MESSAGE_FAILED = 3; private static final int SEND_MESSAGE_FAILED = 4; private static final int INIT_FAILED = 5; private static final int INIT_SUCCESS = 6; //接收消息监听回调 private ReciverMessageListener reciverMessageListener; //接收消息监听回调 private SendMessageListener sendMessageListener; /** * 使用handler将所有的操作统一到主线程 */ @SuppressLint("HandlerLeak") private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case RECEIVER_MESSAGE_SUCCESS://成功接受到数据 reciverMessageListener.onSuccess((byte[]) msg.obj); break; case RECEIVER_MESSAGE_FAILED://接收消息失败 reciverMessageListener.onFaild("接受消息失败"); break; case SEND_MESSAGE_SUCCESS://发送数据成功 sendMessageListener.onSuccess(); break; case SEND_MESSAGE_FAILED://发送数据失败 sendMessageListener.onFaild("发送消息失败"); break; case INIT_SUCCESS://usb主附设备连接陈工 communicationListener.onSuccess(CommunicationCode.USB_OPEN_SUCCESS, "初始化成功"); break; case INIT_FAILED://usb主附设备连接失败 communicationListener.onFaild("初始化失败"); break; } } }; /** * 单例模式 初始化 * * @param context */ private UsbCommunication(Context context) { /** * 为了避免在单利模式下的内存泄露,这里将context统一转换为ApplicationContext */ this.mContext = context.getApplicationContext(); //注册usb连接断开的广播 mUsbDetachedReceiver = new UsbDetachedReceiver(this); IntentFilter intentFilter = new IntentFilter(UsbManager.ACTION_USB_DEVICE_DETACHED); mContext.registerReceiver(mUsbDetachedReceiver, intentFilter); //通过context获取到当前系统的USB管理器 mUsbManager = (UsbManager) mContext.getSystemService(Context.USB_SERVICE); } //单例变量 private static volatile UsbCommunication Instance; /** * 单利模式双重检查 * * @param context * @return */ public static UsbCommunication getInstance(Context context) { if (Instance == null) { synchronized (UsbCommunication.class) { if (Instance == null) { Instance = new UsbCommunication(context); } } } return Instance; } //usb连接开启成功或失败的回调 private CommunicationListener communicationListener; /** * 开启usb连接的接口实现 * * @param communicationListener */ @Override public void openCommunication(CommunicationListener communicationListener) { this.communicationListener = communicationListener; //用来申请usb权限 PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(USB_ACTION), 0); //注册usb连接开启的广播 mOpenDevicesReceiver = new OpenDevicesReceiver(this); IntentFilter intentFilter = new IntentFilter(USB_ACTION); mContext.registerReceiver(mOpenDevicesReceiver, intentFilter); //设置连接成功的监听回调 mOpenDevicesReceiver.setCommunicationListener(communicationListener); /** * 通过usbManager获取当前连接的设备集合 * 遍历集合通过productId过滤不符合条件的设备 */ HashMapdeviceList = mUsbManager.getDeviceList(); if (deviceList != null) { for (UsbDevice usbDevice : deviceList.values()) { int productId = usbDevice.getProductId(); if (productId != 377 && productId != 7205) { if (mUsbManager.hasPermission(usbDevice)) { /** * 通过AOA协议让附件设备进入到accessory模式 */ initAccessory(usbDevice); } else { //申请usb权限 mUsbManager.requestPermission(usbDevice, pendingIntent); } } } } else { //连接失败回调 communicationListener.onFaild("请连接USB"); } } /** * AOA协议部分 * * @param usbDevice */ private void initAccessory(UsbDevice usbDevice) { //获取usb连接通道 UsbDeviceConnection usbDeviceConnection = mUsbManager.openDevice(usbDevice); if (usbDeviceConnection == null) { communicationListener.onFaild("请连接USB"); return; } //根据AOA协议打开Accessory模式 initStringControlTransfer(usbDeviceConnection, 0, "Google, Inc."); // MANUFACTURER initStringControlTransfer(usbDeviceConnection, 1, "AccessoryChat"); // MODEL initStringControlTransfer(usbDeviceConnection, 2, "Accessory Chat"); // DESCRIPTION initStringControlTransfer(usbDeviceConnection, 3, "1.0"); // VERSION initStringControlTransfer(usbDeviceConnection, 4, "http://www.android.com"); // URI initStringControlTransfer(usbDeviceConnection, 5, "0123456789"); // SERIAL usbDeviceConnection.controlTransfer(0x40, 53, 0, 0, new byte[]{}, 0, 100); usbDeviceConnection.close(); initDevice();//子设备初始化 } private void initStringControlTransfer(UsbDeviceConnection deviceConnection, int index, String string) { deviceConnection.controlTransfer(0x40, 52, 0, index, string.getBytes(), string.length(), 100); } //usb设备连接通道 private UsbDeviceConnection mUsbDeviceConnection; //usb接口 private UsbInterface mUsbInterface; //usb输出端点 private UsbEndpoint mUsbEndpointOut; //usb输入端点 private UsbEndpoint mUsbEndpointIn; private void initDevice() { /** * 使用usbManager遍历设备集合,通过productId找出匹配accessory模式的设备 */ HashMap deviceList = mUsbManager.getDeviceList(); Collection values = deviceList.values(); if (!values.isEmpty()) { for (UsbDevice usbDevice : values) { int productId = usbDevice.getProductId(); if (productId == 0x2D00 || productId == 0x2D01) { if (mUsbManager.hasPermission(usbDevice)) { //获取当前usb设备的通讯连接 mUsbDeviceConnection = mUsbManager.openDevice(usbDevice); if (mUsbDeviceConnection != null) { //获取通讯连接接口 mUsbInterface = usbDevice.getInterface(0); //获取通讯连接端点数量 int endpointCount = mUsbInterface.getEndpointCount(); for (int i = 0; i < endpointCount; i++) { //遍历所有端点,找到输入端点与输出端点 UsbEndpoint usbEndpoint = mUsbInterface.getEndpoint(i); if (usbEndpoint.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) { if (usbEndpoint.getDirection() == UsbConstants.USB_DIR_OUT) { mUsbEndpointOut = usbEndpoint;//赋值输出端点 } else if (usbEndpoint.getDirection() == UsbConstants.USB_DIR_IN) { mUsbEndpointIn = usbEndpoint;//赋值输入端点 } } } //当输出端点和输入端点都不为空时,表示usb连接成功,初始化完成,可以进行数据收发 if (mUsbEndpointOut != null && mUsbEndpointIn != null) { mHandler.sendEmptyMessage(INIT_SUCCESS); } } } else { //申请usb权限 mUsbManager.requestPermission(usbDevice, PendingIntent.getBroadcast(mContext, 0, new Intent(USB_ACTION), 0)); } } } } else { //初始化失败 mHandler.sendEmptyMessage(INIT_FAILED); } } /** * 关闭usb连接 * 释放所有资源 */ @Override public void closeCommunication() { if (mUsbDeviceConnection != null) { mUsbDeviceConnection.releaseInterface(mUsbInterface); mUsbDeviceConnection.close(); mUsbDeviceConnection = null; } mUsbEndpointIn = null; mUsbEndpointOut = null; isReceiverMessage = false; mContext.unregisterReceiver(mUsbDetachedReceiver); mContext.unregisterReceiver(mOpenDevicesReceiver); } /** * 发送数据接口实现 * 发送byte[]类型数据 * 通过回调监听成功或失败 * @param bytes * @param listener */ @Override public void sendMessage(final byte[] bytes, SendMessageListener listener) { this.sendMessageListener = listener; if (bytes != null) { /** * 耗时操作在子线程中执行 */ new Thread(new Runnable() { @Override public void run() { /** * 发送数据的地方 , 只接受byte数据类型的数据 */ int i = mUsbDeviceConnection.bulkTransfer(mUsbEndpointOut, bytes, bytes.length, 3000); if (i > 0) {//大于0表示发送成功 mHandler.sendEmptyMessage(SEND_MESSAGE_SUCCESS); } else { mHandler.sendEmptyMessage(SEND_MESSAGE_FAILED); } } }).start(); } else { listener.onFaild("发送数据为null"); } } //接收数据循环变量,usb连接成功后需要一直监听用户发送的数据 private boolean isReceiverMessage = true; //暂定的接收数据的大小,需要优化 private byte[] mBytes = new byte[1024]; /** * 接收数据的实现 * 通过回调来返回接收的数据 * 使用handler来传递接收的数据到主线程 * @param listener */ @Override public void receiveMessage(final ReciverMessageListener listener) { this.reciverMessageListener = listener; new Thread(new Runnable() { @Override public void run() { SystemClock.sleep(1000); while (isReceiverMessage) { /** * 循环接受数据的地方 , 只接受byte数据类型的数据 */ if (mUsbDeviceConnection != null && mUsbEndpointIn != null) { int i = mUsbDeviceConnection.bulkTransfer(mUsbEndpointIn, mBytes, mBytes.length, 3000); if (i > 0) { Message message = Message.obtain(); message.what = RECEIVER_MESSAGE_SUCCESS; message.obj = mBytes; mHandler.sendMessage(message); } } else { mHandler.sendEmptyMessage(RECEIVER_MESSAGE_FAILED); } } } }).start(); } /** * 主设备开启成功,进行从设备唤醒 * * @param usbDevice */ @Override public void openAccessoryModel(UsbDevice usbDevice) { initAccessory(usbDevice); } /** * 主设备权限被拒绝 */ @Override public void openDevicesError() { Toast.makeText(mContext, "USB权限被拒绝", Toast.LENGTH_SHORT).show(); } /** * usb连接断开 释放资源 */ @Override public void usbDetached() { if (mUsbDeviceConnection != null) { mUsbDeviceConnection.releaseInterface(mUsbInterface); mUsbDeviceConnection.close(); mUsbDeviceConnection = null; } mUsbEndpointIn = null; mUsbEndpointOut = null; // mToggle = false; isReceiverMessage = false; mContext.unregisterReceiver(mUsbDetachedReceiver); mContext.unregisterReceiver(mOpenDevicesReceiver); } }
4.5 MainActivity中的实际调用方式
UsbCommunication usbCommunication = UsbCommunication.getInstance(this);//初始化usb连接对象
usbCommunication.openCommunication(new CommunicationListener() {//开启usb连接 @Override public void onSuccess(int code, String msg) {//连接成功 sendMessage.setEnabled(true); getUsbMessage();//接收usb数据 } @Override public void onFaild(String msg) {//连接失败 Toast.makeText(MainActivity.this, msg, Toast.LENGTH_LONG).show(); } });
//接收数据,需要在初始化完成以后
private void getUsbMessage() { //接收数据 usbCommunication.receiveMessage(new ReciverMessageListener() { @Override public void onSuccess(byte[] bytes) { usbMessage = new String(bytes); log.setText(usbMessage); } @Override public void onFaild(String msg) { Toast.makeText(MainActivity.this, msg, Toast.LENGTH_LONG).show(); } }); }
发送数据
String msg = message.getText().toString().trim(); if (TextUtils.isEmpty(msg)) { Toast.makeText(MainActivity.this, "请输入要发送的信息", Toast.LENGTH_LONG).show(); return; } usbCommunication.sendMessage(msg.getBytes(), new SendMessageListener() { @Override public void onSuccess() { Toast.makeText(MainActivity.this, "信息发送成功", Toast.LENGTH_SHORT).show(); } @Override public void onFaild(String msg) { Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT).show(); } });
//usb连接断开时会自动释放资源,也可以主动调用close方法释放资源,
@Override protected void onDestroy() { super.onDestroy(); UsbCommunication.getInstance(this).closeCommunication(); }