package org.schmivits.airball.airdata; import java.io.IOException; import java.util.UUID; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothSocket; import android.util.Log; public class DataScanThread extends Thread { private static final long CONNECTION_TRY_AGAIN_PAUSE = 1000L; private static final long READ_TIMEOUT = 5000L; private static final long READ_PAUSE = 50L; private final BluetoothAdapter mAdapter; private final UUID mServiceUuid; private final HaveData mHaveData; private boolean mRunning = true; public DataScanThread(BluetoothAdapter adapter, UUID serviceUuid, HaveData haveData) { mAdapter = adapter; mServiceUuid = serviceUuid; mHaveData = haveData; } @Override public final void run() { while (mRunning) { try { runOnce(); } catch (IOException e) { Log.v(getClass().getName(), "Unexpected exception: " + e); // Fall through and try again in a while } try { Thread.sleep(CONNECTION_TRY_AGAIN_PAUSE); } catch (InterruptedException e) { Log.v(getClass().getName(), "Interrupted while sleeping, quitting"); mRunning = false; } } } private void runOnce() throws IOException { BluetoothSocket socket = null; try { for (BluetoothDevice paired : mAdapter.getBondedDevices()) { try { // We accept the connection to the first device we find // that is serving on the proper UUID socket = attemptConnection(paired); Log.v(getClass().getName(), "Connected to device " + paired.getName()); break; } catch (IOException e) { Log.v(getClass().getName(), "Failed to connect to device " + paired.getName()); // Didn't work; try the next device } } } finally { mAdapter.cancelDiscovery(); } if (socket != null) { fetchData(socket); } } private BluetoothSocket attemptConnection(BluetoothDevice device) throws IOException { BluetoothSocket socket = device.createRfcommSocketToServiceRecord(mServiceUuid); socket.connect(); return socket; } private void fetchData(BluetoothSocket socket) throws IOException { try { Log.v(getClass().getName(), "Processing data"); NonBlockingLineReader r = new NonBlockingLineReader(socket.getInputStream()); long timeoutBase = 0L; while (true) { String line = r.maybeReadLine(); if (line != null) { // Distribute data to client and continue mHaveData.line(line); timeoutBase = 0L; } else { if (timeoutBase == 0L) { // Begin timeout period timeoutBase = System.currentTimeMillis(); } else { // Already within a timeout period if (System.currentTimeMillis() - timeoutBase > READ_TIMEOUT) { Log.v(getClass().getName(), "Read timeout"); // Timed out, return and try again to reestablish connection return; } else { // Pause before retrying try { Thread.sleep(READ_PAUSE); } catch (InterruptedException e) { Log.v(getClass().getName(), "Interrupted while sleeping, quitting"); mRunning = false; return; } } } } if (interrupted()) { Log.v(getClass().getName(), "Interrupted while processing data, quitting"); mRunning = false; return; } } } finally { Log.v(getClass().getName(), "Closing socket to server"); socket.close(); } } }