Bluetooth Low Energy
BLE is wireless technology.It gives context to the environment around you.It perfect for devices that run for long periods on power sources, such as coin cell batteries.
BLE Permissions
You need BLUETOOTH permission to perform requesting a connection, accepting a connection, and transferring data.You must also declare the BLUETOOTH_ADMIN permission for device discovery or manipulate Bluetooth settings.
Android 6.0+ (API level 23+), users grant permissions to apps while the app is running, not when they install the app.
//onResume() if (ContextCompat.checkSelfPermission(this.getApplicationContext(), android.Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) < >else < ActivityCompat.requestPermissions(this, new String[], Constants.REQUEST_LOCATION_ENABLE_CODE); >
Get the BluetoothAdapter
The BluetoothAdapter represents the device’s Bluetooth adapter.There’s one Bluetooth adapter for the entire system, and your application can interact with it using this object.
private BluetoothAdapter mBluetoothAdapter; . //onCreate BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); mBluetoothAdapter = bluetoothManager.getAdapter();
Enable Bluetooth
If Bluetooth but disabled, then you can request that the user enable Bluetooth without leaving your application.
public static BluetoothAdapter getBluetoothAdapter(Context context)
Scan BLE Devices
To scan BLE devices, you use the startScan() method.Scanning is battery-intensive, you should observe the following guidelines:
- After finding the desired device, stop scanning.
- Set a time limit on your scan. A device that was previously available may have moved out of range, and continuing to scan drains the battery.
startScan() method takes a ScanCallback as a parameter. You must implement this callback for results are returned.
private ScanCallback scanCallback = new ScanCallback() < @Override public void onScanResult(int callbackType, ScanResult result) < super.onScanResult(callbackType, result); bluetoothDevice = result.getDevice(); deviceAddress.setText(bluetoothDevice.getAddress()); deviceName.setText(bluetoothDevice.getName()); progressBar.setVisibility(View.INVISIBLE); >@Override public void onBatchScanResults(List results) < super.onBatchScanResults(results); >@Override public void onScanFailed(int errorCode) < super.onScanFailed(errorCode); Log.d(TAG, "Scanning Failed " + errorCode); progressBar.setVisibility(View.INVISIBLE); >>;
The following snippet shows how to start and stop a scan
private BluetoothLeScanner bluetoothLeScanner; private BluetoothAdapter mBluetoothAdapter; private boolean mScanning; . private void startScanning(final boolean enable) < bluetoothLeScanner = mBluetoothAdapter.getBluetoothLeScanner(); Handler mHandler = new Handler(); if (enable) < //filter for battery service. ListscanFilters = new ArrayList<>(); //default setting. final ScanSettings settings = new ScanSettings.Builder().build(); ScanFilter scanFilter = new ScanFilter.Builder().setServiceUuid(ParcelUuid.fromString(SampleGattAttributes.UUID_BATTERY_SERVICE)).build(); scanFilters.add(scanFilter); mHandler.postDelayed(new Runnable() < @Override public void run() < mScanning = false; progressBar.setVisibility(View.INVISIBLE); bluetoothLeScanner.stopScan(scanCallback); >>, Constants.SCAN_PERIOD); mScanning = true; bluetoothLeScanner.startScan(scanFilters, settings, scanCallback); > else < mScanning = false; bluetoothLeScanner.stopScan(scanCallback); >>
In this example, app provides an activity BluetoothDetectorActivity to connect and display data and display GATT services and characteristics supported by the device.
Connecting to a GATT Server(BLE Device)
Based on user input, Activity communicates with a Service called BluetoothLEService , which interacts with the BLE device via the Android BLE API
BluetoothGattCallback: Used to deliver results to the client, such as connection status, as well as any further GATT client operations.
private BluetoothGattCallback bluetoothGattCallback = new BluetoothGattCallback() < @Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) < super.onConnectionStateChange(gatt, status, newState); Log.d(TAG, "onConnectionStateChange " + newState); String intentAction; if (newState == BluetoothProfile.STATE_CONNECTED) < intentAction = ACTION_GATT_CONNECTED; mConnectionState = STATE_CONNECTED; broadcastUpdate(intentAction); Log.i(TAG, "Connected to GATT server."); // Attempts to discover services after successful connection. Log.i(TAG, "Attempting to start service discovery:" + mBluetoothGatt.discoverServices()); >else if (newState == STATE_DISCONNECTED) < intentAction = ACTION_GATT_DISCONNECTED; mConnectionState = STATE_DISCONNECTED; Log.i(TAG, "Disconnected from GATT server."); broadcastUpdate(intentAction); >> @Override public void onServicesDiscovered(BluetoothGatt gatt, int status) < super.onServicesDiscovered(gatt, status); Log.d(TAG, "onServicesDiscovered " + status); if (status == BluetoothGatt.GATT_SUCCESS) < broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED); >else < Log.w(TAG, "onServicesDiscovered received: " + status); >> @Override public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) < super.onCharacteristicRead(gatt, characteristic, status); Log.d(TAG, "onCharacteristicRead " + status); if (status == BluetoothGatt.GATT_SUCCESS) < broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic); >> . @Override public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) < super.onCharacteristicChanged(gatt, characteristic); Log.d(TAG, "onCharacteristicChanged"); broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic); >. >;
The first step in interacting with a BLE device is connecting to the GATT server on the device. To connect to a GATT server on a BLE device, you use the connectGatt() method.
public boolean connect(String address) < if (mBluetoothAdapter == null || address == null) < Log.w(TAG, "BluetoothAdapter not initialize or unspecified address"); return false; >if (mBluetoothAdapter != null && address.equals(bluetoothAddress) && mBluetoothGatt != null) < Log.d(TAG, "Try to use existing connection"); if (mBluetoothGatt.connect()) < mConnectionState = STATE_CONNECTING; return true; >else < return false; >> final BluetoothDevice bluetoothDevice = mBluetoothAdapter.getRemoteDevice(address); if (bluetoothDevice == null) < Log.w(TAG, "Device not found"); return false; >mBluetoothGatt = bluetoothDevice.connectGatt(this, false, bluetoothGattCallback); bluetoothAddress = address; mConnectionState = STATE_CONNECTING; return true; >
When a particular callback is triggered, it calls the broadcastUpdate() helper method and passes it an action. Data parsing in this section is performed in accordance with the Bluetooth Battery Service Measurement profile specifications
private void broadcastUpdate(final String action) < final Intent intent = new Intent(action); sendBroadcast(intent); >private void broadcastUpdate(final String action, final BluetoothGattCharacteristic characteristic) < final Intent intent = new Intent(action); if (UUID_BATTERY_LEVEL.equals(characteristic.getUuid())) < int format = BluetoothGattCharacteristic.FORMAT_UINT8; final int battery_level = characteristic.getIntValue(format, 0); intent.putExtra(EXTRA_DATA, battery_level+"%"); >sendBroadcast(intent); >
To enable or disable notifications for a given characteristic setCharacteristicNotification to
BluetoothGatt. Reads the requested characteristic from the associated remote device set
readCharacteristic.
public void readCharacteristic(@NonNull BluetoothGattCharacteristic bluetoothGattCharacteristic) < mBluetoothGatt.readCharacteristic(bluetoothGattCharacteristic); >public void setCharacteristicNotification(@NonNull BluetoothGattCharacteristic characteristic, boolean enabled)
In BatteryDetectorActivity , these events are handled by a BroadcastReceiver.
private final BroadcastReceiver mGattUpdateReceiver = new BroadcastReceiver() < @Override public void onReceive(Context context, Intent intent) < final String action = intent.getAction(); if (BluetoothLEService.ACTION_GATT_CONNECTED.equals(action)) < mConnected = true; updateConnectionState("connected"); >else if (BluetoothLEService.ACTION_GATT_DISCONNECTED.equals(action)) < mConnected = false; updateConnectionState("disconnected"); >else if (BluetoothLEService.ACTION_GATT_SERVICES_DISCOVERED.equals(action)) < displayGattServices(mBluetoothLEService.getSupportedGattServices()); >else if (BluetoothLEService.ACTION_DATA_AVAILABLE.equals(action)) < displayData(intent.getStringExtra(BluetoothLEService.EXTRA_DATA)); >> >;
The Following snippet show display Gatt connected service
private void displayGattServices(List gattServices) < if (gattServices == null) return; String uuid = null; String serviceString = "unknown service"; String charaString = "unknown characteristic"; for (BluetoothGattService gattService : gattServices) < uuid = gattService.getUuid().toString(); serviceString = SampleGattAttributes.lookup(uuid); if (serviceString != null) < ListgattCharacteristics = gattService.getCharacteristics(); for (BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) < HashMapcurrentCharaData = new HashMap(); uuid = gattCharacteristic.getUuid().toString(); charaString = SampleGattAttributes.lookup(uuid); if (charaString != null) < serviceName.setText(charaString); >mNotifyCharacteristic = gattCharacteristic; return; > > > >
Connect Bluetooth service
connectDevice.setOnClickListener(new View.OnClickListener() < @Override public void onClick(View v) < if (bluetoothDevice != null) < progressBar.setVisibility(View.VISIBLE); Intent gattServiceIntent = new Intent(BatteryDetectorActivity.this, BluetoothLEService.class); bindService(gattServiceIntent, mServiceConnection, BIND_AUTO_CREATE); >> >); //read characteristic notification from server connectService.setOnClickListener(new View.OnClickListener() < @Override public void onClick(View v) < if (mNotifyCharacteristic != null) < final int charaProp = mNotifyCharacteristic.getProperties(); if ((charaProp | BluetoothGattCharacteristic.PROPERTY_READ) >0) < mBluetoothLEService.readCharacteristic(mNotifyCharacteristic); >if ((charaProp | BluetoothGattCharacteristic.PROPERTY_NOTIFY) > 0) < mBluetoothLEService.setCharacteristicNotification(mNotifyCharacteristic, true); >> > >);
Closing the Client App
Once your app has finished using a BLE device, it should call close() so the app can release resources appropriately.
public void close() < if (mBluetoothGatt == null) < return; >mBluetoothGatt.close(); mBluetoothGatt = null; >
How to test BLE Client?
The BLE Peripheral Simulator is an Android app that allows developers to try out new features of app Bluetooth without the need for a BLE Peripheral Device.
BLE Peripheral with one of three services:
Use the Bluetooth features to connect to the app to Read and Write Characteristics, Subscribe to Notifications for when the Characteristics change, and Read and Write Descriptors.
The device in the central role scans, looking for advertisement of Battery Level Detector.
The device in the peripheral role makes the advertisement of Battery Level.
What is bluetooth adapter in android
Android SDK оснащен возможностью работать с мощными Bluetooth API, способными работать с Bluetooth адаптером устройства, производить поиск находящихся вблизи устройств, передавать данные между смартфонами и многое другое. В этом уроке мы рассмотрим основные возможности работы с Bluetooth, которые пригодятся при разработке приложений, работающих с этой функцией.
Для того, чтобы работать в вашем приложении с Bluetooth, прежде всего нужно импортировать в него Bluetooth API пакет. Чтобы это сделать добавляем в класс, в котором вы будете использовать работу с Bluetooth, следующее:
Для того, чтобы приложение могло работать с Bluetooth, в файле манифеста приложения AndroidManifest.xml нужно добавить соответствующее разрешение:
uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
Инструменты работы с Bluetooth включают в себя класс BluetoothAdapter. Он используется для того, чтобы получить доступ к Bluetooth устройства. Установка этого класса выглядит так:
BluetoothAdapter bluetooth = BluetoothAdapter.getDefaultAdapter();
Если пытаться выполнить эту команду на устройстве, не поддерживающем Bluetooth, то возвращенное значение от попытки использования должно принимать значение «null». Это можно проверить использованием простого оператора if:
BluetoothAdapter bluetooth = BluetoothAdapter.getDefaultAdapter(); if(bluetooth != null)
Далее, после этой проверки, нужно настроить действие программы на случай, если аппарат поддерживает Bluetooth, но на данный момент он отключен пользователем. Поэтому нужно выполнить следующею проверку:
if (bluetooth.isEnabled()) < // Включен. Работаем с Bluetooth. > else < // Отключен. Предлагаем какое то другое действие. >
Используя указанный выше код, можно сделать такую простую операцию. Если Bluetooth включен, мы показываем пользователю сообщение с данными имени и адреса Bluetooth. Если же адаптер выключен, пользователь увидит наше сообщение, говорящее ему, что Bluetooth выключен (как работать с Toast):
String status; if (bluetooth.isEnabled()) < String mydeviceaddress = bluetooth.getAddress(); String mydevicename = bluetooth.getName(); status = mydevicename + ” : ” + mydeviceaddress; > else < status = “Bluetooth отключен”; > Toast.makeText(this, status, Toast.LENGTH_LONG).show();
Чтобы получить имя Bluetooth устройства, мы использовали метод getName(). Если вы уже установили ранее разрешение на использование Bluetooth, то его имя можно задать и программно:
bluetooth.setName("AndroidCoder");
Для более детального отображения состояния Bluetooth устройства можно использовать метод BluetoothAdapter.getState(). В это методе можно получить такие данные:
— STATE_TURNING_ON;
— STATE_ON;
— STATE_TURNING_OFF;
— STATE_OFF.
Учитывая это, код выше может быть переиначен. Например, так:
String state = bluetooth.getState(); status = mydevicename + ” : ” + mydeviceaddress + " : " + state;
Bluetooth адаптер на большинстве устройств выключается по умолчанию для сохранения времени работы батареи.
Что же, на этом наш краткий экскурс в работу класса Bluetooth Adapter окончен. Вы получили самое базовое представление о работе с Bluetooth на Android устройствах. Стоит отметить, что попытки тестировать эти приемы на эмуляторе ни к чему не приведут, нужно проводить тестирование этих методов на реальном устройстве.