AndroidUSB

您所在的位置:网站首页 安卓USB授权默认确定软件 AndroidUSB

AndroidUSB

2024-07-11 21:27:52| 来源: 网络整理| 查看: 265

背景知识

USB是一种数据通信方式,也是一种数据总线,而且是最复杂的总线之一。 硬件上,它是用插头连接。一边是公头(plug),一边是母头(receptacle)。例如,PC上的插座就是母头,USB设备使用公头与PC连接。 目前USB硬件接口分三种,普通PC上使用的叫Type;原来诺基亚功能机时代的接口为Mini USB;目前Android手机使用的Micro USB/TYPE-C。

Host

USB是由Host端控制整个总线的数据传输的。单个USB总线上,只能有一个Host。

OTG

On The Go,这是在USB2.0引入的一种mode,提出了一个新的概念叫主机协商协议(Host Negotiation Protocol),允许两个设备间商量谁去当Host。

想了解更多USB知识,请参考USB官网以及下面这篇文章: http://www.crifan.com/files/doc/docbook/usb_basic/release/html/usb_basic.html

USB HOST/DEVICE/OTG概念:

1.USB 设备分为 HOST (主设备)和SLAVE (从设备),只有当一台 HOST 与一台 SLAVE 连接时才能实现数据的传输。 (1) USBHOST 是指主机。 (2) USBOTG 设备既能做主机,又能做设备。 OTG 技术就是实现在没有 Host 的情况下,实现从设备间的数据传送。 当 OTG 插到电脑上时. OTG 的角色就是连接电脑的 device (读卡器),也就是 SLAVE (从设备);当USB/SD device插到 OTG 上, OTG 的角色就是 HOST 主机。(有些手机也经常用到 OTG的功能)

Android使用(Host连接)

首先应该介绍,USBManager这个类,这个类用于访问USB状态并与USB设备通信。目前只开放HOST模式。 初始化USBManager mUsbManager = ((UsbManager) context.getSystemService(USB_SERVICE)); 里面有几个重要的方法:

1.getDeviceList()——获取当前USB连接从设备的列表,返回一个存储UsbDevice的HashMap 2.getAccessoryList()——这个就是获取Host的列表(用不到) 3.openDevice(UsbDevice)—— 这个方法是USB连接方法,连接成功后会返回一个UsbDeviceConnection对象。 4.requestPermission(UsbDevice,PendingIntent)——这个方法用于请求USB权限。

监听USB插入/拔出

通过广播意图android.hardware.usb.action.USB_STATE,实现插入拔出监听

class USBStateReceive extends BroadcastReceiver { public static final String ACTION_USB_STATE = "android.hardware.usb.action.USB_STATE"; public static final String USB_CONNECTED = "connected"; private IUsbStateChangeListener mUsbStateChangeListener; public void onReceive(Context paramContext, Intent intent) { String action = intent.getAction(); Log.d(TAG, "usb action + " + action); switch (action) { case UsbManager.ACTION_USB_DEVICE_ATTACHED: UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); Log.d(TAG, "device_attached," + device.toString()); if (mUsbStateChangeListener != null) { mUsbStateChangeListener.onAttach(device); } break; case UsbManager.ACTION_USB_DEVICE_DETACHED: device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); Log.d(TAG, "device_detached," + device.toString()); if (mUsbStateChangeListener != null) { mUsbStateChangeListener.onDetach(device); } break; case ACTION_USB_STATE: boolean connected = intent.getBooleanExtra(USB_CONNECTED, false); break; } } public void setUsbStateChangeListener(IUsbStateChangeListener usbStateChangeListener) { this.mUsbStateChangeListener = usbStateChangeListener; } }

这个广播也可以获取到当前插入/拔出的设备信息。可以通过这个广播来监听新插入/拔出的USB设备。

当前连接的USB设备

可以通过getDeviceList获取当前连接的USB设备 为此我们编写一个USBFinder 用来查找USB设备。

package cn.xiaolongonly.usbhelper.usbmodule; import android.hardware.usb.UsbDevice; import android.hardware.usb.UsbManager; import java.util.HashMap; import java.util.Iterator; /** * * * @author xiaolong [email protected] * @version v1.0 * @since 2019/4/10 15:36 */ public class USBFinder { private UsbManager mUsbManager; private static USBFinder usbFinder; private USBFinder(UsbManager usbManager) { this.mUsbManager = usbManager; } /** * Application Context; * */ public static void init(UsbManager usbManager) { usbFinder = new USBFinder(usbManager); } public static USBFinder getInstance() { if (usbFinder == null) { throw new RuntimeException("需要在Application中執行USBFinder.init()"); } return usbFinder; } public HashMap findUsbMap() { HashMap deviceMap = mUsbManager.getDeviceList(); return deviceMap; } public UsbDevice findUsbDevice(int vendorId, int productId) { HashMap deviceMap = mUsbManager.getDeviceList(); Iterator iterator = deviceMap.values().iterator(); UsbDevice localUsbDevice; while (iterator.hasNext()) { localUsbDevice = (UsbDevice) iterator.next(); if (localUsbDevice.getVendorId() == vendorId || localUsbDevice.getProductId() == productId) { return localUsbDevice; } } return null; } } findUsbMap 用于找到当前已连接的USB设备列表,这个用户选择连接非常有用,比如有多个USB设备,选择一个连接。(跟上一个通过广播监听的区别是,有时候一些USB设备默认是插着的,通过上面的广播并不能知道)findUsbDevice 遍历设备列表,通过vendorId和productId找到合适的USB设备,通过这个可以省掉让用户选择的过程,如果连接的设备只有一个的话可以直接用这个。 USB连接,如何确认USB连接及USB授权?

Android 在USBManager 提供了一个 requestPermission(UsbDevice device, PendingIntent pi),这个模式是手机作为HOST对设备做授权。

public void getPermission(Context context, UsbManager usbManager, UsbDevice usbDevice, final UsbPermissionReceiverListener callBack) { if (usbManager.hasPermission(usbDevice)) { callBack.onSuccessful(); return; } mContext = context; IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction("com.android.example.USB_PERMISSION"); mContext.registerReceiver(mUsbReceiver, intentFilter);//注册广播接收者 mUsbReceiver.setUsbPermissionReceiverListener(new UsbPermissionReceiverListener() { @Override public void onSuccessful() { mContext.unregisterReceiver(mUsbReceiver); callBack.onSuccessful(); } @Override public void onFail(String msg) { mContext.unregisterReceiver(mUsbReceiver); callBack.onFail(msg); } }); mUsbReceiver.setUsbDeviceName(usbDevice.getDeviceName());//为广播接受者设置DeviceName名称用于与接收的名称进行对比 PendingIntent mPermissionIntent = PendingIntent.getBroadcast(context, 0, new Intent(ACTION_USB_PERMISSION), 0); usbManager.requestPermission(usbDevice, mPermissionIntent); }

授权广播

class PermissionReceiver extends BroadcastReceiver { protected UsbPermissionReceiverListener mUsbPeramissionRecevierListener = null; protected String mUsbDeviceName = ""; public void onReceive(Context paramContext, Intent intent) { String action = intent.getAction(); Log.d(TAG, "usb action + " + action); if (intent == null) { mUsbPeramissionRecevierListener.onFail("授权失败:未知授权申请!"); } else { if (ACTION_USB_PERMISSION.equals(intent.getAction())) { UsbDevice localUsbDevice = intent.getParcelableExtra("device"); if (localUsbDevice != null) { if (!(intent.getBooleanExtra("permission", false))) {//用户取消授权 if (this.mUsbPeramissionRecevierListener != null) { mUsbPeramissionRecevierListener.onFail("用户取消授权,授权失败!"); } } else { String deviceName = localUsbDevice.getDeviceName(); if (deviceName.equals(this.mUsbDeviceName)) {//若获得的deviceName与_usbDeviceName一致 if (this.mUsbPeramissionRecevierListener != null) { mUsbPeramissionRecevierListener.onSuccessful(); } } else { if (this.mUsbPeramissionRecevierListener != null) { mUsbPeramissionRecevierListener.onFail("授權失敗:設備名稱不一致!"); } } } } else { return; } } else { mUsbPeramissionRecevierListener.onFail("授權失敗:未知授权申请!"); return; } } } public void setUsbPermissionReceiverListener(UsbPermissionReceiverListener paramAsyncTaskListener) { this.mUsbPeramissionRecevierListener = paramAsyncTaskListener; } public void setUsbDeviceName(String usbDeviceName) { this.mUsbDeviceName = usbDeviceName; } }

授权广播类,监听的是com.android.example.USB_PERMISSION

通过以上几个方法我们可以获取到当前连接的USB设备了,接下来就是建立传输通道

数据传输

这边先要获取一个UsbDeviceConnection 对象, 也就是通过USBManager.openDevice(UsbDevice)获取连接的对象。

/** * 选择USB设备和interface,打开。 * * @return */ public int open(UsbDevice usbDevice, int interfaceIndex) { mDevice = usbDevice; if (!setInterface(this.mDevice, interfaceIndex)) { Log.d(TAG, "interfaceIndex OutOfBound!"); return -1; } this.mInterface = mDevice.getInterface(interfaceIndex); if (!(setEndpoint(this.mInterface))) { return -1; } this.mDeviceConnection = this.mManager.openDevice(usbDevice); if (this.mDeviceConnection == null) { return -1; } return 0; }

讲一下为什么这个类需要传interfaceIndex,一般来讲一个UsbDevice 会有多个UsbInterface, 不同的interface是分开的,有不同的功能。每个UsbInterface又会有多个UsbEndpoint,用于处理输入和输出,也就是数据传输。 传入interfaceIndex是为了能够找到符合要求的index.

检验interface和endpoint 是否符合

protected boolean setInterface(UsbDevice mDevice, int interfaceIndex) { if (mDevice != null && mDevice.getInterfaceCount() > interfaceIndex) { return true; } else { return false; } } /** * 设置Endpoint,根据Device的Interface * * @param paramUsbInterface * @return */ protected boolean setEndpoint(UsbInterface paramUsbInterface) { if (paramUsbInterface.getEndpointCount() != 2) { Log.d(TAG, "Endpoint count less than 2.."); return false; } for (int m = 0; m if (ep.getDirection() == UsbConstants.USB_DIR_OUT) { this.mEndpointOut = ep; } else { this.mEndpointIn = ep; } } else { return false; } } return true; }

这两个方法就是用来看是不是能找到对应的UsbInterface和UsbEndpoint,因为我们的需求是要这个既有输入又有输出的UsbInterface。所以做了相应的校验。

接下来是数据传输

public void sendData(byte[] data, IDataSendCallBack iDataSendCallBack, int timeOut) { if (this.mDeviceConnection == null) { if (iDataSendCallBack != null) { iDataSendCallBack.onSendResult(CODE_DEVICE_NO_OPEN, null, "未开启设备,请先执行open()!"); } } this.mDeviceConnection.claimInterface(this.mInterface, true);//调用了本地 bulkTransfer(this.mDeviceConnection, this.mEndpointOut, this.mEndpointIn, data, data.length, timeOut, iDataSendCallBack); this.mDeviceConnection.releaseInterface(this.mInterface);//释放接口 } protected void bulkTransfer(final UsbDeviceConnection usbDeviceConnection, UsbEndpoint outPoint, final UsbEndpoint inPoint, byte[] datas, int dataLength, final int timeLimit, final IDataSendCallBack iDataSendCallBack) { int bulkTransferLength = usbDeviceConnection.bulkTransfer(outPoint, datas, dataLength, timeLimit); if (bulkTransferLength iDataSendCallBack.onSendResult(CODE_SEND_FAIL, datas, "发送失败!"); } } if (iDataSendCallBack != null) { iDataSendCallBack.onSendResult(CODE_SEND_SUCCESS, datas, "發送成功!"); } if (mEndpointIn == null) { if (iDataSendCallBack != null) { iDataSendCallBack.onSendResult(CODE_NO_INPOINT, null, "該interface底下沒有接口端口,无法接收数据!"); } } new Thread(new Runnable() { @Override public void run() { while (true) { byte[] inByte = new byte[1024]; int inLength = usbDeviceConnection.bulkTransfer(inPoint, inByte, inByte.length, timeLimit); if (inLength > 0) { inByte = Arrays.copyOf(inByte, inLength); if (iDataSendCallBack != null) { iDataSendCallBack.onSendResult(CODE_DATA_RECEIVE, inByte, "收到数据!"); } } else { break; } } } }).start(); }

DeviceConnection.claimInterface()占用了这个interface,在发送结束后releaseInterface 相当于释放interface. 项目要求是一次输入,一次输出。所以每次都会开开合合,如果不是这种需求的话应该可以长期开着等全部结束后关闭,类似于Socket。

Talk is cheap, here the code.

项目地址:https://github.com/guoxiaolongonly/USBHelper

参考自:https://blog.csdn.net/cui130/article/details/81329634



【本文地址】

公司简介

联系我们

今日新闻


点击排行

实验室常用的仪器、试剂和
说到实验室常用到的东西,主要就分为仪器、试剂和耗
不用再找了,全球10大实验
01、赛默飞世尔科技(热电)Thermo Fisher Scientif
三代水柜的量产巅峰T-72坦
作者:寞寒最近,西边闹腾挺大,本来小寞以为忙完这
通风柜跟实验室通风系统有
说到通风柜跟实验室通风,不少人都纠结二者到底是不
集消毒杀菌、烘干收纳为一
厨房是家里细菌较多的地方,潮湿的环境、没有完全密
实验室设备之全钢实验台如
全钢实验台是实验室家具中较为重要的家具之一,很多

推荐新闻


图片新闻

实验室药品柜的特性有哪些
实验室药品柜是实验室家具的重要组成部分之一,主要
小学科学实验中有哪些教学
计算机 计算器 一般 打孔器 打气筒 仪器车 显微镜
实验室各种仪器原理动图讲
1.紫外分光光谱UV分析原理:吸收紫外光能量,引起分
高中化学常见仪器及实验装
1、可加热仪器:2、计量仪器:(1)仪器A的名称:量
微生物操作主要设备和器具
今天盘点一下微生物操作主要设备和器具,别嫌我啰嗦
浅谈通风柜使用基本常识
 众所周知,通风柜功能中最主要的就是排气功能。在

专题文章

    CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭