Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can Android broadcast BLE local name like in iOS?

I've got an Android app advertising ble broadcast data with a service uuid and local name. The problem is that this "local name" (aka bluetooth device name) is limited to 8 characters, each is a 16-bit unicode representation, thus 2-bytes per character. Anytime I try to change the name of the device to 9 characters long, ble broadcasting fails to start due to error 1 which is

  public static final int ADVERTISE_FAILED_DATA_TOO_LARGE = 1;

I know the GAP profile broadcast packet is 27 bytes long and 7 are used for headers, thus 20 should remain free for use, not just 16?

Here's the real pickle that tickles my nickel:

When iOS is broadcasting ble advertisement header, I get the full local name of the device as part of the ScanRecord, not just limited to 16 bytes. Only part of the broadcast, I'm not establishing a GATT connection here.

How is iOS able to do this? For example, on my Android, I was able to retrieve a 14-character, 28 bytes long unique id from an iOS advertisement broadcast. 28 bytes is longer than the 27-byte limit imposed by bluetooth 4.0 standard. How is it that Android was able to pick up the full broadcast longer than 27 bytes? And how come my "local name" or device name can only be at most 8 characters or 16 bytes or it won't be able to start broadcasting?

This is my code:

         final BluetoothLeAdvertiser advertiser = mBluetoothAdapter.getBluetoothLeAdvertiser();

        //advertise settings
        final AdvertiseSettings.Builder settingsBuilder = new AdvertiseSettings.Builder();
        settingsBuilder.setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY);
        settingsBuilder.setConnectable(true);
        settingsBuilder.setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_HIGH);

        //advertise data
        AdvertiseData.Builder dataBuilder = new AdvertiseData.Builder();
        ParcelUuid uuid = new ParcelUuid(UUID.fromString("XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"));
        dataBuilder.addServiceUuid(uuid);

        mBluetoothAdapter.setName("12345678"); //8 characters works, 9+ fails
        dataBuilder.setIncludeDeviceName(true);

     if (advertiser!=null) {
         advertiser.startAdvertising(settingsBuilder.build(), dataBuilder.build(), mAdvertiseCallback);
     } 

     mAdvertiseCallback = new AdvertiseCallback() {
         @Override
         public void onStartSuccess(AdvertiseSettings settingsInEffect) {
             super.onStartSuccess(settingsInEffect);
             Log.d(LOGN, "BLE STARTED ADVERTISING BROADCAST "+settingsInEffect);

         }

         @Override
         public void onStartFailure(int errorCode) {
                 super.onStartFailure(errorCode);
                 Log.d(LOGN, "BLE ADVERTISING FAILED TO START: "+errorCode);
         }
    };

Is there a way for Android to include the full local name as part of the broadcast like iOS does?

Thanks!

like image 289
DritanX Avatar asked Mar 03 '15 22:03

DritanX


1 Answers

If you view the overloads for StartAdvertising, you can see there is an additional parameter for the scan response. You can put the local name in the scan response data instead. Remember to remove setIncludeDeviceName from the data builder.

AdvertiseData.Builder scanResponseBuilder = new AdvertiseData.Builder();
mBluetoothAdapter.setName("123456789")
scanResponseBuilder.setIncludeDeviceName(true);

//...

if (advertiser!=null) {
     advertiser.startAdvertising(settingsBuilder.build(), dataBuilder.build(), scanResponseBuilder.SetIncludeDeviceName.build(), mAdvertiseCallback);
 } 
like image 162
James Westgate Avatar answered Oct 11 '22 18:10

James Westgate