How can Android broadcast BLE local name like in iOS?
Asked Answered
R

1

18

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!

Revivalist answered 3/3, 2015 at 22:21 Comment(4)
Anything new? Did you ended up finding something?Structure
Sorry nothing yet :( From what I've heard, iOS conforms to the standard by splitting its broadcast packets into sets of 20-bytes in sequence. If that is true then the fact that Android can put multiple broadcast headers back together means that the hardware stack should also be able to split up its own broadcast headers if they're longer than 20 bytes...Revivalist
Aren't you calling this: "dataBuilder.addServiceUuid" which is going to try to fit service data in the advertising packet as well?Contractual
@LanceNanek where does it say that? developer.android.com/intl/ru/reference/android/bluetooth/le/…Revivalist
A
1

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);
 } 
Anethole answered 15/12, 2020 at 10:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.