Android USB通信入门篇
Android USB开发模式
Android中USB有两种开发模式,一种是host模式,另一种是accessory模式,下面介绍一下这两种模式。
(1)Host模式:如图,此模式中,Android设备充当主机,给USB外部设备供电,常见的Host模式有:鼠标、键盘等。
(2)Accessory模式:如图,和Host模式相反,此模式中,usb设备充当主机,给android手机提供电源,常见的设备:无人机远程控制器等。
进入Hello World
配置AndroidManifest.xml文件中USB模式
在Android系统中,默认是关闭USB模式的,当我们将USB外部设备插入Android设备时,Android系统不会作出任何响应。如果我们要打开系统USB模式,需要在Android清单文件里使用<uses-feature/>
标签声明响应的USB模式
Host模式
<uses-feature android:name="android.hardware.usb.host" />
Accessory模式
<uses-permission android:name="android.hardware.usb.accessory" />
配置USB设备插入的通知和相关USB设备的过滤
若我们希望在插入USB设备时,Android系统能接收到提示性通知,则需要在Android组件<Activity/>
中配置<intent-filter/>
和<meta-data/>
标签配置相关信息,<intent-filter/>
中配置我们要接收的相关类型的信息通知,<meta-data/>
配置我们需要检测的指定的设备,标签内容对应一个xml资源文件,里面配置我们指定的USB设备。如下:
<activity android:name=".ui.ChoiceModelActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<!--host模式下通知的过滤-->
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
</intent-filter>
<!--host模式下指定过滤设备的配置文件-->
<meta-data
android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
android:resource="@xml/device_filter" />
<!--accessory模式下通知的过滤-->
<intent-filter>
<action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />
</intent-filter>
<!--accessory模式下指定过滤设备的配置文件-->
<meta-data
android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"
android:resource="@xml/device_filter" />
</activity>
其中xml资源文件的配置如下:
<?xml version="1.0" encoding="utf-8"?>
<rescources xmlns:android="http://schemas.android.com/apk/res/android">
<!--host模式-->
<usb-device
class=""
vendor-id=""
product-id=""
protoclo=""
subclass="" />
<!--accessory模式-->
<usb-accessory
model="xxx"
manufacturer="xxx" />
Android设备与USB设备连接和通信
无论是Host
模式还是Accessory模式
,在进行检测获取USB设备时,都需要用到UsbManager
类,只是调用不同的方法而已。如下:
Host模式
1)获取UsbManager
2)通过usbManager获取连接到的USB外部设备
3)获取USB设备引用,通过usbManager检测是否有对应权限,若无则请求权限,通过广播接收权限信息获取情况
4)与USB设备进行通信
public static final String action_usb_permission = "cn.appblog.usb.permission";
public void hostModel(Context context) {
//获取UsbManager
UsbManager usbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
//获取usb设备列表
HashMap<String, UsbDevice> deviceList = usbManager.getDeviceList();
Set<Map.Entry<String, UsbDevice>> entries = deviceList.entrySet();
UsbDevice mUsbDevice = null;
for (Map.Entry<String, UsbDevice> entry : entries) {
UsbDevice value = entry.getValue();
String key = entry.getKey();
if (filterDevice(key, value)) {//判断是否是我们要连接的usb设备
mUsbDevice = value;
break;
}
}
if (usbManager.hasPermission(mUsbDevice)) {//检测是否有usb权限
requestPermission(mUsbDevice);
} else {
connect(mUsbDevice);
}
}
/**
* 请求usb权限
* @param usbManager
* @param parcelable
*/
public void requestPermission(Parcelable parcelable, UsbManager usbManager) {
UsbDevice usbDevice = (UsbDevice) parcelable;
if (!usbManager.hasPermission(usbDevice)) {
IntentFilter intentFilter = new IntentFilter(action_usb_permission);
registerReceiver(mMyBroadcastReceiver, intentFilter);
PendingIntent broadcast = PendingIntent.getBroadcast(this, 0, new Intent(action_usb_permission), 0);
usbManager.requestPermission(usbDevice, broadcast);
} else {
Toast.makeText(context, "already have permission", Toast.LENGTH_SHORT).show();
}
}
}
public boolean connect(UsbDevice mUsbDevice) {
if (mUsbDevice != null) {
UsbInterface anInterface = mUsbDevice.getInterface(0);
mUsbDeviceConnection = mUsbManager.openDevice(mUsbDevice);//连接usb设备
if (mUsbDeviceConnection == null) {
Toast.makeText(mContext, "mUsbDeviceConnection can't be null", Toast.LENGTH_SHORT).show();
return false;
}
if (mUsbDeviceConnection.claimInterface(anInterface, true)) {
Toast.makeText(mContext, "找到USB接口", Toast.LENGTH_SHORT).show();
int endpointCount = anInterface.getEndpointCount();
for (int i = 0; i < endpointCount; i++) {
UsbEndpoint endpoint = anInterface.getEndpoint(i);
if (endpoint.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {
if (UsbConstants.USB_DIR_IN == endpoint.getDirection()) {
mUsbEndpoint_in = endpoint;//获取读数据通道
} else {
mUsbEndpoint_out = endpoint;//获取写数据通道
}
}
}
return true;
} else {
mUsbDeviceConnection.close();//关闭连接
Toast.makeText(mContext, "找不到USB接口", Toast.LENGTH_SHORT).show();
}
} else {
Toast.makeText(mContext, "mUsbDevice can't be null", Toast.LENGTH_SHORT).show();
}
return false;
}
/**
* 从usb通信设备中读取数据
* @return
*/
public byte[] readData() {
int inMax = mUsbEndpoint_in.getMaxPacketSize();
byte[] bytes = new byte[inMax];
ByteBuffer byteBuffer = ByteBuffer.allocate(inMax);
UsbRequest usbRequest = new UsbRequest();
usbRequest.initialize(mUsbDeviceConnection, mUsbEndpoint_in);
usbRequest.queue(byteBuffer, inMax);
if (mUsbDeviceConnection.requestWait() == usbRequest) {
bytes = byteBuffer.array();
}
return bytes;
}
/**
* 将数据写入到usb设备中
* @param bytes
*/
public void sendData(byte[] bytes) {
if (mUsbDeviceConnection == null) {
Toast.makeText(mContext, "mUsbDeviceConnection can't be null", Toast.LENGTH_SHORT).show();
return;
}
if (mUsbEndpoint_out == null) {
Toast.makeText(mContext, "mUsbEndpoint_out can't be null", Toast.LENGTH_SHORT).show();
return;
}
int i = mUsbDeviceConnection.bulkTransfer(mUsbEndpoint_out, bytes, bytes.length, 1000);
if (i < 0) {
Toast.makeText(mContext, "failure to write", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(mContext, "success to write", Toast.LENGTH_SHORT).show();
}
}
/**
* 权限广播接收器
*/
private BroadcastReceiver mMyBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action_usb_permission.equals(action)) {
synchronized (this) {
UsbDevice usbDevice = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
if (usbDevice != null) {
if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
connect(usbDevice);
Toast.makeText(context, "success get permission", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(context, "failure get permission", Toast.LENGTH_SHORT).show();
}
} else {
Toast.makeText(context, "the usbDevice be null", Toast.LENGTH_SHORT).show();
}
}
}
}
};
/**
* 筛选出我们想要的usb设备
* @param name
* @param usbDevice
* @return
*/
public boolean filterDevice(String name, UsbDevice usbDevice) {
// TODO: 2019/3/13 对应判断设备是否是我们要连接的设备
return false;
}
Accessory模式
和Host
模式差不多,大致步骤一样,只是相关类不同而已如下
1)获取UsbManager
2)通过usbManager
获取连接到的USB外部设备UsbAccessory
3)获取USB设备引用,通过usbManager
检测是否有对应权限,若无则请求权限,通过广播接收权限信息获取情况
4)与UsbAccessory
设备进行通信
public static final String action_usb_permission = "cn.appblog.usb.permission";
private UsbManager usbManager;
public void hostAccessory(Context context) {
//获取UsbManager
usbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
//获取usb设备列表
UsbAccessory[] accessoryList = usbManager.getAccessoryList();
if (accessoryList == null || accessoryList.length <= = 0) {
Toast.makeText(context, "未查询到对应设备", Toast.LENGTH_SHORT).show();
return;
}
UsbAccessory mUsbAccessory = null;
for (UsbAccessory usbAccessory : accessoryList) {
if (filterDevice(usbAccessory)) {//判断是否使我们要连接的usb设备
break;
}
}
if (usbManager.hasPermission(mUsbAccessory)) {//检测是否有usb权限
requestPermission(mUsbAccessory);//请求usb权限
} else {
connect(mUsbAccessory);//连接usb设备
}
}
/**
* 请求usb权限
*
* @param usbManager
* @param parcelable
*/
public void requestPermission(Parcelable parcelable, UsbManager usbManager) {
UsbAccessory usbAccessory = (UsbAccessory) parcelable;
if (!usbManager.hasPermission(usbAccessory)) {
IntentFilter intentFilter = new IntentFilter(action_usb_permission);
registerReceiver(mMyBroadcastReceiver, intentFilter);
PendingIntent broadcast = PendingIntent.getBroadcast(this, 0, new Intent(action_usb_permission), 0);
usbManager.requestPermission(usbAccessory, broadcast);
} else {
Toast.makeText(context, "already have permission", Toast.LENGTH_SHORT).show();
}
}
private FileInputStream mFileInputStream;
private FileOutputStream mFileOutputStream;
/**
* 连接设备
* @param usbAccessory
* @return
*/
public boolean connect(UsbAccessory usbAccessory) {
ParcelFileDescriptor parcelFileDescriptor = usbManager.openAccessory(usbAccessory);
if (parcelFileDescriptor != null) {
FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
mFileInputStream = new FileInputStream(fileDescriptor);
mFileOutputStream = new FileOutputStream(fileDescriptor);
}
return false;
}
/**
* 写入数据
* @param data
*/
public void write(byte[] data) {
try {
mFileOutputStream.write(data);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 读取数据
*/
public void read() {
int max;//字节数据根据协议来确定
byte[] data = new byte[max];
mFileInputStream.read(data);
}
/**
* 权限广播接收器
*/
private BroadcastReceiver mMyBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action_usb_permission.equals(action)) {
synchronized (this) {
UsbAccessory usbAccessory = intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
if (usbAccessory != null) {
if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
connect(usbAccessory);
Toast.makeText(context, "success get permission", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(context, "failure get permission", Toast.LENGTH_SHORT).show();
}
} else {
Toast.makeText(context, "the usbDevice be null", Toast.LENGTH_SHORT).show();
}
}
}
}
};
/**
* 筛选出我们想要的usb设备
*
* @param usbAccessory
* @return
*/
public boolean filterDevice(UsbAccessory usbAccessory) {
// TODO: 2019/3/13 对应判断设备是否是我们要连接的设备
return false;
}
版权声明:
作者:Joe.Ye
链接:https://www.appblog.cn/index.php/2023/03/29/introduction-to-android-usb-communication/
来源:APP全栈技术分享
文章版权归作者所有,未经允许请勿转载。
共有 0 条评论