Reacting to BLE directed advertising (ADV_DIRECT_IND) in Android
Asked Answered
K

2

7

How to react to directed advertising (ADV_DIRECT_IND == 0001) in Android?

There is a BLE-gadget which sends directed advertising to an Android phone (using hardcoded MAC address of the phone for now) and in my Android app I would like to react and to initiate a connection to the gadget and read the org.bluetooth.characteristic.location_and_speed value from the gadget:

screenshot

Please advise if it's possible by the means of Android 5 API.

Kestrel answered 7/8, 2015 at 14:34 Comment(0)
K
4

Direct advertising does work - at least with HTC M8 phone and Android 5.0 (API level 21 and higher).

The solution has been to add the device addresses to the ScanFilter.

If you leave the filters empty, the scanning callbacks won't be called.

Here my working code:

public static final String TAG = "My_BLE_app";

public static final String DEVICE_1 = "D4:BE:84:72:5B:8E";
public static final String DEVICE_2 = "C4:39:07:19:60:E2";

private Context mContext;
private BluetoothAdapter mBluetoothAdapter;
private BluetoothLeScanner mScanner;
private ScanSettings mSettings;
private List<ScanFilter> mFilters = new ArrayList<ScanFilter>();

First the method for initializing BLE:

public boolean init() {
    BluetoothManager bluetoothManager = (BluetoothManager) mContext.getSystemService(Context.BLUETOOTH_SERVICE);
    mBluetoothAdapter = bluetoothManager.getAdapter();
    if (mBluetoothAdapter == null)
        return false;

    mScanner = mBluetoothAdapter.getBluetoothLeScanner();
    mSettings = new ScanSettings.Builder().setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).build();

    mFilters.add(new ScanFilter.Builder().setDeviceAddress(DEVICE_1).build());
    mFilters.add(new ScanFilter.Builder().setDeviceAddress(DEVICE_2).build());

    return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE);
}

And then the scanning callbacks:

private ScanCallback mDirectedScanCallback = new ScanCallback() {
    @Override
    public void onScanResult(int callbackType, ScanResult result) {
        processResult(result);
    }

    @Override
    public void onBatchScanResults(List<ScanResult> results) {
        for (ScanResult result: results) {
            processResult(result);
        }
    }

    private void processResult(ScanResult result) {
        BluetoothDevice device = result.getDevice();
        if (device == null)
            return;

        String address = device.getAddress();
        if (!BluetoothAdapter.checkBluetoothAddress(address))
            return;

        int rssi = result.getRssi();

        Log.d(TAG, "address=" + address + ", rssi=" + rssi);

        // TODO connect to the device in under 1 second
    }
};

Finally the code to start the scanning:

mScanner.startScan(mFilters, mSettings, mDirectedScanCallback);

One question is still open though:

I don't know how to detect the type of scan at the Android side - that is if the scan was directed or not.

Kestrel answered 13/8, 2015 at 17:43 Comment(0)
W
1

To partially answer the open question:
I've noticed that the ScanRecord.getBytes() is empty - all '\0' - for a directed scan (ADV_DIRECT_IND) - but would contain the advertising data otherwise (ADV_IND).

Whitton answered 16/1, 2017 at 20:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.