Android 使用USB进行数据传输

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 android:name="android.hardware.usb.host"/>

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过滤不符合条件的设备
         */
        HashMap<String, UsbDevice> deviceList = 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<String, UsbDevice> deviceList = mUsbManager.getDeviceList();
        Collection<UsbDevice> 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();
}
评论 7 您还未登录,请先 登录 后发表或查看评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:编程工作室 设计师:CSDN官方博客 返回首页

打赏作者

yangchuan_csdn91

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值