Android Bluetooth Chat

Posted by Control Pad on Fri, 05 Jul 2019 23:36:38 +0200

Bluetooth is one of the most popular methods of data transmission for smart devices. It connects with smart devices through mobile app s to obtain measurement data on devices. We can see it everywhere in our life, such as Bluetooth smart bracelet, Bluetooth electronic scales, Bluetooth ECG measurement equipment and so on.
In this article, I will follow up with the last one to see how to realize text chat between mobile phones through Bluetooth.
First, post some demo s in the previous article.

When you click on any of the two lists on the graph, execute the following code:

mBtAdapter.cancelDiscovery();
String info = ((TextView) v).getText().toString();
String address = info.substring(info.length() - 17);
Intent intent = new Intent();
intent.putExtra(EXTRA_DEVICE_ADDRESS, address);
setResult(Activity.RESULT_OK, intent);
finish();

The final effect of this Bluetooth chat tool is as follows:

Back to the main chat interface:

public void onActivityResult(int requestCode, int resultCode, Intent data) {
   LogUtils.getInstance().e(getClass(), "onActivityResult " + resultCode);
   switch (requestCode) {
    case REQUEST_CONNECT_DEVICE:
        // When DeviceListActivity returns a message connected to the device
         if (resultCode == Activity.RESULT_OK) {
         // MAC Address of Connecting Device
         String address = data.getExtras().getString(
        DeviceListActivity.EXTRA_DEVICE_ADDRESS);
        // Get Bluetooth Objects
        BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
        // Start Connecting Devices
        mChatService.connect(device);
        }
        break;
    case REQUEST_ENABLE_BT:
        // Determine whether Bluetooth is enabled
        if (resultCode == Activity.RESULT_OK) {
        // Establish a connection
        setupChat();
        } else {
        LogUtils.getInstance().e(getClass(), "Bluetooth not enabled");
        Toast.makeText(this, R.string.bt_not_enabled_leaving,
        Toast.LENGTH_SHORT).show();
        finish();
        }
   }
}

Here, I will focus on the connection process in the BluetoothChatService class.
Because Bluetooth chat is the communication between two mobile phones, so they host and slave each other, the main ideas and steps are as follows:
1. Open a thread to get the socket to connect Bluetooth.
2. Open a thread to listen for Bluetooth incoming connections. If the connection is accepted, open a third thread to process all incoming and outgoing data.

public synchronized void connect(BluetoothDevice device) {
    if (mState == STATE_CONNECTING) {
        if (mConnectThread != null) {
            mConnectThread.cancel();
            mConnectThread = null;
        }
    }
    if (mConnectedThread != null) {
        mConnectedThread.cancel();
        mConnectedThread = null;
    }
    mConnectThread = new ConnectThread(device);
    mConnectThread.start();
    setState(STATE_CONNECTING);
    }

Open threads to connect

/**
 * @description:Bluetooth connection thread
 * @author: zzq
 * @time: 2016-8-6 1:18:41 p.m.
 */
private class ConnectThread extends Thread {
private final BluetoothSocket mmSocket;
private final BluetoothDevice mmDevice;
    public ConnectThread(BluetoothDevice device) {
        mmDevice = device;
        BluetoothSocket tmp = null;
        try {
            tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
        } catch (IOException e) {
            LogUtils.getInstance().e(getClass(), "socket Acquisition failure:" + e);
        }
            mmSocket = tmp;
    }
    public void run() {
        LogUtils.getInstance().e(getClass(), "start mConnectThread");
        setName("ConnectThread");
        // mAdapter.cancelDiscovery();
        try {
            mmSocket.connect();
        } catch (IOException e) {
            // Connection failed, update ui
            connectionFailed();
        try {
            mmSocket.close();
        } catch (IOException e2) {
            LogUtils.getInstance().e(getClass(), "Failed to close connection" + e2);
        }
        // Open chat receiving thread
        startChat();
        return;
    }
    synchronized (BluetoothChatService.this) {
        mConnectThread = null;
    }
    connected(mmSocket, mmDevice);
    }
    public void cancel() {
        try {
            mmSocket.close();
        } catch (IOException e) {
            LogUtils.getInstance().e(getClass(), "Failed to close connection" + e);
        }
    }
}
/**
 * Listen for incoming connections
 */
private class AcceptThread extends Thread {
private final BluetoothServerSocket mmServerSocket;
    public AcceptThread() {
        BluetoothServerSocket tmp = null;
        try {
            tmp = mAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
        } catch (IOException e) {
            LogUtils.getInstance().e(getClass(), "--Obtain socket fail:" + e);
        }
            mmServerSocket = tmp;
    }

    public void run() {
        setName("AcceptThread");
            BluetoothSocket socket = null;
            while (mState != STATE_CONNECTED) {
            LogUtils.getInstance().e(getClass(), "----accept-Loop execution-");
        try {
            socket = mmServerSocket.accept();
            } catch (IOException e) {
            LogUtils.getInstance().e(getClass(), "accept() fail" + e);
            break;
            }
// If the connection is accepted
        if (socket != null) {
        synchronized (BluetoothChatService.this) {
        switch (mState) {
            case STATE_LISTEN:
            case STATE_CONNECTING:
            // Start connection threads
                connected(socket, socket.getRemoteDevice());
                break;
            case STATE_NONE:
            case STATE_CONNECTED:
            // Not ready or connected
        try {
            socket.close();
            } catch (IOException e) {
            LogUtils.getInstance().e(getClass(),"These connections cannot be closed" + e);
            }
            break;

        }
        }
    }
}
        LogUtils.getInstance().e(getClass(), "End mAcceptThread");
}

    public void cancel() {
        LogUtils.getInstance().e(getClass(), "cancel " + this);
        try {
            mmServerSocket.close();
            } catch (IOException e) {
            LogUtils.getInstance().e(getClass(), "Failure to close" + e);
            }
    }
}
/**
 * Threads after successful connections handle all incoming and outgoing transmissions
 */
private class ConnectedThread extends Thread {
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
    public ConnectedThread(BluetoothSocket socket) {
        mmSocket = socket;
        InputStream tmpIn = null;
        OutputStream tmpOut = null;
        // Get Bluetooth Socket input and output streams
        try {
            tmpIn = socket.getInputStream();
            tmpOut = socket.getOutputStream();
        } catch (IOException e) {
            LogUtils.getInstance().e(getClass(),"temp sockets not created" + e);
        }
            mmInStream = tmpIn;
            mmOutStream = tmpOut;
    }
    public void run() {
        int bytes;
        String str1 = "";
        // Loop listening for messages
        while (true) {
            try {
                byte[] buffer = new byte[256];
                bytes = mmInStream.read(buffer);
                String readStr = new String(buffer, 0, bytes);// Direct conversion of byte arrays to strings
                String str = bytes2HexString(buffer).replaceAll("00", "").trim();
                if (bytes > 0) {// Send the read message to the main thread
                           mHandler.obtainMessage(BluetoothChatActivity.MESSAGE_READ, bytes, -1,buffer).sendToTarget();
                } else {
                    LogUtils.getInstance().e(getClass(),"disconnected");
        connectionLost();
        if (mState != STATE_NONE) {
            LogUtils.getInstance().e(getClass(), "disconnected");
startChat();
        }
                break;
                }
        } catch (IOException e) {
            LogUtils.getInstance().e(getClass(), "disconnected" + e);
            connectionLost();
        if (mState != STATE_NONE) {
        // Start the service in restart listening mode
            startChat();
        }
        break;
        }
    }
}
/**
 * Write to OutStream connection
 * 
 * @param buffer
 *            Bytes to write
 */
public void write(byte[] buffer) {
        try {
        mmOutStream.write(buffer);
        // Pass the message to the UI
                mHandler.obtainMessage(BluetoothChatActivity.MESSAGE_WRITE, -1,-1, buffer).sendToTarget();

                } catch (IOException e) {
                LogUtils.getInstance().e(getClass(),
"Exception during write:" + e);
            }

        }
public void cancel() {
        try {
            mmSocket.close();
            } catch (IOException e) {
            LogUtils.getInstance().e(getClass(),"close() of connect socket failed:" + e);
            }
        }
    }

About the process is shown in the three threads above, of course, according to the specific situation of the project, such as Bluetooth Protocol Resolution, which is based on the protocol definition.
The change of Bluetooth connection state involved in the code, using handle, sends the state directly to the activity and notifies the activity to update.

 /**
 * Unable to connect, notify Activity
 */
private void connectionFailed() {
    setState(STATE_LISTEN);
    Message msg = mHandler.obtainMessage(BluetoothChatActivity.MESSAGE_TOAST);
    Bundle bundle = new Bundle();
    bundle.putString(BluetoothChatActivity.TOAST, "Unable to connect device");
    msg.setData(bundle);
    mHandler.sendMessage(msg);
}
/**
 * Disconnect the device and notify Activity
 */
private void connectionLost() {
    Message msg = mHandler.obtainMessage(BluetoothChatActivity.MESSAGE_TOAST);
    Bundle bundle = new Bundle();
    bundle.putString(BluetoothChatActivity.TOAST, "Disconnection of equipment");
    msg.setData(bundle);
    mHandler.sendMessage(msg);
}
//When clicking the Send button, the method of sending data to the text in the text input box is as follows:
private void sendMessage(String message) {
    if (mChatService.getState() != BluetoothChatService.STATE_CONNECTED) {
        Toast.makeText(this, R.string.not_connected,Toast.LENGTH_SHORT).show();
        return;
}
    if (message.length() > 0) {
        byte[] send = message.getBytes();
        mChatService.write(send);
    }
}
//Call the write in the BluetoothChatService class to send data
public void write(byte[] out) {
    ConnectedThread r;
    synchronized (this) {
    if (mState != STATE_CONNECTED)
        return;
        r = mConnectedThread;
    }
        r.write(out);
}
//In this way, Bluetooth chat process is like this, if you quit chat, stop all threads;
public synchronized void stop() {
    LogUtils.getInstance().e(getClass(), "---stop()");
    setState(STATE_NONE);
    if (mConnectThread != null) {
        mConnectThread.cancel();
        mConnectThread = null;
}
    if (mConnectedThread != null) {
        mConnectedThread.cancel();
        mConnectedThread = null;
}
    if (mAcceptThread != null) {
        mAcceptThread.cancel();
        mAcceptThread = null;
    }
}

I believe that after reading this article, the problem of Android Bluetooth connection is not too big (spp protocol).
For more information about Android, please pay close attention to Wechat Public Number: Life Android

Topics: socket Mobile Android Mac