2

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
  • And what is your specific question? Status code 8 just means that the connection timed out, usually because you go out of range or due to interference. And in some cases if the clocks in the two devices go out of sync if they are incorrectly trimmed or configured. – Emil Oct 05 '20 at 22:22
  • Take a wild guess. I'm having a problem so it obviously has to be how to fix it or why it's occuring. – Nehir Gökçe Oct 05 '20 at 22:41
  • 3
    Connection Timeout is never a software issue. It's most likely a problem with your hardware if you are sure there should not be any radio interference or similar. – Emil Oct 05 '20 at 22:59
  • For the future viewers I recommend checking this https://stackoverflow.com/questions/54898592/bluetoothgattserver-is-always-disconnecting-after-30-seconds It might be your problem – Tomáš Aresak Malčánek Sep 07 '22 at 08:00

0 Answers0