Android BLE Gatt Connection Issue (Connection Timeout Status:8)

2.3k views Asked by At

I'm developing an Android app that discovers and connects to a GATT service that is being advertised by my rPi 3B+. The iOS app that I've finished developing works without any issue. However, almost every time (95%) my Android app connects to the GATT server and tries to discover the services, the GATT connection times out with the status response code: 8.

Here's my android code:

package com.example.myapplication;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanFilter;
import android.bluetooth.le.ScanResult;
import android.bluetooth.le.ScanSettings;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.ParcelUuid;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

public class MainActivity extends AppCompatActivity implements AdapterView.OnItemClickListener {

BluetoothAdapter bluetoothAdapter;
BluetoothLeScanner bluetoothLeScanner;
BluetoothManager bluetoothManager;
BluetoothScanCallback bluetoothScanCallback;
BluetoothGatt gattClient;
BluetoothGattCharacteristic characteristicID;
TextView scanningText;

final UUID SERVICE_UUID = UUID.fromString("6E400001-B5A3-F393-E0A9-E50E24DCCA9E");
final UUID CHARACTERISTIC_UUID_ID = UUID.fromString("6E400002-B5A3-F393-E0A9-E50E24DCCA9E");
final UUID DESCRIPTOR_UUID_ID = UUID.fromString("00002902-0000-1000-8000-00805F9B34FB");

ArrayList<String> wifiSSIDs = new ArrayList<>() ;
ListView listViewSSID;
ArrayAdapter<String> SSIDadapter;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    getSupportActionBar().setDefaultDisplayHomeAsUpEnabled(true);
    listViewSSID = findViewById(R.id.lv_SSID);
    scanningText = findViewById(R.id.scanningText);
    SSIDadapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, wifiSSIDs);
    listViewSSID.setAdapter(SSIDadapter);
    listViewSSID.setOnItemClickListener(this);

    bluetoothManager = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE);
    bluetoothAdapter = bluetoothManager.getAdapter();
    startScan();
}

@Override
protected void onDestroy() {
    super.onDestroy();
    Log.i("App","App closing...");
    gattClient.disconnect();
    gattClient.close();
}


private void startScan(){

    ScanFilter scanFilter = new ScanFilter.Builder().setServiceUuid(new ParcelUuid(SERVICE_UUID)).build();
    ArrayList<ScanFilter> filters = new ArrayList<>();

    filters.add(scanFilter);

    ScanSettings scanSettings = new ScanSettings.Builder().setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).build();

    Log.i("Bluetooth Scan","startScan()");
    bluetoothScanCallback = new BluetoothScanCallback();
    bluetoothLeScanner = bluetoothAdapter.getBluetoothLeScanner();
    bluetoothLeScanner.startScan(filters, scanSettings, bluetoothScanCallback);
}

private void connectDevice(BluetoothDevice device) {
    if (device == null) Log.i("Bluetooth Connection","Device is null");
    GattClientCallback gattClientCallback = new GattClientCallback();
    gattClient = device.connectGatt(this,false, gattClientCallback, BluetoothDevice.TRANSPORT_LE);
}

private class BluetoothScanCallback extends ScanCallback {
    @Override
    public void onScanResult(int callbackType,final ScanResult result) {
        Log.i("Bluetooth Scan Result", "onScanResult");
        bluetoothLeScanner.stopScan(bluetoothScanCallback); // stop scan
        connectDevice(result.getDevice());
    }

    @Override
    public void onBatchScanResults(List<ScanResult> results) {
        Log.i("Bluetooth Scan Result", "onBathScanResults");
    }

    @Override
    public void onScanFailed(int errorCode) {
        Log.i("Bluetooth Scan Result", "ErrorCode: " + errorCode);
    }
}

private class GattClientCallback extends BluetoothGattCallback {
    @Override
    public void onConnectionStateChange(final BluetoothGatt gatt, int status, int newState) {
        super.onConnectionStateChange(gatt, status, newState);
        Log.i("Bluetooth Connection","onConnectionStateChange");

        if (status == BluetoothGatt.GATT_FAILURE) {
            Log.i("Bluetooth Connection", "onConnectionStateChange GATT FAILURE");
            return;
        } else if (status != BluetoothGatt.GATT_SUCCESS) {
            Log.i("Bluetooth Connection", "onConnectionStateChange != GATT_SUCCESS");
            Log.i("Bluetooth Connection", String.valueOf(status));

            startScan();
            return;
        }
        else {
            final BluetoothDevice device = gatt.getDevice();
            if (newState == BluetoothProfile.STATE_CONNECTED) {

                Log.i("Bluetooth Connection", "onConnectionStateChange CONNECTED");

                new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
                    @Override
                    public void run() {
                    gatt.discoverServices(); }
                }, 500);

            } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
                Log.i("Bluetooth Connection", "onConnectionStateChange DISCONNECTED");
            }
        }
    }

    @Override
    public void onServicesDiscovered(final BluetoothGatt gatt, int status) {
        super.onServicesDiscovered(gatt, status);
        Log.i("Bluetooth Services","onServicesDiscovered");

        new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
            @Override
            public void run() {
                characteristicID = gatt.getService(SERVICE_UUID).getCharacteristic(CHARACTERISTIC_UUID_ID);
                gatt.setCharacteristicNotification(characteristicID,true); }
        }, 500);


        new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
            @Override
            public void run() {
                BluetoothGattDescriptor descriptor = characteristicID.getDescriptor(DESCRIPTOR_UUID_ID);
                descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
                gatt.writeDescriptor(descriptor); }
        }, 500);

    }

    @Override
    public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
        super.onCharacteristicRead(gatt, characteristic, status);
        Log.i("BT Characteristics","onCharacteristicRead");
    }

    @Override
    public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
        super.onCharacteristicWrite(gatt, characteristic, status);
        Log.i("BT Characteristics","onCharacteristicWrite");
    }

    @Override
    public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
        super.onCharacteristicChanged(gatt, characteristic);
        Log.i("BT Characteristics","onCharacteristicChanged");
        Log.i("Characteristic Change",new String(characteristic.getValue()));
        final String characteristicValue = new String(characteristic.getValue());
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                wifiSSIDs.add(characteristicValue);
                SSIDadapter.notifyDataSetChanged();

                listViewSSID.setVisibility(View.VISIBLE);
                scanningText.setVisibility(View.INVISIBLE);
            }
        });
    }

    @Override
    public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
        super.onDescriptorRead(gatt, descriptor, status);
        Log.i("BT Characteristics","onDescriptorRead");
    }

    @Override
    public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
        super.onDescriptorWrite(gatt, descriptor, status);
        Log.i("BT Characteristics","onDescriptorWrite");

        characteristicID.setValue("RW");
        gatt.writeCharacteristic(characteristicID);

    }
}

@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
    String ssid = ((TextView) view).getText().toString();
    Log.i("Item Click","SSID: " + ssid);
    characteristicID.setValue("SSID: " + ssid);
    gattClient.writeCharacteristic(characteristicID);

    Intent intent = new Intent(this, PasswordActivity.class);
    startActivity(intent);
}
}

I can provide the python script code that's running on rPi but I believe that the problem stems from the android code. The log returns:

2020-10-05 14:05:53.710 19952-19952/com.example.myapplication I/Bluetooth Scan: startScan()
2020-10-05 14:05:53.711 19952-19952/com.example.myapplication I/chatty: uid=10299(com.example.myapplication) identical 1 line
2020-10-05 14:05:53.852 19952-19952/com.example.myapplication I/InputMethodManager: startInputInner - mService.startInputOrWindowGainedFocus
2020-10-05 14:05:54.937 19952-19952/com.example.myapplication I/Bluetooth Scan Result: onScanResult
2020-10-05 14:05:56.688 19952-19966/com.example.myapplication I/Bluetooth Connection: onConnectionStateChange
2020-10-05 14:05:56.688 19952-19966/com.example.myapplication I/Bluetooth Connection: onConnectionStateChange CONNECTED
2020-10-05 14:06:02.208 19952-19966/com.example.myapplication I/Bluetooth Connection: onConnectionStateChange
2020-10-05 14:06:02.208 19952-19966/com.example.myapplication I/Bluetooth Connection: onConnectionStateChange != GATT_SUCCESS
2020-10-05 14:06:02.208 19952-19966/com.example.myapplication I/Bluetooth Connection: 8
0

There are 0 answers