package com.bg7yoz.ft8cn.bluetooth; /** * 蓝牙串口的SOCKET * BG7YOZ * 2023-03 */ import android.annotation.SuppressLint; import android.app.Activity; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothSocket; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import java.io.IOException; import java.security.InvalidParameterException; import java.util.Arrays; import java.util.UUID; import java.util.concurrent.Executors; public class BluetoothSerialSocket implements Runnable { private static final UUID BLUETOOTH_SPP = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); private final BroadcastReceiver disconnectBroadcastReceiver; private final Context context; private BluetoothSerialListener listener; private final BluetoothDevice device; private BluetoothSocket socket; private boolean connected; public BluetoothSerialSocket(Context context, BluetoothDevice device) { if(context instanceof Activity) throw new InvalidParameterException("expected non UI context"); this.context = context; this.device = device; disconnectBroadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if(listener != null) listener.onSerialIoError(new IOException("background disconnect")); disconnect(); // disconnect now, else would be queued until UI re-attached } }; } @SuppressLint("MissingPermission") String getName() { return device.getName() != null ? device.getName() : device.getAddress(); } /** * connect-success and most connect-errors are returned asynchronously to listener */ void connect(BluetoothSerialListener listener) throws IOException { this.listener = listener; context.registerReceiver(disconnectBroadcastReceiver, new IntentFilter(BluetoothConstants.INTENT_ACTION_DISCONNECT)); Executors.newCachedThreadPool().submit(this); } void disconnect() { listener = null; // ignore remaining data and errors // connected = false; // run loop will reset connected if(socket != null) { try { socket.close(); } catch (Exception ignored) { } socket = null; } try { context.unregisterReceiver(disconnectBroadcastReceiver); } catch (Exception ignored) { } } void write(byte[] data) throws IOException { if (!connected) throw new IOException("not connected"); socket.getOutputStream().write(data); } @SuppressLint("MissingPermission") @Override public void run() { // connect & read try { socket = device.createRfcommSocketToServiceRecord(BLUETOOTH_SPP); socket.connect(); if(listener != null) listener.onSerialConnect(); } catch (Exception e) { if(listener != null) listener.onSerialConnectError(e); try { socket.close(); } catch (Exception ignored) { } socket = null; return; } connected = true; try { byte[] buffer = new byte[1024]; int len; //noinspection InfiniteLoopStatement while (true) { len = socket.getInputStream().read(buffer); byte[] data = Arrays.copyOf(buffer, len); if(listener != null) listener.onSerialRead(data); } } catch (Exception e) { connected = false; if (listener != null) listener.onSerialIoError(e); try { socket.close(); } catch (Exception ignored) { } socket = null; } } }