BluetoothChatService.java
上传用户:hollekit
上传日期:2021-04-23
资源大小:91k
文件大小:15k
源码类别:

android开发

开发平台:

Java

  1. /*
  2.  * Copyright (C) 2009 The Android Open Source Project
  3.  *
  4.  * Licensed under the Apache License, Version 2.0 (the "License");
  5.  * you may not use this file except in compliance with the License.
  6.  * You may obtain a copy of the License at
  7.  *
  8.  *      http://www.apache.org/licenses/LICENSE-2.0
  9.  *
  10.  * Unless required by applicable law or agreed to in writing, software
  11.  * distributed under the License is distributed on an "AS IS" BASIS,
  12.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13.  * See the License for the specific language governing permissions and
  14.  * limitations under the License.
  15.  */
  16. package com.example.android.BluetoothChat;
  17. import java.io.IOException;
  18. import java.io.InputStream;
  19. import java.io.OutputStream;
  20. import java.util.UUID;
  21. import android.bluetooth.BluetoothAdapter;
  22. import android.bluetooth.BluetoothDevice;
  23. import android.bluetooth.BluetoothServerSocket;
  24. import android.bluetooth.BluetoothSocket;
  25. import android.content.Context;
  26. import android.os.Bundle;
  27. import android.os.Handler;
  28. import android.os.Message;
  29. import android.util.Log;
  30. /**
  31.  * This class does all the work for setting up and managing Bluetooth
  32.  * connections with other devices. It has a thread that listens for
  33.  * incoming connections, a thread for connecting with a device, and a
  34.  * thread for performing data transmissions when connected.
  35.  */
  36. public class BluetoothChatService {
  37.     // Debugging
  38.     private static final String TAG = "BluetoothChatService";
  39.     private static final boolean D = true;
  40.     // Name for the SDP record when creating server socket
  41.     private static final String NAME = "BluetoothChat";
  42.     // Unique UUID for this application
  43.     private static final UUID MY_UUID = UUID.fromString("fa87c0d0-afac-11de-8a39-0800200c9a66");
  44.     // Member fields
  45.     private final BluetoothAdapter mAdapter;
  46.     private final Handler mHandler;
  47.     private AcceptThread mAcceptThread;
  48.     private ConnectThread mConnectThread;
  49.     private ConnectedThread mConnectedThread;
  50.     private int mState;
  51.     // Constants that indicate the current connection state
  52.     public static final int STATE_NONE = 0;       // we're doing nothing
  53.     public static final int STATE_LISTEN = 1;     // now listening for incoming connections
  54.     public static final int STATE_CONNECTING = 2; // now initiating an outgoing connection
  55.     public static final int STATE_CONNECTED = 3;  // now connected to a remote device
  56.     /**
  57.      * Constructor. Prepares a new BluetoothChat session.
  58.      * @param context  The UI Activity Context
  59.      * @param handler  A Handler to send messages back to the UI Activity
  60.      */
  61.     public BluetoothChatService(Context context, Handler handler) {
  62.         mAdapter = BluetoothAdapter.getDefaultAdapter();
  63.         mState = STATE_NONE;
  64.         mHandler = handler;
  65.     }
  66.     /**
  67.      * Set the current state of the chat connection
  68.      * @param state  An integer defining the current connection state
  69.      */
  70.     private synchronized void setState(int state) {
  71.         if (D) Log.d(TAG, "setState() " + mState + " -> " + state);
  72.         mState = state;
  73.         // Give the new state to the Handler so the UI Activity can update
  74.         mHandler.obtainMessage(BluetoothChat.MESSAGE_STATE_CHANGE, state, -1).sendToTarget();
  75.     }
  76.     /**
  77.      * Return the current connection state. */
  78.     public synchronized int getState() {
  79.         return mState;
  80.     }
  81.     /**
  82.      * Start the chat service. Specifically start AcceptThread to begin a
  83.      * session in listening (server) mode. Called by the Activity onResume() */
  84.     public synchronized void start() {
  85.         if (D) Log.d(TAG, "start");
  86.         // Cancel any thread attempting to make a connection
  87.         if (mConnectThread != null) {mConnectThread.cancel(); mConnectThread = null;}
  88.         // Cancel any thread currently running a connection
  89.         if (mConnectedThread != null) {mConnectedThread.cancel(); mConnectedThread = null;}
  90.         // Start the thread to listen on a BluetoothServerSocket
  91.         if (mAcceptThread == null) {
  92.             mAcceptThread = new AcceptThread();
  93.             mAcceptThread.start();
  94.         }
  95.         setState(STATE_LISTEN);
  96.     }
  97.     /**
  98.      * Start the ConnectThread to initiate a connection to a remote device.
  99.      * @param device  The BluetoothDevice to connect
  100.      */
  101.     public synchronized void connect(BluetoothDevice device) {
  102.         if (D) Log.d(TAG, "connect to: " + device);
  103.         // Cancel any thread attempting to make a connection
  104.         if (mState == STATE_CONNECTING) {
  105.             if (mConnectThread != null) {mConnectThread.cancel(); mConnectThread = null;}
  106.         }
  107.         // Cancel any thread currently running a connection
  108.         if (mConnectedThread != null) {mConnectedThread.cancel(); mConnectedThread = null;}
  109.         // Start the thread to connect with the given device
  110.         mConnectThread = new ConnectThread(device);
  111.         mConnectThread.start();
  112.         setState(STATE_CONNECTING);
  113.     }
  114.     /**
  115.      * Start the ConnectedThread to begin managing a Bluetooth connection
  116.      * @param socket  The BluetoothSocket on which the connection was made
  117.      * @param device  The BluetoothDevice that has been connected
  118.      */
  119.     public synchronized void connected(BluetoothSocket socket, BluetoothDevice device) {
  120.         if (D) Log.d(TAG, "connected");
  121.         // Cancel the thread that completed the connection
  122.         if (mConnectThread != null) {mConnectThread.cancel(); mConnectThread = null;}
  123.         // Cancel any thread currently running a connection
  124.         if (mConnectedThread != null) {mConnectedThread.cancel(); mConnectedThread = null;}
  125.         // Cancel the accept thread because we only want to connect to one device
  126.         if (mAcceptThread != null) {mAcceptThread.cancel(); mAcceptThread = null;}
  127.         // Start the thread to manage the connection and perform transmissions
  128.         mConnectedThread = new ConnectedThread(socket);
  129.         mConnectedThread.start();
  130.         // Send the name of the connected device back to the UI Activity
  131.         Message msg = mHandler.obtainMessage(BluetoothChat.MESSAGE_DEVICE_NAME);
  132.         Bundle bundle = new Bundle();
  133.         bundle.putString(BluetoothChat.DEVICE_NAME, device.getName());
  134.         msg.setData(bundle);
  135.         mHandler.sendMessage(msg);
  136.         setState(STATE_CONNECTED);
  137.     }
  138.     /**
  139.      * Stop all threads
  140.      */
  141.     public synchronized void stop() {
  142.         if (D) Log.d(TAG, "stop");
  143.         if (mConnectThread != null) {mConnectThread.cancel(); mConnectThread = null;}
  144.         if (mConnectedThread != null) {mConnectedThread.cancel(); mConnectedThread = null;}
  145.         if (mAcceptThread != null) {mAcceptThread.cancel(); mAcceptThread = null;}
  146.         setState(STATE_NONE);
  147.     }
  148.     /**
  149.      * Write to the ConnectedThread in an unsynchronized manner
  150.      * @param out The bytes to write
  151.      * @see ConnectedThread#write(byte[])
  152.      */
  153.     public void write(byte[] out) {
  154.         // Create temporary object
  155.         ConnectedThread r;
  156.         // Synchronize a copy of the ConnectedThread
  157.         synchronized (this) {
  158.             if (mState != STATE_CONNECTED) return;
  159.             r = mConnectedThread;
  160.         }
  161.         // Perform the write unsynchronized
  162.         r.write(out);
  163.     }
  164.     /**
  165.      * Indicate that the connection attempt failed and notify the UI Activity.
  166.      */
  167.     private void connectionFailed() {
  168.         setState(STATE_LISTEN);
  169.         // Send a failure message back to the Activity
  170.         Message msg = mHandler.obtainMessage(BluetoothChat.MESSAGE_TOAST);
  171.         Bundle bundle = new Bundle();
  172.         bundle.putString(BluetoothChat.TOAST, "Unable to connect device");
  173.         msg.setData(bundle);
  174.         mHandler.sendMessage(msg);
  175.     }
  176.     /**
  177.      * Indicate that the connection was lost and notify the UI Activity.
  178.      */
  179.     private void connectionLost() {
  180.         setState(STATE_LISTEN);
  181.         // Send a failure message back to the Activity
  182.         Message msg = mHandler.obtainMessage(BluetoothChat.MESSAGE_TOAST);
  183.         Bundle bundle = new Bundle();
  184.         bundle.putString(BluetoothChat.TOAST, "Device connection was lost");
  185.         msg.setData(bundle);
  186.         mHandler.sendMessage(msg);
  187.     }
  188.     /**
  189.      * This thread runs while listening for incoming connections. It behaves
  190.      * like a server-side client. It runs until a connection is accepted
  191.      * (or until cancelled).
  192.      */
  193.     private class AcceptThread extends Thread {
  194.         // The local server socket
  195.         private final BluetoothServerSocket mmServerSocket;
  196.         public AcceptThread() {
  197.             BluetoothServerSocket tmp = null;
  198.             // Create a new listening server socket
  199.             try {
  200.                 tmp = mAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
  201.             } catch (IOException e) {
  202.                 Log.e(TAG, "listen() failed", e);
  203.             }
  204.             mmServerSocket = tmp;
  205.         }
  206.         public void run() {
  207.             if (D) Log.d(TAG, "BEGIN mAcceptThread" + this);
  208.             setName("AcceptThread");
  209.             BluetoothSocket socket = null;
  210.             // Listen to the server socket if we're not connected
  211.             while (mState != STATE_CONNECTED) {
  212.                 try {
  213.                     // This is a blocking call and will only return on a
  214.                     // successful connection or an exception
  215.                     socket = mmServerSocket.accept();
  216.                 } catch (IOException e) {
  217.                     Log.e(TAG, "accept() failed", e);
  218.                     break;
  219.                 }
  220.                 // If a connection was accepted
  221.                 if (socket != null) {
  222.                     synchronized (BluetoothChatService.this) {
  223.                         switch (mState) {
  224.                         case STATE_LISTEN:
  225.                         case STATE_CONNECTING:
  226.                             // Situation normal. Start the connected thread.
  227.                             connected(socket, socket.getRemoteDevice());
  228.                             break;
  229.                         case STATE_NONE:
  230.                         case STATE_CONNECTED:
  231.                             // Either not ready or already connected. Terminate new socket.
  232.                             try {
  233.                                 socket.close();
  234.                             } catch (IOException e) {
  235.                                 Log.e(TAG, "Could not close unwanted socket", e);
  236.                             }
  237.                             break;
  238.                         }
  239.                     }
  240.                 }
  241.             }
  242.             if (D) Log.i(TAG, "END mAcceptThread");
  243.         }
  244.         public void cancel() {
  245.             if (D) Log.d(TAG, "cancel " + this);
  246.             try {
  247.                 mmServerSocket.close();
  248.             } catch (IOException e) {
  249.                 Log.e(TAG, "close() of server failed", e);
  250.             }
  251.         }
  252.     }
  253.     /**
  254.      * This thread runs while attempting to make an outgoing connection
  255.      * with a device. It runs straight through; the connection either
  256.      * succeeds or fails.
  257.      */
  258.     private class ConnectThread extends Thread {
  259.         private final BluetoothSocket mmSocket;
  260.         private final BluetoothDevice mmDevice;
  261.         public ConnectThread(BluetoothDevice device) {
  262.             mmDevice = device;
  263.             BluetoothSocket tmp = null;
  264.             // Get a BluetoothSocket for a connection with the
  265.             // given BluetoothDevice
  266.             try {
  267.                 tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
  268.             } catch (IOException e) {
  269.                 Log.e(TAG, "create() failed", e);
  270.             }
  271.             mmSocket = tmp;
  272.         }
  273.         public void run() {
  274.             Log.i(TAG, "BEGIN mConnectThread");
  275.             setName("ConnectThread");
  276.             // Always cancel discovery because it will slow down a connection
  277.             mAdapter.cancelDiscovery();
  278.             // Make a connection to the BluetoothSocket
  279.             try {
  280.                 // This is a blocking call and will only return on a
  281.                 // successful connection or an exception
  282.                 mmSocket.connect();
  283.             } catch (IOException e) {
  284.                 connectionFailed();
  285.                 // Close the socket
  286.                 try {
  287.                     mmSocket.close();
  288.                 } catch (IOException e2) {
  289.                     Log.e(TAG, "unable to close() socket during connection failure", e2);
  290.                 }
  291.                 // Start the service over to restart listening mode
  292.                 BluetoothChatService.this.start();
  293.                 return;
  294.             }
  295.             // Reset the ConnectThread because we're done
  296.             synchronized (BluetoothChatService.this) {
  297.                 mConnectThread = null;
  298.             }
  299.             // Start the connected thread
  300.             connected(mmSocket, mmDevice);
  301.         }
  302.         public void cancel() {
  303.             try {
  304.                 mmSocket.close();
  305.             } catch (IOException e) {
  306.                 Log.e(TAG, "close() of connect socket failed", e);
  307.             }
  308.         }
  309.     }
  310.     /**
  311.      * This thread runs during a connection with a remote device.
  312.      * It handles all incoming and outgoing transmissions.
  313.      */
  314.     private class ConnectedThread extends Thread {
  315.         private final BluetoothSocket mmSocket;
  316.         private final InputStream mmInStream;
  317.         private final OutputStream mmOutStream;
  318.         public ConnectedThread(BluetoothSocket socket) {
  319.             Log.d(TAG, "create ConnectedThread");
  320.             mmSocket = socket;
  321.             InputStream tmpIn = null;
  322.             OutputStream tmpOut = null;
  323.             // Get the BluetoothSocket input and output streams
  324.             try {
  325.                 tmpIn = socket.getInputStream();
  326.                 tmpOut = socket.getOutputStream();
  327.             } catch (IOException e) {
  328.                 Log.e(TAG, "temp sockets not created", e);
  329.             }
  330.             mmInStream = tmpIn;
  331.             mmOutStream = tmpOut;
  332.         }
  333.         public void run() {
  334.             Log.i(TAG, "BEGIN mConnectedThread");
  335.             byte[] buffer = new byte[1024];
  336.             int bytes;
  337.             // Keep listening to the InputStream while connected
  338.             while (true) {
  339.                 try {
  340.                     // Read from the InputStream
  341.                     bytes = mmInStream.read(buffer);
  342.                     // Send the obtained bytes to the UI Activity
  343.                     mHandler.obtainMessage(BluetoothChat.MESSAGE_READ, bytes, -1, buffer)
  344.                             .sendToTarget();
  345.                 } catch (IOException e) {
  346.                     Log.e(TAG, "disconnected", e);
  347.                     connectionLost();
  348.                     break;
  349.                 }
  350.             }
  351.         }
  352.         /**
  353.          * Write to the connected OutStream.
  354.          * @param buffer  The bytes to write
  355.          */
  356.         public void write(byte[] buffer) {
  357.             try {
  358.                 mmOutStream.write(buffer);
  359.                 // Share the sent message back to the UI Activity
  360.                 mHandler.obtainMessage(BluetoothChat.MESSAGE_WRITE, -1, -1, buffer)
  361.                         .sendToTarget();
  362.             } catch (IOException e) {
  363.                 Log.e(TAG, "Exception during write", e);
  364.             }
  365.         }
  366.         public void cancel() {
  367.             try {
  368.                 mmSocket.close();
  369.             } catch (IOException e) {
  370.                 Log.e(TAG, "close() of connect socket failed", e);
  371.             }
  372.         }
  373.     }
  374. }