From 7d5755d96d3bed9667b8bb401d3a14c2f0fbaf47 Mon Sep 17 00:00:00 2001 From: fdp <1286779656@qq.com> Date: Wed, 24 Sep 2025 20:44:59 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8A=A0=E5=85=A5=E8=93=9D=E7=89=99=E7=9B=91?= =?UTF-8?q?=E5=90=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../agent_service/BleMediaService.kt | 387 +++++++++++++++++- 1 file changed, 385 insertions(+), 2 deletions(-) diff --git a/local_plugins/agent_service/android/src/main/kotlin/com/yunqiinnovation/agent_service/BleMediaService.kt b/local_plugins/agent_service/android/src/main/kotlin/com/yunqiinnovation/agent_service/BleMediaService.kt index 97d2e9a1d..3caa6efa4 100644 --- a/local_plugins/agent_service/android/src/main/kotlin/com/yunqiinnovation/agent_service/BleMediaService.kt +++ b/local_plugins/agent_service/android/src/main/kotlin/com/yunqiinnovation/agent_service/BleMediaService.kt @@ -21,6 +21,14 @@ import kotlin.coroutines.CoroutineContext import kotlinx.coroutines.Dispatchers import com.yunqiinnovation.ble_service.BleConst import com.yunqiinnovation.ble_service.BleService +// 添加蓝牙相关导入 +import android.bluetooth.BluetoothAdapter +import android.bluetooth.BluetoothDevice +import android.bluetooth.BluetoothManager +import android.content.BroadcastReceiver +import android.content.IntentFilter +import android.content.pm.PackageManager +import androidx.core.content.ContextCompat /** * BLE代理服务 @@ -28,6 +36,7 @@ import com.yunqiinnovation.ble_service.BleService * 1. 语音代理初始化和管理 * 2. BLE设备连接管理 * 3. 后台扫描结果处理 + * 4. 蓝牙设备连接监听 */ class BleMediaService : Service(), CoroutineScope { @@ -37,6 +46,9 @@ class BleMediaService : Service(), CoroutineScope { private const val NOTIFICATION_ID = 1002 private const val PREF_NAME = "deep_voice_config" + // 目标蓝牙设备名称 + private const val TARGET_DEVICE_NAME = "DeapSound" + // ChatAgent配置参数键 private const val KEY_AZURE_SPEECH_KEY = "azureSpeechKey" private const val KEY_AZURE_SPEECH_REGION = "azureSpeechRegion" @@ -75,6 +87,301 @@ class BleMediaService : Service(), CoroutineScope { // 当前启动Intent private var currentIntent: Intent? = null + + // 蓝牙相关组件 + private var bluetoothAdapter: BluetoothAdapter? = null + private var bluetoothReceiver: BroadcastReceiver? = null + // 添加标志位跟踪广播接收器注册状态 + private var isBluetoothReceiverRegistered = false + // 添加定期检查蓝牙状态的协程作业 + private var bluetoothCheckJob: kotlinx.coroutines.Job? = null + + /** + * 蓝牙设备连接状态广播接收器 + * 监听蓝牙设备的连接和断开事件 + */ + private fun createBluetoothReceiver(): BroadcastReceiver { + return object : BroadcastReceiver() { + override fun onReceive(context: Context?, intent: Intent?) { + when (intent?.action) { + BluetoothDevice.ACTION_ACL_CONNECTED -> { + val device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE) + device?.let { handleDeviceConnected(it) } + } + BluetoothDevice.ACTION_ACL_DISCONNECTED -> { + val device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE) + device?.let { handleDeviceDisconnected(it) } + } + BluetoothAdapter.ACTION_STATE_CHANGED -> { + val state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR) + handleBluetoothStateChanged(state) + } + } + } + } + } + + /** + * 处理蓝牙设备连接事件 + * @param device 连接的蓝牙设备 + */ + private fun handleDeviceConnected(device: BluetoothDevice) { + val deviceName = device.name ?: "Unknown" + val deviceAddress = device.address ?: "Unknown" + + Log.i(TAG, "蓝牙设备已连接: $deviceName ($deviceAddress)") + + // 检查是否是目标设备 + if (deviceName.equals(TARGET_DEVICE_NAME, ignoreCase = true)) { + Log.i(TAG, "检测到目标设备 '$TARGET_DEVICE_NAME' 连接!") + Log.i(TAG, "设备信息:") + Log.i(TAG, " - 设备名称: $deviceName") + Log.i(TAG, " - 设备地址: $deviceAddress") + Log.i(TAG, " - 设备类型: ${getDeviceTypeString(device.type)}") + Log.i(TAG, " - 绑定状态: ${getBondStateString(device.bondState)}") + + // 可以在这里添加更多的处理逻辑,比如自动连接BLE服务等 + onTargetDeviceConnected(device) + } + } + + /** + * 处理蓝牙设备断开事件 + * @param device 断开的蓝牙设备 + */ + private fun handleDeviceDisconnected(device: BluetoothDevice) { + val deviceName = device.name ?: "Unknown" + val deviceAddress = device.address ?: "Unknown" + + Log.i(TAG, "蓝牙设备已断开: $deviceName ($deviceAddress)") + + if (deviceName.equals(TARGET_DEVICE_NAME, ignoreCase = true)) { + Log.i(TAG, "目标设备 '$TARGET_DEVICE_NAME' 已断开连接") + onTargetDeviceDisconnected(device) + } + } + + /** + * 处理蓝牙适配器状态变化 + * @param state 蓝牙适配器状态 + */ + private fun handleBluetoothStateChanged(state: Int) { + when (state) { + BluetoothAdapter.STATE_OFF -> { + Log.w(TAG, "蓝牙已关闭") + // 蓝牙关闭时,注销设备连接监听器(保留状态监听器) + unregisterDeviceConnectionReceiver() + } + BluetoothAdapter.STATE_ON -> { + Log.i(TAG, "蓝牙已开启") + // 蓝牙开启后,重新注册设备连接监听器 + registerDeviceConnectionReceiver() + // 检查已连接的设备 + checkAlreadyConnectedDevices() + } + BluetoothAdapter.STATE_TURNING_OFF -> { + Log.i(TAG, "蓝牙正在关闭...") + } + BluetoothAdapter.STATE_TURNING_ON -> { + Log.i(TAG, "蓝牙正在开启...") + } + } + } + + /** + * 目标设备连接时的处理逻辑 + * @param device 连接的目标设备 + */ + private fun onTargetDeviceConnected(device: BluetoothDevice) { + // 在这里可以添加目标设备连接后的特殊处理逻辑 + // 比如自动启动某些功能、发送通知等 + Log.i(TAG, "目标设备 '${device.name}' 连接成功,执行相关处理逻辑") + } + + /** + * 目标设备断开时的处理逻辑 + * @param device 断开的目标设备 + */ + private fun onTargetDeviceDisconnected(device: BluetoothDevice) { + // 在这里可以添加目标设备断开后的处理逻辑 + Log.i(TAG, "目标设备 '${device.name}' 断开连接,执行清理逻辑") + } + + /** + * 获取设备类型字符串 + * @param type 设备类型 + * @return 设备类型描述 + */ + private fun getDeviceTypeString(type: Int): String { + return when (type) { + BluetoothDevice.DEVICE_TYPE_CLASSIC -> "经典蓝牙" + BluetoothDevice.DEVICE_TYPE_LE -> "低功耗蓝牙(BLE)" + BluetoothDevice.DEVICE_TYPE_DUAL -> "双模蓝牙" + else -> "未知类型" + } + } + + /** + * 获取绑定状态字符串 + * @param bondState 绑定状态 + * @return 绑定状态描述 + */ + private fun getBondStateString(bondState: Int): String { + return when (bondState) { + BluetoothDevice.BOND_NONE -> "未绑定" + BluetoothDevice.BOND_BONDING -> "正在绑定" + BluetoothDevice.BOND_BONDED -> "已绑定" + else -> "未知状态" + } + } + + /** + * 检查已连接的蓝牙设备 + * 在服务启动或蓝牙开启时调用,检查是否有目标设备已经连接 + */ + private fun checkAlreadyConnectedDevices() { + try { + bluetoothAdapter?.let { adapter -> + if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.BLUETOOTH_CONNECT) + == PackageManager.PERMISSION_GRANTED) { + + val bondedDevices = adapter.bondedDevices + Log.i(TAG, "检查已绑定的设备数量: ${bondedDevices?.size ?: 0}") + + bondedDevices?.forEach { device -> + val deviceName = device.name ?: "Unknown" + Log.d(TAG, "已绑定设备: $deviceName (${device.address})") + + if (deviceName.equals(TARGET_DEVICE_NAME, ignoreCase = true)) { + Log.i(TAG, "发现已绑定的目标设备: $deviceName") + // 注意:这里只能检查绑定状态,无法直接判断连接状态 + // 实际连接状态需要通过广播接收器监听 + } + } + } else { + Log.w(TAG, "缺少蓝牙连接权限,无法检查已连接设备") + } + } + } catch (e: Exception) { + Log.e(TAG, "检查已连接设备时发生异常", e) + } + } + + /** + * 初始化蓝牙监听器 + * 设置蓝牙适配器和注册广播接收器 + */ + private fun initializeBluetoothListener() { + try { + // 获取蓝牙管理器和适配器 + val bluetoothManager = getSystemService(Context.BLUETOOTH_SERVICE) as? BluetoothManager + bluetoothAdapter = bluetoothManager?.adapter + + if (bluetoothAdapter == null) { + Log.w(TAG, "设备不支持蓝牙功能") + return + } + + // 创建蓝牙广播接收器 + if (bluetoothReceiver == null) { + bluetoothReceiver = createBluetoothReceiver() + } + + // 首先注册蓝牙状态变化监听器(始终保持注册) + registerBluetoothStateReceiver() + + // 如果蓝牙已开启,注册设备连接监听器 + if (bluetoothAdapter!!.isEnabled) { + Log.i(TAG, "蓝牙已开启,注册设备连接监听器") + registerDeviceConnectionReceiver() + // 检查已连接的设备 + checkAlreadyConnectedDevices() + } else { + Log.w(TAG, "蓝牙未开启,仅注册状态监听器") + } + + } catch (e: Exception) { + Log.e(TAG, "初始化蓝牙监听器时发生异常", e) + } + } + + /** + * 注册蓝牙状态变化监听器 + * 这个监听器始终保持注册状态,用于监听蓝牙开关状态 + */ + private fun registerBluetoothStateReceiver() { + try { + if (!isBluetoothReceiverRegistered && bluetoothReceiver != null) { + val stateFilter = IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED) + registerReceiver(bluetoothReceiver, stateFilter) + isBluetoothReceiverRegistered = true + Log.i(TAG, "蓝牙状态监听器注册成功") + } + } catch (e: Exception) { + Log.e(TAG, "注册蓝牙状态监听器时发生异常", e) + } + } + + /** + * 注册设备连接监听器 + * 仅在蓝牙开启时注册,用于监听设备连接和断开事件 + */ + private fun registerDeviceConnectionReceiver() { + try { + if (isBluetoothReceiverRegistered && bluetoothReceiver != null) { + // 先注销现有的接收器 + unregisterReceiver(bluetoothReceiver!!) + + // 重新注册包含所有事件的接收器 + val fullFilter = IntentFilter().apply { + addAction(BluetoothDevice.ACTION_ACL_CONNECTED) + addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED) + addAction(BluetoothAdapter.ACTION_STATE_CHANGED) + } + + registerReceiver(bluetoothReceiver, fullFilter) + Log.i(TAG, "设备连接监听器注册成功") + } + } catch (e: Exception) { + Log.e(TAG, "注册设备连接监听器时发生异常", e) + } + } + + /** + * 注销设备连接监听器 + * 蓝牙关闭时调用,但保留状态监听器 + */ + private fun unregisterDeviceConnectionReceiver() { + try { + if (isBluetoothReceiverRegistered && bluetoothReceiver != null) { + // 注销当前接收器 + unregisterReceiver(bluetoothReceiver!!) + + // 重新注册仅包含状态变化的接收器 + val stateFilter = IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED) + registerReceiver(bluetoothReceiver, stateFilter) + Log.i(TAG, "设备连接监听器已注销,保留状态监听器") + } + } catch (e: Exception) { + Log.e(TAG, "注销设备连接监听器时发生异常", e) + } + } + + /** + * 完全注销蓝牙广播接收器 + * 仅在服务销毁时调用 + */ + private fun unregisterBluetoothReceiver() { + try { + if (isBluetoothReceiverRegistered && bluetoothReceiver != null) { + unregisterReceiver(bluetoothReceiver!!) + isBluetoothReceiverRegistered = false + Log.i(TAG, "蓝牙广播接收器已完全注销") + } + } catch (e: Exception) { + Log.e(TAG, "注销蓝牙广播接收器时发生异常", e) + } + } override fun onCreate() { super.onCreate() @@ -84,9 +391,77 @@ class BleMediaService : Service(), CoroutineScope { isRunning.set(true) startForeground(NOTIFICATION_ID, createNotification()) + // 初始化蓝牙监听器 + initializeBluetoothListener() + + // 启动定期蓝牙状态检查 + startBluetoothStatusCheck() + Log.i(TAG, "BLE代理服务已启动") } - + + /** + * 启动定期蓝牙状态检查 + * 每30秒检查一次蓝牙状态,确保监听器正常工作 + */ + private fun startBluetoothStatusCheck() { + bluetoothCheckJob = launch { + while (isRunning.get()) { + try { + kotlinx.coroutines.delay(30000) // 30秒检查一次 + checkAndRestoreBluetoothListener() + } catch (e: Exception) { + Log.e(TAG, "蓝牙状态检查时发生异常", e) + } + } + } + Log.i(TAG, "蓝牙状态定期检查已启动") + } + + /** + * 检查并恢复蓝牙监听器 + * 确保在蓝牙开启时监听器正常工作 + */ + private fun checkAndRestoreBluetoothListener() { + try { + bluetoothAdapter?.let { adapter -> + val isBluetoothEnabled = adapter.isEnabled + Log.d(TAG, "蓝牙状态检查: 蓝牙${if (isBluetoothEnabled) "已开启" else "已关闭"}, 接收器${if (isBluetoothReceiverRegistered) "已注册" else "未注册"}") + + if (isBluetoothEnabled && isBluetoothReceiverRegistered) { + // 蓝牙开启且接收器已注册,检查是否需要重新注册设备连接监听器 + // 这里可以通过尝试获取当前注册的IntentFilter来判断 + // 但Android没有直接的API,所以我们采用重新注册的方式确保监听器有效 + Log.d(TAG, "重新确认设备连接监听器注册状态") + registerDeviceConnectionReceiver() + } else if (isBluetoothEnabled && !isBluetoothReceiverRegistered) { + // 蓝牙开启但接收器未注册,重新初始化 + Log.w(TAG, "检测到蓝牙已开启但监听器未注册,重新初始化") + initializeBluetoothListener() + } else if (!isBluetoothEnabled && isBluetoothReceiverRegistered) { + // 蓝牙关闭但接收器仍注册,保持状态监听器 + Log.d(TAG, "蓝牙已关闭,确保仅保留状态监听器") + unregisterDeviceConnectionReceiver() + } + } ?: run { + // 蓝牙适配器为空,重新初始化 + Log.w(TAG, "蓝牙适配器为空,重新初始化监听器") + initializeBluetoothListener() + } + } catch (e: Exception) { + Log.e(TAG, "检查和恢复蓝牙监听器时发生异常", e) + } + } + + /** + * 停止蓝牙状态检查 + */ + private fun stopBluetoothStatusCheck() { + bluetoothCheckJob?.cancel() + bluetoothCheckJob = null + Log.i(TAG, "蓝牙状态定期检查已停止") + } + override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { Log.i(TAG, "BleAgentService.onStartCommand: ${intent?.action}") @@ -269,6 +644,14 @@ class BleMediaService : Service(), CoroutineScope { override fun onDestroy() { Log.i(TAG, "BLE代理服务正在销毁...") + // 停止蓝牙状态检查 + stopBluetoothStatusCheck() + + // 完全注销蓝牙广播接收器 + unregisterBluetoothReceiver() + bluetoothReceiver = null + bluetoothAdapter = null + // 取消所有协程 cancel() @@ -335,4 +718,4 @@ class BleMediaService : Service(), CoroutineScope { return builder.build() } -} \ No newline at end of file +} \ No newline at end of file