package com.xc3fff0e.xmanager; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothServerSocket; import android.bluetooth.BluetoothSocket; import java.io.InputStream; import java.io.OutputStream; import java.util.HashMap; import java.util.UUID; public class BluetoothController { public static final String STATE_NONE = "none"; public static final String STATE_LISTEN = "listen"; public static final String STATE_CONNECTING = "connecting"; public static final String STATE_CONNECTED = "connected"; private AcceptThread acceptThread; private ConnectThread connectThread; private ConnectedThread connectedThread; private String state = STATE_NONE; private static BluetoothController instance; public static synchronized BluetoothController getInstance() { if(instance == null) { instance = new BluetoothController(); } return instance; } public synchronized void start(BluetoothConnect bluetoothConnect, BluetoothConnect.BluetoothConnectionListener listener, String tag, UUID uuid, BluetoothAdapter bluetoothAdapter) { if (connectThread != null) { connectThread.cancel(); connectThread = null; } if (connectedThread != null) { connectedThread.cancel(); connectedThread = null; } if (acceptThread != null) { acceptThread.cancel(); acceptThread = null; } acceptThread = new AcceptThread(bluetoothConnect, listener, tag, uuid, bluetoothAdapter); acceptThread.start();} public synchronized void connect(BluetoothDevice device, BluetoothConnect bluetoothConnect, BluetoothConnect.BluetoothConnectionListener listener, String tag, UUID uuid, BluetoothAdapter bluetoothAdapter) { if (state.equals(STATE_CONNECTING)) { if (connectThread != null) { connectThread.cancel(); connectThread = null; } } if (connectedThread != null) { connectedThread.cancel(); connectedThread = null; } connectThread = new ConnectThread(device, bluetoothConnect, listener, tag, uuid, bluetoothAdapter); connectThread.start(); } public synchronized void connected(BluetoothSocket socket, final BluetoothDevice device, BluetoothConnect bluetoothConnect, final BluetoothConnect.BluetoothConnectionListener listener, final String tag) { if (connectThread != null) { connectThread.cancel(); connectThread = null; } if (connectedThread != null) { connectedThread.cancel(); connectedThread = null; } if (acceptThread != null) { acceptThread.cancel(); acceptThread = null; } connectedThread = new ConnectedThread(socket, bluetoothConnect, listener, tag); connectedThread.start(); bluetoothConnect.getActivity().runOnUiThread(new Runnable() { @Override public void run() { HashMap deviceMap = new HashMap<>(); deviceMap.put("name", device.getName()); deviceMap.put("address", device.getAddress()); listener.onConnected(tag, deviceMap); } }); } public synchronized void stop(BluetoothConnect bluetoothConnect, final BluetoothConnect.BluetoothConnectionListener listener, final String tag) { if (connectThread != null) { connectThread.cancel(); connectThread = null; } if (connectedThread != null) { connectedThread.cancel(); connectedThread = null; } if (acceptThread != null) { acceptThread.cancel(); acceptThread = null; } state = STATE_NONE; bluetoothConnect.getActivity().runOnUiThread(new Runnable() { @Override public void run() { listener.onConnectionStopped(tag); } }); } public void write(byte[] out) { ConnectedThread r; synchronized (this) { if (!state.equals(STATE_CONNECTED)) return; r = connectedThread; } r.write(out); } public void connectionFailed(BluetoothConnect bluetoothConnect, final BluetoothConnect.BluetoothConnectionListener listener, final String tag, final String message) { state = STATE_NONE; bluetoothConnect.getActivity().runOnUiThread(new Runnable() { @Override public void run() { listener.onConnectionError(tag, state, message); } }); } public void connectionLost(BluetoothConnect bluetoothConnect, final BluetoothConnect.BluetoothConnectionListener listener, final String tag) { state = STATE_NONE; bluetoothConnect.getActivity().runOnUiThread(new Runnable() { @Override public void run() { listener.onConnectionError(tag, state, "Bluetooth connection is disconnected"); } }); } public String getState() { return state; } private class AcceptThread extends Thread { private BluetoothServerSocket serverSocket; private BluetoothConnect bluetoothConnect; private BluetoothConnect.BluetoothConnectionListener listener; private String tag; public AcceptThread(BluetoothConnect bluetoothConnect, BluetoothConnect.BluetoothConnectionListener listener, String tag, UUID uuid, BluetoothAdapter bluetoothAdapter) { this.bluetoothConnect = bluetoothConnect; this.listener = listener; this.tag = tag; try { serverSocket = bluetoothAdapter.listenUsingRfcommWithServiceRecord(tag, uuid); } catch (Exception e) { e.printStackTrace(); } state = STATE_LISTEN; } @Override public void run() { BluetoothSocket bluetoothSocket; while (!state.equals(STATE_CONNECTED)) { try { bluetoothSocket = serverSocket.accept(); } catch (Exception e) { e.printStackTrace(); break; } if (bluetoothSocket != null) { synchronized (BluetoothController.this) { switch (state) { case STATE_LISTEN: case STATE_CONNECTING: connected(bluetoothSocket, bluetoothSocket.getRemoteDevice(), bluetoothConnect, listener, tag); break; case STATE_NONE: case STATE_CONNECTED: try { bluetoothSocket.close(); } catch (Exception e) { e.printStackTrace(); } break; } } } } } public void cancel() { try { serverSocket.close(); } catch (Exception e) { e.printStackTrace(); } } } private class ConnectThread extends Thread { private BluetoothDevice device; private BluetoothSocket socket; private BluetoothConnect bluetoothConnect; private BluetoothConnect.BluetoothConnectionListener listener; private String tag; private BluetoothAdapter bluetoothAdapter; public ConnectThread(BluetoothDevice device, BluetoothConnect bluetoothConnect, BluetoothConnect.BluetoothConnectionListener listener, String tag, UUID uuid, BluetoothAdapter bluetoothAdapter) { this.device = device; this.bluetoothConnect = bluetoothConnect; this.listener = listener; this.tag = tag; this.bluetoothAdapter = bluetoothAdapter; try { socket = device.createRfcommSocketToServiceRecord(uuid); } catch (Exception e) { e.printStackTrace(); } state = STATE_CONNECTING; } @Override public void run() { bluetoothAdapter.cancelDiscovery(); try { socket.connect(); } catch (Exception e) { try { socket.close(); } catch (Exception e2) { e2.printStackTrace(); } connectionFailed(bluetoothConnect, listener, tag, e.getMessage()); return; } synchronized (BluetoothController.this) { connectThread = null; } connected(socket, device, bluetoothConnect, listener, tag); } public void cancel() { try { socket.close(); } catch (Exception e) { e.printStackTrace(); } } } private class ConnectedThread extends Thread { private BluetoothSocket socket; private InputStream inputStream; private OutputStream outputStream; private BluetoothConnect bluetoothConnect; private BluetoothConnect.BluetoothConnectionListener listener; private String tag; public ConnectedThread(BluetoothSocket socket, BluetoothConnect bluetoothConnect, BluetoothConnect.BluetoothConnectionListener listener, String tag) { this.bluetoothConnect = bluetoothConnect; this.listener = listener; this.tag = tag; this.socket = socket; try { inputStream = socket.getInputStream(); outputStream = socket.getOutputStream(); } catch (Exception e) { e.printStackTrace(); } state = STATE_CONNECTED; } public void run() { while (state.equals(STATE_CONNECTED)) { try { final byte[] buffer = new byte[1024]; final int bytes = inputStream.read(buffer); bluetoothConnect.getActivity().runOnUiThread(new Runnable() { @Override public void run() { listener.onDataReceived(tag, buffer, bytes); } }); } catch (Exception e) { e.printStackTrace(); connectionLost(bluetoothConnect, listener, tag); break; } } } public void write(final byte[] buffer) { try { outputStream.write(buffer); bluetoothConnect.getActivity().runOnUiThread(new Runnable() { @Override public void run() { listener.onDataSent(tag, buffer); } }); } catch (Exception e) { e.printStackTrace(); } } public void cancel() { try { socket.close(); } catch (Exception e) { e.printStackTrace(); } } } }