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
Related
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;
}
}
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.
My android app requires connecting to a bluetooth printer (Zebra Bt Printer) to print tickets, this printer doesn't require authentication (it's set Authentication:OFF), but i cant create a connection with it because the app asks to make pairing by entering a pin, i've tried default values like 0000 and 1234 but any of them works.
This is the code i use to create a connection with the printer:
Set<BluetoothDevice> devices = bluetoothAdapter.getBondedDevices();
for (BluetoothDevice device : devices) {
if (device.getAddress().equals(PRINTER_DEVICE_MAC_ADDRESS)) {
bluetoothDevice = bluetoothAdapter.getRemoteDevice(PRINTER_DEVICE_MAC_ADDRESS);
if (bluetoothDevice != null) {
try {
clientSocket = bluetoothDevice.createRfcommSocketToServiceRecord(uuid);
clientSocket.connect();
} catch (IOException e) {
e.printStackTrace();
}
}
}
When it executes the line :
clientSocket.connect();
is where appears the dialog for entering the pin for making the connection with the device, but i dont know what code to enter or how to avoid this dialog.
-I'm using Galaxy Tab 3 with Android 4.1.2
-Developing in Api 14
Zebra offers Android SDKs for use with their printers. Specifically, There's a BluetoothConnectionInsecure class that allows you to connect to your printers without having to provide pairing information: http://www.zebra.com/us/en/products-services/software/link-os/link-os-sdk.html. Full samples are included in the JavaDoc.
If you cannot use the SDK, then BitBank's suggestion of using CreateInsecureRfCommSocket() is a good choice to make. Here are some articles concerning its usage:
http://developer.android.com/reference/android/bluetooth/BluetoothDevice.html#createInsecureRfcommSocketToServiceRecord(java.util.UUID)
How to create Insecure RFCOMM Socket in Android?
I want to create a p2p connection between a normal android WiFi device and another android device with WiFi direct support.
Am successfully able to create a group(uisng createGroup of WifiP2pManager) and using the SSID and pass phrase given by the android I am also successfully able to connect a normal WiFi device to my WiFi-direct enabled device( in which I created group using wifi direct apis).
But here android gives some random WiFi SSID and pass phrase , which results in me looking at the adb logs always for SSID name and then entering in the other device.
Is there anyway in which I can set the SSID and passphrase of my choice?
Thanks
Kozlov
requestGroupInfo() enables you to get both the SSID and passphrase, however, I don't think it's possible to adjust these (yet)..
Firstly, the best way would be not to change but only retrieve the WifiP2p settings and pass them you a connecting legacy device (one that does not support WifiP2p because only there you need a passphrase) using a different channel like bluetooth or NFC. A QR code may also work.
The previous Message showed you, how to get you SSID and Passphrase. The Passphrase can't be changed, however, the SSID can. The Wifi Direct spec settles the SSID to be "DIRECT__" where xy are some random generated letters during setup. So you cant change this prefix "DIRECT" and the two letters, because both the letters and passphrase are generated in internal libraries and only a read only copy is passed back to the application.
However you can change what comes afterwards the SSID prefix using reflection API.
private void openWifiDirectChannel(String name){
WifiP2pManager manager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
WifiP2pManager.Channel channel = manager.initialize(this, getMainLooper(), null);
//Use reflection API to get the hidden method for setting the P2P network name
try {
Method m = manager.getClass().getMethod(
"setDeviceName",
WifiP2pManager.Channel.class, String.class, WifiP2pManager.ActionListener.class );
m.invoke(manager, channel, name, new WifiP2pManager.ActionListener() {
public void onSuccess() {
//Code for Success in changing name
}
public void onFailure(int reason) {
//Code to be done while name change Fails
}
});
} catch (Exception e)
e.printStackTrace();
}
I'm trying to use my Android phone as a handsfree kit (like the one for cars) in order to connect to another phone (any phone) and perform some handsfree functionality like (answer an incoming call, reject,.. etc) which can be done using the AT commands for handsfree profile.
For that, I'm using the well-known Bluetooth chat App, and reflection work around in order to establish a connection with any device:
Method m = device.getClass().getMethod("createRfcommSocket", new Class[] {int.class});
tmp = (BluetoothSocket) m.invoke(device,1);
However, in order to achieve the handsfree functionality and understand the AT commands that I'm sending, the connected phone needs to be over the handsfree profile which uses the UUID: "0000111f-0000-1000-8000-00805F9B34FB"
Therefore, is there a way to achieve a connection to the handsfree profile?
Thanks!
You should only use this code when you have no other choice. The 1 in this code is the RFCOMMÂ port. Each service has it's own RFCOMM port. This port is usually random between 1 and 31. You need to know which port the service (here handsfree profile) is using on the device that you want to connect to. You have to use the createRfcommSocketToServiceRecord method from the BluetoothDevice object to do this:
try { clientSocket = bluetoothDevice.createRfcommSocketToServiceRecord( serviceUUID ); }
catch (IOException e)
{
// handle error
}
This code is the correct way to use Bluetooth and should replace the one you're using.