The BluetoothLE API was introduced in API 18. However, the way of scanning devices has changed in API 21. The searching of devices must start with defining the service UUID that is to be scanned (either officailly adopted 16-bit UUID's or proprietary ones). This example illustrates, how to make an API independent way of searching for BLE devices:
public class BTDevice {
String address;
String name;
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public interface ScanningAdapter {
void startScanning(String name, String[] uuids);
void stopScanning();
List<BTDevice> getFoundDeviceList();
}
public class BluetoothScanningFactory implements ScanningAdapter {
private ScanningAdapter mScanningAdapter;
public BluetoothScanningFactory() {
if (isNewerAPI()) {
mScanningAdapter = new LollipopBluetoothLEScanAdapter();
} else {
mScanningAdapter = new JellyBeanBluetoothLEScanAdapter();
}
}
private boolean isNewerAPI() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP;
}
@Override
public void startScanning(String[] uuids) {
mScanningAdapter.startScanning(uuids);
}
@Override
public void stopScanning() {
mScanningAdapter.stopScanning();
}
@Override
public List<BTDevice> getFoundDeviceList() {
return mScanningAdapter.getFoundDeviceList();
}
}
API 18:
import android.annotation.TargetApi;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.os.Build;
import android.os.Parcelable;
import android.util.Log;
import bluetooth.model.BTDevice;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
public class JellyBeanBluetoothLEScanAdapter implements ScanningAdapter{
BluetoothAdapter bluetoothAdapter;
ScanCallback mCallback;
List<BTDevice> mBluetoothDeviceList;
public JellyBeanBluetoothLEScanAdapter() {
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
mCallback = new ScanCallback();
mBluetoothDeviceList = new ArrayList<>();
}
@Override
public void startScanning(String[] uuids) {
if (uuids == null || uuids.length == 0) {
return;
}
UUID[] uuidList = createUUIDList(uuids);
bluetoothAdapter.startLeScan(uuidList, mCallback);
}
private UUID[] createUUIDList(String[] uuids) {
UUID[] uuidList = new UUID[uuids.length];
for (int i = 0 ; i < uuids.length ; ++i) {
String uuid = uuids[i];
if (uuid == null) {
continue;
}
uuidList[i] = UUID.fromString(uuid);
}
return uuidList;
}
@Override
public void stopScanning() {
bluetoothAdapter.stopLeScan(mCallback);
}
@Override
public List<BTDevice> getFoundDeviceList() {
return mBluetoothDeviceList;
}
private class ScanCallback implements BluetoothAdapter.LeScanCallback {
@Override
public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
if (isAlreadyAdded(device)) {
return;
}
BTDevice btDevice = new BTDevice();
btDevice.setName(new String(device.getName()));
btDevice.setAddress(device.getAddress());
mBluetoothDeviceList.add(btDevice);
Log.d("Bluetooth discovery", device.getName() + " " + device.getAddress());
Parcelable[] uuids = device.getUuids();
String uuid = "";
if (uuids != null) {
for (Parcelable ep : uuids) {
uuid += ep + " ";
}
Log.d("Bluetooth discovery", device.getName() + " " + device.getAddress() + " " + uuid);
}
}
private boolean isAlreadyAdded(BluetoothDevice bluetoothDevice) {
for (BTDevice device : mBluetoothDeviceList) {
String alreadyAddedDeviceMACAddress = device.getAddress();
String newDeviceMACAddress = bluetoothDevice.getAddress();
if (alreadyAddedDeviceMACAddress.equals(newDeviceMACAddress)) {
return true;
}
}
return false;
}
}
}
API 21:
import android.annotation.TargetApi;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanFilter;
import android.bluetooth.le.ScanResult;
import android.bluetooth.le.ScanSettings;
import android.os.Build;
import android.os.ParcelUuid;
import bluetooth.model.BTDevice;
import java.util.ArrayList;
import java.util.List;
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public class LollipopBluetoothLEScanAdapter implements ScanningAdapter {
BluetoothLeScanner bluetoothLeScanner;
ScanCallback mCallback;
List<BTDevice> mBluetoothDeviceList;
public LollipopBluetoothLEScanAdapter() {
bluetoothLeScanner = BluetoothAdapter.getDefaultAdapter().getBluetoothLeScanner();
mCallback = new ScanCallback();
mBluetoothDeviceList = new ArrayList<>();
}
@Override
public void startScanning(String[] uuids) {
if (uuids == null || uuids.length == 0) {
return;
}
List<ScanFilter> filterList = createScanFilterList(uuids);
ScanSettings scanSettings = createScanSettings();
bluetoothLeScanner.startScan(filterList, scanSettings, mCallback);
}
private List<ScanFilter> createScanFilterList(String[] uuids) {
List<ScanFilter> filterList = new ArrayList<>();
for (String uuid : uuids) {
ScanFilter filter = new ScanFilter.Builder()
.setServiceUuid(ParcelUuid.fromString(uuid))
.build();
filterList.add(filter);
};
return filterList;
}
private ScanSettings createScanSettings() {
ScanSettings settings = new ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_BALANCED)
.build();
return settings;
}
@Override
public void stopScanning() {
bluetoothLeScanner.stopScan(mCallback);
}
@Override
public List<BTDevice> getFoundDeviceList() {
return mBluetoothDeviceList;
}
public class ScanCallback extends android.bluetooth.le.ScanCallback {
@Override
public void onScanResult(int callbackType, ScanResult result) {
super.onScanResult(callbackType, result);
if (result == null) {
return;
}
BTDevice device = new BTDevice();
device.setAddress(result.getDevice().getAddress());
device.setName(new StringBuffer(result.getScanRecord().getDeviceName()).toString());
if (device == null || device.getAddress() == null) {
return;
}
if (isAlreadyAdded(device)) {
return;
}
mBluetoothDeviceList.add(device);
}
private boolean isAlreadyAdded(BTDevice bluetoothDevice) {
for (BTDevice device : mBluetoothDeviceList) {
String alreadyAddedDeviceMACAddress = device.getAddress();
String newDeviceMACAddress = bluetoothDevice.getAddress();
if (alreadyAddedDeviceMACAddress.equals(newDeviceMACAddress)) {
return true;
}
}
return false;
}
}
}
Get found device list by calling:
scanningFactory.startScanning({uuidlist});
wait few seconds...
List<BTDevice> bluetoothDeviceList = scanningFactory.getFoundDeviceList();