如何从特定的蓝牙配置文件获取已连接的设备列表

问题描述 投票:0回答:2

是否有办法从支持配置文件(HDD、Spp 和音频)获取连接的设备列表。要求就像我的设备将支持 HDD、SPP 和音频,所以我必须过滤支持所有这些配置文件的设备。有没有办法过滤设备?

android android-bluetooth bluetooth-profile
2个回答
6
投票

是的,这是可能的,但您的 Android 应用程序必须面向 SDK 11 或更高版本 (Android 3.0.X)。

您的问题的解决方案是您必须查询您的 Android 设备已知的所有蓝牙设备。 已知我指的是所有配对的已连接或未连接的设备以及未配对的已连接设备。

我们稍后会过滤掉未连接的设备,因为您只需要当前连接的设备。


  • 首先您需要检索
    BluetoothAdapter

最终蓝牙适配器 btAdapter = 蓝牙适配器.getDefaultAdapter();

  • 其次,您需要确保蓝牙可用并已打开:

if (btAdapter != null && btAdapter.isEnabled()) // null 表示否 蓝牙!

如果蓝牙未打开,您可以使用文档中不推荐的

btAdapter.enable()
或要求用户这样做:以编程方式在Android上启用蓝牙

  • 第三,您需要定义一个状态数组(以过滤掉 未连接的设备):

最终 int[] states = new int[] {BluetoothProfile.STATE_CONNECTED, 蓝牙配置文件.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) {
        }
    };
    

现在,由于您必须重复查询 Android SDK 中所有可用蓝牙配置文件的过程(A2Dp、GATT、GATT_SERVER、手机、健康、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 !

0
投票

扩展@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")
//    }
}
© www.soinside.com 2019 - 2024. All rights reserved.