I'm trying to programmatically pair a phone to a bluetooth device. Although I am able to do so, a window still pops up asking the user to enter the PIN.
Is there any way to hide this window?
What I'm doing:
Getting a BluetoothDevice object of the target;
Attempt to create a bond:
Class class1 = Class.forName("android.bluetooth.BluetoothDevice");
Method createBondMethod = class1.getMethod("createBond");
createBondMethod.invoke(device);
Listening to BluetoothDevice.ACTION_PAIRING_REQUEST I attempt to set the Pin:
Method m = device.getClass().getMethod("setPin", byte[].class);
m.invoke(device, pin);
device.getClass().getMethod("setPairingConfirmation", boolean.class).invoke(device, true);
Although I am aware Android might not give us this option due to malicious software, I'd very much like to hide the window that asks for the PIN (it's not necessary because the bonding is complete even when the user doesn't enter any data into that window) since my app targets kids, they might not be able to complete the pairing themselves.
Related
I am developing an Android application, where I use Bluetooth Low Energy.
My code logic includes using the BluetoothAdapter and method getRemoteDevice(MAC-adddress).
The problem is that when I use this method, Android seems to have cached it. Because when I am not close or the device is not on, it still creates the BluetoothDevice-object with the name and all that. But I cannot connect ofcourse.
How can I prevent Android from caching this old BluetoothDevice?
I have tried reflection with
Method m = device.getClass().getMethod("removeBond", (Class[]) null);
m.invoke(device, (Object[]) null);
But it wont yield any better result.
Thank you!
According to the documentation for getRemoteDevice:
A BluetoothDevice will always be returned for a valid hardware
address, even if this adapter has never seen that device.
So, it is not caching the result, it is just creating a dumb BluetoothDevice object, which has no idea if that MAC address even exists.
You could attempt to connect to the GATT service of the device, or start discovery, or use the LE scanner object, and use the appropriate callback to check if the connection has succeeded or not.
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
Is there any way for Android to connect to a Bluetooth device using a specific port instead of using service UUID?
I know this option is available in other platforms which provide Bluetooth support (Java ME for example by specifying a "btspp://" style URL).
Thanks!
Ok, it's been a while, but I found a solution to the problem. I actually intended to give up and use UUID, but I kept getting a Service Discovery Failed (IO)exception, and when I tried to find a solution to the service discovery issue, I found the solution to my original question... Ain't life something?:)
Anyways, this is the link I stumbled upon, though you should note there is a mistake in the answer (they actually simply connected to port 1, instead of using a service UUID).
And after this short history lesson, here is the solution:
Using reflection, it is possible to create the Rfcomm socket connecting to a port number instead of UUID:
int bt_port_to_connect = 5; // just an example, could be any port number you wish
BluetoothDevice device = ... ; // get the bluetooth device (e.g., using bt discovery)
BluetoothSocket deviceSocket = null;
...
// IMPORTANT: we create a reference to the 'createInsecureRfcommSocket' method
// and not(!) to the 'createInsecureRfcommSocketToServiceRecord' (which is what the
// android SDK documentation publishes
Method m = device.getClass().getMethod("createInsecureRfcommSocket", new Class[] {int.class});
deviceSocket = (BluetoothSocket) m.invoke(device,bt_port_to_connect);
A few things to notice:
since we're using Invoke, the first parameter is the object we're invoking the method on, the second parameter of invoke is actually the first function parameter)
There is also a secure version available ('createRfcommSocket'), which accepts a bluetooth channel number as a single parameter (again, since this is invoke style, you'll need to pass the object to invoke the method on, as mentioned in -1- )
I found what appears to be a link to these functions' prototypes
Good luck to all.
Bluetooth Android connections are exclusively done via UUID. Each Bluetooth device has a UUID for every service it runs (see Bluetooth SDP).
You just give Android the UUID to watch for and, in client mode, it will find a socket to connect to automatically (including port). In server mode, it will wait for the specified device to initiate a connection using the specified UUID.
The BluetoothSocket object is also valid when connection is established (use getInput/Output Stream)
See Server Socket documentation and Client Socket documentation.
If you really want to check everything, you can see what Android decodes from the other device's SDP and the UUID you provided.
Use this tutorial to get the Bluetooth interface (very easy to do).
Then the code should look something like this:
IBluetooth ib =getIBluetooth();
Int otherDevicePort = ib.getRemoteServiceChannel(otherDeviceAddress, UUID);
I'm using bluecove which allow me to do so with the function Connector.open().
I use the following url:
btspp://" + phoneID + ":" + phonePort
N.b.: Some options can be added (e.g.: authenticate=false; or encrypt=false;).
With phoneID being the the being the Bluetooth address and phonePort the port number.
How to find the Bluetooth address?
From this link:
From the Home screen, open the app drawer, then open “Settings“.
Select “System“. (Skip this step on some models)
Scroll down to the bottom and tap “About Phone“, “About device“, or “About tablet“.
Scroll down to the bottom and tap “Status“.
Scroll down and the “Bluetooth address” will be shown in the list.
How to find the port number?
I haven't been able to find which port is supposed to be used yet...
I used 5 and it works but I need to research why and if I want to change the phone I will need to know if I also need to change the port.
I have an app where I am programmatically controlling Bluetooth pairing and unpairing. I can pair before connection and unpair afterwards. The reason I need to do this is specific to my application and not in the scope of my question.
Basically what I am doing is:
Get a reference ib to IBluetooth object as described in this answer
Register a BroadcastReceiver for android.bluetooth.device.action.PAIRING_REQUEST
Call ib.createBond(address)
Wait for BroadcastReceiver to trigger
Convert user pin into bytes with convertPinToBytes()
Call ib.setPin(address, pinBytes) from within BroadcastReceiver
Anyways, this approach works great, except for the fact that when I do the pairing, I get a notification in the Status bar requesting that the user enter a PIN to complete the pairing. But this is in fact unnecessary, because by the time the user sees this, my app has already used setPin(). I'd really like for that notification to either a) not appear at all, or b) be dismissed automatically somehow.
I realize this may not even be possible, but I thought I would ask in case someone has a creative idea.
Try setting the confirmation first in the PAIRING_REQUEST
BluetoothDevice device = intent.getParcelableExtra("android.bluetooth.device.extra.DEVICE");
device.getClass().getMethod("setPairingConfirmation", boolean.class).invoke(device, true);
device.getClass().getMethod("cancelPairingUserInput").invoke(device);
This worked for me between two Android devices using RFCOMM but I'm not entering any PINs
Since Android API 19 Google switched these Methods to public Methods, so there is no need for Reflection any more. :)
Do this in the PAIRING_REQUEST notification event:
BluetoothDevice localBluetoothDevice = (BluetoothDevice)intent.getParcelableExtra("android.bluetooth.device.extra.DEVICE");
Class localClass = localBluetoothDevice.getClass();
Class[] arrayOfClass = new Class[0];
localClass.getMethod("cancelPairingUserInput", arrayOfClass).invoke(paramBluetoothDevice, null)).booleanValue();
But you gotta tell me how did you pair your remote device without the user to enter Passkey/PIN? off course, you know the PIN for the remote device which is trying to pair to your device but how did you provide that PIN to the remote device.
My android application is in blueotooth SPP server mode and listening for client devices,
my application knows the passcode required for pairing of that devices.
My question is,
Is it possible to handle pairing request through application.
Thanks and Regards.
No - because from a security point of view it is important for the user to be aware of pairing. The idea is that devices are paired and bonded once, then onwards connections happen automatically initiated by applications without need for re-pairing (or user intervention)
Yes, it is possible to do pairing through application. I did pairing in my application.
for this you have to made IBluetooth interface object accessible by this way:
IBluetooth mBluetoothService;
Field fie = Class.forName(bluetoothAdapter.getClass().getName()).getDeclaredField("mService");
fie.setAccessible(true);
mBluetoothService = (IBluetooth) fie.get(bluetoothAdapter);
By using this object you can pair with device using IBluetooth interface functions.
(normal Sequence for Auto Pairing)::
mBluetoothService.setPin(deviceAddress, PIN);
mBluetoothService.setTrust(deviceAddress);
mBluetoothService.createBond(deviceAddress);
mBluetoothService.setPairingConfirmation(deviceAddress, false);
mBluetoothService.cancelPairingUserInput(deviceAddress);
By using those function you can pair with any BT device programmatically.