//usb串口通信
implementation 'com.github.mik3y:usb-serial-for-android:3.5.1'
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import androidx.appcompat.app.AppCompatActivity;
import com.xxx.gjg.R;
import com.xxx.gjg.widget.usb.UsbDeviceManage;
public class TmpActivity extends AppCompatActivity {
public static void open(Context context) {
Intent starter = new Intent(context, TmpActivity.class);
context.startActivity(starter);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tmp);
UsbDeviceManage.getInstance().refresh(this, null);
}
@Override
protected void onNewIntent(Intent intent) {
if ("android.hardware.usb.action.USB_DEVICE_ATTACHED".equals(intent.getAction())) {
Log.i("调试信息", "onNewIntent: USB device detected");
}
super.onNewIntent(intent);
}
@Override
protected void onResume() {
UsbDeviceManage.getInstance().onResume(this);
super.onResume();
}
@Override
protected void onPause() {
UsbDeviceManage.getInstance().onPause(this);
super.onPause();
}
@Override
protected void onDestroy() {
super.onDestroy();
}
public void clickTest(View view) {
}
}
<activity
android:name=".ui.acy.TmpActivity"
android:exported="false">
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
</intent-filter>
<meta-data
android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
android:resource="@xml/device_filter" />
</activity>
device_filter.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- 0x0403 / 0x60??: FTDI -->
<usb-device vendor-id="1027" product-id="24577" /> <!-- 0x6001: FT232R -->
<usb-device vendor-id="1027" product-id="24592" /> <!-- 0x6010: FT2232H -->
<usb-device vendor-id="1027" product-id="24593" /> <!-- 0x6011: FT4232H -->
<usb-device vendor-id="1027" product-id="24596" /> <!-- 0x6014: FT232H -->
<usb-device vendor-id="1027" product-id="24597" /> <!-- 0x6015: FT230X, FT231X, FT234XD -->
<!-- 0x10C4 / 0xEA??: Silabs CP210x -->
<usb-device vendor-id="4292" product-id="60000" /> <!-- 0xea60: CP2102 and other CP210x single port devices -->
<usb-device vendor-id="4292" product-id="60016" /> <!-- 0xea70: CP2105 -->
<usb-device vendor-id="4292" product-id="60017" /> <!-- 0xea71: CP2108 -->
<!-- 0x067B / 0x23?3: Prolific PL2303x -->
<usb-device vendor-id="1659" product-id="8963" /> <!-- 0x2303: PL2303HX, HXD, TA, ... -->
<usb-device vendor-id="1659" product-id="9123" /> <!-- 0x23a3: PL2303GC -->
<usb-device vendor-id="1659" product-id="9139" /> <!-- 0x23b3: PL2303GB -->
<usb-device vendor-id="1659" product-id="9155" /> <!-- 0x23c3: PL2303GT -->
<usb-device vendor-id="1659" product-id="9171" /> <!-- 0x23d3: PL2303GL -->
<usb-device vendor-id="1659" product-id="9187" /> <!-- 0x23e3: PL2303GE -->
<usb-device vendor-id="1659" product-id="9203" /> <!-- 0x23f3: PL2303GS -->
<!-- 0x1a86 / 0x?523: Qinheng CH34x -->
<usb-device vendor-id="6790" product-id="21795" /> <!-- 0x5523: CH341A -->
<usb-device vendor-id="6790" product-id="29987" /> <!-- 0x7523: CH340 -->
<!-- CDC driver -->
<usb-device vendor-id="9025" /> <!-- 0x2341 / ......: Arduino -->
<usb-device vendor-id="5824" product-id="1155" /> <!-- 0x16C0 / 0x0483: Teensyduino -->
<usb-device vendor-id="1003" product-id="8260" /> <!-- 0x03EB / 0x2044: Atmel Lufa -->
<usb-device vendor-id="7855" product-id="4" /> <!-- 0x1eaf / 0x0004: Leaflabs Maple -->
<usb-device vendor-id="3368" product-id="516" /> <!-- 0x0d28 / 0x0204: ARM mbed -->
<usb-device vendor-id="1155" product-id="22336" /><!-- 0x0483 / 0x5740: ST CDC -->
<usb-device vendor-id="11914" product-id="5" /> <!-- 0x2E8A / 0x0005: Raspberry Pi Pico Micropython -->
<usb-device vendor-id="11914" product-id="10" /> <!-- 0x2E8A / 0x000A: Raspberry Pi Pico SDK -->
<usb-device vendor-id="6790" product-id="21972" /><!-- 0x1A86 / 0x55D4: Qinheng CH9102F -->
</resources>
UsbDeviceManage
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbManager;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.text.SpannableStringBuilder;
import android.util.Log;
import com.blankj.utilcode.util.ToastUtils;
import com.hoho.android.usbserial.driver.UsbSerialDriver;
import com.hoho.android.usbserial.driver.UsbSerialPort;
import com.hoho.android.usbserial.driver.UsbSerialProber;
import com.hoho.android.usbserial.util.SerialInputOutputManager;
import com.xxx.gjg.BuildConfig;
import com.xxx.gjg.app.AppApplication;
import com.xxx.gjg.utils.CabinetDoorUtils;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
/**
* usb设备管理(主要用于读卡器)
* 注意事项:Activity 设置 singleTop
* <intent-filter>
* <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
* </intent-filter>
* <meta-data
* android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
* android:resource="@xml/device_filter" />
*/
public class UsbDeviceManage implements SerialInputOutputManager.Listener {
private BroadcastReceiver broadcastReceiver;
private int deviceId;
private int portNum;
private int baudRate;
private boolean withIoManager;
private UsbListener mUsbListener;
@Override
public void onNewData(byte[] data) {
mainLooper.post(() -> {
receive(data);
if (mUsbListener != null) {
mUsbListener.onNewData(data);
}
});
}
@Override
public void onRunError(Exception e) {
mainLooper.post(() -> {
status("connection lost: " + e.getMessage());
disconnect();
if (mUsbListener != null) {
mUsbListener.onRunError(e);
}
});
}
private enum UsbPermission {Unknown, Requested, Granted, Denied}
private static final String INTENT_ACTION_GRANT_USB = BuildConfig.APPLICATION_ID + ".GRANT_USB";
private static final int WRITE_WAIT_MILLIS = 2000;
private static final int READ_WAIT_MILLIS = 2000;
private UsbPermission usbPermission = UsbPermission.Unknown;
private UsbSerialPort usbSerialPort;
private SerialInputOutputManager usbIoManager;
private boolean connected = false;
private Handler mainLooper;
private final ArrayList<ListItem> listItems = new ArrayList<>();
private static UsbDeviceManage instance;
private UsbDeviceManage() {
}
public static UsbDeviceManage getInstance() {
if (instance == null) {
synchronized (UsbDeviceManage.class) {
if (instance == null) {
instance = new UsbDeviceManage();
}
}
}
return instance;
}
public void refresh(Context context, UsbListener usbListener) {
listItems.clear();
mUsbListener = usbListener;
UsbManager usbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
UsbSerialProber usbDefaultProber = UsbSerialProber.getDefaultProber();
UsbSerialProber usbCustomProber = CustomProber.getCustomProber();
for (UsbDevice device : usbManager.getDeviceList().values()) {
UsbSerialDriver driver = usbDefaultProber.probeDevice(device);
if (driver == null) {
driver = usbCustomProber.probeDevice(device);
}
if (driver != null) {
for (int port = 0; port < driver.getPorts().size(); port++)
listItems.add(new ListItem(device, port, driver));
} else {
listItems.add(new ListItem(device, 0, null));
}
}
Log.i("调试信息", "开始监听=>usb连接设备数量: " + listItems.size());
if (!listItems.isEmpty()) {
deviceId = listItems.get(0).device.getDeviceId();
portNum = listItems.get(0).port;
baudRate = 19200;
withIoManager = true;
// 获取设备的厂商ID和产品ID listItems.get(0).device
//int vendorId = device.getVendorId();
//int productId = device.getProductId();
//
获取设备的描述信息
//String deviceName = device.getDeviceName();
//String deviceClass = device.getDeviceClass();
//String deviceSubclass = device.getDeviceSubclass();
//String deviceProtocol = device.getDeviceProtocol();
}
startReceiver();
}
private void startReceiver() {
broadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (INTENT_ACTION_GRANT_USB.equals(intent.getAction())) {
usbPermission = intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)
? UsbPermission.Granted : UsbPermission.Denied;
connect();
}
}
};
mainLooper = new Handler(Looper.getMainLooper());
}
/*
* Serial + UI
*/
private void connect() {
UsbDevice device = null;
UsbManager usbManager = (UsbManager) AppApplication.getApplication().getSystemService(Context.USB_SERVICE);
for (UsbDevice v : usbManager.getDeviceList().values()) {
if (v.getDeviceId() == deviceId)
device = v;
}
if (device == null) {
status("connection failed: device not found");
return;
}
UsbSerialDriver driver = UsbSerialProber.getDefaultProber().probeDevice(device);
if (driver == null) {
driver = CustomProber.getCustomProber().probeDevice(device);
}
if (driver == null) {
status("connection failed: no driver for device");
return;
}
if (driver.getPorts().size() < portNum) {
status("connection failed: not enough ports at device");
return;
}
usbSerialPort = driver.getPorts().get(portNum);
UsbDeviceConnection usbConnection = usbManager.openDevice(driver.getDevice());
if (usbConnection == null && usbPermission == UsbPermission.Unknown && !usbManager.hasPermission(driver.getDevice())) {
usbPermission = UsbPermission.Requested;
int flags = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ? 1 << 25 : 0;
PendingIntent usbPermissionIntent = PendingIntent.getBroadcast(AppApplication.getApplication(), 0, new Intent(INTENT_ACTION_GRANT_USB), flags);
usbManager.requestPermission(driver.getDevice(), usbPermissionIntent);
return;
}
if (usbConnection == null) {
if (!usbManager.hasPermission(driver.getDevice()))
status("connection failed: permission denied");
else
status("connection failed: open failed");
return;
}
try {
usbSerialPort.open(usbConnection);
try {
usbSerialPort.setParameters(baudRate, 8, 1, UsbSerialPort.PARITY_NONE);
} catch (UnsupportedOperationException e) {
status("unsupport setparameters");
}
if (withIoManager) {
usbIoManager = new SerialInputOutputManager(usbSerialPort, this);
usbIoManager.start();
}
status("connected");
connected = true;
// controlLines.start();
} catch (Exception e) {
status("connection failed: " + e.getMessage());
disconnect();
}
}
private void disconnect() {
connected = false;
// controlLines.stop();
if (usbIoManager != null) {
usbIoManager.setListener(null);
usbIoManager.stop();
}
usbIoManager = null;
try {
usbSerialPort.close();
} catch (IOException ignored) {
}
usbSerialPort = null;
}
private void send(String str) {
if (!connected) {
ToastUtils.showLong("not connected");
return;
}
try {
byte[] data = (str + '\n').getBytes();
Log.i("调试信息", "send: " + HexDump.dumpHexString(data));
// SpannableStringBuilder spn = new SpannableStringBuilder();
// spn.append("send " + data.length + " bytes\n");
// spn.append(HexDump.dumpHexString(data)).append("\n");
// spn.setSpan(new ForegroundColorSpan(getResources().getColor(R.color.colorSendText)), 0, spn.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
// receiveText.append(spn);
usbSerialPort.write(data, WRITE_WAIT_MILLIS);
} catch (Exception e) {
onRunError(e);
}
}
private void read() {
if (!connected) {
ToastUtils.showLong("not connected");
return;
}
try {
byte[] buffer = new byte[8192];
int len = usbSerialPort.read(buffer, READ_WAIT_MILLIS);
receive(Arrays.copyOf(buffer, len));
} catch (IOException e) {
// when using read with timeout, USB bulkTransfer returns -1 on timeout _and_ errors
// like connection loss, so there is typically no exception thrown here on error
status("connection lost: " + e.getMessage());
disconnect();
}
}
private void receive(byte[] data) {
SpannableStringBuilder spn = new SpannableStringBuilder();
spn.append("receive " + data.length + " bytes\n");
// if (data.length > 0)
// spn.append(HexDump.dumpHexString(data)).append("\n");
receiveText.append(spn);
// Log.i("调试信息", "receive1: " + HexDump.dumpHexString(data));
Log.i("调试信息", "receive2: " + CabinetDoorUtils.BinaryToHexString(data));
Log.i("调试信息", "receive3: " + hexByteArrayToAscii(data));
Log.i("调试信息", "receive4: " + HexUtils.hexByteArrayToAscii(data));
Log.i("调试信息", "receive5: " + CabinetDoorUtils.BinaryToHexString(HexUtils.asciiToHexByteArray(HexUtils.hexByteArrayToAscii(data))));
}
public static String hexByteArrayToAscii(byte[] bytes) {
StringBuilder output = new StringBuilder("");
for (int i = 0; i < bytes.length; i++) {
output.append((char) bytes[i]);
}
return output.toString();
}
void status(String str) {
Log.i("调试信息", "status: " + str);
if (mUsbListener != null) {
mUsbListener.state(str);
}
}
public static class ListItem {
UsbDevice device;
int port;
UsbSerialDriver driver;
ListItem(UsbDevice device, int port, UsbSerialDriver driver) {
this.device = device;
this.port = port;
this.driver = driver;
}
}
/**
* 在Activity#onResume父类方法之前调用
* 示例:
*
* @Override protected void onResume(){Test.getInstance().onResume(this);super.onResume();}
*/
public void onResume(Context context) {
if (broadcastReceiver == null) {
return;
}
context.registerReceiver(broadcastReceiver, new IntentFilter(INTENT_ACTION_GRANT_USB));
if (usbPermission == UsbPermission.Unknown || usbPermission == UsbPermission.Granted)
mainLooper.post(this::connect);
}
/**
* 解除广播
* 示例:
*
* @Override protected void onPause() { Test.getInstance().onPause(this); super.onPause(); }
*/
public void onPause(Context context) {
if (connected) {
status("disconnected");
disconnect();
}
context.unregisterReceiver(broadcastReceiver);
}
public interface UsbListener {
/**
* 当新的传入数据可用时调用
*/
void onNewData(byte[] data);
/**
* 因错误中止时调用
*/
void onRunError(Exception e);
/**
* 状态
*/
default void state(String str) {
}
}
}
package com.xxx.gjg.widget.usb;
import com.hoho.android.usbserial.driver.FtdiSerialDriver;
import com.hoho.android.usbserial.driver.ProbeTable;
import com.hoho.android.usbserial.driver.UsbSerialProber;
/**
* add devices here, that are not known to DefaultProber
*
* if the App should auto start for these devices, also
* add IDs to app/src/main/res/xml/device_filter.xml
*/
public class CustomProber {
static UsbSerialProber getCustomProber() {
ProbeTable customTable = new ProbeTable();
customTable.addProduct(0x1234, 0x0001, FtdiSerialDriver.class); // e.g. device with custom VID+PID
customTable.addProduct(0x1234, 0x0002, FtdiSerialDriver.class); // e.g. device with custom VID+PID
return new UsbSerialProber(customTable);
}
}
import java.security.InvalidParameterException;
/**
* Clone of Android's /core/java/com/android/internal/util/HexDump class, for use in debugging.
* Changes: space separated hex strings
*/
public class HexDump {
private final static char[] HEX_DIGITS = {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
};
public static String dumpHexString(byte[] array) {
return dumpHexString(array, 0, array.length);
}
public static String dumpHexString(byte[] array, int offset, int length) {
StringBuilder result = new StringBuilder();
byte[] line = new byte[8];
int lineIndex = 0;
for (int i = offset; i < offset + length; i++) {
if (lineIndex == line.length) {
for (int j = 0; j < line.length; j++) {
if (line[j] > ' ' && line[j] < '~') {
result.append(new String(line, j, 1));
} else {
result.append(".");
}
}
result.append("\n");
lineIndex = 0;
}
byte b = array[i];
result.append(HEX_DIGITS[(b >>> 4) & 0x0F]);
result.append(HEX_DIGITS[b & 0x0F]);
result.append(" ");
line[lineIndex++] = b;
}
for (int i = 0; i < (line.length - lineIndex); i++) {
result.append(" ");
}
for (int i = 0; i < lineIndex; i++) {
if (line[i] > ' ' && line[i] < '~') {
result.append(new String(line, i, 1));
} else {
result.append(".");
}
}
return result.toString();
}
public static String toHexString(byte b) {
return toHexString(toByteArray(b));
}
public static String toHexString(byte[] array) {
return toHexString(array, 0, array.length);
}
public static String toHexString(byte[] array, int offset, int length) {
char[] buf = new char[length > 0 ? length * 3 - 1 : 0];
int bufIndex = 0;
for (int i = offset; i < offset + length; i++) {
if (i > offset)
buf[bufIndex++] = ' ';
byte b = array[i];
buf[bufIndex++] = HEX_DIGITS[(b >>> 4) & 0x0F];
buf[bufIndex++] = HEX_DIGITS[b & 0x0F];
}
return new String(buf);
}
public static String toHexString(int i) {
return toHexString(toByteArray(i));
}
public static String toHexString(short i) {
return toHexString(toByteArray(i));
}
public static byte[] toByteArray(byte b) {
byte[] array = new byte[1];
array[0] = b;
return array;
}
public static byte[] toByteArray(int i) {
byte[] array = new byte[4];
array[3] = (byte) (i & 0xFF);
array[2] = (byte) ((i >> 8) & 0xFF);
array[1] = (byte) ((i >> 16) & 0xFF);
array[0] = (byte) ((i >> 24) & 0xFF);
return array;
}
public static byte[] toByteArray(short i) {
byte[] array = new byte[2];
array[1] = (byte) (i & 0xFF);
array[0] = (byte) ((i >> 8) & 0xFF);
return array;
}
private static int toByte(char c) {
if (c >= '0' && c <= '9')
return (c - '0');
if (c >= 'A' && c <= 'F')
return (c - 'A' + 10);
if (c >= 'a' && c <= 'f')
return (c - 'a' + 10);
throw new InvalidParameterException("Invalid hex char '" + c + "'");
}
/** accepts any separator, e.g. space or newline */
public static byte[] hexStringToByteArray(String hexString) {
int length = hexString.length();
byte[] buffer = new byte[(length + 1) / 3];
for (int i = 0; i < length; i += 3) {
buffer[i / 3] = (byte) ((toByte(hexString.charAt(i)) << 4) | toByte(hexString.charAt(i + 1)));
}
return buffer;
}
}
package com.xxx.gjg.widget.usb;
/**
* 进制转换工具类
*/
public class HexUtils {
/**
* 16进制转Ascii
*/
public static String hexByteArrayToAscii(byte[] bytes) {
StringBuilder output = new StringBuilder("");
for (int i = 0; i < bytes.length; i++) {
output.append((char) bytes[i]);
}
return output.toString();
}
/**
* Ascii转16进制
*/
public static byte[] asciiToHexByteArray(String str) {
int length = str.length();
byte[] result = new byte[length];
for (int i = 0; i < length; i++) {
result[i] = (byte) str.charAt(i);
}
return result;
}
/**
* 16进制表示的字符串转换为字节数组
*
* @param hexString 16进制表示的字符串
* @return byte[] 字节数组
*/
public static byte[] hexStringToByteArray(String hexString) {
hexString = hexString.replaceAll(" ", "");
int len = hexString.length();
byte[] bytes = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
// 两位一组,表示一个字节,把这样表示的16进制字符串,还原成一个字节
bytes[i / 2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4) + Character
.digit(hexString.charAt(i + 1), 16));
}
return bytes;
}
/**
* 将字节数组转换成十六进制的字符串
*
* @return
*/
public static String BinaryToHexString(byte[] bytes) {
String hexStr = "0123456789ABCDEF";
String result = "";
String hex = "";
for (byte b : bytes) {
hex = String.valueOf(hexStr.charAt((b & 0xF0) >> 4));
hex += String.valueOf(hexStr.charAt(b & 0x0F));
result += hex + " ";
}
return result;
}
}
package com.xxx.gjg.widget.usb;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbManager;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.text.SpannableStringBuilder;
import android.util.Log;
import com.blankj.utilcode.util.ToastUtils;
import com.hoho.android.usbserial.driver.UsbSerialDriver;
import com.hoho.android.usbserial.driver.UsbSerialPort;
import com.hoho.android.usbserial.driver.UsbSerialProber;
import com.hoho.android.usbserial.util.SerialInputOutputManager;
import com.xxx.gjg.BuildConfig;
import com.xxx.gjg.app.AppApplication;
import com.xxx.gjg.utils.CabinetDoorUtils;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
/**
* usb设备管理(主要用于读卡器)
* 注意事项:Activity 设置 singleTop
* <intent-filter>
* <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
* </intent-filter>
* <meta-data
* android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
* android:resource="@xml/device_filter" />
*/
public class UsbDeviceManage implements SerialInputOutputManager.Listener {
private BroadcastReceiver broadcastReceiver;
private int deviceId;
private int portNum;
private int baudRate;
private boolean withIoManager;
private UsbListener mUsbListener;
@Override
public void onNewData(byte[] data) {
mainLooper.post(() -> {
receive(data);
if (mUsbListener != null) {
mUsbListener.onNewData(data);
}
});
}
@Override
public void onRunError(Exception e) {
mainLooper.post(() -> {
status("connection lost: " + e.getMessage());
disconnect();
if (mUsbListener != null) {
mUsbListener.onRunError(e);
}
});
}
private enum UsbPermission {Unknown, Requested, Granted, Denied}
private static final String INTENT_ACTION_GRANT_USB = BuildConfig.APPLICATION_ID + ".GRANT_USB";
private static final int WRITE_WAIT_MILLIS = 2000;
private static final int READ_WAIT_MILLIS = 2000;
private UsbPermission usbPermission = UsbPermission.Unknown;
private UsbSerialPort usbSerialPort;
private SerialInputOutputManager usbIoManager;
private boolean connected = false;
private Handler mainLooper;
private final ArrayList<ListItem> listItems = new ArrayList<>();
private static UsbDeviceManage instance;
private UsbDeviceManage() {
}
public static UsbDeviceManage getInstance() {
if (instance == null) {
synchronized (UsbDeviceManage.class) {
if (instance == null) {
instance = new UsbDeviceManage();
}
}
}
return instance;
}
public void refresh(Context context, UsbListener usbListener) {
listItems.clear();
mUsbListener = usbListener;
UsbManager usbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
UsbSerialProber usbDefaultProber = UsbSerialProber.getDefaultProber();
UsbSerialProber usbCustomProber = CustomProber.getCustomProber();
for (UsbDevice device : usbManager.getDeviceList().values()) {
UsbSerialDriver driver = usbDefaultProber.probeDevice(device);
if (driver == null) {
driver = usbCustomProber.probeDevice(device);
}
if (driver != null) {
for (int port = 0; port < driver.getPorts().size(); port++)
listItems.add(new ListItem(device, port, driver));
} else {
listItems.add(new ListItem(device, 0, null));
}
}
Log.i("调试信息", "开始监听=>usb连接设备数量: " + listItems.size());
if (!listItems.isEmpty()) {
deviceId = listItems.get(0).device.getDeviceId();
portNum = listItems.get(0).port;
baudRate = 19200;
withIoManager = true;
// 获取设备的厂商ID和产品ID listItems.get(0).device
//int vendorId = device.getVendorId();
//int productId = device.getProductId();
//
获取设备的描述信息
//String deviceName = device.getDeviceName();
//String deviceClass = device.getDeviceClass();
//String deviceSubclass = device.getDeviceSubclass();
//String deviceProtocol = device.getDeviceProtocol();
}
startReceiver();
}
private void startReceiver() {
broadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (INTENT_ACTION_GRANT_USB.equals(intent.getAction())) {
usbPermission = intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)
? UsbPermission.Granted : UsbPermission.Denied;
connect();
}
}
};
mainLooper = new Handler(Looper.getMainLooper());
}
/*
* Serial + UI
*/
private void connect() {
UsbDevice device = null;
UsbManager usbManager = (UsbManager) AppApplication.getApplication().getSystemService(Context.USB_SERVICE);
for (UsbDevice v : usbManager.getDeviceList().values()) {
if (v.getDeviceId() == deviceId)
device = v;
}
if (device == null) {
status("connection failed: device not found");
return;
}
UsbSerialDriver driver = UsbSerialProber.getDefaultProber().probeDevice(device);
if (driver == null) {
driver = CustomProber.getCustomProber().probeDevice(device);
}
if (driver == null) {
status("connection failed: no driver for device");
return;
}
if (driver.getPorts().size() < portNum) {
status("connection failed: not enough ports at device");
return;
}
usbSerialPort = driver.getPorts().get(portNum);
UsbDeviceConnection usbConnection = usbManager.openDevice(driver.getDevice());
if (usbConnection == null && usbPermission == UsbPermission.Unknown && !usbManager.hasPermission(driver.getDevice())) {
usbPermission = UsbPermission.Requested;
int flags = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ? 1 << 25 : 0;
PendingIntent usbPermissionIntent = PendingIntent.getBroadcast(AppApplication.getApplication(), 0, new Intent(INTENT_ACTION_GRANT_USB), flags);
usbManager.requestPermission(driver.getDevice(), usbPermissionIntent);
return;
}
if (usbConnection == null) {
if (!usbManager.hasPermission(driver.getDevice()))
status("connection failed: permission denied");
else
status("connection failed: open failed");
return;
}
try {
usbSerialPort.open(usbConnection);
try {
usbSerialPort.setParameters(baudRate, 8, 1, UsbSerialPort.PARITY_NONE);
} catch (UnsupportedOperationException e) {
status("unsupport setparameters");
}
if (withIoManager) {
usbIoManager = new SerialInputOutputManager(usbSerialPort, this);
usbIoManager.start();
}
status("connected");
connected = true;
// controlLines.start();
} catch (Exception e) {
status("connection failed: " + e.getMessage());
disconnect();
}
}
private void disconnect() {
connected = false;
// controlLines.stop();
if (usbIoManager != null) {
usbIoManager.setListener(null);
usbIoManager.stop();
}
usbIoManager = null;
try {
usbSerialPort.close();
} catch (IOException ignored) {
}
usbSerialPort = null;
}
private void send(String str) {
if (!connected) {
ToastUtils.showLong("not connected");
return;
}
try {
byte[] data = (str + '\n').getBytes();
Log.i("调试信息", "send: " + HexDump.dumpHexString(data));
// SpannableStringBuilder spn = new SpannableStringBuilder();
// spn.append("send " + data.length + " bytes\n");
// spn.append(HexDump.dumpHexString(data)).append("\n");
// spn.setSpan(new ForegroundColorSpan(getResources().getColor(R.color.colorSendText)), 0, spn.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
// receiveText.append(spn);
usbSerialPort.write(data, WRITE_WAIT_MILLIS);
} catch (Exception e) {
onRunError(e);
}
}
private void read() {
if (!connected) {
ToastUtils.showLong("not connected");
return;
}
try {
byte[] buffer = new byte[8192];
int len = usbSerialPort.read(buffer, READ_WAIT_MILLIS);
receive(Arrays.copyOf(buffer, len));
} catch (IOException e) {
// when using read with timeout, USB bulkTransfer returns -1 on timeout _and_ errors
// like connection loss, so there is typically no exception thrown here on error
status("connection lost: " + e.getMessage());
disconnect();
}
}
private void receive(byte[] data) {
SpannableStringBuilder spn = new SpannableStringBuilder();
spn.append("receive " + data.length + " bytes\n");
// if (data.length > 0)
// spn.append(HexDump.dumpHexString(data)).append("\n");
receiveText.append(spn);
// Log.i("调试信息", "receive1: " + HexDump.dumpHexString(data));
Log.i("调试信息", "receive2: " + CabinetDoorUtils.BinaryToHexString(data));
Log.i("调试信息", "receive3: " + hexByteArrayToAscii(data));
Log.i("调试信息", "receive4: " + HexUtils.hexByteArrayToAscii(data));
Log.i("调试信息", "receive5: " + CabinetDoorUtils.BinaryToHexString(HexUtils.asciiToHexByteArray(HexUtils.hexByteArrayToAscii(data))));
}
public static String hexByteArrayToAscii(byte[] bytes) {
StringBuilder output = new StringBuilder("");
for (int i = 0; i < bytes.length; i++) {
output.append((char) bytes[i]);
}
return output.toString();
}
void status(String str) {
Log.i("调试信息", "status: " + str);
if (mUsbListener != null) {
mUsbListener.state(str);
}
}
public static class ListItem {
UsbDevice device;
int port;
UsbSerialDriver driver;
ListItem(UsbDevice device, int port, UsbSerialDriver driver) {
this.device = device;
this.port = port;
this.driver = driver;
}
}
/**
* 在Activity#onResume父类方法之前调用
* 示例:
*
* @Override protected void onResume(){Test.getInstance().onResume(this);super.onResume();}
*/
public void onResume(Context context) {
if (broadcastReceiver == null) {
return;
}
context.registerReceiver(broadcastReceiver, new IntentFilter(INTENT_ACTION_GRANT_USB));
if (usbPermission == UsbPermission.Unknown || usbPermission == UsbPermission.Granted)
mainLooper.post(this::connect);
}
/**
* 解除广播
* 示例:
*
* @Override protected void onPause() { Test.getInstance().onPause(this); super.onPause(); }
*/
public void onPause(Context context) {
if (connected) {
status("disconnected");
disconnect();
}
context.unregisterReceiver(broadcastReceiver);
}
public interface UsbListener {
/**
* 当新的传入数据可用时调用
*/
void onNewData(byte[] data);
/**
* 因错误中止时调用
*/
void onRunError(Exception e);
/**
* 状态
*/
default void state(String str) {
}
}
}
<!-- usb权限=>刷卡用 -->
<uses-permission android:name="android.permission.USB_PERMISSION" />
<uses-feature android:name="android.hardware.usb.host" />