1

Hey I am working on application in which I am using BLE to transfer User ID from mobile to mobile by using my application when they interact with each other , which means in one mobile my app will work as Peripheral Mode and in other it will work as a Central mode. So what I have done is I open my first app as a Peripheral Mode which starts advertising and other as Central which starts a service in background to scan device and make connection to read data. This functionality works fine I send message(User ID) from Peripheral to central it pops on central device. Now I want to send User ID of Central Mode device to Peripheral.

As per my understanding, In BLE we cannot send data from central to peripheral we can only scan from central. But I heard that we can write characteristics from Peripheral to get some response in back So is it possible that i can send my Used ID from Central to Peripheral through response or any other alternate way is possible? I want to do thisBLE Handshake

I am just new in BLE so I have no idea how to perform this functionality. I am sharing my code that what I am doing below :

SO Central Mode or You say scanning which I start in background service is:

GATT Service

public class GattService extends Service {
private static int NOTIFICATION_ID = 0;
public static final ParcelUuid UUID = ParcelUuid.fromString("0000FED8-0000-1000-8000-00805F9B34FB");
public static final java.util.UUID SERVICE_UUID = java.util.UUID.fromString("00001111-0000-1000-8000-00805F9B34FB");
public static final java.util.UUID CHAR_UUID = java.util.UUID.fromString("00002222-0000-1000-8000-00805F9B34FB");

private BluetoothAdapter bluetoothAdapter;
private BluetoothGattServer server;
private BluetoothLeAdvertiser bluetoothLeAdvertiser;
private boolean start;

@Override
public void onCreate() {
    super.onCreate();
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    setupBluetooth();
    return Service.START_STICKY;
}

private void setupBluetooth() {

    BluetoothManager bluetoothManager = (BluetoothManager) this.getApplicationContext().getSystemService(Context.BLUETOOTH_SERVICE);
    server = bluetoothManager.openGattServer(this, serverCallback);
    initServer();
    bluetoothAdapter = bluetoothManager.getAdapter();
    advertise();
}

private void initServer() {
    BluetoothGattService service = new BluetoothGattService(SERVICE_UUID, BluetoothGattService.SERVICE_TYPE_PRIMARY);
    BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(CHAR_UUID, BluetoothGattCharacteristic.PROPERTY_WRITE | BluetoothGattCharacteristic.PROPERTY_READ, BluetoothGattCharacteristic.PERMISSION_READ | BluetoothGattCharacteristic.PERMISSION_WRITE);
    service.addCharacteristic(characteristic);
    server.addService(service);
}

private void advertise() {

    bluetoothLeAdvertiser = bluetoothAdapter.getBluetoothLeAdvertiser();
    AdvertiseData advertisementData = getAdvertisementData();
    AdvertiseSettings advertiseSettings = getAdvertiseSettings();
    bluetoothLeAdvertiser.startAdvertising(advertiseSettings, advertisementData, advertiseCallback);
    start = true;
}

private AdvertiseData getAdvertisementData() {
    AdvertiseData.Builder builder = new AdvertiseData.Builder();
    builder.setIncludeTxPowerLevel(true);
    builder.addServiceUuid(UUID);
    bluetoothAdapter.setName("BLE client");
    builder.setIncludeDeviceName(true);
    return builder.build();
}

private AdvertiseSettings getAdvertiseSettings() {
    AdvertiseSettings.Builder builder = new AdvertiseSettings.Builder();
    builder.setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_BALANCED);
    builder.setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_HIGH);
    builder.setConnectable(true);
    return builder.build();
}

private final AdvertiseCallback advertiseCallback = new AdvertiseCallback() {
    @SuppressLint("Override")
    @Override
    public void onStartSuccess(AdvertiseSettings advertiseSettings) {
        final String message = "Advertisement successful";
        sendNotification(message);
    }

    @SuppressLint("Override")
    @Override
    public void onStartFailure(int i) {
        final String message = "Advertisement failed error code: " + i;
        sendNotification(message);

    }

};

private BluetoothGattServerCallback serverCallback = new BluetoothGattServerCallback() {
    @Override
    public void onConnectionStateChange(BluetoothDevice device, int status, int newState) {
        super.onConnectionStateChange(device, status, newState);
        if (newState == BluetoothProfile.STATE_CONNECTED) {
            sendNotification("Client connected");
        }
    }

    @Override
    public void onServiceAdded(int status, BluetoothGattService service) {
        super.onServiceAdded(status, service);
    }

    @Override
    public void onCharacteristicReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattCharacteristic characteristic) {
        super.onCharacteristicReadRequest(device, requestId, offset, characteristic);

        server.sendResponse(device, requestId, BluetoothGatt.GATT_FAILURE, 0, null);
    }


    @Override
    public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId, BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) {
        super.onCharacteristicWriteRequest(device, requestId, characteristic, preparedWrite, responseNeeded, offset, value);
        byte[] bytes = value;
        String message = new String(bytes);
        sendNotification(message);

        if (characteristic.getUuid().equals(CHAR_UUID)) {
            server.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, 0, null);

        }

        int length = value.length;
        byte[] reversed = new byte[length];
        for (int i = 0; i < length; i++) {
            reversed[i] = value[length - (i + 1)];
        }
        characteristic.setValue(reversed);
        server.notifyCharacteristicChanged(device, characteristic, true);

    }

    @Override
    public void onDescriptorReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattDescriptor descriptor) {
        super.onDescriptorReadRequest(device, requestId, offset, descriptor);
    }

    @Override
    public void onDescriptorWriteRequest(BluetoothDevice device, int requestId, BluetoothGattDescriptor descriptor, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) {
        super.onDescriptorWriteRequest(device, requestId, descriptor, preparedWrite, responseNeeded, offset, value);


    }

    @Override
    public void onExecuteWrite(BluetoothDevice device, int requestId, boolean execute) {
        super.onExecuteWrite(device, requestId, execute);
    }

    @Override
    public void onNotificationSent(BluetoothDevice device, int status) {
        super.onNotificationSent(device, status);
    }

    @Override
    public void onMtuChanged(BluetoothDevice device, int mtu) {
        super.onMtuChanged(device, mtu);
    }

};

@Override
public void onDestroy() {
    if (start) {
        bluetoothLeAdvertiser.stopAdvertising(advertiseCallback);
    }
    super.onDestroy();
}

private void sendNotification(String message) {
    NotificationManager notificationManager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);

    int notificationId = 1;
    String channelId = "channel-01";
    String channelName = "Channel Name";
    int importance = NotificationManager.IMPORTANCE_HIGH;

    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
        NotificationChannel mChannel = new NotificationChannel(
                channelId, channelName, importance);
        notificationManager.createNotificationChannel(mChannel);
    }

    NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this, channelId)
            .setSmallIcon(R.mipmap.ic_launcher)
            .setContentTitle(getString(R.string.app_name))
            .setContentText(message)
            .setAutoCancel(true);

    Intent intent = new Intent(this, MainActivity.class);

    TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
    stackBuilder.addNextIntent(intent);
    PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(
            0,
            PendingIntent.FLAG_UPDATE_CURRENT
    );
    mBuilder.setContentIntent(resultPendingIntent);

    notificationManager.notify(notificationId, mBuilder.build());
}

@Override
public IBinder onBind(Intent intent) {
    return null;
}
}

And my Peripheral device which send Characteristic after successful connection is:

public class ServicesList extends AppCompatActivity implements AdapterView.OnItemClickListener {
private ListView servicesList;
private LinearLayout messageContainer;
private BluetoothDevice device;
private List<String> servicesListNames;
private ArrayAdapter<String> servicesAdapter;
private Handler handler;
private List<BluetoothGattService> services;
private BluetoothGatt currentGatt;
private EditText message;
private Button send;
private BluetoothGattCharacteristic characteristic;
private ProgressDialog dialog;
public static final java.util.UUID DES_UUID = java.util.UUID.fromString("00003333-0000-1000-8000-00805F9B34FB");

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.services_list);
    handler = new Handler();
    dialog = new ProgressDialog(this);
    dialog.setCancelable(false);
    dialog.setMessage("Loading");
    device = getIntent().getExtras().getParcelable("device");
    servicesList = (ListView) findViewById(R.id.services_list);
    messageContainer = (LinearLayout) findViewById(R.id.message_container);
    message = (EditText) findViewById(R.id.message);
    send = (Button) findViewById(R.id.send);
    currentGatt = device.connectGatt(this, false, gattCallback);
    dialog.show();
    servicesListNames = new ArrayList<>();
    servicesAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, servicesListNames);
    servicesList.setAdapter(servicesAdapter);
    servicesList.setOnItemClickListener(this);
    send.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if(!message.getText().toString().trim().isEmpty()) {
                characteristic.setValue(message.getText().toString().getBytes());
                currentGatt.writeCharacteristic(characteristic);
                message.setText("");
            }
        }
    });


}

private BluetoothGattCallback gattCallback = new BluetoothGattCallback() {
    @Override
    public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
        super.onConnectionStateChange(gatt, status, newState);
        if(newState == BluetoothProfile.STATE_CONNECTED) {
            currentGatt.discoverServices();
        }else{
            if(dialog.isShowing()){
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        dialog.hide();
                    }
                });
            }
        }
    }

    @Override
    public void onServicesDiscovered(final BluetoothGatt gatt, int status) {
        super.onServicesDiscovered(gatt, status);
        services = currentGatt.getServices();
        for(BluetoothGattService service : services){
            Log.d("Khurram", "Uuid = " + service.getUuid().toString());
            servicesListNames.add(Helper.getServiceName(service.getUuid().toString()));
            handler.post(new Runnable() {
                @Override
                public void run() {
                    servicesAdapter.notifyDataSetChanged();
                }
            });
        }
        if (dialog.isShowing()){
            handler.post(new Runnable() {
                @Override
                public void run() {
                    dialog.hide();
                }
            });
        }
    }

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

        if (status == BluetoothGatt.GATT_SUCCESS) {
   //                log("Characteristic read successfully");
            readCharacteristic(characteristic);
        } else {
   //                logError("Characteristic read unsuccessful, status: " + status);
            // Trying to read from the Time Characteristic? It doesnt have the property or 
   permissions
            // set to allow this. Normally this would be an error and you would want to:
            // disconnectGattServer();
        }
    }

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

    }

    @Override
    public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic 
   characteristic) {
        super.onCharacteristicChanged(gatt, characteristic);

        readCharacteristic(characteristic);
    }

    @Override
    public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) 
{
        super.onDescriptorRead(gatt, descriptor, status);

    }

    @Override
    public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) 
 {
        super.onDescriptorWrite(gatt, descriptor, status);
    }

    @Override
    public void onReliableWriteCompleted(BluetoothGatt gatt, int status) {
        super.onReliableWriteCompleted(gatt, status);


    }

    @Override
    public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
        super.onReadRemoteRssi(gatt, rssi, status);
    }

    @Override
    public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
        super.onMtuChanged(gatt, mtu, status);
    }
};

@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
    if(services != null){
        BluetoothGattService notificationService = services.get(position);
        if(notificationService.getUuid().equals(GattService.SERVICE_UUID)){
            characteristic = notificationService.getCharacteristic(GattService.CHAR_UUID);
            if(characteristic != null) {
                messageContainer.setVisibility(View.VISIBLE);
            }

        }else{
            Toast.makeText(this, "Testing", Toast.LENGTH_SHORT).show();
        }
    }
}

private void readCharacteristic(BluetoothGattCharacteristic characteristic) {
    byte[] messageBytes = characteristic.getValue();
  log("Read: " + StringUtils.byteArrayInHexFormat(messageBytes));
    String message = StringUtils.stringFromBytes(messageBytes);
    if (message == null) {
        logError("Unable to convert bytes to string");
        Toast.makeText(this, "Unable to convert bytes to string", Toast.LENGTH_SHORT).show();
        return;
    }

    Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
}
}

So what I am doing is I have a EditText in peripheral in which i enter the text like User ID and I am returning it back from service as response after reversing it and show notification in Central Mode.

But I am not able to get the response Can you guys help me please ?

If you guys know my scenario you can also assist me with new way through BLE by which I can exchange data between 2 android phones.

Thanks,

4

0 回答 0