21

The Bluetooth device I am trying to connect has always the same pincode. This should make it possible to pair the device by setting the pin programmatically.

After trying to search how this could be done, I ended up with the code below:

BluetoothDevice device = getDevice();

//To avoid the popup notification:
device.getClass().getMethod("setPairingConfirmation", boolean.class).invoke(device, true);
device.getClass().getMethod("cancelPairingUserInput", boolean.class).invoke(device, true);
byte[] pin = ByteBuffer.allocate(4).putInt(1234).array();
//int pinn = 1234;

//Entering pin programmatically:  
Method ms = device.getClass().getMethod("setPin", byte[].class);
//Method ms = device.getClass().getMethod("setPasskey", int.class);
ms.invoke(device, pin);

//Bonding the device:
Method mm = device.getClass().getMethod("createBond", (Class[]) null);
mm.invoke(device, (Object[]) null);

cancelPairingUserInput gives me a NoSuchMethodException, which is weird because the method does exist in BluetoothDevice class.

Is looks like Setpin or SetPasskey doesn't do anything. The device just wont pair. It only pairs after manually entering the pin.

So the only line of code that works is:

//Bonding the device:
Method mm = device.getClass().getMethod("createBond", (Class[]) null);
mm.invoke(device, (Object[]) null);

Logcat output:

09-27 12:34:46.408: ERROR/App(11671): cancelPairingUserInput [boolean]
        java.lang.NoSuchMethodException: cancelPairingUserInput [boolean]
        at java.lang.Class.getConstructorOrMethod(Class.java:460)
        at java.lang.Class.getMethod(Class.java:915)
        at test.app.bluetooth.model.BluetoothDiscoveryAndPairing.pair(BluetoothDiscoveryAndPairing.java:97)
        at test.app.bluetooth.model.BluetoothDiscoveryAndPairing.access$000(BluetoothDiscoveryAndPairing.java:25)
        at test.app.bluetooth.model.BluetoothDiscoveryAndPairing$1.onReceive(BluetoothDiscoveryAndPairing.java:79)
        at android.app.LoadedApk$ReceiverDispatcher$Args.run(LoadedApk.java:756)
        at android.os.Handler.handleCallback(Handler.java:615)
        at android.os.Handler.dispatchMessage(Handler.java:92)
        at android.os.Looper.loop(Looper.java:137)
        at android.app.ActivityThread.main(ActivityThread.java:4921)
        at java.lang.reflect.Method.invokeNative(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:511)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1038)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:805)
        at dalvik.system.NativeStart.main(Native Method)

So what am I doing wrong?

Duncan Jones
  • 67,400
  • 29
  • 193
  • 254
user1816451
  • 241
  • 1
  • 2
  • 6

2 Answers2

13

The hidden method cancelPairingUserInput does not exist in your device. Don't use it.

  1. You should register BroadcastReceiver for android.bluetooth.device.action.PAIRING_REQUEST
  2. Call createBond()
  3. Wait for BroadcastReceiver to trigger
  4. In BroadcastReceiver if action is android.bluetooth.device.action.PAIRING_REQUEST call this method
public void setBluetoothPairingPin(BluetoothDevice device)
{
    byte[] pinBytes = convertPinToBytes("0000");
    try {
          Log.d(TAG, "Try to set the PIN");
          Method m = device.getClass().getMethod("setPin", byte[].class);
          m.invoke(device, pinBytes);
          Log.d(TAG, "Success to add the PIN.");
          try {
                device.getClass().getMethod("setPairingConfirmation", boolean.class).invoke(device, true);
                Log.d(TAG, "Success to setPairingConfirmation.");
            } catch (Exception e) {
                // TODO Auto-generated catch block
                Log.e(TAG, e.getMessage());
                e.printStackTrace();
            } 
        } catch (Exception e) {
          Log.e(TAG, e.getMessage());
          e.printStackTrace();
        }
}

It also works on a device with Jelly Bean version (4.1.2) of Android.

ben75
  • 29,217
  • 10
  • 88
  • 134
KRiadh
  • 246
  • 2
  • 5
  • 2
    Can this be done in API Level before 19 ? The android.bluetooth.device.action.PAIRING_REQUEST was only introduced on the API 19 – FOliveira Jul 01 '14 at 14:52
  • 2
    Why is setPairingConfirmation() needed ? Android docs say that it only applies for PAIRING_VARIANT_PASSKEY_CONFIRMATION, not legacy pairing. Furthermore, on Android6 it requires BLUETOOTH_PRIVILEGED – Sergio Martins Jan 12 '17 at 11:45
  • In case anyone cannot access convertPinToBytes the source can be found here: https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/bluetooth/BluetoothDevice.java – Richardweber32 Nov 08 '18 at 11:05
  • 4
    This does not work, as it requires BLUETOOTH_PRIVILEGED permission, which is only available on system apps. – Daniel Aug 29 '19 at 22:21
3

this is works for me:

    IntentFilter filter2 = new IntentFilter(
            "android.bluetooth.device.action.PAIRING_REQUEST");
    mActivity.registerReceiver(
            pairingRequest, filter2);

private final BroadcastReceiver pairingRequest = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {

        if (intent.getAction().equals("android.bluetooth.device.action.PAIRING_REQUEST")) {
            mBluetoothDevice = needed;
                try {
                    byte[] pin = (byte[]) BluetoothDevice.class.getMethod("convertPinToBytes", String.class).invoke(BluetoothDevice.class, "1234");
                    Method m = mBluetoothDevice.getClass().getMethod("setPin", byte[].class);
                    m.invoke(mBluetoothDevice, pin);
                    mBluetoothDevice.getClass().getMethod("setPairingConfirmation", boolean.class).invoke(mBluetoothDevice, true);
}
    catch(Exception e)
{

    e.printStackTrace();

}
Péter Hidvégi
  • 743
  • 6
  • 21
  • is this code required by only that device which is trying to pair? Don't we need any code on other device which is being paired? – Dhruvam Gupta Sep 21 '16 at 19:18
  • You don't need any code to the other device. You should just accept the connection. (I wrote this code for an android phone which connected to a mobile printer.) – Péter Hidvégi Mar 22 '17 at 18:32