Is Bluetooth OOB pairing really supported in Android? - android

I am a complete newbie to the world of Android.Please forgive me if my question is too naive.
I have been working on a sample application to realize Bluetooth pairing between a Linux Box (FC-21 running Bluez-5.42) and an Android tablet. I am using NFC to transfer the Bluetooth name, address and OOB data from the PC to Android.
I am able to send the above data from PC to Android over NFC (beam to be precise) and I am able to parse and decode all the data at the Android side.
With the Bluetooth address of the Linux box available at Android, I can call CreateBond() to pair the Android tablet with Linux Box. I have tested this part and it works as expected.
Now, the problem with this method is that, during Bluetooth pairing Numeric comparison or passkey entry association model is used, which I feel is an aberration to the user experience when he is using NFC to do the pairing.
Since I already have the OOB data of the PC, I would like to use the OOB association for pairing such that the user experience is not compromised.
To do this, when I replace CreateBond() with CreateBondOutOfBand() [using reflection], no pairing request is sent from Android to the Linux PC.
try {
showLog("Pairing started");
Method m = bDev.getClass().getMethod("createBondOutOfBand", byte[].class, byte[].class);
showLog("Found method");
Boolean flag = (Boolean) m.invoke(bDev, Hash, Rand,(Object[]) null);
//Method m = bDev.getClass().getMethod("createBond", (Class[]) null);
//Boolean flag = (Boolean) m.invoke(bDev, (Object[]) null);
if(flag)
showLog("Pairing successfully finished.");
else
showLog("Pairing failed");
} catch (Exception e) {
showLog("Pairing failed.");
}
I searched online but could not find any concrete evidence that OOB pairing can be implemented in Android.
Further, to check the behavior of native Android, I created a NFC tag with the Bluetooth name, address and OOB data of the Linux box. When I held the tag against the Android tablet, Bluettoth pairing was started but it was still not using OOB association model.
My questions are as follows,
Is OOB association model really supported on Android?
If OOB association model is supported, is CreateBondOutOfBand() the
API to be used or is there any other API that I need to use?
Any inputs would be greatly appreciated.
Thanks,
Sai

According to this,
Android 9 introduces new restrictions on the use of non-SDK
interfaces, whether directly, via reflection, or via JNI. These
restrictions are applied whenever an app references a non-SDK
interface or attempts to obtain its handle using reflection or JNI.
Since createBondOutOfBand() and removeBond() are hidden from public documentation, these methods are restricted from Android 9. Calling these methods using reflection will cause exceptions.

I don't use NFC but I use reflection to use createBondOutOfBand.
In addition, this code does work on Motorola lineage rom 7.1 (on Moto G4 play and Moto E 2015) and on Samsung official rom 7.0 (Galaxy S6), but does not work on LG G5 or G6 official rom 7.0 (the authentication always fails).
Here is my code (not really different from yours #saai63).
private boolean createBondOutOfBand(final byte[] oobKey) {
try {
if (DEBUG) {
Log.d(LOG_TAG, "createBondOutOfBand entry");
}
Class c = Class.forName("android.bluetooth.OobData");
Constructor constr = c.getConstructor();
Object oobData = constr.newInstance();
Method method = c.getMethod("setSecurityManagerTk", byte[].class);
method.invoke(oobData, oobKey);
Method m = mBluetoothDevice.getClass().getMethod("createBondOutOfBand", int.class, c);
boolean res = (boolean)m.invoke(mBluetoothDevice, BluetoothDevice.TRANSPORT_AUTO, oobData);
if (DEBUG) {
Log.d(LOG_TAG, "createBondOutOfBand result => " + res);
}
return res;
}
catch (Exception e) {
Log.e(LOG_TAG, "Error when calling createBondOutOfBand", e);
return false;
}
}

Related

How to Programmatically Clear Bluetooth Cache using GattServer

I'm slightly familiar with BLE and I am facing some problem with an inherited code. So the app works like that:
With BLE enabled the app scans for devices
The app displays the devices found
The user selects the device to pair with
The app pairs with the device
The problem I'm facing is that after pairing several times (it varies) the phone is not able to discover devices, hence blocking the user to pair.
I'm using GattServer to connect with the client device, and I'm reseting the services as below:
public void resetBluetoothGattServer() {
Log.i(TAG," resetBluetoothGattServer: bluetoothGattServer: "+ bluetoothGattServer);
if (bluetoothGattServer != null) {
if(!bluetoothGattServer.getServices().isEmpty()){
Log.i(TAG," resetBluetoothGattServer: clearing services on bluetooth Gatt Server");
bluetoothGattServer.clearServices();
}
Log.i(TAG," resetBluetoothGattServer: closing bluetoothGattServer");
bluetoothGattServer.close();
}
bluetoothGattServer = openGattServer();
}
Restarting the phone, turning bluetooth off and then back on, and uninstalling and installing the app won't fix the problem. The only solution is to clear the cache from the Bluetooth Share app on the android apps manager.
This post How to programmatically force bluetooth low energy service discovery on Android without using cache adresses to a similar problem but since we are not using BluetoothGatt to connect it's no a suitable solution. Neither will be to refactor the whole inherited code.
I'm asking you if there is a way to clear the cache programmatically using BluetoothGattServer.
One solution - solve this issue using reflection.
private void refreshDeviceCache(BluetoothGatt gatt) {
try {
Method localMethod = gatt.getClass().getMethod("refresh");
if(localMethod != null) {
localMethod.invoke(gatt);
}
} catch(Exception localException) {
Log.d("Exception", localException.toString());
}
}
Note : I am not recommended this way

Android Bluetooth PIN pairing without user interface on Android 4.2+

There are similar questions to this here already, but the answers and suggestions relate to older versions of Android. I understand that the bluetooth stack has been completely revised from 4.2 onwards and older solutions do not work anymore.
I have tried all the older solutions to no avail. the use of the private APIs no longer works because they have changed. I dont mind using private APIs but it must work on the newest versions and later (ie API 17+)
I am trying to do the following:
set up a bluetooth pairing between an Android device and an embedded device using legacy PIN pairing without the embedded device being discoverable nor the user having to manually enter the PIN. In fact I want no PIN entry dialog box at all.
The plan is that the two devices have a predefined shared secret PIN, so that I can perform the pairing programmatically and then open an RFCOMM connection between them. All of this without UI. The hardware address of the embedded device is known to the Android program.
There is no security issue here. the project involves just talking to a nearyby, small embedded device through BT as simple as possible.
Ideas that might work on Android 4.2 (Jelly Bean) most welcome, thanks.
turns out some of the problem was inside the embedded device. on the Android side, the following works:
BluetoothSocket s = null;
try
{
s = device.createInsecureRfcommSocketToServiceRecord(SerialPortServiceClass_UUID);
}
catch (IOException e)
{
Log.e(TAG, "BT connect failed", e);
return false;
}
where
private static final UUID SerialPortServiceClass_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");

Android bluetooth setpin function

My Android device is trying to connect to a sensor via Bluetooth.
As a normal Bluetooth device, I will need to pragmatically set up the pin code (usually 0000 or 1234)
for the sensor side since it is silent and would not pop up the request dialogue.
I did not find any related clue on the Android dev site.
Does anyone can tell me if there is any approach available to achieve this?
To set the PIN, you can call by reflection the hidden method setPin(byte[]) from the BluetoothDevice class.
Example:
try {
Log.d("setPin()", "Try to set the PIN");
Method m = device.getClass().getMethod("setPin", byte[].class);
m.invoke(device, pin);
Log.d("setPin()", "Success to add the PIN");
} catch (Exception e) {
Log.e("setPin()", e.getMessage());
}
Where device is your BluetoothDevice and pin a byte[] array which contains the bluetooth device pin.
But I think, you'll prefer to use the method setPasskey(int). It would be easier for you because you want to set a passkey like "0000" or "1234".
[UPDATE]
Previous source links are dead and the class has been updated. Apparently setPasskey does not exist anymore. Follow the documentation link below to find the information you need.
Sources: BluetoothDevice Android documention

Android Bluetooth Low Energy Motorola API pairing

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.

Unable to accept incoming Bluetooth connection in Android

Maybe similar to the unanswered thread here, but we have an Android application (tested on multiple handsets and multiple Android 2.1+ versions) which needs to listen for and accept connections from a remote bluetooth device. The remote device is a digital pen, but the main point is that the pen is paired with the phone and then sends data via SPP, which uses OBEX, which uses RFComm so all that should be fine.
Currently the application works by allowing the Android device to receive the OBEX payload and then get the app to look in the bluetooth folder to pick up the payload, but we want the application to be able to talk directly to the remote device. Keep in mind the remote connects to the android phone, the phone does not connect to the pen.
Our test code is based on the sample BluetoothChat application available in the Android samples, but essentially adapter.listenUsingRfcommWithServiceRecord never gets called and the best that we see in the Motorola Defy+ DDMS logs is:
INFO/BtOppRfcommListener(2577): Accepted connectoin from 00:07:CF:55:94:FB
INFO/BtOpp Service(2577): Start Obex Server
DEBUG/Obex ServerSession(2577): java.io.IOException: Software caused connection abort
This appears to show that the connection is accepted by Android but not made available to the application. The UUID used is the same UUID used in the JME version of the same application and was provided by the pen supplier.
The most common mistake we android developers do while copying BluetoothChat app code is we don't follow the flow of that app.
The common errors while implementing this code, like "Service Discovery Failed", "Software caused connection abort", "Connection aborted by peer", "Unable to start Service Discovery" , "Connection Lost" is the outcome of neglecting the flow.
I have faced all these issues while implementing the BluetoothChat code in my app and the solution was to correct the flow.
For example in my case :
OnCreate:
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
OnStart:
if(this.mChatService == null)
this.mChatService = new BluetoothChatService(this, mHandler);
OnResume:
if ((mChatService != null) && (mBluetoothAdapter.isEnabled())) {
// Only if the state is STATE_NONE, do we know that we haven't started already
if (mChatService.getState() == BluetoothChatService.STATE_NONE) {
// Start the Bluetooth chat services
mChatService.start();
}
}
OnDestroy:
if(mTransferService != null) mTransferService.stop();
onActivityResult:
case REQUEST_CONNECT_DEVICE:
// When DeviceListActivity returns with a device to connect
if (resultCode == Activity.RESULT_OK) {
if (mChatService.getState() == BluetoothChatService.STATE_NONE) {
// Start the Bluetooth chat services
mChatService.start();
}
if(mChatService .getState() != BluetoothChatService.STATE_CONNECTED){
String address = data.getExtras().getString(ViewContactList.EXTRA_DEVICE_ADDRESS);
// Get the BLuetoothDevice object
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
device = mBluetoothAdapter.getRemoteDevice(address);
// Attempt to connect to the device
mChatService.connect(device);
}
else{
if(messageString.length() > 0)
MyCurrentActivity.this.sendMessage(messageString);
}
In simple words, implement the code in such a way both devices are in mState = STATE_LISTEN , before you will call
mChatService.connect(device);
In our case the only solution we found which could reliably accept Bluetooth OPP data from a remote device was to use the 'hidden' Android API. If you check the Android source, there are additional methods defined which are annotated #hide which excludes them from the exported Android jar and the API docs.
Using these methods should be avoided if possible and are not guaranteed to be consistent across Android versions.
There are two ways to include these in your code:
use reflection
include an additional development JAR at compile time which exposes these methods, but make sure this JAR is not packaged with your application.
We opted for #1 as our requirements were minimal.
Access the Method
Class<?>[] args = new Class[] { int.class };
Method listenMethod = BluetoothAdapter.class.getMethod(listenMethod, args);
Where the method name is one of (in order of preference) listenUsingEncryptedRfcommOn, listenUsingRfcommOn or listenUsingUnencrytptedRfcommOn
Create a server socket
BluetoothAdapter target = *your adapter, probably the default one*;
BluetoothServerSocket sock = (BluetoothServerSocket) (listenMethod.invoke(target, new Object[] { channel }));
Where in our case the OPP channel is 12
Fin
Provided you manage to get a BluetoothServerSocket back (exception handling is omitted, your mileage may vary, user discretion advised, no warrantee provided etc etc) you should be able to use it to listen for incoming OPP data.

Categories

Resources