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