How to programmatically pair a bluetooth device on Android
Asked Answered
B

10

20

For my application I'm trying to programmatically pair a bluetooth device. I'm able to show the pairing dialog for the device I want to pair and I can enter a pincode. When I press "Pair" the dialog is removed and nothing happens.

I only need to support devices with Android 2.0 and newer.

Currently I am using the following code to start the pairing progress:


public void pairDevice(BluetoothDevice device) {
        String ACTION_PAIRING_REQUEST = "android.bluetooth.device.action.PAIRING_REQUEST";
        Intent intent = new Intent(ACTION_PAIRING_REQUEST);
        String EXTRA_DEVICE = "android.bluetooth.device.extra.DEVICE";
        intent.putExtra(EXTRA_DEVICE, device);
        String EXTRA_PAIRING_VARIANT = "android.bluetooth.device.extra.PAIRING_VARIANT";
        int PAIRING_VARIANT_PIN = 0;
        intent.putExtra(EXTRA_PAIRING_VARIANT, PAIRING_VARIANT_PIN);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        context.startActivity(intent);
    }

Before starting a pairing request I stop scanning for new devices.

My application has the following bluetooth permissions:

  • android.permission.BLUETOOTH_ADMIN
  • android.permission.BLUETOOTH
Bolometer answered 14/2, 2011 at 7:54 Comment(3)
i spent several days looking for a solution to this exact issue. it appears that google considers force-pairing to be a security issue, so the ACTION types you have listed here don't actually exist. i found the class you reference here: developer.oesf.biz/em/developer/reference/cinnamon/android/… but it's not in the official docs: developer.android.com/reference/android/bluetooth/…Bartholomeo
@FireFLy have you got any solution ?Laine
Using reflection you can call the method createBond from the BluetoothDevice class. Solution: See this post: How to unpair or delete paired bluetooth device programmatically on android(#9608640)? There is also a solution for unpair.Beason
A
9

I managed to auto request a pairing procedure with keyboard featured devices through an app working as a service checking the presence of a specific kind of device and a modified version of the Settings app.

I have to say that I was working on a custom device running Android 4.0.3 without external controls (no back/Home/confirm buttons): pairing a controller on boot complete without any interaction until PIN request was mandatory.

First I created a service starting an activity on boot (with android.intent.action.BOOT_COMPLETED and android.permission.RECEIVE_BOOT_COMPLETED) that checks periodically the presence of a 1344 class device (a keyboard, the only way to input data on request) on the onReceive callback:

public void onReceive(Context context, Intent intent) 
...
    BluetoothDevice dev = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
...
if(dev.getBluetoothClass().getDeviceClass() == 1344){...}

Once filtered I choose the first keyboard available and then I pass the BT address to the Settings app:

Intent btSettingsIntent = new Intent(Settings.ACTION_BLUETOOTH_SETTINGS);
btSettingsIntent.putExtra("btcontroller", dev.getAddress());
startActivityForResult(btSettingsIntent, 1);

The tricky part was looking for the best position to call the pairing process. Using only the

intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, PAIRING_VARIANT_PIN);

led me to a paring dialog that once closed left me with the device paired, but unusable.

Digging into the classes of com.Android.settings.Bluetooth I found my way through the

createDevicePreference(CachedBluetoothDevice cachedDevice) 

in the DeviceListPreferenceFragment.

From there I did compare my previously selected BT address with those available coming up and once successfully matched I call

cachedDevice.startPairing();

I know, it's tricky and requires access to the Android source code, but in a custom environment it works.

I hope this could be helpful.

Adapt answered 8/10, 2012 at 14:46 Comment(1)
this doesn't answer the questionTracay
H
5

It's my answer:

in onCreate() write this:

    registerReceiver(incomingPairRequestReceiver, new IntentFilter(BluetoothDevice.ACTION_PAIRING_REQUEST));

then create variable

private final BroadcastReceiver incomingPairRequestReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if (BluetoothDevice.ACTION_PAIRING_REQUEST.equals(action)) {
            BluetoothDevice dev = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
            //pair from device: dev.getName()
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                dev.setPairingConfirmation(true);
                //successfull pairing
            } else {
                //impossible to automatically perform pairing,
                //your Android version is below KITKAT
            }
        }
    }
};
Homager answered 4/4, 2016 at 9:37 Comment(1)
setPairingConfirmation(boolean confirm) needs BLUETOOTH_PRIVILEGED permission, but this permission is not available to third party applications. See Android DevelopersTriumph
L
4

Unfortunately, I think the best that you are going to get is opening up Settings/Wireless & networks/Bluetooth Settings for the user like so:

    Intent intent = new Intent(Settings.ACTION_BLUETOOTH_SETTINGS);
    startActivityForResult(intent, REQUEST_PAIR_DEVICE);
Lattimer answered 14/1, 2012 at 1:9 Comment(1)
Using kiosk mode makes this very difficult, so I choose to open the bluetooth settings.Jarvisjary
M
3

Using reflection you can call the method createBond from the BluetoothDevice class.

See this post: How to unpair or delete paired bluetooth device programmatically on android?

There is also a solution for unpair.

Mickeymicki answered 22/1, 2013 at 19:11 Comment(2)
..which is removed since JB aka 4.1.xAfar
It hasn't been removed, this still works with my 4.3 Nexus 4 and its still very much in the source codeZalea
F
2

Reflection is DODGY, different manufacturers can change these underlying methods as they wish! I have tested many different apps on our 10 devices here and these reflection method only works fully on roughly 75% of devices. If you want an app that works for everyone be very careful when using reflection - try some cloud testing to test your app on 100+ devices and check the failure rate.

In this case reflection is not needed at all since API 19 (KitKat 4.4)

BluetoothDevice has new method CreateBond.

 private void pairDevice(BluetoothDevice device) {

            device.createBond();
    }

developer.android.com/reference/android/bluetooth/BluetoothDevice.html

Futurism answered 11/12, 2015 at 10:58 Comment(2)
it's possible to test bluetooth on cloud based testing tools ?Headman
Haven't looked recently, last year I tried and no cloud testing company I contacted would allow me to do this type of test.Futurism
E
0

May be you need to startActivityForResult instead of only startActivity?

Other option is to look into the BluetoothChat application sample and start an RFComm connection socket, as soon as you start the socket a pairing request will automatically appear without needing to send a separate intent for pairing. This way you won't need to handle pairing.

http://developer.android.com/resources/samples/BluetoothChat/index.html

Either answered 24/4, 2011 at 9:30 Comment(0)
C
0

I am using this class to do connection between my client smartphone and the server device:

private class ConnectThread extends Thread
{
    private final BluetoothSocket mmSocket;

    private final UUID WELL_KNOWN_UUID = UUID.fromString("00001101-0000-1000-8000-00805f9b34fb");

    public ConnectThread(BluetoothDevice device)
    {
        // Use a temporary object that is later assigned to mmSocket,because
        // mmSocket is final
        BluetoothSocket tmp = null;

        // Get a BluetoothSocket to connect with the given BluetoothDevice
        try
        {
            tmp = device.createRfcommSocketToServiceRecord(WELL_KNOWN_UUID);
            //This is the trick
            Method m = device.getClass().getMethod("createRfcommSocket", new Class[] { int.class });
            tmp = (BluetoothSocket) m.invoke(device, 1);
        } catch (Exception e)
        {
            e.printStackTrace();
        }

        mmSocket = tmp;
    }

    public void run()
    {
        DebugLog.i(TAG, "Trying to connect...");
        // Cancel discovery because it will slow down the connection
        mBluetoothAdapter.cancelDiscovery();

        try
        {
            // Connect the device through the socket. This will block
            // until it succeeds or throws an exception
            mmSocket.connect();
            DebugLog.i(TAG, "Connection stablished");
        } catch (IOException connectException)
        {
            // Unable to connect; close the socket and get out
            DebugLog.e(TAG, "Fail to connect!", connectException);
            try
            {
                mmSocket.close();
            } catch (IOException closeException)
            {
                DebugLog.e(TAG, "Fail to close connection", closeException);
            }
            return;
        }
    }

    /** Will cancel an in-progress connection, and close the socket */
    public void cancel()
    {
        try
        {
            mmSocket.close();
        } catch (IOException e)
        {
        }
    }
}

First, get the BluetoothDevice object that you want to connect (listing paired devices or discoverying devices). Then do:

ConnectThread ct = new ConnectThread(device);
ct.start();

Because connect() is a blocking call, this connection procedure should always be performed in a thread separate from the main activity thread. See Android Developers for more detailed info.

Cropdusting answered 5/3, 2014 at 15:19 Comment(3)
i want to implements one device send image to another device via bluetooth..but i stuck in Accept Thread..what to do..??Soupandfish
@Umang, my answer is just to pairing devices. Exchange information between them is another history. I suggest that you create a post detailing your problem.Cropdusting
can you look this : #23649442Soupandfish
K
-1

I've found that using different values for PAIRING_VARIANT_PIN result in different pairing UI behaviours.

See this page: http://code.google.com/p/backport-android-bluetooth/source/browse/trunk/backport-android-bluetooth201/src/backport/android/bluetooth/BluetoothDevice.java?spec=svn67&r=67

I suspect the problem you're having is that both devices are Bluetooth 2.1, in which case a pairing request should result in a 6 digit passkey being displayed on both devices.

The best result I was able to achieve was using PAIRING_VARIANT_PIN = 0. When prompted by my application, I entered pin 1234 and a 6 digit passkey appeared on my target device. The pairing UI finished and that was that.

Either you need to find out how to initiate a Bluetooth 2.1 pairing request, using some other pairing variant or pairing variant pin. Or, you're not catching the result of the activity that's running properly.

Given the amount of time I've been trying to do this, I've decided that my end users will just have to pair using the android settings before using my application.

Karolyn answered 21/10, 2011 at 12:35 Comment(2)
@Peter O. Stack Overflow notifies me that you've edited this. As this is my first post, I've some questions, if you don't mind: - I can't remember my original message, so I can't see what you deleted. Is there a way to do this? - Have you a solution to the question per chance? - Is there a way to message users directly, rather than do what I'm doing now? Thanks in advance.Karolyn
1. Click the date after the word "edited" to see the edit history. 2. No, I don't have a solution to the problem, as I am not that familiar with the subject. 3. No, not directly, as in private messaging. But if either user has at least 100 reputation and the other user has at least 20 reputation, the former user can create a gallery chat room and invite the other user to enter it.Pellicle
E
-1

This is how I get it:

Bluetooth device = mBtAdapter.getRemoteDevice(address);
//address:11:23:FF:cc:22 
Method m = device.getClass()        
 .getMethod("createBond", (Class[]) null);
         m.invoke(device, (Object[]) null); // send pairing dialog request

After pairing//
       connectDevice(address);
Eggett answered 15/1, 2015 at 9:49 Comment(0)
B
-3

in addition to my comment, by the way, even if these ACTION types did exist, that's not how you use them. here's an example:

Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST);
intent.putExtra(EXTRA_DEVICE, device);
int PAIRING_VARIANT_PIN = 272;
intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, PAIRING_VARIANT_PIN);
sendBroadcast(intent);
Bartholomeo answered 24/6, 2011 at 18:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.