/biodyn/src/br/unb/biodyn/BluetoothService.java
Java | 581 lines | 342 code | 91 blank | 148 comment | 40 complexity | c15baf3c99cb043e7dc5d8d925622c89 MD5 | raw file
Possible License(s): Apache-2.0
- /*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * Modified for biodyn project
- */
- package br.unb.biodyn;
- import java.io.IOException;
- import java.io.InputStream;
- import java.lang.reflect.InvocationTargetException;
- import java.lang.reflect.Method;
- import java.util.UUID;
- import br.unb.biodyn.model.LogFormat;
- import android.app.Service;
- import android.bluetooth.BluetoothAdapter;
- import android.bluetooth.BluetoothDevice;
- import android.bluetooth.BluetoothServerSocket;
- import android.bluetooth.BluetoothSocket;
- import android.content.BroadcastReceiver;
- import android.content.Context;
- import android.content.Intent;
- import android.content.IntentFilter;
- import android.os.IBinder;
- import android.support.v4.content.LocalBroadcastManager;
- import android.util.Log;
- /**
- * This class does all the work for setting up and managing Bluetooth
- * connections with other devices. It has a thread that listens for incoming
- * connections, a thread for connecting with a device, and a thread for
- * performing data transmissions when connected.
- */
- public class BluetoothService extends Service {
- /********************************** CONSTANTS ***********************************/
- // Debugging
- private static final String TAG = "BluetoothChatService";
- private static final boolean DEBUG = true;
- // Constants that indicate the current connection state
- public static final int STATE_NONE = 0; // we're doing nothing
- public static final int STATE_LISTEN = 1; // now listening for incoming
- // connections
- public static final int STATE_CONNECTING = 2; // now initiating an outgoing
- // connection
- public static final int STATE_CONNECTED = 3; // now connected to a remote
- // device
- // Message types sent to UI Thread
- public static final int MESSAGE_STATE_CHANGE = 1;
- public static final int MESSAGE_READ = 2;
- public static final int MESSAGE_WRITE = 3;
- public static final int MESSAGE_DEVICE_NAME = 4;
- public static final int MESSAGE_TOAST = 5;
- // Action to start this service
- public static final String ACTION_BLUETOOTH_SERVICE = "br.unb.biodyn.BluetoothService";
- public static final String KEY_HANDLER = "handler";
- // Action to connect to device
- protected static final String ACTION_CONNECT_TO_DEVICE = "br.unb.biodyn.BluetoothService.connect_device";
- protected static final String KEY_DEVICE_TO_CONNECT = "device_to_connect";
- // Action to stop all threads
- protected static final String ACTION_STOP_ALL_THREADS = "br.unb.biodyn.BluetoothService.stop_all_threads";
- // Actions to communicate wth activity
- protected static final String ACTION_DATA_RECEIVED = "br.unb.biodyn.BluetoothService.data_received";
- protected static final String KEY_DATA_RECEIVED = "data_received";
- protected static final String ACTION_MESSAGE_DEVICE_NAME = "br.unb.biodyn.BluetoothService.device_name";
- protected static final String KEY_DEVICE_NAME = "device_name";
- protected static final String ACTION_MESSAGE_SHOW_TOAST = "br.unb.biodyn.BluetoothService.show_toast";
- protected static final String KEY_TOAST_MESSAGE = "toast_message";
- // Name for the SDP record when creating server socket
- private static final String NAME = "BluetoothChat";
- // Unique UUID for this application
- private static final UUID MY_UUID = UUID
- .fromString("fa87c0d0-afac-11de-8a39-0800200c9a66");
- /********************************** CLASS FIELDS ***********************************/
- private final BluetoothAdapter mAdapter = BluetoothAdapter
- .getDefaultAdapter();
- private AcceptThread mAcceptThread;
- private ConnectThread mConnectThread;
- private ConnectedThread mConnectedThread;
- private int mState;
- private StringBuilder currentMessage=new StringBuilder();
- private BroadcastReceiver mReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (intent.getAction().equals(ACTION_CONNECT_TO_DEVICE)) {
- BluetoothDevice device = (BluetoothDevice) intent.getExtras()
- .get(KEY_DEVICE_TO_CONNECT);
- try {
- connect(device);
- } catch (Exception e) {
- Log.e(TAG, "exception in the receiver: ", e);
- }
- } else if (intent.getAction().equals(ACTION_STOP_ALL_THREADS)) {
- stop();
- }
- }
- };
- /********************************** LIFECYCLE METHODS ***********************************/
- @Override
- public void onCreate() {
- super.onCreate();
- // Registering BroadcastReceiver to receive some commands
- IntentFilter filter = new IntentFilter();
- filter.addAction(ACTION_CONNECT_TO_DEVICE);
- filter.addAction(ACTION_STOP_ALL_THREADS);
- LocalBroadcastManager.getInstance(this).registerReceiver(mReceiver,
- filter);
- // Drawable dr = getResources().getDrawable(R.drawable.app_icon);
- // // Bitmap bitmap = ((BitmapDrawable) dr).getBitmap();
- // Intent i = new Intent(this, MainActivity.class);
- // i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP
- // | Intent.FLAG_ACTIVITY_SINGLE_TOP);
- // PendingIntent pi = PendingIntent.getActivity(this, 0, i, 0);
- // Notification note = new NotificationCompat.Builder(this)
- // .setContentTitle("Biodyn application")
- // .setContentText("Bluetooth connection active")
- // .setSmallIcon(R.drawable.app_icon)
- // // .setLargeIcon(Bitmap.createScaledBitmap(bitmap, 82, 50,
- // // true))
- // .setContentIntent(pi).build();
- // note.flags |= Notification.FLAG_NO_CLEAR;
- // startForeground(1, note);
- start();
- };
- @Override
- public int onStartCommand(Intent intent, int flags, int startId) {
- mState = STATE_NONE;
- return super.onStartCommand(intent, flags, startId);
- }
- @Override
- public void onDestroy() {
- LocalBroadcastManager.getInstance(this).unregisterReceiver(mReceiver);
- stop();
- super.onDestroy();
- }
- @Override
- public IBinder onBind(Intent intent) {
- return null;
- }
- /********************************** OTHER METHODS ***********************************/
- /**
- * Set the current state of the chat connection
- *
- * @param state
- * An integer defining the current connection state
- */
- private synchronized void setState(int state) {
- LogFormat.setLogMessage(LogFormat.BLUETOOTHSERVICE, "setState() " + mState + " -> " + state);
- mState = state;
- // TODO send intent with state if necessary
- }
- public synchronized int getState() {
- return mState;
- }
- /**
- * Start the chat service. Specifically start AcceptThread to begin a
- * session in listening (server) mode.
- */
- public synchronized void start() {
- LogFormat.setLogMessage(LogFormat.BLUETOOTHSERVICE, "start");
- // Cancel any thread attempting to make a connection
- if (mConnectThread != null) {
- mConnectThread.cancel();
- mConnectThread = null;
- }
- // Cancel any thread currently running a connection
- if (mConnectedThread != null) {
- mConnectedThread.cancel();
- mConnectedThread = null;
- }
- // Start the thread to listen on a BluetoothServerSocket
- if (mAcceptThread == null) {
- mAcceptThread = new AcceptThread();
- mAcceptThread.start();
- }
- setState(STATE_LISTEN);
- }
- /**
- * Start the ConnectThread to initiate a connection to a remote device.
- *
- * @param device
- * The BluetoothDevice to connect
- * @throws InvocationTargetException
- * @throws IllegalAccessException
- * @throws IllegalArgumentException
- */
- public synchronized void connect(BluetoothDevice device)
- throws IllegalArgumentException, IllegalAccessException,
- InvocationTargetException {
-
- LogFormat.setLogMessage(LogFormat.BLUETOOTHSERVICE, "connect to: " + device);
-
- // Cancel any thread attempting to make a connection
- if (mState == STATE_CONNECTING) {
- if (mConnectThread != null) {
- mConnectThread.cancel();
- mConnectThread = null;
- }
- }
- // Cancel any thread currently running a connection
- if (mConnectedThread != null) {
- mConnectedThread.cancel();
- mConnectedThread = null;
- }
- // Start the thread to connect with the given device
- mConnectThread = new ConnectThread(device);
- mConnectThread.start();
- setState(STATE_CONNECTING);
- }
- /**
- * Start the ConnectedThread to begin managing a Bluetooth connection
- *
- * @param socket
- * The BluetoothSocket on which the connection was made
- * @param device
- * The BluetoothDevice that has been connected
- */
- public synchronized void connected(BluetoothSocket socket,
- BluetoothDevice device) {
- if (DEBUG)
- Log.d(TAG, "connected");
- // Cancel the thread that completed the connection
- if (mConnectThread != null) {
- mConnectThread.cancel();
- mConnectThread = null;
- }
- // Cancel any thread currently running a connection
- if (mConnectedThread != null) {
- mConnectedThread.cancel();
- mConnectedThread = null;
- }
- // Cancel the accept thread because we only want to connect to one
- // device
- if (mAcceptThread != null) {
- mAcceptThread.cancel();
- mAcceptThread = null;
- }
- // Start the thread to manage the connection and perform transmissions
- mConnectedThread = new ConnectedThread(socket);
- mConnectedThread.start();
- // Send the name of the connected device back to the UI Activity
- Intent intent = new Intent(ACTION_MESSAGE_DEVICE_NAME);
- intent.putExtra(KEY_DEVICE_NAME, device.getName());
- LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
- setState(STATE_CONNECTED);
- }
- /**
- * Stop all threads
- */
- public synchronized void stop() {
- LogFormat.setLogMessage(LogFormat.BLUETOOTHSERVICE,"stop");
-
- if (mConnectThread != null) {
- mConnectThread.cancel();
- mConnectThread = null;
- }
- if (mConnectedThread != null) {
- mConnectedThread.cancel();
- mConnectedThread = null;
- }
- if (mAcceptThread != null) {
- mAcceptThread.cancel();
- mAcceptThread = null;
- }
- setState(STATE_NONE);
- }
- /**
- * Indicate that the connection attempt failed and notify the UI Activity.
- */
- private void connectionFailed() {
- setState(STATE_LISTEN);
- // Send a failure message back to the Activity
- Intent intent = new Intent(ACTION_MESSAGE_SHOW_TOAST);
- intent.putExtra(KEY_TOAST_MESSAGE, "Unable to connect device");
- // TODO extract to strings.xml
- LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
- start();
- }
- /**
- * Indicate that the connection was lost and notify the UI Activity.
- */
- private void connectionLost() {
- setState(STATE_LISTEN);
- // Send a failure message back to the Activity
- Intent intent = new Intent(ACTION_MESSAGE_SHOW_TOAST);
- intent.putExtra(KEY_TOAST_MESSAGE, "Device connection was lost");
- // TODO extract to strings.xml
- LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
- start();
- }
- /********************************** PRIVATE CLASSES ***********************************/
- /**
- * This thread runs while listening for incoming connections. It behaves
- * like a server-side client. It runs until a connection is accepted (or
- * until cancelled).
- */
- private class AcceptThread extends Thread {
- // The local server socket
- private final BluetoothServerSocket mmServerSocket;
- public AcceptThread() {
- BluetoothServerSocket tmp = null;
- // Create a new listening server socket
- try {
- tmp = mAdapter
- .listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
- } catch (IOException e) {
- LogFormat.setLogMessageException(LogFormat.BLUETOOTHSERVICE,"listen() failed", e);
- }
- mmServerSocket = tmp;
- }
- public void run() {
- LogFormat.setLogMessage(LogFormat.BLUETOOTHSERVICE, "BEGIN mAcceptThread" + this);
-
- setName("AcceptThread");
- BluetoothSocket socket = null;
- // Listen to the server socket if we're not connected
- while (mState != STATE_CONNECTED) {
- try {
- // This is a blocking call and will only return on a
- // successful connection or an exception
- socket = mmServerSocket.accept();
- } catch (IOException e) {
- LogFormat.setLogMessageException(LogFormat.BLUETOOTHSERVICE,"accept() failed" , e);
- break;
- }
- // If a connection was accepted
- if (socket != null) {
- synchronized (BluetoothService.this) {
- switch (mState) {
- case STATE_LISTEN:
- case STATE_CONNECTING:
- // Situation normal. Start the connected thread.
- connected(socket, socket.getRemoteDevice());
- break;
- case STATE_NONE:
- case STATE_CONNECTED:
- // Either not ready or already connected. Terminate
- // new socket.
- try {
- socket.close();
- } catch (IOException e) {
- LogFormat.setLogMessageException(LogFormat.BLUETOOTHSERVICE,"Could not close unwanted socket", e);
- }
- break;
- }
- }
- }
- }
- if (DEBUG)
- LogFormat.setLogMessage(LogFormat.BLUETOOTHSERVICE,"END mAcceptThread" );
- }
- public void cancel() {
- LogFormat.setLogMessage(LogFormat.BLUETOOTHSERVICE,"Cancel" + this );
- try {
- mmServerSocket.close();
- } catch (IOException e) {
- LogFormat.setLogMessageException(LogFormat.BLUETOOTHSERVICE,"close() of server failed", e);
- }
- }
- }
- /**
- * This thread runs while attempting to make an outgoing connection with a
- * device. It runs straight through; the connection either succeeds or
- * fails.
- */
- private class ConnectThread extends Thread {
- private final BluetoothSocket mmSocket;
- private final BluetoothDevice mmDevice;
- public ConnectThread(BluetoothDevice device)
- throws IllegalArgumentException, IllegalAccessException,
- InvocationTargetException {
- mmDevice = device;
- BluetoothSocket tmp = null;
- // Get a BluetoothSocket for a connection with the
- // given BluetoothDevice
- // try {
- // tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
- try {
- Method m = device.getClass()
- .getMethod("createInsecureRfcommSocket",
- new Class[] { int.class });
- tmp = (BluetoothSocket) m.invoke(device, 1);
- } catch (Exception e) {
- LogFormat.setLogMessageException(LogFormat.BLUETOOTHSERVICE, "error in connectThread:", e);
- }
- mmSocket = tmp;
- }
- public void run() {
- LogFormat.setLogMessage(LogFormat.BLUETOOTHSERVICE,"BEGIN mConnectThread");
- setName("ConnectThread");
- // Always cancel discovery because it will slow down a connection
- mAdapter.cancelDiscovery();
- // Make a connection to the BluetoothSocket
- try {
- // This is a blocking call and will only return on a
- // successful connection or an exception
- mmSocket.connect();
- } catch (IOException e) {
- connectionFailed();
- LogFormat.setLogMessageException(LogFormat.BLUETOOTHSERVICE, "connectionFailed", e);
- // Close the socket
- try {
- mmSocket.close();
- } catch (IOException e2) {
- LogFormat.setLogMessageException(LogFormat.BLUETOOTHSERVICE, "unable to close() socket during connection failure", e);
- }
- // Start the service over to restart listening mode
- BluetoothService.this.start();
- return;
- }
- // Reset the ConnectThread because we're done
- synchronized (BluetoothService.this) {
- mConnectThread = null;
- }
- // Start the connected thread
- connected(mmSocket, mmDevice);
- }
- public void cancel() {
- try {
- mmSocket.close();
- } catch (IOException e) {
- LogFormat.setLogMessageException(LogFormat.BLUETOOTHSERVICE, "close() of connect socket failed", e);
- }
- }
- }
- /**
- * This thread runs during a connection with a remote device. It handles all
- * incoming and outgoing transmissions.
- */
- private class ConnectedThread extends Thread {
- private final BluetoothSocket mmSocket;
- private final InputStream mmInStream;
- public ConnectedThread(BluetoothSocket socket) {
- LogFormat.setLogMessage(LogFormat.BLUETOOTHSERVICE, "create ConnectedThread");
- mmSocket = socket;
- InputStream tmpIn = null;
- // Get the BluetoothSocket input stream
- try {
- tmpIn = socket.getInputStream();
- } catch (IOException e) {
- LogFormat.setLogMessageException(LogFormat.BLUETOOTHSERVICE, "temp sockets not created", e);
- }
- mmInStream = tmpIn;
- }
- public void run() {
- LogFormat.setLogMessage(LogFormat.BLUETOOTHSERVICE, "BEGIN mConnectedThread");
- byte[] buffer = new byte[1024];
- int bytes;
- // Keep listening to the InputStream while connected
- while (true) {
- try {
- // Read from the InputStream
- bytes = mmInStream.read(buffer);
- String readMessage = new String(buffer, 0, bytes);
- currentMessage.append(readMessage);
- int firstIndex = currentMessage.toString().indexOf("Peso:");
- int lastIndex = currentMessage.toString().indexOf(" Kg");
- if (firstIndex != -1 && lastIndex != -1
- && lastIndex > firstIndex) {
- String message = currentMessage.substring(firstIndex+5,
- lastIndex);
-
- Float messageInFloat = Float.valueOf(message);
- Intent intent = new Intent(ACTION_DATA_RECEIVED);
- intent.putExtra(KEY_DATA_RECEIVED, messageInFloat);
- // TODO extract to strings.xml
- LocalBroadcastManager
- .getInstance(BluetoothService.this)
- .sendBroadcast(intent);
- currentMessage = new StringBuilder();
- }
- } catch (IOException e) {
- LogFormat.setLogMessageException(LogFormat.BLUETOOTHSERVICE, "disconnected", e);
- connectionLost();
- break;
- }
- }
- }
- public void cancel() {
- try {
- mmSocket.close();
- } catch (IOException e) {
- LogFormat.setLogMessageException(LogFormat.BLUETOOTHSERVICE, "close() of connect socket failed", e);
- }
- }
- }
- }