I was working with a BLE device, which needs to set the device time during pairing. Writing to the time characteristic in any other time does not effectively set the time.
Currently I am using the Android OS's Bluetooth Manager for pairing. And the progress of pairing is notified to my app through broadcast intent.
public void onReceive(Context context, Intent intent) {
....
switch (action) {
case BluetoothDevice.ACTION_BOND_STATE_CHANGED:
if(state == BluetoothDevice.BOND_BONDED){
//Write to the Date-Time Characteristic
}
else if(state==BluetoothDevice.BOND_BONDING){
}
else if(state==BluetoothDevice.BONE_NONE){
}
....
}
...
}
My question is how to inject code to the position commented above to complete the Date-Time setting? Apparently, the Android OS Bluetooth Manager does not set the time during its entire pairing process. Does Android allow two applications (OS Bluetooth Manager and my application) write to the remote gatt within a single connection session?
It may not possible for you to write the data-time i.e. the characteristic during the pairing procedure(well if you do not need pairing that should be fine). Reason is that you may first get service and get characteristic handle then write it, this may not happen with the same time of the pairing; it depends your remote device's security level setting.
My question is how to inject code to the position commented above to complete the Date-Time setting?
You can register a broadcast receiver to receive the bonding event.
Does Android allow two applications (OS Bluetooth Manager and my application) write to the remote gatt within a single connection session?
Sure, because you are using the same BluetoothAdapter :-)
Related
I am having a Arduino with BLE which has to send some data to any/all android phones over Bluetooth in it's range. My android phone should have a app which i intend to make will notify about data received.
How can i make such android app which auto-connects to any nearby BLE , if found without pairing even for first time and exchange data. I mean how in any application i can implement auto-connect without key pairing.I found that setting autoconnect=true will do this task , but i am not sure.
Any help, even some resource i will refer and clear my doubts.
The pre-requisites and steps are (code snippets in Java):
HC-XX module or similar BLE-device on the Arduino-side set to security mode 1 and security level 1 (no security AND no pairing)
Android 4.3 (API level 18) with built-in platform support for Bluetooth Low Energy (BLE)
Check on the device (mobile) that BLE is enabled
// Ensures Bluetooth is available on the device and it is enabled. If not,
// displays a dialog requesting user permission to enable Bluetooth.
if (bluetoothAdapter == null || !bluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
Find the BLE device(s). You use the startLeScan() method. This method takes a BluetoothAdapter.LeScanCallback as a parameter. You must implement this callback, because that is how scan results are returned. Because scanning is battery-intensive, you should observe the following guidelines:
As soon as you find the desired device, stop scanning.
Never scan on a loop, and 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.
If you want to scan for only specific types of peripherals, you can instead call startLeScan(UUID[], BluetoothAdapter.LeScanCallback), providing an array of UUID objects that specify the GATT services your app supports.
The first step in interacting with a BLE device is connecting to it— more specifically, connecting to the GATT server on the device. To connect to a GATT server on a BLE device, you use the connectGatt() method. This method takes three parameters: a Context object, autoConnect (boolean indicating whether to automatically connect to the BLE device as soon as it becomes available), and a reference to a BluetoothGattCallback.
// Here we set autoconnect to true
bluetoothGatt = device.connectGatt(this, true, gattCallback);
To sum up auto connect alone will not do the job as you want no pairing. So security mode 1 and security level 1 (no security at all) has to be set. So make sure by using software sided encryption/auto sign-in that no unauthorized persons use your device
Read more about BLE in Android in detail here
Read more about BLE security in detail here
Is it possible to automatically connect to Bluetooth Low Energy (BLE) devices?
The Android documentation indicates that the [BluetoothDevice.connectGatt()](https://developer.android.com/reference/android/bluetooth/BluetoothDevice.html#connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback)) has a autoConnect parameter:
boolean indicating whether to automatically connect to the BLE device
as soon as it becomes available
However, to call this, you need a BluetoothDevice first. AFAIK the only way to get this is by scanning available devices. Setting up a scan every time to connect to a device doesn't seem like a desirable way. Also, I tried using nRF Control Master Panel to connect to my peripheral using the autoConnect = true, but this does not connect to the device. Connecting without the autoConnect however does make it connect, and I've managed to read and write data from and to my peripheral this way with success.
The general way in Bluetooth to have two devices paired. However, searching for my BLE device and using BluetoothDevice.createBond() does not seem to work. In my ACTION_BOND_STATE_CHANGED-callback, the EXTRA_BOND_STATE and EXTRA_PREVIOUS_BOND_STATE just go from BOND_BONDING to BOND_NONE and back. I don't read out an error or anything - so maybe I'm missing something here. Here's the callback:
private final BroadcastReceiver mGattUpdateReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(action)) {
final int state = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.ERROR);
final int prevState = intent.getIntExtra(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE, BluetoothDevice.ERROR);
Log.e(TAG, "prevState " + prevState + ", state " + state);
}
}
};
So this type of bonding does not seem to work.
My question is: am I doing something wrong for pairing or the autoConnect? Or is how I currently have it working the only correct way? It seems like a real pain (and battery-drain) to have to scan for devices every time, see if the device is there, if so read data and check back tomorrow, otherwise check back in an hour or so. The point of Bluetooth is that it should pair directly whenever it is near, isn't it?
It does work without rescan. You do not need pairing at all. Just call BluetoothGatt.connect() again for gatt object you aquired from first connection.
You will receive onConnectionStateChange event in your BluetoothGattCallback as soon as ble device will be available again. If you use autoconnect option, you don't even need to call BluetoothGatt.connect() method. Just monitor your cllback, and don't forget to close BluetoothGatt with close() if you don't see any connection for too long.
And yes, to obtain first connection you should scan for ble devices with BluetoothAdapter.startLeScan, not the common bluetooth devices scan.
using the android 4.4 BLE APIs on my Nexus7, i'm able to successfully interact with a peripheral BLE device -- connect, disconnect, read, write....
if however an active connection breaks for whatever reason (in this case, the peripheral is reset), i observe the following behavior....
my peripheral (by design) begins advertising after any active connection is terminated (for whatever reason); i can see this via my bluetooth packet sniffer....
i receive the onConnectionStateChanged callback as expected in my android app, at which point i invoke close() on my active BluetoothGatt instance; this is the same procedure i follow during a "normal" disconnect initiated from the client...
shortly after this, the android BLE stack tries to re-connect to the same peripheral; through the packet sniffer i can see the BLE connection request going out over the air...
my app, however, did not initiate this re-connection; indeed, i see no information from any bluetooth log suggesting this even happened!!!!
is there some "mode" in the BLE stack where it attempts to re-establish busted connections automatically???
thanks....
This happens on various Android phones whether the autoConnect flag is set to false or true.
Couldn't yet find a complete solution, it seems as the android BLE stack is spontaneously re-initiating the connection once it is getting the advertising signal again, just ignoring that it was the app that disconnected on purpose...
A partial solution may involve not using the BluetoothGatt.connect() method as explained here:
https://stackoverflow.com/a/23749770/4144487
So, a sample connect method can look like:
void connect(Context context) {
if (mGatt != null) {
mGatt.close();
}
mGatt = mDevice.connectGatt(context, false, callback);
}
To explain the importance of this issue, when it happens the peripheral thinks it is connected and my "real" app can't find it any more. At some phones like Galaxy S3 and Redmi note 3 I found that closing the bluetooth switch from the notification bar is "releasing" the peripheral and allowing me to discover the device. At others like Nexus 5x only a phone reboot will do the trick.
I've observed this happening if you use autoConnect=true when calling BluetoothGatt#connectGatt(). Generally I've found that it is best to use autoConnect=false, but with some devices you simply cannot connect unless you use true, so I usually do both. I try false first and if that fails then use true and then the behavior you're describing is something you simply have to work around.
Everywhere I look I find this method "getBondedDevices()" for my bluetooth adapter. However, I have my tablet and another bluetooth device sitting next to me, and I can't figure out how to actually get the device to show up on the list of bonded devices.
In Bluetooth terms, "bonded" and "paired" are basically synonyms (officially, the process of pairing leads to a bond, but most people use them interchangeable). In order for your device to be added to that list, you must go through the process of Discovery, which is how one device searches and finds another, and then Pair the two together.
You can actually do this from the device settings as a user, but if you are looking to so so within the context of an app, your process will likely look something like this:
Register a BroadcastReceiver for BluetoothDevice.ACTION_FOUND and BluetoothAdapter. ACTION_DISCOVERY_FINISHED
Start discovery by calling BluetoothAdapter.startDiscovery()
Your receiver will get called with the first action every time a new device is found in range, and you can inspect it to see if it's the one you want to connect with. You can call BluetoothAdapter.cancelDiscovery() once you've found it to not waste the battery any more than necessary.
When discovery is complete, if you haven't canceled it, your receiver will get called with the second action; so you know not to expect any more devices.
With a device instance in hand, open a BluetoothSocket and connect(). If the devices are not already bonded, this will initiate pairing and may show some system UI for a PIN code.
Once paired, your device will show up in the bonded devices list until the user goes into settings and removes it.
The connect() method also actually opens the socket link, and when it returns without throwing an exception the two devices are connected.
Now connected, you can call getInputStream() and getOutputStream() from the socket to read and write data.
Basically, you can inspect the list of bonded devices to quickly get access to an external device, but in most applications you will be doing a combination of this and true discovery to make sure you can always connect to the remote device regardless of what the user does. If a device is already bonded, you'd just be doing steps 5-7 to connect and communicate.
For more information and sample code, check out the "Discovering Devices" and "Connecting Devices" sections of the Android SDK Bluetooth Guide.
HTH
API level 19 and above you can call createBond() on BluetoothDevice instace to which you want to connect.
You will require some permissions to discover and list the visible devices
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
Code to discover and list the devices:
bluetoothFilter.addAction(BluetoothDevice.ACTION_FOUND);
bluetoothFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
bluetoothFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
registerReceiver(bluetoothReceiver, bluetoothFilter);
private BroadcastReceiver bluetoothReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
Log.e("bluetoothReceiver", "ACTION_FOUND");
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
devicesList.add((device.getName() != null ? device.getName() : device.getAddress()));
bluetoothDevicesAdapter.notifyDataSetChanged();
} else if (BluetoothAdapter.ACTION_DISCOVERY_STARTED.equals(action)) {
Log.e("bluetoothReceiver", "ACTION_DISCOVERY_STARTED");
} else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
Log.e("bluetoothReceiver", "ACTION_DISCOVERY_FINISHED");
getActivity().unregisterReceiver(bluetoothReceiver);
}
}
};
Just call createBond() on selected device.
I need to continuously poll for getting bluetooth devices connections/disconnections in my activity to update a listView with the currenctly available devices.
I use btAdapter.startDiscovery() but it is not permanent ... how can i correctly get the on/off events for the devices?
I would suggest using a broadcastreceiver to listen for the specific events you are talking about. You could even fire off another discovery mode after it comes out of its current discovery mode to have it keep scanning
BluetoothAdapter.ACTION_DISCOVERY_FINISHED
BluetoothDevice.ACTION_ACL_CONNECTED
BluetoothDevice.ACTION_ACL_DISCONNECTED
You can use the intent extra's to be able to get the name (ect) from the device that connects
I would read http://developer.android.com/guide/topics/wireless/bluetooth.html and
http://developer.android.com/reference/android/content/BroadcastReceiver.html