How to Realize Bluetooth Pairing Connection in Android

  • 2021-12-12 09:47:01
  • OfStack

Catalog the scope of this article Prepare Search Pairing Connect Pit pit pit

Scope of application of this article

The Bluetooth part of Android is very complex and involves many nouns and functions. The pairing connection method introduced in this paper is suitable for 1-type Bluetooth headsets, audio, etc. It is not connected with Bluetooth BLE or wants to use Bluetooth for Socket communication.

Let's introduce several names first:

Profile:

A very important feature of Bluetooth is that all Bluetooth products do not need to implement all Bluetooth specifications. To make it easier to maintain compatibility between Bluetooth devices, Profile is defined in the Bluetooth specification. Profile defines how a device implements a connection or application. You can think of Profile as a connection layer or application layer. The connection in our title is actually to connect various Profile. The following are all Profile implemented by Android.

A2dp:

Indicates Bluetooth stereo, and Bluetooth headset listening to those, there is also an Avrcp audio/video remote control configuration file, which is used to pause when listening to songs, up and down song selection.

Handset, Handfree:

Related to the phone, Bluetooth answer and hang up the phone.

Others:

btservice on the basic operation of Bluetooth directory, 1 cut from here; Application of hdp Bluetooth in Medical Treatment; hid: Human-computer interaction interface, Bluetooth mouse keyboard or something is this; pbap: Telephone Directory Access Protocol (Phonebook Access Profile)...

Prepare

Add the required permissions in AndroidManifest. xml


<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />

Turn on Bluetooth


mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (!mBluetoothAdapter.isEnabled()) {
   Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
   startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
}

Registered broadcast
Because Bluetooth search, pairing and connection state change are all sent by the system through broadcasting, it is necessary to register these broadcasts to obtain the state change.


IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(BluetoothDevice.ACTION_FOUND);
intentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
intentFilter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
intentFilter.addAction(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);
intentFilter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
registerReceiver(mReceiver, intentFilter);

Search

Gets the paired devices. For devices that have been paired successfully before, the system will store its information locally. When you call the search again, the system will not rediscover the device.


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

Search equipment


mBluetoothAdapter.startDiscovery();

After the system finds a new Bluetooth device, it will send the information of this device through broadcasting. Therefore, we need to intercept Intent whose Action is BluetoothDevice.ACTION_FOUND and get the equipment information.


BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);

Pairing

The key point is coming, I have done a series of preparatory work, and I will start pairing connection after I get BluetoothDevice. But the pit is also here. First of all, Bluetooth devices must be paired successfully before connecting different Profile. If you connect some models directly, you can connect them, but most of them don't respond. Then the pairing interface is opened above Android 4.4 API 19. For the previous system, we can only obtain the interface through reflection.

Pairing


if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
    //Android 4.4 API 19  The above is only open Bond Interface 
    device.createBond();
} else {
    //API 19  Call the following with reflection Bond Interface 
    try {
        device.getClass().getMethod("connect").invoke(device);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

Successful pairing sends broadcast BluetoothDevice.ACTION_BOND_STATE_CHANGED


// Device binding state change 
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.ERROR);
// Connect automatically after receiving notification of successful binding 
if (item != null && bondState == BluetoothDevice.BOND_BONDED) {
    connectDevice(item);
}

Several states of pairing


    public static final int BOND_NONE = 10;
    public static final int BOND_BONDING = 11;
    public static final int BOND_BONDED = 12;

Connect

Pairing (binding) and connection are two different processes. Pairing means that two devices find each other's existence, can get each other's name, address and other information, and have the ability to establish a connection. Connection means that two devices share an RFCOMM channel and have the ability to transfer data to each other. You can't start connecting until you confirm that you are bound. Connecting is actually connecting Profile supported by this Bluetooth device.

You can observe the process of setting Bluetooth connection in 1, that is, start pairing first, and then start connecting all supported Profile after successful pairing. This step is also a pit, and there is no detailed description of this block on the Internet. I also turned over the source code of Setting for half a day to find this logic. However, the system application can directly call the connected method, but it is not open...

First of all, we need to get Profile in advance. Here, take A2dp as an example. Other principles are the same.


        mBluetoothAdapter.getProfileProxy(this, new BluetoothProfile.ServiceListener() {
            @Override
            public void onServiceConnected(int profile, BluetoothProfile proxy) {
                if (mA2dpService == null) {
                    mA2dpService = (BluetoothA2dp) proxy;
                }
            }

            @Override
            public void onServiceDisconnected(int profile) {
            }
        }, BluetoothProfile.A2DP);

When we receive a broadcast of successful pairing or determine that the device has been successfully paired, we call the connect method of Profile to connect. But this method was given to @ hide by Google. Use reflection like above 1...


mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (!mBluetoothAdapter.isEnabled()) {
   Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
   startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
}
0

Successful connection sends broadcast BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED


mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (!mBluetoothAdapter.isEnabled()) {
   Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
   startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
}
1

Several states of connection


mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (!mBluetoothAdapter.isEnabled()) {
   Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
   startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
}
2

Pit pit pit

Haha, do you think it's over when you connect? ! There are still some pits in here for me to tell you.

Don't forget to turn off Profile. We in order to connect is not obtained Profile, after the completion of the connection 1 must close it, 1 straight if not closed will report an error.


mBluetoothAdapter.closeProfileProxy(BluetoothProfile.A2DP, mA2dpService);
mA2dpService = null;

After the Bluetooth connection is successful, the system will inform the mobile phone that the status has changed, just like switching the horizontal and vertical screens 1, and the life cycle of Activity needs to be called again. At that time, I found that as long as I connected successfully, my interface flashed 1 and returned to the original state. I wondered for a long time, and then I thought it was a reflection connection that caused the program to restart abnormally... After several gropes, I found that it was because android: configChanges was not set.


mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (!mBluetoothAdapter.isEnabled()) {
   Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
   startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
}
4

In fact, I have thought of the first two attributes, but the last one, This should never normally happen written in the official document. I naively believed it, and I didn't try it. In the end, there is really no way to write all the attributes, and then reduce them one by one. Finally, it is found that none of these three attributes can be reduced.

说明
"keyboard" 键盘类型发生了变化 — 例如,用户插入了1个外置键盘。
"keyboardHidden" 键盘无障碍功能发生了变化 — 例如,用户显示了硬件键盘。
"navigation" 导航类型(轨迹球/方向键)发生了变化。(这种情况通常永远不会发生。)

The above is how Android realizes the Bluetooth pairing connection function in detail. For more information about Android Bluetooth pairing connection function, please pay attention to other related articles on this site!


Related articles: