How to programmatically pair and connect a HID bluetooth device(Bluetooth Keyboard) on Android
Asked Answered
Z

2

12

I am able to pair a bluetooth keyboard but not able to connect so as to make it an input device. I went through the documentation provided at developer site - http://developer.android.com/guide/topics/connectivity/bluetooth.html#Profiles

It says that the Android Bluetooth API provides implementations for the following Bluetooth profiles but you can implement the interface BluetoothProfile to write your own classes to support a particular Bluetooth profile.

  • Headset
  • A2DP
  • Health Device

There is no documentation how to implement BluetoothProfile for HID bluetooth device(Keyboard)

Android has itself implemented bluetooth connection for HID devices but those API's are hidden. I tried reflection to use them too. I do not get any error but keyboard does not get connected as input device. This is what i have done -

private void connect(final BluetoothDevice bluetoothDevice) {
    if(bluetoothDevice.getBluetoothClass().getDeviceClass() == 1344){
        final BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
            BluetoothProfile.ServiceListener mProfileListener = new BluetoothProfile.ServiceListener() {
                @Override
                public void onServiceConnected(int profile, BluetoothProfile proxy) {
                    Log.i("btclass", profile + "");

                    if (profile == getInputDeviceHiddenConstant()) {
                        Class instance = null;
                        try {
                            //instance = Class.forName("android.bluetooth.IBluetoothInputDevice");
                            instance = Class.forName("android.bluetooth.BluetoothInputDevice");
                            Method connect = instance.getDeclaredMethod("connect", BluetoothDevice.class);
                            Object value = connect.invoke(proxy, bluetoothDevice);
                            Log.e("btclass", value.toString());
                        } catch (ClassNotFoundException e) {
                            e.printStackTrace();
                        } catch (InvocationTargetException e) {
                            e.printStackTrace();
                        } catch (NoSuchMethodException e) {
                            e.printStackTrace();
                        } catch (IllegalAccessException e) {
                            e.printStackTrace();
                        }



                    }
                }

                @Override
                public void onServiceDisconnected(int profile) {

                }
            };

            mBluetoothAdapter.getProfileProxy(this, mProfileListener,getInputDeviceHiddenConstant());


    }

}

public static int getInputDeviceHiddenConstant() {
    Class<BluetoothProfile> clazz = BluetoothProfile.class;
    for (Field f : clazz.getFields()) {
        int mod = f.getModifiers();
        if (Modifier.isStatic(mod) && Modifier.isPublic(mod) && Modifier.isFinal(mod)) {
            try {
                if (f.getName().equals("INPUT_DEVICE")) {
                    return f.getInt(null);
                }
            } catch (Exception e) {
                Log.e("", e.toString(), e);
            }
        }
    }
    return -1;
}
Zoraidazorana answered 15/3, 2016 at 8:59 Comment(3)
Did you managed to get a HID connection working? Im stuck with the problem that newer android version do not have the bluetooth HID profile. What Android version did you use?Afroamerican
@DutchKev - I tried it on Android 4.4.2 and as i answered below you cannot connect it programatically. Also i am not aware of newer android versions whether they provide bluetooth HID profile or not.Zoraidazorana
Thanks or replying. see the below code.. I continued working on the same problem last night, and got a few steps further.. When I first connect 'manually' trough the normal Android bluetooth connection handler.. I can then, with reflection, create an L2CAP bluetooth socketAfroamerican
Z
8

Due to security reasons, it is not possible for third party applications to connect to a bluetooth keyboard as the application can be a keylogger. So it can be only done manually by the user.

Zoraidazorana answered 3/4, 2016 at 11:40 Comment(1)
Do you have any sources for this?Dipietro
A
1

Here is the code I used on Android Marshmallow (6.0).. To get an L2CAP connection started (Needed for HID)

public static BluetoothSocket createL2CAPBluetoothSocket(String address, int psm){
    return createBluetoothSocket(BluetoothSocket.TYPE_L2CAP, -1, false,false, address, psm);
}

// method for creating a bluetooth client socket
private static BluetoothSocket createBluetoothSocket(int type, int fd, boolean auth, boolean encrypt, String address, int port){
    Log.e(TAG, "Creating socket with " + address + ":" + port);

    try {
        Constructor<BluetoothSocket> constructor = BluetoothSocket.class.getDeclaredConstructor(
                int.class, int.class,boolean.class,boolean.class,String.class, int.class);
        constructor.setAccessible(true);
        BluetoothSocket clientSocket = (BluetoothSocket) constructor.newInstance(type,fd,auth,encrypt,address,port);
        return clientSocket;
    }catch (Exception e) {
        e.printStackTrace();
    }

    return null;
}

public Boolean connect(View v) {

    try {
        // TODO: Check bluetooth enabled
        mDevice = getController();

        if (mDevice != null) {
            Log.e(TAG, "Controller is paired");

            // Create socket
            mSocket = createL2CAPBluetoothSocket(mDevice.getAddress(), 0x1124);

            if (mSocket != null) {

                if (!mSocket.isConnected()) {
                    mSocket.connect();
                }

                Log.e(TAG, "Socket successfully created");

                ConnectedThread mConnectedThread = new ConnectedThread(mSocket);
                mConnectedThread.run();
            }

        } else {
            showToast("Controller is not connected");
        }

        return true;

    } catch (Exception e) {
        e.printStackTrace();

        if (e instanceof IOException){
            // handle this exception type
        } else {
            // We didn't expect this one. What could it be? Let's log it, and let it bubble up the hierarchy.

        }

        return false;
    }
}

private BluetoothDevice getController() {
    Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();

    if (pairedDevices.size() > 0) {
        for (BluetoothDevice device : pairedDevices) {
            if (device.getName().equals("Wireless Controller"))    // Change to match DS4 - node name
            {
                Log.d(TAG, "Found device named: " + device.getName());

                return device;
            }
        }
    }

    return null;
}

It can still have problems creating the Service, and you need to set the correct L2CAP PSAM for the device, but hope it can help..

Afroamerican answered 20/4, 2016 at 11:28 Comment(2)
So are you able to connect the bluetooth keyboard programatically on Android 6.0Zoraidazorana
@DutchKevv, you mentioned you need to set the correct L2CAP PSAM for the device. If I'm interpreting your code correctly, it looks like this was 0x1124 for your device. How did you discover this value? Is there a method you can run to discover it, or did you find it in the device manufacturers documentation?Pokpoke

© 2022 - 2024 — McMap. All rights reserved.