In third and last article about BLE for Android you will find out how to pair with BLE devices and what are current android capabilities of playing peripheral (server) mode. Code examples are written on C# using Xamarin platform.
What is pairing?
In order to secure communication between devices and prevent unauthorized access, device playing peripheral role may enable characteristic protection.
If peripheral device enabled protection for characteristic, you need to pair with device in order to access characteristic values. Pairing is done through means of alert dialog, asking you to enter secure code. This code is provided by peripheral device you want to pair with, and is generated each time pairing is requested.
Android shows pairing dialog on first unauthorized access to peripheral characteristic. For example you may try to read secured characteristic value of peripheral. In this case OnCharacteristicRead callback would return status: GattStatus.InsufficientAuthentication, after which pairing process will be started.
There are two variants of showing pairing dialog. First is when system shows it on top of the current application view as you have seen on the previous screenshot. Second variant requires clicking on pairing request message in android notification area.
Now, there is no direct way to force android show pairing dialog using one of the described variants. Sometimes, it is shown directly, sometimes from notification area. So be ready to inform user to check notification area if it is not shown on top of the current activity.
Observing pairing state
There are situations when you would like to know from your code the result of pairing. To do so you have to register receiver of BluetoothDevice.ActionBondStateChanged event.
To register we need to pass BroadcasReceiver object, overriding OnReceive method, called during pairing procedure. We can use OnReceive to observe pairing state in the following way:
Pairing process starts with state Bonding. After you entered pairing code and pressed ok button inside pairing dialog, it can be changed from Bonded (in case of success) or None (in case of failure).
Pressing Cancel button on pairing dialog can lead to strange behaviour. Logically it should trigger bonding state change to None. Unfortunetely, on my Nexus 7 and Nexus 5 devices it changes bonding state to Bonded. Hope, it would be fixed in the next android firmware versions.
After pairing is done, you should unregister receiver:
Peripheral role (GATT server)
After android has introduced in 4.3 version BLE support, quickly became clear that support is not full. Things haven’t changed in 4.4 version. The insufficiency is that you cannot advertise when your application plays peripheral role. What does it mean? It means that devices playing central role cannot see you as a peripheral and therefore establish connection.
However, there is a workaround to make your android device visible as a BLE-server to other device.
Your android smartphone should be in both BLE client and server mode. Device to which it connects, must know beforehand about services smartphone provide as a server. In the moment of connection client saves information about you, and use it later to work with you as a server.
It can be done only one a low level of BLE protocol implementation, so you cannot do this from another Android device using existing Bluetooth API.
Initializing GATT Server
To enable BLE peripheral role, we need to open GATT server using BluetoothManager instance, through OpenGattServer() method:
To observe BLE events as a server, we pass BluetoothGattServerCallback class implementation as a second parameter of OpenGattServer method. The approach is similar to one we used in first article with BluetoothGattCallback. Here is the example of gattObserver implementation:
These are not all callbacks, but they can be considered as main ones. Each callback is triggered in a response to corresponding BLE events, described further in the article.
Services of GATT Server
After GATT server is opened, you need to add services used by clients to retrieve data. Let’s create a service that will allow clients to write us some data and read them.
Firstly, we need to create characteristics that we would later associate with service.
In the constructor we pass characteristic UUID address, type of characteristic and client permissions. So, we specified one write characteristic allowing client to write us data, without waiting for response. Also, we will add read characteristic allowing client to read data, but only if it is paired with our smartphone, because of encryption.
Next step is to created service and associate our characteristics with it:
Finally, we can add created service to GATT server:
This would trigger OnServiceAdded callback indication whether operation was successful.
Interaction with client-device
When client device connects or disconnects from server, OnConnectionStateChange callback is triggered, providing connected/disconnected device, connection state and status.
When client sends a write request OnCharacteristicWriteRequest callback is triggered.
If client anticipates response, to know whether write command was successful or not, we call SendResponce method of BluetoothGattServer.
In the same way we can receive and handle characteristic read requests, descriptor write/read requests. Unfortunately, you cannot receive and handle characteristic notify requests, as it is not yet supported by Android versions 4.3 and 4.4.
In the last part of this article series you have learned about pairing between BLE devices and how it is done on Android, how make Android device play peripheral role and how receive and handle client data requests.
All code examples presented in this article are used in a demo project, which you can download here.