First of all I read SOLVED: GATT callback fails to register and took the steps suggested in that post to solve this issue with no success. The recommended fix in there if you ha
Android OS < 6.0:
mBluetoothDevice.connectGatt(context, false, callback);
Android OS >= 6.0:
mBluetoothDevice.connectGatt(context, false, callback, BluetoothDevice.TRANSPORT_LE);
Ultimately, hardware equipment is needed to completely solve this problem.
After months of research and pulling my hair out, I have found a solution that is not normally talked about.
Your normal connect request looks something like this:
cGatt.connectGatt(this, false, gattCallback);
There is another version of the connectGatt command, with a 4th parameter. This parameter specifies what type of bluetooth device you are connecting to. I added a "2" to specify that I am connecting via Bluetooth LE. (it's called "transport", forgive me if my explanation is incorrect, but it solved all my problems)
Try this:
cGatt.connectGatt(this, false, gattCallback, 2);
And BAM, now my #133 nightmare is over (I pray)!
Somehow BluetoothLeScanner.startScan() helps
private final Handler mMainHandler = new Handler(Looper.getMainLooper());
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && mBluetoothAdapter.isEnabled() && mBleScanner != null) {
mBleScanner.stopScan(mLeScanCallback);
}
} else if (status == 133 && newState == BluetoothProfile.STATE_DISCONNECTED) {
if (D) Log.e(TAG, "connectGatt status == 133");
mMainHandler.post(mDisconnectRunnable);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && mBluetoothAdapter.isEnabled()) {
mBleScanner = mBluetoothAdapter.getBluetoothLeScanner();
mBleScanner.startScan(null, new ScanSettings.Builder().setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).build(),
mLeScanCallback);
}
mMainHandler.postDelayed(mConnectRunnable, 10000);
}
}
private ScanCallback mLeScanCallback = new ScanCallback() {
@Override
public void onScanResult(int callbackType, ScanResult result) {
super.onScanResult(callbackType, result);
if (result.getDevice().getAddress().equals(mBluetoothDeviceAddress)) {
mMainHandler.post(mConnectRunnable);
if (mBleScanner != null) {
mBleScanner.stopScan(mLeScanCallback);
mBleScanner = null;
}
}
}
};
Alright I have figured it out. The issue was mainly an oversight of when I was reading through the BluetoothGatt documentation. I was calling .disconnect(), but not .close(). Since the Galaxy s4 can only handle 6 connections at a time, my service was only running 6 times. Adding the .close() to my code allowed it to properly shut down the connection and freed up those used connections.
Source that made me re-read the docs more carefully!
So remember to use .close() on your BluetoothGatt object if you have a recurring connection to the same device(s)!!
Try to use next workaround:
private static boolean gatt_status_133 = false;
final Handler handler = new Handler();
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
mConnectionState = STATE_CONNECTED;
Log.i(TAG, "Connected to GATT server.");
// Attempts to discover services after successful connection.
Log.i(TAG, "Attempting to start service discovery:" +
mBluetoothGatt.discoverServices());
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
if(status == 133)
{
gatt_status_133=true;
}
else{
mConnectionState = STATE_DISCONNECTED;
Log.i(TAG, "Disconnected from GATT server.");
}
}
}
@RequiresApi(api = Build.VERSION_CODES.M)
public boolean connect(final String address) {
if (mBluetoothAdapter == null || address == null) {
Log.w(TAG, "BluetoothAdapter not initialized or unspecified address.");
return false;
}
// Previously connected device. Try to reconnect.
if (mBluetoothDeviceAddress != null && address.equals(mBluetoothDeviceAddress)
&& mBluetoothGatt != null) {
Log.d(TAG, "Trying to use an existing mBluetoothGatt for connection.");
if (mBluetoothGatt.connect()) {
mConnectionState = STATE_CONNECTING;
return true;
} else {
return false;
}
}
final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
if (device == null) {
Log.w(TAG, "Device not found. Unable to connect.");
return false;
}
mBluetoothGatt= device.connectGatt(this, false, mGattCallback, BluetoothDevice.TRANSPORT_LE);
Log.d(TAG, "Trying to create a new connection.");
mBluetoothDeviceAddress = address;
mConnectionState = STATE_CONNECTING;
handler.postDelayed(new Runnable() {
@Override
public void run() {
if(gatt_status_133)
{
Log.d(TAG, "Catch issue");
connect(address);
gatt_status_133=false;
}
}
}, 4000);
return true;
}
On some devices, it got fixed with
mBluetoothDevice.connectGatt(context, false, callback, BluetoothDevice.TRANSPORT_LE);
on some devices like Samsung S7, A8, it was a problem with the ScanSettings.Builder().setReportDelay(400) // or 500ms. it should not be 0 or more like 1000ms.
ScanSettings settings = new ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_BALANCED)
.setReportDelay(400)
.build();