Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android reconnect to bluetooth device if connection lost

My phone is connecting to a bluetooth device and it works normally. It connect and the connection holds. I can change orientation, have my app in the background, I can close app and when I turn it back on it will automatically connect. But from app users I get some reports that the connection is lost after a period of time(no pattern detected). I have tried to recreate this but with no luck. So to avoid this problem I want to implement an automatic reconnect to the previously selected device if connection is lost.

I did some reasearch that this could be done by implementing a broadcast reciever that would detect: android.bluetooth.device.action.ACL_DISCONNECTED

What my questions are:

  • I already have a broadcast reciever that is triggered on device bootup. Should I extend this reciever to add the ACL_DISCONNECTED or add a separate reciever?
  • My BluetoothService is initialised on my mainactivity, but I will need to reconnect from the intent. How to do that.

Thanks for your answer.

BluetoothServis code:

public class BluetoothService
{
    // Debugging
    private static final String TAG = "BluetoothService";    
    private static final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");

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

// Constants that indicate the current connection state
public static final int STATE_NONE = 0;       // we're doing nothing
public static final int STATE_CONNECTING = 1; // now initiating an outgoing connection
public static final int STATE_CONNECTED = 2;  // now connected to a remote device

public BluetoothService(Context context, Handler handler)
{
    mAdapter = BluetoothAdapter.getDefaultAdapter();
    mState = STATE_NONE;
    mHandler = handler;
    mContext = context;
}

private synchronized void setState(int state)
{
    mState = state;
    mHandler.obtainMessage(MainActivity.MESSAGE_STATE_CHANGE, state, -1).sendToTarget();
}

public synchronized int getState()
{
    return mState;
}

public synchronized void start()
{
    if (mConnectThread != null) 
    {
        mConnectThread.cancel(); 
        mConnectThread = null;
    }

    if (mConnectedThread != null)
    {
        mConnectedThread.cancel(); 
        mConnectedThread = null;
    }
}

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);
}

public synchronized void connected(BluetoothSocket socket, BluetoothDevice device, final String socketType)
{
    if (mConnectThread != null)
    {
        mConnectThread.cancel();
        mConnectThread = null;
    }

    if (mConnectedThread != null)
    {
        mConnectedThread.cancel(); 
        mConnectedThread = null;
    }

    mConnectedThread = new ConnectedThread(socket, socketType);
    mConnectedThread.start();

    Message msg = mHandler.obtainMessage(MainActivity.MESSAGE_DEVICE_NAME);
    Bundle bundle = new Bundle();
    bundle.putString(MainActivity.DEVICE_NAME, device.getName());
    msg.setData(bundle);
    mHandler.sendMessage(msg);

    setState(STATE_CONNECTED);
}

public synchronized void stop()
{
    if (mConnectThread != null)
    {
        mConnectThread.cancel();
        mConnectThread = null;
    }

    if (mConnectedThread != null)
    {
        mConnectedThread.cancel();
        mConnectedThread = null;
    }

    setState(STATE_NONE);
}

public void write(byte[] out)
{
    ConnectedThread r;
    synchronized (this)
    {
        if (mState != STATE_CONNECTED) return;
        r = mConnectedThread;
    }
    r.write(out);
}

private void connectionFailed()
{
    Message msg = mHandler.obtainMessage(MainActivity.MESSAGE_TOAST);
    Bundle bundle = new Bundle();
    bundle.putString(MainActivity.TOAST, mContext.getResources().getString(R.string.cant_connect));
    msg.setData(bundle);
    mHandler.sendMessage(msg);

    BluetoothService.this.start();
}  

private class ConnectThread extends Thread
{
    private final BluetoothSocket mmSocket;
    private final BluetoothDevice mmDevice;
    private String mSocketType;

    public ConnectThread(BluetoothDevice device)
    {
        mmDevice = device;
        BluetoothSocket tmp = null;
        mSocketType = "Secure";  

        // another option createInsecureRfcommSocketToServiceRecord
        try
        {
            tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
        } 

        catch (IOException e)
        {
            Log.e(TAG, "Socket Type: " + mSocketType + "create() failed", e);
        }

        /*
        Method m = null;
        try {
            m = mmDevice.getClass().getMethod("createRfcommSocket", new Class[] {int.class});
            tmp = (BluetoothSocket) m.invoke(mmDevice, 1);

        } catch (Exception e) {

            e.printStackTrace();
        }*/


        mmSocket = tmp;            
    }

    public void run()
    {
        Log.i(TAG, "BEGIN mConnectThread SocketType:" + mSocketType);
        setName("ConnectThread" + mSocketType);

        mAdapter.cancelDiscovery();

        try
        {
            mmSocket.connect();
            Log.i(TAG, "ConnectThread running");
        } 

        catch (IOException e)
        {
            try
            {
                mmSocket.close();
            } 

            catch (IOException e2)
            {
                Log.e(TAG, "unable to close() " + mSocketType + " socket during connection failure", e2);
            }

            connectionFailed();
            return;
        }

        synchronized (BluetoothService.this)
        {
            mConnectThread = null;
        }

        connected(mmSocket, mmDevice, mSocketType);
    }

    public void cancel()
    {
        try
        {
            mmSocket.close();
        }

        catch (IOException e)
        {
            Log.e(TAG, "close() of connect " + mSocketType + " socket failed", e);
        }
    }
}

private class ConnectedThread extends Thread
{
    private final BluetoothSocket mmSocket;
    private final OutputStream mmOutStream;

    public ConnectedThread(BluetoothSocket socket, String socketType)
    {
        mmSocket = socket;
        OutputStream tmpOut = null;

        try
        {
            tmpOut = socket.getOutputStream();
        } 

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

        mmOutStream = tmpOut;
    }

    public void run()
    {

    }

    public void write(byte[] buffer)
    {
        try
        {
            mmOutStream.write(buffer);

            try
            {
                sleep(2000);
            } 

            catch (InterruptedException e)
            {
                e.printStackTrace();
            }
        } 

        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);
        }
    }
}

}

like image 455
Tadej Vengust Avatar asked May 06 '15 06:05

Tadej Vengust


People also ask

How do I reconnect to a forgotten Bluetooth device?

Unforget a Device on Android What is this? To Unforget the device, you need to reset the network settings. To do that, open your phone's Settings and then scroll down to “System.” From the System tab, you will see “Reset Options” from where you should reset the phone. Click Reset Options.

Why Android Cannot detect Bluetooth device?

If your Bluetooth devices won't connect, it's likely because the devices are out of range, or aren't in pairing mode. If you're having persistent Bluetooth connection problems, try resetting your devices, or having your phone or tablet "forget" the connection.

Why is my Bluetooth device not discoverable?

It's usually because the device's own Bluetooth is switched off, or isn't in pairing mode. Check the user manual to find out how to make it discoverable by turning on pairing mode. With some headphones, it's a case of holding the power button down for longer, but with other devices there's a dedicated Bluetooth button.


1 Answers

I solved this in 2 stages. First I created a new broadcast reciever because my existing one was for ACTION_BOOT_COMPLETED and had to be declared in the android manifest. The one I created had to be dynamic because I needed an instance of MainActivity:

 if (bluetoothLostReceiver == null)
        {
            bluetoothLostReceiver = new BluetoothLostReceiver();
            bluetoothLostReceiver.setMainActivity(this);
            IntentFilter filter = new IntentFilter("android.bluetooth.device.action.ACL_DISCONNECTED");
            registerReceiver(bluetoothLostReceiver, filter);
        }

And in my reciever I tried a new connect to the printer. I added an additional paramenter tryBluetoothReconnect so that if I wanted to close the connection it wouldn't try to reconnect.

public class BluetoothLostReceiver extends BroadcastReceiver {

    MainActivity main = null;

    public void setMainActivity(MainActivity main)
    {
        this.main = main;
    }

    @Override
    public void onReceive(Context context, Intent intent) {

        if(BluetoothDevice.ACTION_ACL_DISCONNECTED.equals(intent.getAction()) && Global.tryBluetoothReconnect)
        {
            if(Global.PosPrinterDeviceName != null && !Global.PosPrinterDeviceName.equals(""))
                main.connectPrinter(Global.PosPrinterDeviceName);
        }else
        {
            Global.tryBluetoothReconnect = true;
        }
    }
}

I also upgraded my Bluetooth service so that if connection was not successful (connectionFailed() method) it would try 4 more times:

    if(tryCount >= 4)
    {
        tryCount = 0;

        Message msg = mHandler.obtainMessage(MainActivity.MESSAGE_TOAST);
        Bundle bundle = new Bundle();
        bundle.putString(MainActivity.TOAST, mContext.getResources().getString(R.string.cant_connect));
        msg.setData(bundle);
        mHandler.sendMessage(msg);

        BluetoothService.this.start();
    }
    else
    {
        tryCount++;
        connect(bluetoothDevice);
    }

Hope this helps anyone with the same problem.

like image 52
Tadej Vengust Avatar answered Oct 13 '22 02:10

Tadej Vengust