Android Open Source - Phone2Phone Connection Service






From Project

Back to project page Phone2Phone.

License

The source code is released under:

Apache License

If you think the Android project Phone2Phone listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package com.bluetooth.phone2phone;
/*from  w w  w.  j  a va 2 s  . c  om*/
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.UUID;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;

public class ConnectionService  {
  private static final String TAG = "ConnectionService";
  private static final boolean debug = true;

  //Name for the SDP record when creating server socket
  private static final String NAME = "Phone2Phone";
  private static final UUID MY_UUID = UUID.fromString("63c9c9be-4890-4d0d-9fa0-68694f310f37");

  //Member fields
  private final BluetoothAdapter mAdapter;
  private AcceptThread mAcceptThread;
  private ConnectThread mConnectThread;
  private ConnectedThread mConnectedThread;
  private int mState;
  private final Handler mHandler;

  //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
  
  /**
   * Constructor. Prepares a new BluetoothChat session.
   *
   * @param context The UI Activity Context
   * @param handler A Handler to send messages back to the UI Activity
   */
  public ConnectionService(Context context, Handler handler) {
    mAdapter = BluetoothAdapter.getDefaultAdapter();
    mState = STATE_NONE;
    mHandler = handler;
  }

  /**
   * Set the current state of the chat connection
   *
   * @param state An integer defining the current connection state
   */
  private synchronized void setState(int state) {
    if (debug) Log.d(TAG, "setState() " + mState + " -> " + state);
    mState = state;

    // Give the new state to the Handler so the UI Activity can update
    mHandler.obtainMessage(Main.MESSAGE_STATE_CHANGE, state, -1).sendToTarget();
  }

  /**
   * Return the current connection state.
   */
  public synchronized int getState() {
    return mState;
  }

  /**
   * Start the chat service. Specifically start AcceptThread to begin a
   * session in listening (server) mode. Called by the Activity onResume()
   */
  public synchronized void start() {
    if (debug) Log.d(TAG, "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
   */
  public synchronized void connect(BluetoothDevice device) {
    if (debug) Log.d(TAG, "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);
    String address = device.getAddress();
    Message message = mHandler.obtainMessage(Main.MESSAGE_SAVE_DEVICE, 0, 0, address);
    mHandler.sendMessage(message);

    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
    Message msg = mHandler.obtainMessage(Main.MESSAGE_DEVICE_NAME);
    Bundle bundle = new Bundle();
    bundle.putString(Main.DEVICE_NAME, device.getName());
    msg.setData(bundle);
    mHandler.sendMessage(msg);

    setState(STATE_CONNECTED);
  }

  /**
   * Stop all threads
   */
  public synchronized void stop() {
    if (debug) Log.d(TAG, "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);
  }

  /**
   * Write to the ConnectedThread in an unsynchronized manner
   *
   * @param out The bytes to write
   * @see ConnectedThread#write(byte[])
   */
  public void write(byte[] out) {
    //Create temporary object
    ConnectedThread r;
    //Synchronize a copy of the ConnectedThread
    synchronized (this) {
      if (mState != STATE_CONNECTED) return;
      r = mConnectedThread;
    }
    // Perform the write unsynchronized
    r.write(out);
  }

  /**
   * 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
    Message msg = mHandler.obtainMessage(Main.MESSAGE_TOAST);
    Bundle bundle = new Bundle();
    bundle.putString(Main.TOAST, "Unable to connect device");
    msg.setData(bundle);
    mHandler.sendMessage(msg);
    
    //Reset address of last device
    msg = mHandler.obtainMessage(Main.MESSAGE_RESET_DEVICE);
    mHandler.sendMessage(msg);    
  }

  /**
   * 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
    Message msg = mHandler.obtainMessage(Main.MESSAGE_TOAST);
    Bundle bundle = new Bundle();
    bundle.putString(Main.TOAST, "Device connection was lost");
    msg.setData(bundle);
    mHandler.sendMessage(msg);
  }

  /**
   * 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) {
        Log.e(TAG, "listen() failed", e);
      }
      mmServerSocket = tmp;
    }

    public void run() {
      if (debug) Log.d(TAG, "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) {
          Log.e(TAG, "accept() failed", e);
          break;
        }

        // If a connection was accepted
        if (socket != null) {
          synchronized (ConnectionService.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) {
                Log.e(TAG, "Could not close unwanted socket", e);
              }
              break;
            }
          }
        }
      }
      if (debug) Log.i(TAG, "END mAcceptThread");
    }

    public void cancel() {
      if (debug) Log.d(TAG, "cancel " + this);
      try {
        mmServerSocket.close();
      } 
      catch (IOException e) {
        Log.e(TAG, "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) {
      mmDevice = device;
      BluetoothSocket tmp = null;

      // Get a BluetoothSocket for a connection with the
      // given BluetoothDevice
      try {
        tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
      } catch (IOException e) {
        Log.e(TAG, "create() failed", e);
      }
      mmSocket = tmp;
    }

    public void run() {
      Log.i(TAG, "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();
        // Close the socket
        try {
          mmSocket.close();
        } catch (IOException e2) {
          Log.e(TAG, "unable to close() socket during connection failure", e2);
        }
        // Start the service over to restart listening mode
        ConnectionService.this.start();
        return;
      }

      // Reset the ConnectThread because we're done
      synchronized (ConnectionService.this) {
        mConnectThread = null;
      }

      // Start the connected thread
      connected(mmSocket, mmDevice);
    }

    public void cancel() {
      try {
        mmSocket.close();
      } catch (IOException e) {
        Log.e(TAG, "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;
    private final OutputStream mmOutStream;

    //Used to alternate between reading a file name and a file
    private int count = 0;
    
    public ConnectedThread(BluetoothSocket socket) {
      Log.d(TAG, "create ConnectedThread");

      mmSocket = socket;
      InputStream tmpIn = null;
      OutputStream tmpOut = null;

      // Get the BluetoothSocket input and output streams
      try {
        tmpIn = socket.getInputStream();
        tmpOut = socket.getOutputStream();

      } catch (IOException e) {
        Log.e(TAG, "temp sockets not created", e);
      }

      mmInStream = tmpIn;
      mmOutStream = tmpOut;
    }

    public void run() {

      Log.i(TAG, "BEGIN mConnectedThread");
      byte[] buffer = new byte[Main.BUFFER_SIZE];
      int bytes;

      // Keep listening to the InputStream while connected
      while (true) {
        try {
          // Read from the InputStream
          bytes = mmInStream.read(buffer);

          if((count % 2)==0){
            //Even numbers are for file names

            // Send the obtained bytes to the UI Activity
            mHandler.obtainMessage(Main.MESSAGE_READ_FILENAME, bytes, -1, buffer)
            .sendToTarget();
          }
          else{
            //Odd numbers are for files

            // Send the obtained bytes to the UI Activity
            mHandler.obtainMessage(Main.MESSAGE_READ_FILE, bytes, -1, buffer)
            .sendToTarget();
          }

          count = count+1;
                    
          Log.d("ConnectionService-ConnectedThread","read buffer="+buffer);
          //Log.d("ConnectionService-ConnectedThread","is read buffer=file? "+ Arrays.equals(buffer, Main.file));
        } 
        catch (IOException e) {
          Log.e(TAG, "disconnected", e);
          connectionLost();
          break;
        }

      }
    }

    /**
     * Write to the connected OutStream.
     *
     * @param buffer The bytes to write
     */
    public void write(byte[] buffer) {
      try {
        mmOutStream.write(buffer);
        mmOutStream.flush();

        if((count % 2)==0){
          //Even numbers are for file names

          // Share the sent message back to the UI Activity
          mHandler.obtainMessage(Main.MESSAGE_WRITE_FILENAME, -1, -1, buffer)
          .sendToTarget();
        }
        else{
          //Odd numbers are for files

          // Share the sent message back to the UI Activity
          mHandler.obtainMessage(Main.MESSAGE_WRITE_FILE, -1, -1, buffer)
          .sendToTarget();
        }

        count = count+1;
        
        Log.d("ConnectionService-ConnectedThread","write buffer="+buffer);
        //Log.d("ConnectionService-ConnectedThread","is write buffer=file? "+ Arrays.equals(buffer, Main.file));
      } catch (IOException e) {
        Log.e(TAG, "Exception during write", e);
      }
    }

    public void cancel() {
      try {
        mmSocket.close();
      } catch (IOException e) {
        Log.e(TAG, "close() of connect socket failed", e);
      }
    }
  }

}




Java Source Code List

com.bluetooth.phone2phone.ConnectionService.java
com.bluetooth.phone2phone.Main.java