|
|
|
@ -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>(BluetoothDevice.EXTRA_DEVICE) |
|
|
|
device?.let { handleDeviceConnected(it) } |
|
|
|
} |
|
|
|
BluetoothDevice.ACTION_ACL_DISCONNECTED -> { |
|
|
|
val device = intent.getParcelableExtra<BluetoothDevice>(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() |
|
|
|
} |
|
|
|
} |
|
|
|
} |