Как получить список подключенных устройств из определенного профиля Bluetooth

Есть ли в любом случае получить список подключенных устройств из профилей поддержки (HDD,Spp и аудио). Требование в том, что мое устройство будет поддерживать HDD,SPP и аудио, поэтому мне нужно отфильтровать устройства, которые поддерживают все эти профили. Есть ли способ фильтровать устройства?

2 ответа

Да, это возможно, но ваше Android-приложение должно быть ориентировано на SDK 11 или более позднюю версию ( Android 3.0.X).

Решение вашего вопроса заключается в том, что вы должны запросить все устройства BluetoothDevices, известные на вашем устройстве Android. Под известным я подразумеваю все сопряженные подключенные или неподключенные устройства и непарные подключенные устройства.

Мы отфильтруем неподключенные устройства позже, поскольку вам нужны только подключенные устройства.


  • Сначала вам нужно получить BluetoothAdapter:

окончательный BluetoothAdapter btAdapter = BluetoothAdapter.getDefaultAdapter();

  • Во-вторых, вам нужно убедиться, что Bluetooth доступен и включен:

if (btAdapter! = null && btAdapter.isEnabled ()) // null означает отсутствие Bluetooth!

Если Bluetooth не выключен, вы можете использовать btAdapter.enable() что не рекомендуется в документации или попросить пользователя сделать это: Программно включить Bluetooth на Android

  • В-третьих, вам нужно определить массив состояний (чтобы отфильтровать неподключенные устройства):

final int [] states = new int [] {BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_CONNECTING};

  • В-четвертых, вы создаете BluetoothProfile.ServiceListener который содержит два обратных вызова, запускаемых при подключении и отключении службы:

    final BluetoothProfile.ServiceListener listener = new BluetoothProfile.ServiceListener() {
        @Override
        public void onServiceConnected(int profile, BluetoothProfile proxy) {
        }
    
        @Override
        public void onServiceDisconnected(int profile) {
        }
    };
    

Теперь, поскольку вам нужно повторить процесс запроса для всех доступных профилей Bluetooth в Android SDK ( A2Dp, GATT, GATT_SERVER, Handset, Health, SAP), вы должны выполнить следующие действия:

В onServiceConnected Поместите условие, которое проверяет текущий профиль, чтобы мы добавили найденные устройства в правильную коллекцию и использовали: proxy.getDevicesMatchingConnectionStates(states) отфильтровать неподключенные устройства:

switch (profile) {
    case BluetoothProfile.A2DP:
        ad2dpDevices.addAll(proxy.getDevicesMatchingConnectionStates(states));
        break;
    case BluetoothProfile.GATT: // NOTE ! Requires SDK 18 !
        gattDevices.addAll(proxy.getDevicesMatchingConnectionStates(states));
        break;
    case BluetoothProfile.GATT_SERVER: // NOTE ! Requires SDK 18 !
        gattServerDevices.addAll(proxy.getDevicesMatchingConnectionStates(states));
        break;
    case BluetoothProfile.HEADSET: 
        headsetDevices.addAll(proxy.getDevicesMatchingConnectionStates(states));
        break;
    case BluetoothProfile.HEALTH: // NOTE ! Requires SDK 14 !
        healthDevices.addAll(proxy.getDevicesMatchingConnectionStates(states));
        break;
    case BluetoothProfile.SAP: // NOTE ! Requires SDK 23 !
        sapDevices.addAll(proxy.getDevicesMatchingConnectionStates(states));
        break;
}

И, наконец, последнее, что нужно сделать, это запустить процесс запроса:

btAdapter.getProfileProxy(yourContext, listener, BluetoothProfile.A2DP);
btAdapter.getProfileProxy(yourContext, listener, BluetoothProfile.GATT); // NOTE ! Requires SDK 18 !
btAdapter.getProfileProxy(yourContext, listener, BluetoothProfile.GATT_SERVER); // NOTE ! Requires SDK 18 !
btAdapter.getProfileProxy(yourContext, listener, BluetoothProfile.HEADSET);
btAdapter.getProfileProxy(yourContext, listener, BluetoothProfile.HEALTH); // NOTE ! Requires SDK 14 !
btAdapter.getProfileProxy(yourContext, listener, BluetoothProfile.SAP); // NOTE ! Requires SDK 23 !

расширяя ответ @Mack, мне удалось создать составной элемент, который возвращает список подключенных в данный момент устройств с кнопкой обновления:

вот полный код:

      package com.example.audio_output_selector

import android.Manifest
import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothDevice
import android.bluetooth.BluetoothManager
import android.bluetooth.BluetoothProfile
import android.content.Context
import android.content.pm.PackageManager
import android.util.Log
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.platform.LocalContext
import androidx.core.app.ActivityCompat

@Composable
fun getConnectedBluetoothDevices(): List<BluetoothDevice> {
    val context = LocalContext.current
    val bluetoothManager = context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
    val bluetoothAdapter: BluetoothAdapter = bluetoothManager.getAdapter()
    if (bluetoothAdapter.isEnabled == false) {
        Log.i("MainActivity", "Bluetooth is not enabled")
    }

    if (ActivityCompat.checkSelfPermission(
            context,
            Manifest.permission.BLUETOOTH_CONNECT
        ) != PackageManager.PERMISSION_GRANTED
    ) {
        Log.i("MainActivity", "Should Requesting Bluetooth permission")
        return emptyList()
    }

    var connectedBluetoothDevices by remember {
        mutableStateOf(
            ConnectedBluetoothDevices(
                emptyList(), emptyList(), emptyList(), emptyList(), emptyList()
            )
        )
    }

    var currentBluetoothProfile: BluetoothProfile? = null
    var isRefreshing by remember { mutableStateOf(false) }

    LaunchedEffect(bluetoothAdapter, currentBluetoothProfile, isRefreshing) {
        if (isRefreshing) {
            bluetoothAdapter.getProfileProxy(context, object : BluetoothProfile.ServiceListener {
                override fun onServiceConnected(profile: Int, proxy: BluetoothProfile) {
                    currentBluetoothProfile = proxy
                    connectedBluetoothDevices = handleBluetoothService(profile, proxy)
                }

                override fun onServiceDisconnected(profile: Int) {
                    if (profile == BluetoothProfile.A2DP) {
                        Log.i("MainActivity", "A2DP devices disconnected")
                    }
                }
            }, BluetoothProfile.A2DP)
        }
        isRefreshing = false
    }


    //  bluetoothAdapter.getProfileConnectionState(BluetoothProfile.A2DP) == BluetoothProfile.STATE_CONNECTED
    bluetoothAdapter.getProfileProxy(context, object : BluetoothProfile.ServiceListener {
        override fun onServiceConnected(profile: Int, proxy: BluetoothProfile) {
            connectedBluetoothDevices = handleBluetoothService(profile, proxy)
        }

        override fun onServiceDisconnected(profile: Int) {
            if (profile == BluetoothProfile.A2DP) {
                Log.i("MainActivity", "A2DP devices disconnected")
            }
        }
    }, BluetoothProfile.A2DP)

    Button(onClick = { isRefreshing = true }) {
        Text("Refresh BT")
    }

    // currently we are relating only on A2DP devices
    // but we could use them later with a little change if needed
    return connectedBluetoothDevices.a2dpDevices
}

fun handleBluetoothService(profile: Int, proxy: BluetoothProfile): ConnectedBluetoothDevices {
    val states = intArrayOf(
        BluetoothProfile.STATE_CONNECTED,
//        BluetoothProfile.STATE_CONNECTING,
//        BluetoothProfile.STATE_DISCONNECTED,
//        BluetoothProfile.STATE_DISCONNECTING
    )

    val ad2dpDevices = mutableListOf<BluetoothDevice>()
    val gattDevices = mutableListOf<BluetoothDevice>()
    val gattServerDevices = mutableListOf<BluetoothDevice>()
    val headsetDevices = mutableListOf<BluetoothDevice>()
    val sapDevices = mutableListOf<BluetoothDevice>()

    when (profile) {
        BluetoothProfile.A2DP -> ad2dpDevices.addAll(proxy.getDevicesMatchingConnectionStates(states))
        BluetoothProfile.GATT -> gattDevices.addAll(proxy.getDevicesMatchingConnectionStates(states))
        BluetoothProfile.GATT_SERVER -> gattServerDevices.addAll(
            proxy.getDevicesMatchingConnectionStates(
                states
            )
        )

        BluetoothProfile.HEADSET -> headsetDevices.addAll(
            proxy.getDevicesMatchingConnectionStates(
                states
            )
        )

        BluetoothProfile.SAP -> sapDevices.addAll(proxy.getDevicesMatchingConnectionStates(states))
    }
    return ConnectedBluetoothDevices(
        ad2dpDevices,
        gattDevices,
        gattServerDevices,
        headsetDevices,
        sapDevices
    )
//    to get the connected devices of selected profile
//    if (profile == BluetoothProfile.A2DP) {
//        val a2dp = proxy as BluetoothProfile
//        val devices = a2dp.connectedDevices
//        Log.i("MainActivity", "A2DP devices: $devices")
//    }
}

data class ConnectedBluetoothDevices(
    val a2dpDevices: List<BluetoothDevice>,
    val gattDevices: List<BluetoothDevice>,
    val gattServerDevices: List<BluetoothDevice>,
    val headsetDevices: List<BluetoothDevice>,
    val sapDevices: List<BluetoothDevice>,
)
Другие вопросы по тегам