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:
Please advise if it's possible by the means of Android 5 API.
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.
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
).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With