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
Related
Context:
I am working on a FIDO-U2F bluetooth authenticator with a nRF52 BLE SoC. and want it to test with google example.
So far I have implemented the FIDO Bluetooth specification and I have a device that advertises as a FIDO-compatible device.
Thanks to nRF Connect I have ensured that all the services and characteristics are correctly exposed and that I can interact with it only when my device is securely paired (with LTK):
Problem:
When the app scans for eligible FIDO device, it does not find mine.
I am stuck on the screen that ask to press a button for 5s, which I don't need to since my device responds to pairing request without user interaction and is already paired with my SAMSUNG A8.
I/BluetoothDevicePreference: onDeviceAttributesChanged :: Device = (N) D8BE86, isBonded = 12 , mIsOnProgressAddVI = false
I/Fido: [BleScanner] startScan()
E/Fido: [BluetoothPairingStateProvider] getUuids() returns null for device: D8:BE:86:4A:E5:65
I/Fido: [PreferredTransportProvider] BLE enabled but no device is paired
I/Fido: [AuthenticateBaseChimeraActivity] User selected transport ble
I/Fido: [ViewController] Accepting proposed view {"viewName":"ble_instructions","anyU2fDevicesPaired":false}: outranks current (2 > 0)
I/Fido: [ViewPresenter] viewSelected(...) ble_instructions
I/Fido: [U2fRequestController] onResultReceived(null, ErrorResponseData{errorCode=5})
I/Fido: [BleScanner] stopScan()
I tried to remove pairing data and all I have is:
I/BluetoothDevicePreference: onDeviceAttributesChanged :: Device = (N) D8BE86, isBonded = 10 , mIsOnProgressAddVI = false
The advertising flags are currently set to "BR/EDR not supported", but I also tried "LE Limited Discoverable Mode" and "LE General Discoverable Mode" without success.
I looked into android-fido sources but the BLE scan seems imported from elsewhere, I cannot debug it in this project.
Any pointer is welcome
Have you got to this screen?
We may need to add Service Data field (0x16) into advertising packet. This is mentioned in FIDO specification here
Android code snippet for advertising with Service Data field added:
AdvertiseData data = new AdvertiseData.Builder()
.addServiceUuid(new ParcelUuid(fido2GattService.getUuid()))
.setIncludeDeviceName(true)
.addServiceData(new ParcelUuid(fido2GattService.getUuid()), new byte[] {(byte)192, (byte)192, (byte)192})
.build();
If you want to capture bluetooth packets to see what is your advertising packet, you can use PacketLogger (for MacOS)
Here is the screenshot of the advertising packet
The red box is Service Data
Background:
I have a BLE peripheral with two modes: "Application" and "Bootloader". In both modes, the device advertises with the same MAC address.
To switch from one mode to the other, the BLE peripheral must reboot itself. In doing so, it has to disconnect any active BLE connection.
The BLE peripheral only stays in Bootloader mode for about 5 seconds. If nobody connects to it within that window, it switches to Application mode.
The Problem:
Android takes a very long time to reconnect to the BLE device, long enough that I'm missing the 5 second window. The raw code has a few layers down to the BluetoothGATT and BluetoothAdapter layers, but the sequence of calls boils down to:
BluetoothGattCharacteristic c = mCharacteristics.get(POWER_STATE_UUID);
c.setValue(SHUTDOWN_VALUE);
mBluetoothGatt.writeCharacteristic(c);
// Signalled by BluetoothGattCallback.onCharacteristicWrite
bleWriteCondition.await();
mBluetoothGatt.disconnect();
// Wait for the underlying layer to confirm we're disconnected
while( mConnectionState != BluetoothProfile.STATE_DISCONNECTED ) {
// Signalled by BluetoothGattCallback.onConnectionStateChange
bleStateCondition.await();
}
mBluetoothGatt.connect();
while (mConnectionState != BluetoothProfile.STATE_CONNECTED) {
// Signalled by BluetoothGattCallback.onConnectionStateChange
bleStateCondition.await();
if (bleStateCondition.stat != 0) {
break;
}
}
Am I going about this entirely the wrong way? I've tried calling close() on the BluetoothGatt instance, then generating a new one with BluetoothDevice.connectGatt, but I get the same extremely slow behavior.
I'm testing on a Samsung Galaxy S4, API level 21.
The problem here is that the gatt connect call issues a background connection request. It can take quite a long time for this call to result in a connection. A description of the two types of connection request is here : Direct vs Background connections
The absolute fastest way to get a connection is to do a scan and upon finding your device issue a direct connection request to it. As the scan has just found it, you know it is there and the connection will complete quickly. This is more complicated than your example code, but will be most effective given your small window. A scan is the most aggressive way to find a device. However, if you already have the device object, you could just call a direct connection request on the device.
Scans are issued using code like this :
scanner = bluetoothAdapter.getBluetoothLeScanner();
settings = new ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
.build();
filters = new ArrayList<ScanFilter>();
ScanFilter uuidFilter = new ScanFilter.Builder()
.setServiceUuid(YOUR_SERVICE_UUID).build();
filters.add(uuidFilter);
scanner.startScan(filters, settings, myScanCallback);
Upon finding your device (using the scan callback), issue a direct connection request via this method call :
myGatt = myDevice.connectGatt(this, false, myGattCallback);
The key part being the parameter of false. The connection request will time out in around 30s if the device is not found.
I'm trying to connect to a specific device using my Android APP, until now what I was able to do is get the paired items doing this :
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
Set < BluetoothDevice > pairedDevices = bluetoothAdapter.getBondedDevices();
if (pairedDevices.size() > 0) {
for (BluetoothDevice device: pairedDevices) {
mDeviceName.add(device.getName());
mDeviceMAC.add(device.getAddress());
}
}
bluetoothClass.setDeviceName(mDeviceName);
bluetoothClass.setDeviceMac(mDeviceMAC);
Where I get the MAC and the Device name of all of my paired devices. The thing that I would like to do is when I select one it connects to the Bluetooth device.
EXAMPLE
On a Samsung S4 when I turn on the Bluetooth it popups a Dialog whitch contains all of my paired devices and when I click on anyone it connects (I've i'm able to ...) so basically I want to do this, since now I've been getting the paired devices (I don't know if it's the best way to get that but it does) and then when user click on anyone it connects to the device.
It's something like this question but it's unfortunately unanswered.
It's impossible to give you an example within this format, so I have provided you
with a good sample and helpful links to help you understand the sample.
I recommend you follow the steps I have provided and then, when you have
specific problems, you can bring it here, with the code snippet you are having
difficulty with.
I recommend you use download this sample code:
http://developer.android.com/samples/BluetoothChat/index.html
If you haven't already, it's good to study this:
http://developer.android.com/reference/android/bluetooth/BluetoothDevice.html
This is a good tutorial and they have many tutorials:
http://www.tutorialspoint.com/android/android_bluetooth.htm
You will need the following permissions in your manifest:
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
This is one intent that is advisable to use, to check to see if BT is enabled:
if (!mBluetoothAdapter.isEnabled()) {
android.content.Intent enableIntent = new android.content.Intent(
android.bluetooth.BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
}
and to make your device discoverable to other devices:
if (mBluetoothAdapter.getScanMode() !=
android.bluetooth.BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
android.content.Intent discoverableIntent =
new android.content.Intent(
android.bluetooth.BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverableIntent.putExtra(
android.bluetooth.BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION,
300); // You are able to set how long it is discoverable.
startActivity(discoverableIntent);
}
As I mentioned in my answer here:
You can avoid using an intent to search for paired devices. When
connecting to a device that is not paired, a notification will pop up
asking to pair the devices. Once paired this message should not show
again for these devices, the connection should be automatic (according
to how you have written your program).
I use an intent to enable bluetooth, and to make my device
discoverable, I then set up my code to connect, and press a button to
connect. In your case, you will need to ensure your accessories are
discoverable also. In my case I use a unique UUID, and both devices
must recognise this to connect. This can only be used if you are
programming both devices, whether both are android or one android and
one other device type.
You will need to understand how to use sockets, this is how the devices communicate.
I recommend studying these two links:
http://developer.android.com/reference/android/bluetooth/BluetoothSocket.html
http://developer.android.com/reference/android/bluetooth/BluetoothServerSocket.html
Sockets are used to set up connections between devices. There will be a server socket and device sockets (determined by many factors, the programmer, the actual devices). The server socket listens for incoming connections, when a connection is accepted the devices connect, each with a simple socket.
I am not sure how much you know about threading.
The connection needs to be managed with threads:
http://developer.android.com/guide/components/processes-and-threads.html
http://android-developers.blogspot.com.au/2009/05/painless-threading.html
The connection between the devices is managed on threads separate from the User
Interface thread. This is to prevent the phone from locking up while it is
setting up, seeking and making a BT connection.
For instance:
AcceptThread - the thread that listens for a connection and accepts the connection (via the serversocket). This thread can run for an extended time waiting for a device to connect with.
ConnectThread - the thread that the device connecting to the server uses to connect to the serversocket.
ConnectedThread - this is the thread that manages the connection between both sockets.
Let me know if this helps you.
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.
I am working on using the BT 4.0 API that Motorola has provided with the RAZR. In one of their documents it states to use the Android API to pair before connecting and using their framework. Per their instructions I have been pairing with OS Bluetooth settings application, but it never prompts me for a key. It will pair but doesn't appear to bond, and this is critical for me.
My question is, when they say "using the Android API" is this referring to simply using the OS Bluetooth utility to pair before hand (like I have been doing), or is there some way to do it with code in my application. They reference the "createBond()" function which, to my knowledge, is not an accessible function (at least not without some squirrely libraries or reflection).
Any advice is greatly appreciated, especially anyone who has used the API successfully, if they could give an account of their process. I'm just looking for some clarity at this point :)
Lloyd,
You are correct, follow the instructions in the link you posted.
Outside of coding, when they say use the standard android api for "non-le" operations, they mean go ahead and pair the ble device the same way you would any bluetooth classic devices inside android settings -> wireless & network -> bluetooth -> scan for devices.
If the device you are using is a motorola le compatible device the ble device will be paired but not connected.
Now, in the code, you can detect this paired device through the same method of
BluetoothAdapter.getDefaultAdapter().getBondedDevices()
To double check if your Android Phone is LE compatible, run this code:
public static boolean checkBLESupport() {
boolean deviceSupportsLE;
try {
#SuppressWarnings({ "unused", "rawtypes" })
Class object = Class.forName("android.server.BluetoothGattService");
deviceSupportsLE = true;
} catch (Exception e) {
deviceSupportsLE = false;
}
return deviceSupportsLE;
}
And to double check if the bluetooth device you paired is LE, when you are looping through the bonded devices.
Check the device with this code.
if (device.getBluetoothClass() == null) {
Log.i(TAG, "This device is BLE compatible");
b = true;
} else {
Log.i(TAG, "This device is not BLE");
b = false;
}
Now for establishing connection from your LE compatible phone to your LE compatible bluetooth device, follow the Gatt service instructions under the link you posted. http://developer.motorola.com/docs/bluetooth-low-energy-api/
Take note that under this example it is connecting to a bluetooth low energy heart rate monitor.
If you are not trying to connect to the heart rate monitor with LE heart rate profile, here is a link to another Motorola document that details creating your own LE Profile to use with the GATT framework. http://developer.motorola.com/docs/bluetooth-low-energy-gatt-framework-api/
If the instructions are not clear enough at any point in either of these documents, motorola offers sample android applications using the frameworks in those documents.
I guess motorola stack has BLE support. But what i feel is that it does not pair with the devices that require bonding though It does work some sensors. I have tried with a proximity sensor that require bonding. It never gets paired though the devices is discovered with Razr which even does not with S3.
There's a helpful video here.
Late to the game, but can confirm -
If your BLE Peripheral requires bonding, Moto X - and some other older Motorola devices - MUST be paired via Bluetooth Settings prior to programmatic connection via the Android GATT interface.
If you bond via the createBond method, or reading of an encrypted characteristic, your connection will be dropped typically in under 60 seconds, despite DDMS logs that show a good bond may be established.