UsbSerial/usbserial/src/main/java/com/felhr/usbserial/SerialPortBuilder.java

286 wiersze
10 KiB
Java

package com.felhr.usbserial;
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 com.annimon.stream.Optional;
import com.annimon.stream.Stream;
import com.felhr.utils.Utils;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.atomic.AtomicBoolean;
public class SerialPortBuilder {
private static final String ACTION_USB_PERMISSION = "com.felhr.usbserial.USB_PERMISSION";
private static final int MODE_START = 0;
private static final int MODE_OPEN = 1;
private static SerialPortBuilder SerialPortBuilder;
private List<UsbDeviceStatus> devices;
private List<UsbSerialDevice> serialDevices = new ArrayList<>();
private ArrayBlockingQueue<PendingUsbPermission> queuedPermissions = new ArrayBlockingQueue<>(100);
private AtomicBoolean processingPermission = new AtomicBoolean(false);
private PendingUsbPermission currentPendingPermission;
private UsbManager usbManager;
private SerialPortCallback serialPortCallback;
private InitSerialPortThread initSerialPortThread;
private int baudRate, dataBits, stopBits, parity, flowControl;
private int mode = 0;
private boolean broadcastRegistered = false;
private SerialPortBuilder(SerialPortCallback serialPortCallback){
this.serialPortCallback = serialPortCallback;
}
public static SerialPortBuilder createSerialPortBuilder(SerialPortCallback serialPortCallback){
if(SerialPortBuilder == null) {
SerialPortBuilder = new SerialPortBuilder(serialPortCallback);
return SerialPortBuilder;
}else {
return SerialPortBuilder;
}
}
public List<UsbDevice> getPossibleSerialPorts(Context context){
usbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
HashMap<String, UsbDevice> allDevices = usbManager.getDeviceList();
List<UsbDevice> devices = Stream.of(allDevices.values())
.filter(UsbSerialDevice::isSupported)
.toList();
return devices;
}
public boolean getSerialPorts(Context context){
initReceiver(context);
if(devices == null || devices.size() == 0) { // Not previous devices detected
devices = Stream.of(getPossibleSerialPorts(context))
.map(UsbDeviceStatus::new)
.toList();
if(devices.size() == 0)
return false;
for(UsbDeviceStatus deviceStatus : devices){
queuedPermissions.add(createUsbPermission(context, deviceStatus));
}
if(!processingPermission.get()){
launchPermission();
}
}else{ // Previous devices detected and maybe pending permissions intent launched
List<UsbDeviceStatus> newDevices = Stream.of(getPossibleSerialPorts(context))
.map(UsbDeviceStatus::new)
.filter(p -> !devices.contains(p))
.toList();
if(newDevices.size() == 0)
return false;
for(UsbDeviceStatus deviceStatus : newDevices){
queuedPermissions.add(createUsbPermission(context, deviceStatus));
}
devices.addAll(newDevices);
if(!processingPermission.get()){
launchPermission();
}
}
return true;
}
public boolean openSerialPorts(Context context, int baudRate, int dataBits,
int stopBits, int parity, int flowControl){
this.baudRate = baudRate;
this.dataBits = dataBits;
this.stopBits = stopBits;
this.parity = parity;
this.flowControl = flowControl;
this.mode = MODE_OPEN;
return getSerialPorts(context);
}
public boolean disconnectDevice(UsbSerialDevice usbSerialDevice){
usbSerialDevice.syncClose();
serialDevices = Utils.removeIf(serialDevices, p -> usbSerialDevice.getDeviceId() == p.getDeviceId());
return true;
}
public boolean disconnectDevice(UsbDevice usbDevice){
Optional<UsbSerialDevice> optionalDevice = Stream.of(serialDevices)
.filter(p -> usbDevice.getDeviceId() == p.getDeviceId())
.findSingle();
if(optionalDevice.isPresent()){
UsbSerialDevice disconnectedDevice = optionalDevice.get();
disconnectedDevice.syncClose();
serialDevices = Utils.removeIf(serialDevices, p -> usbDevice.getDeviceId() == p.getDeviceId());
return true;
}
return false;
}
public void unregisterListeners(Context context){
if(broadcastRegistered){
context.unregisterReceiver(usbReceiver);
broadcastRegistered = false;
}
}
private PendingUsbPermission createUsbPermission(Context context, UsbDeviceStatus usbDeviceStatus){
PendingIntent mPendingIntent = PendingIntent.getBroadcast(context, 0, new Intent(ACTION_USB_PERMISSION), 0);
PendingUsbPermission pendingUsbPermission = new PendingUsbPermission();
pendingUsbPermission.pendingIntent = mPendingIntent;
pendingUsbPermission.usbDeviceStatus = usbDeviceStatus;
return pendingUsbPermission;
}
private void launchPermission(){
try {
processingPermission.set(true);
currentPendingPermission = queuedPermissions.take();
usbManager.requestPermission(currentPendingPermission.usbDeviceStatus.usbDevice,
currentPendingPermission.pendingIntent);
} catch (InterruptedException e) {
e.printStackTrace();
processingPermission.set(false);
}
}
private void initReceiver(Context context){
if(!broadcastRegistered) {
IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_USB_PERMISSION);
context.registerReceiver(usbReceiver, filter);
broadcastRegistered = true;
}
}
private void createAllPorts(UsbDeviceStatus usbDeviceStatus){
int interfaceCount = usbDeviceStatus.usbDevice.getInterfaceCount();
for(int i=0;i<=interfaceCount-1;i++) {
if(usbDeviceStatus.usbDeviceConnection == null) {
usbDeviceStatus.usbDeviceConnection = usbManager.openDevice(usbDeviceStatus.usbDevice);
}
UsbSerialDevice usbSerialDevice = UsbSerialDevice.createUsbSerialDevice(
usbDeviceStatus.usbDevice,
usbDeviceStatus.usbDeviceConnection,
i);
serialDevices.add(usbSerialDevice);
}
}
private final BroadcastReceiver usbReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(ACTION_USB_PERMISSION)) {
boolean granted = intent.getExtras().getBoolean(UsbManager.EXTRA_PERMISSION_GRANTED);
if (granted) {
createAllPorts(currentPendingPermission.usbDeviceStatus);
if(queuedPermissions.size() > 0) {
launchPermission();
}else{
processingPermission.set(false);
if(mode == MODE_START) {
serialPortCallback.onSerialPortsDetected(serialDevices);
}else{
initSerialPortThread = new InitSerialPortThread(serialDevices);
initSerialPortThread.start();
}
}
} else {
if(queuedPermissions.size() > 0) {
launchPermission();
}else{
processingPermission.set(false);
if(mode == MODE_START) {
serialPortCallback.onSerialPortsDetected(serialDevices);
}else{
initSerialPortThread = new InitSerialPortThread(serialDevices);
initSerialPortThread.start();
}
}
}
}
}
};
private class InitSerialPortThread extends Thread {
private List<UsbSerialDevice> usbSerialDevices;
public InitSerialPortThread(List<UsbSerialDevice> usbSerialDevices) {
this.usbSerialDevices = usbSerialDevices;
}
@Override
public void run() {
int n =1;
for (UsbSerialDevice usbSerialDevice : usbSerialDevices) {
if (!usbSerialDevice.isOpen) {
if (usbSerialDevice.syncOpen()) {
usbSerialDevice.setBaudRate(baudRate);
usbSerialDevice.setDataBits(dataBits);
usbSerialDevice.setStopBits(stopBits);
usbSerialDevice.setParity(parity);
usbSerialDevice.setFlowControl(flowControl);
usbSerialDevice.setPortName(UsbSerialDevice.COM_PORT + String.valueOf(n));
n++;
}
}
}
serialPortCallback.onSerialPortsDetected(serialDevices);
}
}
private class UsbDeviceStatus {
public UsbDevice usbDevice;
public UsbDeviceConnection usbDeviceConnection;
public boolean open;
public UsbDeviceStatus(UsbDevice usbDevice) {
this.usbDevice = usbDevice;
}
@Override
public boolean equals(Object obj) {
UsbDeviceStatus usbDeviceStatus= (UsbDeviceStatus) obj;
return usbDeviceStatus.usbDevice.getDeviceId() == usbDevice.getDeviceId();
}
}
private class PendingUsbPermission{
public PendingIntent pendingIntent;
public UsbDeviceStatus usbDeviceStatus;
}
}