FT8CN/ft8CN/app/src/main/java/com/bg7yoz/ft8cn/bluetooth/BluetoothSerialService.java

214 wiersze
6.4 KiB
Java
Executable File

package com.bg7yoz.ft8cn.bluetooth;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import androidx.annotation.Nullable;
import java.io.IOException;
import java.util.LinkedList;
import java.util.Queue;
/**
* 蓝牙串口有关的服务
* BG7YOZ
* 2023-03
*/
public class BluetoothSerialService extends Service implements BluetoothSerialListener {
public class SerialBinder extends Binder {
public BluetoothSerialService getService() { return BluetoothSerialService.this; }
}
private enum QueueType {Connect, ConnectError, Read, IoError}
private static class QueueItem {
QueueType type;
byte[] data;
Exception e;
QueueItem(QueueType type, byte[] data, Exception e) { this.type=type; this.data=data; this.e=e; }
}
private final Handler mainLooper;
private final IBinder binder;
private final Queue<QueueItem> queue1, queue2;
private BluetoothSerialSocket socket;
private BluetoothSerialListener listener;
private boolean connected;
/**
* Lifecylce
*/
public BluetoothSerialService() {
mainLooper = new Handler(Looper.getMainLooper());
binder = new SerialBinder();
queue1 = new LinkedList<>();
queue2 = new LinkedList<>();
}
@Override
public void onDestroy() {
//cancelNotification();
disconnect();
super.onDestroy();
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return binder;
}
/**
* Api
*/
public void connect(BluetoothSerialSocket socket) throws IOException {
socket.connect(this);
this.socket = socket;
connected = true;
}
public void disconnect() {
connected = false; // ignore data,errors while disconnecting
//cancelNotification();
if(socket != null) {
socket.disconnect();
socket = null;
}
}
public void write(byte[] data) throws IOException {
if(!connected)
throw new IOException("not connected");
socket.write(data);
}
public void attach(BluetoothSerialListener listener) {
if(Looper.getMainLooper().getThread() != Thread.currentThread())
throw new IllegalArgumentException("not in main thread");
//cancelNotification();
// use synchronized() to prevent new items in queue2
// new items will not be added to queue1 because mainLooper.post and attach() run in main thread
synchronized (this) {
this.listener = listener;
}
for(QueueItem item : queue1) {
switch(item.type) {
case Connect: listener.onSerialConnect (); break;
case ConnectError: listener.onSerialConnectError (item.e); break;
case Read: listener.onSerialRead (item.data); break;
case IoError: listener.onSerialIoError (item.e); break;
}
}
for(QueueItem item : queue2) {
switch(item.type) {
case Connect: listener.onSerialConnect (); break;
case ConnectError: listener.onSerialConnectError (item.e); break;
case Read: listener.onSerialRead (item.data); break;
case IoError: listener.onSerialIoError (item.e); break;
}
}
queue1.clear();
queue2.clear();
}
public void detach() {
if (connected){
disconnect();
}
listener = null;
}
/**
* SerialListener
*/
public void onSerialConnect() {
if(connected) {
synchronized (this) {
if (listener != null) {
mainLooper.post(() -> {
if (listener != null) {
listener.onSerialConnect();
} else {
queue1.add(new QueueItem(QueueType.Connect, null, null));
}
});
} else {
queue2.add(new QueueItem(QueueType.Connect, null, null));
}
}
}
}
public void onSerialConnectError(Exception e) {
if(connected) {
synchronized (this) {
if (listener != null) {
mainLooper.post(() -> {
if (listener != null) {
listener.onSerialConnectError(e);
} else {
queue1.add(new QueueItem(QueueType.ConnectError, null, e));
//cancelNotification();
disconnect();
}
});
} else {
queue2.add(new QueueItem(QueueType.ConnectError, null, e));
//cancelNotification();
disconnect();
}
}
}
}
public void onSerialRead(byte[] data) {
if(connected) {
synchronized (this) {
if (listener != null) {
mainLooper.post(() -> {
if (listener != null) {
listener.onSerialRead(data);
} else {
queue1.add(new QueueItem(QueueType.Read, data, null));
}
});
} else {
queue2.add(new QueueItem(QueueType.Read, data, null));
}
}
}
}
public void onSerialIoError(Exception e) {
if(connected) {
synchronized (this) {
if (listener != null) {
mainLooper.post(() -> {
if (listener != null) {
listener.onSerialIoError(e);
} else {
queue1.add(new QueueItem(QueueType.IoError, null, e));
//cancelNotification();
disconnect();
}
});
} else {
queue2.add(new QueueItem(QueueType.IoError, null, e));
//cancelNotification();
disconnect();
}
}
}
}
}