0
votes

I'm developing an Android App which has to connect +/- 120 BLE GATT servers a day, which there are at least 3 of those servers on simultaneously with exactly the same services and characteristics. I've been experiecing all kinds of problems with Android BLE, even though following all standards and default patterns.

Everyday happens that I have to, at least once, reset the tablet to default settings, because 'Bluetooth has stopped working', in which I can't find the cause of this. This has been very frustrating in which I can't stand this type of maintenance every day (hard reset).

At first, I tried BLE for Android SDK 18, in which behaved in very strange ways, showing bad results with just one day of usage. So I started using the Lollipop version of manipulating Android BLE, which shows some improvements.

I’ve been experiencing these problems for days now and all because I get unexpected results, for example onCharacteristicRead returns but data is null. Or for example, I call discoverServices() after onConnectionStateChanged with STATE_CONNECTED, so after some time onServicesDiscovered() is called but getServices() returns null. All these problems only happen after disconnecting from the first server. The first server it connects reads and writes everything correctly, but then I disconnect() and onConnectionStateChanged(), so I then close(). So then I connect to the next server, and I start getting these problems (all GATT operations are on the main thread, all connections are made properly, and properly disposed), so I have to disconnect and connect so the can app read the GATT attributes properly.

I have 3 characteristics to read, and after reading the 3rd one, I start writting 3 characteristics.

I've been through the bluetooth logs and I can see unexpected stuff happening. This log is when the app reads everything properly (it's always and only the first GATT server the app connects to):

10-11 09:08:05.350 15989-15989/efp.android.sample D/BluetoothAdapter: STATE_ON
10-11 09:08:05.350 15989-15989/efp.android.sample D/BluetoothAdapter: STATE_ON
10-11 09:08:05.350 15989-15989/efp.android.sample D/BluetoothLeScanner: Start Scan
10-11 09:08:05.351 15989-15989/efp.android.sample D/BluetoothAdapter: STATE_ON
10-11 09:08:05.352 15989-15989/efp.android.sample D/BluetoothAdapter: STATE_ON
10-11 09:08:05.353 15989-15989/efp.android.sample D/BluetoothAdapter: STATE_ON
10-11 09:08:05.354 15989-15989/efp.android.sample D/BluetoothAdapter: STATE_ON
10-11 09:08:05.362 15989-15994/efp.android.sample I/art: Do partial code cache collection, code=48KB, data=60KB
10-11 09:08:05.362 15989-15994/efp.android.sample I/art: After code cache collection, code=48KB, data=60KB
10-11 09:08:05.362 15989-15994/efp.android.sample I/art: Increasing code cache capacity to 256KB
10-11 09:08:05.457 15989-16002/efp.android.sample D/BluetoothLeScanner: onClientRegistered() - status=0 clientIf=5 mClientIf=0
10-11 09:08:05.513 15989-15989/efp.android.sample W/IInputConnectionWrapper: getCursorCapsMode on inactive InputConnection
10-11 09:08:05.681 15989-16023/efp.android.sample D/ScanRecord: parseFromBytes
10-11 09:08:05.681 15989-15989/efp.android.sample D/LAURASTAR_BLE: onScanResult
10-11 09:08:05.682 15989-15989/efp.android.sample D/BluetoothAdapter: STATE_ON
10-11 09:08:05.683 15989-15989/efp.android.sample D/BluetoothAdapter: STATE_ON
10-11 09:08:05.684 15989-15989/efp.android.sample D/BluetoothAdapter: STATE_ON
10-11 09:08:05.685 15989-15989/efp.android.sample D/BluetoothAdapter: STATE_ON
10-11 09:08:05.685 15989-15989/efp.android.sample D/BluetoothLeScanner: Stop Scan
10-11 09:08:05.692 15989-15989/efp.android.sample D/BluetoothGatt: connect() - device: F5:8E:C1:91:DC:CC, auto: false
10-11 09:08:05.692 15989-15989/efp.android.sample D/BluetoothAdapter: isSecureModeEnabled
10-11 09:08:05.699 15989-15989/efp.android.sample D/BluetoothGatt: registerApp()
10-11 09:08:05.699 15989-15989/efp.android.sample D/BluetoothGatt: registerApp() - UUID=ebf41986-8aad-4796-a537-7319c00f0f46
10-11 09:08:05.802 15989-16002/efp.android.sample D/BluetoothGatt: onClientRegistered() - status=0 clientIf=5
10-11 09:08:06.332 15989-16001/efp.android.sample D/LAURASTAR_BLE: onConnectionStateChange:
10-11 09:08:06.332 15989-16001/efp.android.sample D/BluetoothGatt: discoverServices() - device: F5:8E:C1:91:DC:CC
10-11 09:08:06.343 15989-16002/efp.android.sample D/BluetoothGatt: onSearchComplete() = Device=F5:8E:C1:91:DC:CC Status=0
10-11 09:08:06.343 15989-16002/efp.android.sample D/LAURASTAR_BLE: onServicesDiscovered:
10-11 09:08:07.143 15989-16002/efp.android.sample W/BluetoothGatt: onCharacteristicRead() - Device=F5:8E:C1:91:DC:CC handle=51 Status=0
10-11 09:08:07.233 15989-16002/efp.android.sample W/BluetoothGatt: onCharacteristicRead() - Device=F5:8E:C1:91:DC:CC handle=14 Status=0
10-11 09:08:07.324 15989-16023/efp.android.sample W/BluetoothGatt: onCharacteristicRead() - Device=F5:8E:C1:91:DC:CC handle=23 Status=0
10-11 09:08:08.136 15989-16023/efp.android.sample D/BluetoothGatt: cancelOpen() - device: F5:8E:C1:91:DC:CC
10-11 09:08:08.146 15989-16001/efp.android.sample D/BluetoothGatt: onClientConnectionState() - status=0 clientIf=5 device=F5:8E:C1:91:DC:CC
10-11 09:08:08.151 15989-16001/efp.android.sample D/LAURASTAR_BLE: onConnectionStateChange:
10-11 09:08:08.265 15989-15989/efp.android.sample D/BluetoothGatt: close()
10-11 09:08:08.266 15989-15989/efp.android.sample D/BluetoothGatt: unregisterApp() - mClientIf=5

After disconnecting from the first GATT server to connect to the second GATT server, I have to constantly disconnect and reconnect to read characteristics, all though it always reads the first characteristic properly.

Here's the log of when reading occurs with problems... So if reading has errors I need to disconnect and reconnect (and even if reading has errors after reconnect, it closes, scans and tries again).

10-12 08:03:48.133 30409-30409/efp.android.sample D/BluetoothAdapter: STATE_ON
10-12 08:03:48.133 30409-30409/efp.android.sample D/BluetoothAdapter: STATE_ON
10-12 08:03:48.134 30409-30409/efp.android.sample D/BluetoothLeScanner: Start Scan
10-12 08:03:48.134 30409-30409/efp.android.sample D/BluetoothAdapter: STATE_ON
10-12 08:03:48.137 30409-30409/efp.android.sample D/BluetoothAdapter: STATE_ON
10-12 08:03:48.260 30409-31121/efp.android.sample D/BluetoothLeScanner: onClientRegistered() - status=0 clientIf=6 mClientIf=0
10-12 08:03:48.391 30409-30422/efp.android.sample D/ScanRecord: parseFromBytes
10-12 08:03:48.395 30409-30409/efp.android.sample D/LAURASTAR_BLE: onScanResult
10-12 08:03:48.397 30409-30409/efp.android.sample D/BluetoothAdapter: STATE_ON
10-12 08:03:48.397 30409-30409/efp.android.sample D/BluetoothAdapter: STATE_ON
10-12 08:03:48.398 30409-30409/efp.android.sample D/BluetoothAdapter: STATE_ON
10-12 08:03:48.399 30409-30409/efp.android.sample D/BluetoothAdapter: STATE_ON
10-12 08:03:48.399 30409-30409/efp.android.sample D/BluetoothLeScanner: Stop Scan
10-12 08:03:48.410 30409-30409/efp.android.sample D/BluetoothGatt: connect() - device: F5:8E:C1:91:DC:CC, auto: false
10-12 08:03:48.410 30409-30409/efp.android.sample D/BluetoothAdapter: isSecureModeEnabled
10-12 08:03:48.411 30409-30409/efp.android.sample D/BluetoothGatt: registerApp()
10-12 08:03:48.411 30409-30409/efp.android.sample D/BluetoothGatt: registerApp() - UUID=ce6919e5-e4f7-4180-a313-557e168a7c5a
10-12 08:03:48.514 30409-30422/efp.android.sample D/BluetoothGatt: onClientRegistered() - status=0 clientIf=6
10-12 08:03:48.745 30409-31121/efp.android.sample D/BluetoothGatt: onClientConnectionState() - status=0 clientIf=6 device=F5:8E:C1:91:DC:CC
10-12 08:03:48.755 30409-31121/efp.android.sample D/BluetoothGatt: discoverServices() - device: F5:8E:C1:91:DC:CC
10-12 08:03:48.915 30409-30414/efp.android.sample I/art: Do partial code cache collection, code=19KB, data=28KB
10-12 08:03:48.916 30409-30414/efp.android.sample I/art: After code cache collection, code=19KB, data=28KB
10-12 08:03:48.916 30409-30414/efp.android.sample I/art: Increasing code cache capacity to 128KB
10-12 08:03:48.982 30409-30422/efp.android.sample D/BluetoothGatt: onClientConnParamsChanged() - Device=F5:8E:C1:91:DC:CC interval=6 status=0 (I DONT THINK THIS SHOULD HAPPEN)
10-12 08:03:49.688 30409-30421/efp.android.sample D/BluetoothGatt: onSearchComplete() = Device=F5:8E:C1:91:DC:CC Status=0
10-12 08:03:49.689 30409-30421/efp.android.sample D/LAURASTAR_BLE: onServicesDiscovered:
10-12 08:03:49.711 30409-30422/efp.android.sample D/BluetoothGatt: onClientConnParamsChanged() - Device=F5:8E:C1:91:DC:CC interval=36 status=0
10-12 08:03:50.467 30409-31121/efp.android.sample W/BluetoothGatt: onCharacteristicRead() - Device=F5:8E:C1:91:DC:CC handle=51 Status=0
10-12 08:03:50.557 30409-30422/efp.android.sample W/BluetoothGatt: onCharacteristicRead() - Device=F5:8E:C1:91:DC:CC handle=14 Status=5 (status NOT SUCCESS ...)
10-12 08:03:50.830 30409-30422/efp.android.sample D/BluetoothGatt: onClientConnParamsChanged() - Device=F5:8E:C1:91:DC:CC interval=6 status=0
10-12 08:03:51.533 30409-31121/efp.android.sample W/BluetoothGatt: onCharacteristicRead() - Device=F5:8E:C1:91:DC:CC handle=14 Status=137 (status NOT SUCCESS ...)
10-12 08:03:51.533 30409-31121/efp.android.sample D/LAURASTAR_BLE: Data is empty. (null)
10-12 08:03:51.533 30409-31121/efp.android.sample D/BluetoothGatt: cancelOpen() - device: F5:8E:C1:91:DC:CC
10-12 08:03:51.561 30409-30422/efp.android.sample D/BluetoothGatt: onClientConnectionState() - status=0 clientIf=6 device=F5:8E:C1:91:DC:CC
10-12 08:03:51.565 30409-30422/efp.android.sample D/LAURASTAR_BLE: onConnectionStateChange:
10-12 08:03:51.565 30409-30422/efp.android.sample D/BluetoothAdapter: isSecureModeEnabled
10-12 08:03:51.609 30409-31121/efp.android.sample D/BluetoothGatt: onClientConnectionState() - status=0 clientIf=6 device=F5:8E:C1:91:DC:CC
10-12 08:03:51.610 30409-31121/efp.android.sample D/LAURASTAR_BLE: onConnectionStateChange:
10-12 08:03:51.610 30409-31121/efp.android.sample D/BluetoothGatt: discoverServices() - device: F5:8E:C1:91:DC:CC
10-12 08:04:01.091 30409-31121/efp.android.sample D/BluetoothGatt: onSearchComplete() = Device=F5:8E:C1:91:DC:CC Status=0
10-12 08:04:01.091 30409-31121/efp.android.sample D/LAURASTAR_BLE: onServicesDiscovered:
10-12 08:04:02.048 30409-31121/efp.android.sample W/BluetoothGatt: onCharacteristicRead() - Device=F5:8E:C1:91:DC:CC handle=51 Status=0
10-12 08:04:02.438 30409-30421/efp.android.sample W/BluetoothGatt: onCharacteristicRead() - Device=F5:8E:C1:91:DC:CC handle=14 Status=0
10-12 08:04:02.829 30409-30421/efp.android.sample W/BluetoothGatt: onCharacteristicRead() - Device=F5:8E:C1:91:DC:CC handle=23 Status=0
10-12 08:04:02.898 30409-30414/efp.android.sample I/art: Do partial code cache collection, code=48KB, data=61KB
10-12 08:04:02.899 30409-30414/efp.android.sample I/art: After code cache collection, code=48KB, data=61KB
10-12 08:04:02.899 30409-30414/efp.android.sample I/art: Increasing code cache capacity to 256KB
10-12 08:04:04.389 30409-30422/efp.android.sample D/BluetoothGatt: cancelOpen() - device: F5:8E:C1:91:DC:CC
10-12 08:04:04.402 30409-30421/efp.android.sample D/BluetoothGatt: onClientConnectionState() - status=0 clientIf=6 device=F5:8E:C1:91:DC:CC
10-12 08:04:04.406 30409-30421/efp.android.sample D/LAURASTAR_BLE: onConnectionStateChange:
10-12 08:04:04.502 30409-30409/efp.android.sample V/InputMethodManager: Starting input: tba=android.view.inputmethod.EditorInfo@d981ae5 nm : efp.android.sample ic=com.android.internal.widget.EditableInputConnection@41369ba
10-12 08:04:04.502 30409-30409/efp.android.sample I/InputMethodManager: [IMM] startInputInner - mService.startInputOrWindowGainedFocus
10-12 08:04:04.503 30409-30409/efp.android.sample D/InputTransport: Input channel constructed: fd=70
10-12 08:04:04.503 30409-30409/efp.android.sample D/InputTransport: Input channel destroyed: fd=73
10-12 08:04:04.519 30409-30409/efp.android.sample D/BluetoothGatt: close()
10-12 08:04:04.520 30409-30409/efp.android.sample D/BluetoothGatt: unregisterApp() - mClientIf=6

In this log, this is visible, after successfuly reading the first characteristic:

W/BluetoothGatt: onCharacteristicRead() - Device=F5:8E:C1:91:DC:CC handle=14 Status=5

And then onClientConnParamsChanged is called after discoverServices() is called, and before onServicesDiscovered() is called.

All my code seems to be correct... So the logic is the following:

Start by receiving the user's desired server mac address, so the app can scan and find it.

I have a TextWatcher implemented in a EditText, so when the user inserts a mac address, the app looks for BLE devices with the address inserted.

String macToFind = "";
private class ScanIronFieldsTextWatcher implements TextWatcher {

    View view;
    public ScanIronFieldsTextWatcher(View view) { this.view = view; }

    @Override
    public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {}

    @Override
    public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {}


    public void afterTextChanged(Editable editable) {

        switch (view.getId()) {
            case R.id.txt_mac_address: {
                String originalText =  txtMacAddress.getText().toString().toUpperCase();
                String macToFind = Tools.getValidMacAddress(originalText);
                if(mConnectedGatt != null && mConnectedGatt.getDevice().getAddress().equals(macToFind)) {
                    mConnectedGatt.connect();
                }
                else {
                    if(mConnectedGatt != null) {
                        mConnectedGatt.close();
                        mConnectedGatt = null;
                    }

                    //Search mac address
                    writeToActivityLog("Looking for " + macToFind +"...", LogAdapter.MESSAGE_TYPE_NORMAL);
                    hideKeyboard();
                    startScan();
                }
            }
        }
    }
}

After the user inserts a mac address, startScan() is started.

startScan()

private void startScan() {
        if (!mBluetoothAdapter.isEnabled()) {
            writeToActivityLog("Bluetooth is off!", LogAdapter.MESSAGE_TYPE_ERROR);
            return;
        }
        try {
            ScanFilter scanFilter = new ScanFilter.Builder().setDeviceAddress(macToFind).build();
            ArrayList<ScanFilter> filters = new ArrayList<ScanFilter>();
            filters.add(scanFilter);

            ScanSettings settings = new ScanSettings.Builder().setScanMode(ScanSettings.SCAN_MODE_BALANCED).build();
            mBluetoothAdapter.getBluetoothLeScanner().startScan(filters, settings, mScanCallback);


            retryingHandler = new Handler();
            retryingHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    showProgress(false);
                    stopScan();

                    if (mDevices.size() == 0) {
                        writeToActivityLog("Server not found.", LogAdapter.MESSAGE_TYPE_ERROR);
                    } else {
                        mDevices.clear();
                    }
                }
            }, SCAN_TIME);
        } catch (IllegalArgumentException e) {
            writeToActivityLog("Invalid Address!", LogAdapter.MESSAGE_TYPE_ERROR);
        }
    }

mScanCallback:

private ScanCallback mScanCallback = new ScanCallback() {
        @Override
        public void onScanResult(int callbackType, ScanResult result) {
            Log.d(TAG, "onScanResult");
            processResult(result);
        }

        @Override
        public void onBatchScanResults(List<ScanResult> results) {
            Log.d(TAG, "onBatchScanResults: "+results.size()+" results");
            for (ScanResult result : results) {
                processResult(result);
            }
        }

        @Override
        public void onScanFailed(int errorCode) { Log.w(TAG, "LE Scan Failed: "+errorCode); }

        private void processResult(final ScanResult result) {
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    if(mConnectedGatt == null) {
                        stopScan();
                        final BluetoothDevice device = result.getDevice();
                        mDevices.put(device.hashCode(), device);

                        writeToActivityLog("Server found!", LogAdapter.MESSAGE_TYPE_NORMAL);
                        writeToActivityLog("Connecting to " + macToFind + "...", LogAdapter.MESSAGE_TYPE_NORMAL);

                        mConnectedGatt = device.connectGatt(NewDeviceControlActivity.this, false, mGattCallback);
                        retryingHandler.removeCallbacksAndMessages(null);
                    }
                }
            });
        }
    };

mGattCallback

private BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
        @Override
        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
            super.onConnectionStateChange(gatt, status, newState);

            if (newState == BluetoothProfile.STATE_CONNECTED) {
                writeToActivityLog("Connected.", LogAdapter.MESSAGE_TYPE_SUCCESS);
                mConnected = true;

                if(!gatt.discoverServices()) {
                    writeToActivityLog("Impossible discoverServices().", LogAdapter.MESSAGE_TYPE_ERROR);
                    if(!retrying)
                        retrying = true;
                    mConnectedGatt.disconnect();
                }
            }
            else if(newState == BluetoothProfile.STATE_DISCONNECTED) {

                writeToActivityLog("Disconnected.", LogAdapter.MESSAGE_TYPE_NORMAL);
                if(!currentIron.hasCompletedSetup()) {
                    showProgress(true);

                    if(retrying) {
                        writeToActivityLog("Trying again...", LogAdapter.MESSAGE_TYPE_NORMAL);
                        if(mConnectedGatt != null)
                            mConnectedGatt.connect();
                    }
                    else {
                        writeToActivityLog("Trying again but also scanning again... (r)", LogAdapter.MESSAGE_TYPE_NORMAL);
                        retrying = false;
                        if(mConnectedGatt != null)
                            mConnectedGatt.close();
                        mHandler.postDelayed(new Runnable() {
                            @Override
                            public void run() {
                                startScan();
                            }
                        }, 2000);
                    }
                }
            }
        }

        @Override
        public void onServicesDiscovered(final BluetoothGatt gatt, int status) {
            super.onServicesDiscovered(gatt, status);
            Log.d(TAG, "onServicesDiscovered:");

            mHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    startObtainingIronData(gatt);
                }
            }, 700);
        }

        @Override
        public void onCharacteristicRead(BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic, final int status) {
            super.onCharacteristicRead(gatt, characteristic, status);


            byte[] data = characteristic.getValue();
            if(status != BluetoothGatt.GATT_SUCCESS) {
                runOnUiThread(new Runnable() { @Override public void run() {Toast.makeText(NewDeviceControlActivity.this, ("BluetoothGatt: Response != GATT_SUCCESS ("+status+")."), Toast.LENGTH_SHORT).show();}});
            }

            if (characteristic.getUuid().toString().contains(Iron.IRON_CODES[4])) {
                //First characteristic read succesfully
                final String version = new String(data);
                runOnUiThread(new Runnable() { @Override public void run() {Toast.makeText(NewDeviceControlActivity.this, ("Version "+version), Toast.LENGTH_SHORT).show();}});

                //Request to read second characteristic
                BluetoothGattCharacteristic characteristic2 = getCharacteristic(gatt, Iron.IRON_CODES[0]);
                gatt.readCharacteristic(characteristic2);
            }
            else if (characteristic.getUuid().toString().contains(Iron.IRON_CODES[0])) {
                //Read second characteristic
                if(data == null || data.length == 0) { //returns with  status=137
                    Log.d(TAG, "Data is empty " + (data == null ? "(null)" : data));//This ALWAYS happens except the first server the app connects too
                    writeToActivityLog("Data is empty. "+ (data == null ? "(null)" : data), LogAdapter.MESSAGE_TYPE_ERROR);
                    if(!retrying)
                        retrying = true;
                    mConnectedGatt.disconnect();
                    return;
                }
                else {
                    if (data[2] == 4) {
                        //Request to read third characteristic
                        BluetoothGattCharacteristic characteristic2 = getCharacteristic(gatt, Iron.IRON_CODES[1]);
                        if(characteristic2 != null)
                            gatt.readCharacteristic(characteristic2);
                        else {
                            writeToActivityLog("Impossible readCharacteristic Machine Type" , LogAdapter.MESSAGE_TYPE_ERROR);
                            if(!retrying)
                                retrying = true;

                            mConnectedGatt.disconnect();
                        }
                    }
                }
            }
            else if (characteristic.getUuid().toString().contains(Iron.IRON_CODES[1])) {
                //Read third characteristic
                if(data[0] == 0) {
                    BluetoothGattCharacteristic characteristic2 = getCharacteristic(gatt, Iron.IRON_CODES[2]);
                    long now = System.currentTimeMillis();
                    byte[] nowBytes = new byte[]{(byte) ((int) (now & 255L)), (byte) ((int) (now >> 8)), (byte) ((int) (now >> 16)), (byte) ((int) (now >> 24))};
                    characteristic2.setValue(nowBytes);

                    writeToActivityLog("Read all information succesfully.", LogAdapter.MESSAGE_TYPE_NORMAL);

                    //Request to write first characteristic
                    if (!gatt.writeCharacteristic(characteristic2)){
                        writeToActivityLog("Impossible to write timestamp.", LogAdapter.MESSAGE_TYPE_ERROR);
                        if(!retrying)
                            retrying = true;
                        mConnectedGatt.disconnect();
                    }

                }
            }
        }

        @Override
        public void onCharacteristicWrite(final BluetoothGatt gatt, BluetoothGattCharacteristic characteristic2, int status) {
            super.onCharacteristicWrite(gatt, characteristic2, status);

            if(status == BluetoothGatt.GATT_SUCCESS) {
                showProgress(false);

                if(characteristic2.getUuid().toString().contains(Iron.IRON_CODES[2])) {

                    //Wrote first characteristic
                    String intToWrite = "0x01";
                    BluetoothGattCharacteristic characteristic = getCharacteristic(gatt, Iron.IRON_CODES[1]);
                    characteristic.setValue(Integer.decode(intToWrite), BluetoothGattCharacteristic.FORMAT_UINT8, 0);

                    //Request to write second characteristic
                    if (!gatt.writeCharacteristic(characteristic)) {
                        writeToActivityLog("Impossible to write first characteristic!.", LogAdapter.MESSAGE_TYPE_ERROR);
                        if(!retrying)
                            retrying = true;
                        mConnectedGatt.disconnect();
                    }
                }
                else if(characteristic2.getUuid().toString().contains(Iron.IRON_CODES[1])) {

                        //Wrote second characteristic
                        service.sendData(), new Callback<String>() {
                                    @Override
                                    public void onResponse(Call<String> call, Response<String> response) {

                                            //Write third characteristic
                                            BluetoothGattCharacteristic characteristic = getCharacteristic(gatt, Iron.IRON_CODES[3]);
                                            characteristic.setValue(0x40, android.bluetooth.BluetoothGattCharacteristic.FORMAT_UINT8, 0);
                                            gatt.writeCharacteristic(characteristic);


                                    }
                                    @Override
                                    public void onFailure(Call<String> call, Throwable t) {

                                        if(mConnectedGatt != null)
                                            mConnectedGatt.disconnect();
                                    }
                                });
                        }
                }
                else if(characteristic2.getUuid().toString().contains(Iron.IRON_CODES[3])) {
                    //Wrote third characteristic
                    writeToActivityLog("Data written successfully.", LogAdapter.MESSAGE_TYPE_SUCCESS);

                    if(mConnectedGatt != null)
                        mConnectedGatt.disconnect();
                }

            }
        }
    };

I have tried running all mConnectedGatt operations in runOnUIThread, but had same results. All the characteristics UUID are correct, and the characteristics being written AREN'T the same ones being read.

I do not have the problem of the GATT server 'walking' away from the app, nor being too far. I'm running the software on three Samsung Galaxy Tab A 10.1 2016, which all return the same results.

So my results are basically these:

Expected (which only happens with the first server the app connects to):

  • Looking for MAC
  • Server found!
  • Connecting to MAC
  • Connected.
  • (read first characteristic) Version:
  • (read second characteristic)
  • (read third characteristic)
  • (write first characteristic)
  • (write second characteristic)
  • (write third characteristic)
  • Disconnected.

What happens (attempting to connect to another server):

  • Looking for MAC
  • Server found!
  • Connecting to MAC
  • Connected.
  • (read first characteristic) Version:
  • Data is empty! (null)
  • Disconnected.
  • Trying again...
  • Connected.
  • (read first characteristic) Version:
  • (read second characteristic)
  • (read third characteristic)
  • (write first characteristic)
  • (write second characteristic)
  • (write third characteristic)
  • Disconnected.

And I'm guessing to many reconnections is what is causing the 'Bluetooth has stopped working'. I can't figure out why is this happening!

Please, if someone can spend some time to help me figure out what is happening, I would be so appreciated... Thank you

1
Did you add some new ble services on your project? if it is may be you can try to clear bluetooth cache. Go to settings->applications click more icon at the right top. click system apps. select Bluetooth from list. clear storage. (sometimes it does not clear cache at first time, click two times to this button) I hope it solve the problemhasbi
@hasbi What do you mean by new ble services?James
I mean adding new characteristichasbi
It is worth mentioning, that in the snippet you provided, there is no handling on GATT operation failures (status != BluetoothGatt.GATT_SUCCESS). This means that onConnectionStateChange may be called, to inform connection, while previously connected, onServicesDiscovered may be called, but the gatt client relates to a previous client Object. Finally, the onClientConnectionState is unrelated to the issue, it just informed that the Client/Server have exchanged some protocol details, such as channel used, priority, etc.Bonatti

1 Answers

0
votes

This worked for me :-

http://www.java2s.com/Open-Source/Android_Free_Code/Development/sdk/io_relayr_ble_serviceBluetoothGattReceiver_java.htm

This is using Rx library. Please try the following dependencies:-

compile "com.polidea.rxandroidble:rxandroidble:1.4.2"

implementation 'io.reactivex.rxjava2:rxjava:2.1.5'

implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'