1

I got a BLE tutorial working. I can send and receive data on the SPS service, this data TX RX is done in Dialog_BTLE_Characteristics. It looks like the characteristics & services are passed from Activity_BTLE_Services to Dialog_BTLE_Characteristic class using the following commands.

Dialog_BTLE_Characteristic dialog_btle_characteristic = new Dialog_BTLE_Characteristic();
dialog_btle_characteristic.setTitle(uuid);
dialog_btle_characteristic.setService(mBTLE_Service);
dialog_btle_characteristic.setCharacteristic(characteristic);

then the characteristics are used in Dialog_BTLE_Characteristic class to send data (output):

characteristic.setValue(output);
service.writeCharacteristic(characteristic);

Now I want to send and receive data inside a Fragment. How do I pass that characteristics and services to the Fragment?

Your help will be great. Marinus

2 Answers 2

0

It it bad practice to do BLE operations in a fragment. Create a helper class that does the BLE operations and only send decoded data to fragments/actvities for display purposes.

Sign up to request clarification or add additional context in comments.

Comments

0

I think if you were to separate the code into different files you might have a better time moving around.

What I recommend is that you pass the characteristic and device ID to the fragment using a bundle:

    public static MyFragment newInstance(int someInt) {
        MyFragment myFragment = new MyFragment();

        Bundle args = new Bundle();
        args.putString("someInt", someString);
        myFragment.setArguments(args);

        return myFragment;
    }

    //-------

    // In the fragment

    getArguments().getInt("someString");

I have been writing some pretty abismal code for a few years but it does get a lot of the heavy lifting out the way:

    //By the way, I think this is the server, better known as "Central Module", not the peripheral. I've had this misunderstanding until recently and still need to change the code
    public class BLEPeripheral {

        private String deviceId;
        private BLEManager connector;
        private BluetoothAdapter bluetoothAdapter;
        private BluetoothLeScanner bluetoothLeScanner;
        private BluetoothGatt bluetoothGatt;
        private BluetoothGattService bluetoothGattService = null;
        private HashMap<String, Command<String>> subscriptions;

        private boolean connected = false;

        public boolean isConnected() {
            return connected;
        }

        public BLEPeripheral(BLEManager connector, String deviceId) {
            this.connector = connector;
            this.deviceId = deviceId;

            this.connector.onDisconnected();
            final BluetoothManager bluetoothManager = (BluetoothManager) this.connector.getContext().getSystemService(Context.BLUETOOTH_SERVICE);
            bluetoothAdapter = bluetoothManager.getAdapter();

            if (bluetoothAdapter == null || !bluetoothAdapter.isEnabled()) {
                this.connector.enableBluetooth();
                return;
            }

            if (!this.connector.checkPermission()) return;

            scanForDevice();
        }

        public void scanForDevice() {
            connected = false;
            connector.log("BT ENABLED: SCANNING FOR DEVICES");
            connector.reportState(BleManagerStatus.SEARCH_START);
            bluetoothLeScanner = bluetoothAdapter.getBluetoothLeScanner();
            bluetoothLeScanner.startScan(mLEScanCallback);
        }

        public void stopScan() {
            connector.reportState(BleManagerStatus.SCAN_CANCEL);
            bluetoothLeScanner.stopScan(mLEScanCallback);
        }

        private final ScanCallback mLEScanCallback = new ScanCallback() {
            @Override
            public void onScanResult(int callbackType, ScanResult result) {
                BluetoothDevice device = result.getDevice();
                ScanRecord record = result.getScanRecord();
                if (record == null) {
                    connector.log(String.format("Device [%s] has no scan record", device.getAddress()));
                    return;
                }

                String name = record.getDeviceName();
                String UUID = null;

                if (record.getServiceUuids() != null) {
                    for (ParcelUuid pId : record.getServiceUuids()) {
                        if (pId.getUuid().toString().equals(deviceId)) {
                            UUID = pId.getUuid().toString();
                        }
                    }
                }
                if (UUID == null) {
                    if (name != null) connector.log(String.format("Discovered Device [%s]. Continuing search", name));
                    return;
                }
                connector.log(String.format("Peripheral [%s] located on Device [%s]. Attempting connection", UUID, name));
                bluetoothGatt = device.connectGatt(connector.getContext(), true, mGattCallback);
                stopScan();
                connector.reportState(BleManagerStatus.DEVICE_FOUND);
                super.onScanResult(callbackType, result);
            }
        };

        private void closeGatt() {
            connector.reportState(BleManagerStatus.DICSONNECT);
            connector.onDisconnected();
            if (bluetoothGatt == null) {
                return;
            }
            bluetoothGatt.close();
            bluetoothGatt = null;
            scanForDevice();
        }

        private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
            StringBuilder buffer;
                    @Override
                    public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
                        connector.onConnectionStateChange(newState);
                        if (newState == BluetoothProfile.STATE_CONNECTED) {
                            connector.log("Connected to device GATT. Discovering services");
                            connector.reportState(BleManagerStatus.DEVICE_CONNECTED);
                            bluetoothGatt.discoverServices();
                        } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
                            connector.log("Disconnected from GATT server. Continuing scanning");
                            closeGatt();
                        }
                    }

                    @Override
                    public void onServicesDiscovered(BluetoothGatt gatt, int status) {
                        if (status == BluetoothGatt.GATT_SUCCESS) {
                            if (bluetoothGatt.getServices() != null) {
                                connector.log("Services discovered: ["+bluetoothGatt.getServices().size()+"]");
                                for (BluetoothGattService service : bluetoothGatt.getServices()) {
                                    if (service.getUuid().toString().equals(deviceId)) {
                                        bluetoothGattService = service;
                                        connector.onConnected();
                                        connector.log("Service discovered");
                                        connector.log("Attempting characteristic subscription");
                                        connector.subscribeToCharacteristics();
                                    }
                                }
                            }

                        } else {
                            connector.log(String.format("onServicesDiscovered received: [%s]", status));
                        }
                    }

                    @Override
                    public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
                        if (status == BluetoothGatt.GATT_SUCCESS) {
                            connector.log(String.format("onCharacteristicRead received: [%s] value: [%s]", characteristic.getUuid().toString(), new String(characteristic.getValue())));
                        } else {
                            connector.log(String.format("onCharacteristicRead fail received: [%s]", status));
                        }
                    }

                    @Override
                    public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
                        super.onCharacteristicWrite(gatt, characteristic, status);
                        if (status == BluetoothGatt.GATT_SUCCESS) {
                            connector.log(String.format("onCharacteristicWrite received: [%s] value: [%s]", characteristic.getUuid().toString(), new String(characteristic.getValue())));
                        }
                    }

                    @Override
                    public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
                        String packet = new String(characteristic.getValue());
                        if (packet.equals(String.valueOf((char)2))) {
                            buffer = new StringBuilder();
                        } else if (packet.equals(String.valueOf((char)3))) {
                            if (subscriptions == null || subscriptions.size() == 0) return;

                            Command<String> handler = subscriptions.get(characteristic.getUuid().toString());
                            if (handler != null) handler.execute(new String(buffer.toString()));
                        } else {
                            buffer.append(packet);
                        }
                    }
                };

        public BluetoothGattService getService() {
            return bluetoothGattService;
        }

        private BluetoothGattCharacteristic findCharacteristicById(String id) {
            if (bluetoothGattService.getCharacteristics() != null) {
                return bluetoothGattService.getCharacteristic(java.util.UUID.fromString(id));
            }
            return null;
        }

        public void subscribe(String characteristicId, Command<String> handler){
            if (subscriptions == null) subscriptions = new HashMap<>();
            BluetoothGattCharacteristic characteristic = findCharacteristicById(characteristicId);

            if (characteristic == null) {
                connector.log("Characteristic does not exist");
                return;
            }
            connected = true;
            connector.reportState(BleManagerStatus.CHARACTERISTIC_SUBSCRIBED);
            bluetoothGatt.setCharacteristicNotification(characteristic, true);
            BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"));
            descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
            bluetoothGatt.writeDescriptor(descriptor);

            subscriptions.put(characteristicId, handler);
        }

        public void writeCharacteristic(String characteristicId, String data) {
            BluetoothGattCharacteristic characteristic = findCharacteristicById(characteristicId);
            if (characteristic != null) {
                characteristic.setValue(data);
                bluetoothGatt.writeCharacteristic(characteristic);
                connector.log(String.format("Wrote [%s] to [%s]", data, characteristicId));
            } else {
                connector.log(String.format("[%s] not found on device", characteristicId));
            }
        }

        public void readCharacteristic(String characteristicId) {
            BluetoothGattCharacteristic characteristic = findCharacteristicById(characteristicId);
            if (characteristic == null) return;
            bluetoothGatt.readCharacteristic(characteristic);
        }
    }

[SOURCE CODE]

Then I just need to pass an instance of BLEManager in, which is just a simple interface:

    public interface BLEManager {
        void log(String message);
        void reportState(BleManagerStatus status);
        void onConnectionStateChange(int newState);
        Context getContext();
        void enableBluetooth();
        void onConnected();
        void subscribeToCharacteristics();
        void onDisconnected();
        boolean checkPermission();
    }

[SOURCE CODE]

And your fragment / activity can just implement that. I think this is called an adapter pattern, because I'm abstracting the implementation of BLE away from the Android lifecycle.

  1. this a video of one of the things I did with it. I built the tank as well :)
  2. here is the Raspberry Pi part

4 Comments

Please excuse my java, still need to convert it to Kotlin :)
Thank you Quintin, Its a lot to take in but I will try it
Quintin, I will come back to you on this one to show you how I understand what to do.
It took me a long time to come to grips with this stuff too, I've done it all in my spare time - hope you come right

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.