You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1354 lines
46 KiB
1354 lines
46 KiB
import 'dart:async';
|
|
import 'dart:convert';
|
|
import 'dart:io';
|
|
|
|
import 'package:firebase_auth/firebase_auth.dart';
|
|
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
|
import 'package:get_storage/get_storage.dart';
|
|
import 'package:get/get.dart';
|
|
import 'package:ble_service/ble_service.dart';
|
|
import 'package:agent_service/agent_service.dart';
|
|
import '../models/user_Info.dart' as userInfo;
|
|
import '/data/models/appconfig_model.dart';
|
|
|
|
import '../../data/models/appconfig.dart';
|
|
import '../../core/utils/logger.dart';
|
|
import 'bluetooth_manager.dart';
|
|
import 'language_manager.dart';
|
|
import 'network/dio_manager.dart';
|
|
|
|
// 重新导出BLE连接状态常量,让外部可以通过BleManager访问
|
|
export 'package:ble_service/ble_service.dart' show BleConnectionState;
|
|
|
|
/// 命令类型常量(与原生层保持一致)
|
|
class BleCommands {
|
|
static const int GET_VERSION = 0x01;
|
|
static const int GET_PRODUCT_ID = 0x02;
|
|
static const int GET_PRODUCT_COLOR = 0x03;
|
|
static const int GET_BATTERY_INFO = 0x04;
|
|
static const int CONTROL_CODEC = 0x05;
|
|
static const int GET_WAKEUP_VERSION = 0x08;
|
|
}
|
|
|
|
/// 判断编解码控制指令是否成功
|
|
///
|
|
/// 根据 rawData 第二字节是否为非 0 来判断:
|
|
/// - 成功:第二字节不为 0
|
|
/// - 失败或无法解析:返回 false
|
|
bool _isCodecControlSuccess(Map<dynamic, dynamic> data) {
|
|
final dynamic raw = data['rawData'];
|
|
if (raw == null) return false;
|
|
|
|
int? secondByte;
|
|
|
|
if (raw is List) {
|
|
if (raw.length >= 2) {
|
|
final s = raw[1];
|
|
if (s is int) {
|
|
secondByte = s;
|
|
} else if (s is num) {
|
|
secondByte = s.toInt();
|
|
} else if (s is String) {
|
|
final t = s.trim();
|
|
if (t.startsWith('0x') || t.startsWith('0X')) {
|
|
secondByte = int.tryParse(t.substring(2), radix: 16);
|
|
} else {
|
|
secondByte = int.tryParse(t);
|
|
}
|
|
}
|
|
}
|
|
} else if (raw is String) {
|
|
final normalized = raw.trim().replaceAll('[', '').replaceAll(']', '');
|
|
final parts =
|
|
normalized.split(RegExp(r'[,\s]+')).where((e) => e.isNotEmpty).toList();
|
|
if (parts.length >= 2) {
|
|
final t = parts[1].trim();
|
|
if (t.startsWith('0x') || t.startsWith('0X')) {
|
|
secondByte = int.tryParse(t.substring(2), radix: 16);
|
|
} else {
|
|
secondByte = int.tryParse(t);
|
|
}
|
|
}
|
|
} else if (raw is Map) {
|
|
final dynamic s = raw['second'] ?? raw['status2'] ?? raw['result'];
|
|
if (s is int) {
|
|
secondByte = s;
|
|
} else if (s is num) {
|
|
secondByte = s.toInt();
|
|
} else if (s is String) {
|
|
final t = s.trim();
|
|
if (t.startsWith('0x') || t.startsWith('0X')) {
|
|
secondByte = int.tryParse(t.substring(2), radix: 16);
|
|
} else {
|
|
secondByte = int.tryParse(t);
|
|
}
|
|
}
|
|
} else {
|
|
// 无法解析的类型
|
|
return false;
|
|
}
|
|
|
|
return secondByte != null && secondByte != 0;
|
|
}
|
|
|
|
/// 蓝牙设备信息缓存模型
|
|
class DeviceInfo {
|
|
final String address;
|
|
final String name;
|
|
|
|
// 整体电池电量
|
|
final int batteryLevel;
|
|
|
|
// 详细电池信息
|
|
final int leftEarBattery;
|
|
final int rightEarBattery;
|
|
final int caseBattery;
|
|
|
|
// 充电状态
|
|
final bool leftEarCharging;
|
|
final bool rightEarCharging;
|
|
final bool caseCharging;
|
|
|
|
final String firmwareVersion;
|
|
final String firmwareProductId;
|
|
final String firmwareProductColor;
|
|
final DateTime lastUpdated;
|
|
|
|
//唤醒词版本
|
|
final String wakeupLeftVersion;
|
|
final String wakeupRightVersion;
|
|
|
|
DeviceInfo({
|
|
required this.address,
|
|
required this.name,
|
|
this.batteryLevel = 0,
|
|
this.leftEarBattery = 0,
|
|
this.rightEarBattery = 0,
|
|
this.caseBattery = 0,
|
|
this.leftEarCharging = false,
|
|
this.rightEarCharging = false,
|
|
this.caseCharging = false,
|
|
this.firmwareVersion = '',
|
|
this.firmwareProductId = '',
|
|
this.firmwareProductColor = '',
|
|
DateTime? lastUpdated,
|
|
this.wakeupLeftVersion = '',
|
|
this.wakeupRightVersion = '',
|
|
}) : lastUpdated = lastUpdated ?? DateTime.now();
|
|
|
|
/// 创建更新后的设备信息副本
|
|
DeviceInfo copyWith({
|
|
String? address,
|
|
String? name,
|
|
int? batteryLevel,
|
|
int? leftEarBattery,
|
|
int? rightEarBattery,
|
|
int? caseBattery,
|
|
bool? leftEarCharging,
|
|
bool? rightEarCharging,
|
|
bool? caseCharging,
|
|
String? firmwareVersion,
|
|
String? firmwareProductId,
|
|
String? firmwareProductColor,
|
|
String? wakeupLeftVersion,
|
|
String? wakeupRightVersion,
|
|
}) {
|
|
return DeviceInfo(
|
|
address: address ?? this.address,
|
|
name: name ?? this.name,
|
|
batteryLevel: batteryLevel ?? this.batteryLevel,
|
|
leftEarBattery: leftEarBattery ?? this.leftEarBattery,
|
|
rightEarBattery: rightEarBattery ?? this.rightEarBattery,
|
|
caseBattery: caseBattery ?? this.caseBattery,
|
|
leftEarCharging: leftEarCharging ?? this.leftEarCharging,
|
|
rightEarCharging: rightEarCharging ?? this.rightEarCharging,
|
|
caseCharging: caseCharging ?? this.caseCharging,
|
|
firmwareVersion: firmwareVersion ?? this.firmwareVersion,
|
|
firmwareProductId: firmwareProductId ?? this.firmwareProductId,
|
|
firmwareProductColor: firmwareProductColor ?? this.firmwareProductColor,
|
|
lastUpdated: DateTime.now(),
|
|
wakeupLeftVersion: wakeupLeftVersion ?? this.wakeupLeftVersion,
|
|
wakeupRightVersion: wakeupRightVersion ?? this.wakeupRightVersion,
|
|
);
|
|
}
|
|
|
|
@override
|
|
String toString() {
|
|
return 'DeviceInfo(address: $address, name: $name, '
|
|
'battery: $batteryLevel%, L: $leftEarBattery%, R: $rightEarBattery%, Case: $caseBattery%, '
|
|
'charging: L:$leftEarCharging, R:$rightEarCharging, C:$caseCharging, '
|
|
'version: $firmwareVersion, '
|
|
'wakeupLeftVersion: $wakeupLeftVersion, '
|
|
'wakeupRightVersion: $wakeupRightVersion)';
|
|
}
|
|
}
|
|
|
|
/// BLE管理器 - 专门处理BLE设备连接和信息管理
|
|
class BleManager extends GetxService {
|
|
static BleManager get to => Get.find<BleManager>();
|
|
|
|
// BLE服务实例
|
|
final BleService _bleService = BleService();
|
|
// 经典蓝牙实例
|
|
|
|
// 当前连接的设备信息
|
|
String? currentDeviceAddress;
|
|
String? _currentDeviceName;
|
|
|
|
// BLE连接状态
|
|
final _connectionState = BleConnectionState.disconnected.obs;
|
|
int get connectionState => _connectionState.value;
|
|
|
|
// 公开的连接状态流,供外部监听
|
|
RxInt get connectionStateRx => _connectionState;
|
|
|
|
// 连接状态监听
|
|
final _isCall = false.obs;
|
|
final _isConnected = false.obs;
|
|
bool get isConnected => _isConnected.value;
|
|
bool get isCall => _isCall.value;
|
|
|
|
// 设备信息缓存
|
|
final deviceInfo = Rx<DeviceInfo?>(null); // 使用 Rx 包装
|
|
|
|
//添加编码器状态跟踪
|
|
final _isCodecActive = false.obs;
|
|
bool get isCodecActive => _isCodecActive.value;
|
|
RxBool get isCodecActiveRx => _isCodecActive;
|
|
bool _awaitingCodecOpen = false; //是否正在等待编码器打开的成功应答
|
|
bool _awaitingCodecClose = false; //是否正在等待编码器关闭的成功应答
|
|
|
|
// 订阅
|
|
StreamSubscription<dynamic>? _statusSubscription;
|
|
StreamSubscription<dynamic>? _dataSubscription;
|
|
final GetStorage _storage = GetStorage();
|
|
|
|
final _wakeupVoiceUpgradeProgress = 0.obs; // 唤醒语音升级进度
|
|
RxInt get wakeupVoiceUpgradeProgress => _wakeupVoiceUpgradeProgress;
|
|
|
|
final _wakeupVoiceUpgradeStatus =
|
|
0.obs; // 唤醒语音升级状态 0: 未升级 1: 升级中 2: 升级成功 3: 升级失败
|
|
RxInt get wakeupVoiceUpgradeStatus => _wakeupVoiceUpgradeStatus;
|
|
|
|
/// 初始化
|
|
@override
|
|
void onInit() {
|
|
super.onInit();
|
|
Logger.info('BLE管理器初始化');
|
|
|
|
// 设置BLE事件监听
|
|
_setupBleListener();
|
|
}
|
|
|
|
/// 释放资源
|
|
@override
|
|
void onClose() {
|
|
_statusSubscription?.cancel();
|
|
_dataSubscription?.cancel();
|
|
super.onClose();
|
|
}
|
|
|
|
/// 设置BLE事件监听
|
|
void _setupBleListener() {
|
|
//Logger.info('lxm--_setupBleListener被调用,开始设置BLE事件监听');
|
|
_statusSubscription?.cancel();
|
|
_dataSubscription?.cancel();
|
|
|
|
try {
|
|
Logger.info('lxm--开始监听BLE状态更新流');
|
|
// 监听BLE状态更新
|
|
_statusSubscription = _bleService.onStatusUpdated.listen(
|
|
(event) {
|
|
Logger.info('lxm--收到BLE状态更新事件: $event');
|
|
if (event is Map) {
|
|
Logger.info('lxm--事件是Map类型,开始处理');
|
|
// 处理连接状态更新
|
|
if (event['type'] == 'connectionStateChanged') {
|
|
Logger.info('lxm--处理连接状态变化事件');
|
|
final state = event['state'] as int;
|
|
final oldState = _connectionState.value;
|
|
_connectionState.value = state;
|
|
|
|
Logger.d('BleManager', '🔄 BLE状态更新: $oldState → $state');
|
|
Logger.d('BleManager', '📡 通知监听器状态变化: ${_connectionState.value}');
|
|
|
|
// 连接状态转换
|
|
if (state == BleConnectionState.connected) {
|
|
Logger.info('lxm--BLE设备已连接');
|
|
_isConnected.value = true;
|
|
|
|
// 在连接成功后延迟 300 毫秒获取设备信息(可根据需要调整时间)
|
|
Future.delayed(const Duration(milliseconds: 300), () {
|
|
// 可选:检查是否仍处于连接状态
|
|
if (_isConnected.value) {
|
|
Logger.info('lxm--连接后延迟获取设备信息(当前被注释)');
|
|
// fetchDeviceInfo();
|
|
}
|
|
});
|
|
} else if (state == BleConnectionState.disconnected ||
|
|
state == BleConnectionState.error) {
|
|
Logger.info('lxm--BLE设备已断开或发生错误');
|
|
_isConnected.value = false;
|
|
_awaitingCodecOpen = false;
|
|
_awaitingCodecClose = false;
|
|
_isCodecActive.value = false;
|
|
Logger.info('lxm--断开连接时重置设备信息为0');
|
|
_updateDeviceInfoIfNeeded(
|
|
batteryLevel: 0,
|
|
leftEarBattery: 0,
|
|
rightEarBattery: 0,
|
|
caseBattery: 0,
|
|
leftEarCharging: false,
|
|
rightEarCharging: false,
|
|
caseCharging: false,
|
|
firmwareVersion: '',
|
|
firmwareProductId: '',
|
|
firmwareProductColor: '',
|
|
wakeupLeftVersion: '',
|
|
wakeupRightVersion: '',
|
|
);
|
|
// 断开连接时不清除设备信息,保留最后的电量信息
|
|
// 只有在需要完全清除设备时才重置信息
|
|
}
|
|
}
|
|
|
|
if (event['type'] == 'wakeupVoiceUpgradeProgress') {
|
|
// 唤醒语音升级进度
|
|
Logger.info('lxm--处理唤醒语音升级进度事件: $event');
|
|
_wakeupVoiceUpgradeProgress.value =
|
|
event['progress'] as int? ?? 0;
|
|
_wakeupVoiceUpgradeStatus.value = 1; // 升级中
|
|
Logger.info(
|
|
'lxm--唤醒语音升级进度: ${_wakeupVoiceUpgradeProgress.value}%');
|
|
}
|
|
if (event['type'] == 'wakeupVoiceUpgradeSuccess') {
|
|
// 唤醒语音升级状态
|
|
Logger.info('lxm--处理唤醒语音升级状态事件: $event');
|
|
_wakeupVoiceUpgradeStatus.value = 2; // 升级成功
|
|
Logger.info('lxm--唤醒语音升级状态: ${_wakeupVoiceUpgradeStatus.value}');
|
|
}
|
|
|
|
if (event['type'] == 'wakeupVoiceUpgradeFailure') {
|
|
// 唤醒语音升级状态
|
|
Logger.info('lxm--处理唤醒语音升级状态事件: $event');
|
|
_wakeupVoiceUpgradeStatus.value = 3; // 升级失败
|
|
Logger.info('lxm--唤醒语音升级状态: ${_wakeupVoiceUpgradeStatus.value}');
|
|
}
|
|
|
|
Logger.info('lxm--准备调用_processDeviceInfo处理设备信息');
|
|
// 处理设备信息
|
|
_processDeviceInfo(event);
|
|
} else {
|
|
Logger.info('lxm--事件不是Map类型: ${event.runtimeType}');
|
|
}
|
|
},
|
|
onError: (error) {
|
|
Logger.error('lxm--BLE状态事件流错误: $error');
|
|
},
|
|
);
|
|
|
|
Logger.info('lxm--BLE状态监听器设置完成');
|
|
// 监听BLE数据流
|
|
} catch (e) {
|
|
Logger.error('lxm--设置BLE事件监听器失败: ${e.toString()}');
|
|
}
|
|
}
|
|
|
|
/// 处理来自原生层的设备信息
|
|
void _processDeviceInfo(Map<dynamic, dynamic> event) {
|
|
try {
|
|
Logger.info('lxm--_processDeviceInfo被调用');
|
|
Logger.info('lxm--接收到的事件数据: $event');
|
|
|
|
// 检查是否是设备信息响应
|
|
if (event.containsKey('command') && event.containsKey('success')) {
|
|
Logger.info('lxm--事件包含command和success字段');
|
|
final bool success = event['success'] as bool;
|
|
Logger.info('lxm--命令执行成功状态: $success');
|
|
|
|
if (!success) {
|
|
Logger.warning('lxm--设备命令执行失败: ${event['command']}');
|
|
return;
|
|
}
|
|
|
|
// 根据命令类型处理不同信息
|
|
final command = event['command'];
|
|
Logger.info('lxm--命令类型: $command (${command.runtimeType})');
|
|
|
|
if (command is int) {
|
|
Logger.info('lxm--基于命令ID处理: $command');
|
|
// 基于命令ID处理
|
|
_processDeviceInfoByCommandId(command, event);
|
|
} else if (command is String) {
|
|
Logger.info('lxm--基于命令名称处理: $command');
|
|
// 基于命令名称处理
|
|
_processDeviceInfoByCommandName(command, event);
|
|
} else {
|
|
Logger.warning('lxm--未知的命令类型: ${command.runtimeType}');
|
|
}
|
|
} else {
|
|
Logger.info('lxm--事件不包含command或success字段,跳过处理');
|
|
Logger.info('lxm--事件包含的键: ${event.keys.toList()}');
|
|
}
|
|
} catch (e) {
|
|
Logger.error('lxm--处理设备信息异常: ${e.toString()}');
|
|
Logger.error('lxm--异常堆栈: ${StackTrace.current}');
|
|
}
|
|
}
|
|
|
|
/// 根据命令ID处理设备信息
|
|
void _processDeviceInfoByCommandId(
|
|
int commandId, Map<dynamic, dynamic> data) {
|
|
Logger.info('lxm--_processDeviceInfoByCommandId被调用,命令ID: $commandId');
|
|
Logger.info('lxm--命令数据: $data');
|
|
|
|
switch (commandId) {
|
|
case BleCommands.GET_VERSION:
|
|
Logger.info('lxm--处理版本信息命令');
|
|
_updateVersionInfoFromData(data);
|
|
break;
|
|
case BleCommands.GET_PRODUCT_ID:
|
|
Logger.info('lxm--处理产品ID命令');
|
|
_updateProductIdFromData(data);
|
|
break;
|
|
case BleCommands.GET_PRODUCT_COLOR:
|
|
Logger.info('lxm--处理产品颜色命令(暂未实现)');
|
|
break;
|
|
case BleCommands.GET_BATTERY_INFO:
|
|
Logger.info('lxm--处理电池信息命令,准备调用_updateBatteryInfoFromData');
|
|
_updateBatteryInfoFromData(data);
|
|
Logger.info('lxm--电池信息处理完成');
|
|
break;
|
|
case BleCommands.CONTROL_CODEC:
|
|
Logger.info('lxm--处理编解码控制命令');
|
|
// 处理通话状态
|
|
print(" CONTROL_CODEC: $commandId,$data");
|
|
|
|
final bool codecSuccess = _isCodecControlSuccess(data);
|
|
if (_awaitingCodecOpen) {
|
|
//如果正在等待打开编解码器
|
|
_isCodecActive.value = codecSuccess; // 只在等待打开时更新状态
|
|
_awaitingCodecOpen = false;
|
|
} else if (_awaitingCodecClose) {
|
|
if (codecSuccess) {
|
|
_isCodecActive.value = false;
|
|
}
|
|
_awaitingCodecClose = false;
|
|
}
|
|
|
|
if (codecSuccess) {
|
|
print("lxm--编解码控制成功 (rawData 第二字节非 0)");
|
|
Logger.info('lxm--编解码控制成功 (rawData 第二字节非 0)');
|
|
} else {
|
|
print("lxm--编解码控制失败 (rawData 为 [162, 0] 或无法解析)");
|
|
Logger.warning('lxm--编解码控制失败 (rawData 为 [162, 0] 或无法解析)');
|
|
}
|
|
|
|
break;
|
|
case BleCommands.GET_WAKEUP_VERSION:
|
|
Logger.info('lxm--处理唤醒语音版本命令');
|
|
_updateWakeupVersionFromData(data);
|
|
break;
|
|
default:
|
|
Logger.warning('lxm--未处理的命令ID: $commandId,数据: $data');
|
|
print(" 未处理的命令ID: $commandId,$data");
|
|
}
|
|
}
|
|
|
|
/// 根据命令名称处理设备信息
|
|
void _processDeviceInfoByCommandName(
|
|
String commandName, Map<dynamic, dynamic> data) {
|
|
switch (commandName) {
|
|
case 'batteryInfo':
|
|
_updateBatteryInfoFromData(data);
|
|
break;
|
|
case 'versionInfo':
|
|
_updateVersionInfoFromData(data);
|
|
break;
|
|
case 'productId':
|
|
_updateProductIdFromData(data);
|
|
break;
|
|
case 'productColor':
|
|
break;
|
|
case 'Error':
|
|
print(" Error: $commandName,$data");
|
|
break;
|
|
default:
|
|
print(" 未处理的命令名称: $commandName,$data");
|
|
Logger.info('未处理的命令名称: $commandName');
|
|
}
|
|
}
|
|
|
|
/// 更新电池信息
|
|
void _updateBatteryInfoFromData(Map<dynamic, dynamic> data) {
|
|
try {
|
|
Logger.info('lxm--_updateBatteryInfoFromData被调用');
|
|
Logger.info('lxm--接收到的原始数据: $data');
|
|
|
|
// 确保数据中包含电池信息
|
|
if (!data.containsKey('leftEarBattery') ||
|
|
!data.containsKey('rightEarBattery') ||
|
|
!data.containsKey('caseBattery')) {
|
|
Logger.warning('lxm--电池信息数据不完整,缺少必要字段');
|
|
Logger.warning('lxm--数据包含的键: ${data.keys.toList()}');
|
|
return;
|
|
}
|
|
|
|
Logger.info('lxm--原始电池数据解析:');
|
|
Logger.info(
|
|
'lxm-- leftEarBattery原始值: ${data['leftEarBattery']} (类型: ${data['leftEarBattery'].runtimeType})');
|
|
Logger.info(
|
|
'lxm-- rightEarBattery原始值: ${data['rightEarBattery']} (类型: ${data['rightEarBattery'].runtimeType})');
|
|
Logger.info(
|
|
'lxm-- caseBattery原始值: ${data['caseBattery']} (类型: ${data['caseBattery'].runtimeType})');
|
|
Logger.info(
|
|
'lxm-- leftEarCharging原始值: ${data['leftEarCharging']} (类型: ${data['leftEarCharging'].runtimeType})');
|
|
Logger.info(
|
|
'lxm-- rightEarCharging原始值: ${data['rightEarCharging']} (类型: ${data['rightEarCharging'].runtimeType})');
|
|
Logger.info(
|
|
'lxm-- caseCharging原始值: ${data['caseCharging']} (类型: ${data['caseCharging'].runtimeType})');
|
|
Logger.info(
|
|
'lxm-- batteryLevel原始值: ${data['batteryLevel']} (类型: ${data['batteryLevel']?.runtimeType})');
|
|
|
|
// 提取电池信息
|
|
final int leftBattery = (data['leftEarBattery'] as int? ?? 0) == 127
|
|
? -1 // 特殊值127转换为-1
|
|
: (data['leftEarBattery'] as int? ?? 0) > 100
|
|
? 0 // 大于100的值重置为0
|
|
: (data['leftEarBattery'] as int? ?? 0); // 正常值
|
|
|
|
final int rightBattery = (data['rightEarBattery'] as int? ?? 0) == 127
|
|
? -1 // 特殊值127转换为-1
|
|
: (data['rightEarBattery'] as int? ?? 0) > 100
|
|
? 0 // 大于100的值重置为0
|
|
: (data['rightEarBattery'] as int? ?? 0); // 正常值
|
|
|
|
final int caseBattery = (data['caseBattery'] as int? ?? 0) == 127
|
|
? -1 // 特殊值127转换为-1
|
|
: (data['caseBattery'] as int? ?? 0) > 100
|
|
? 0 // 大于100的值重置为0
|
|
: (data['caseBattery'] as int? ?? 0); // 正常值
|
|
final bool leftCharging = data['leftEarCharging'] as bool? ?? false;
|
|
final bool rightCharging = data['rightEarCharging'] as bool? ?? false;
|
|
final bool caseCharging = data['caseCharging'] as bool? ?? false;
|
|
|
|
// 获取整体电量(原生层使用左耳电量作为主要指示)
|
|
final int overallBattery = data['batteryLevel'] as int? ?? leftBattery;
|
|
|
|
Logger.info('lxm--处理后的电池数据:');
|
|
Logger.info('lxm-- leftBattery: $leftBattery');
|
|
Logger.info('lxm-- rightBattery: $rightBattery');
|
|
Logger.info('lxm-- caseBattery: $caseBattery');
|
|
Logger.info('lxm-- leftCharging: $leftCharging');
|
|
Logger.info('lxm-- rightCharging: $rightCharging');
|
|
Logger.info('lxm-- caseCharging: $caseCharging');
|
|
Logger.info('lxm-- overallBattery: $overallBattery');
|
|
|
|
Logger.info('lxm--准备调用_updateDeviceInfoIfNeeded');
|
|
|
|
// 更新设备信息
|
|
_updateDeviceInfoIfNeeded(
|
|
batteryLevel: overallBattery,
|
|
leftEarBattery: leftBattery,
|
|
rightEarBattery: rightBattery,
|
|
caseBattery: caseBattery,
|
|
leftEarCharging: leftCharging,
|
|
rightEarCharging: rightCharging,
|
|
caseCharging: caseCharging,
|
|
);
|
|
|
|
Logger.info(
|
|
'lxm--设备电池信息已更新: 电量=$overallBattery%, 左耳=$leftBattery%, 右耳=$rightBattery%, 充电仓=$caseBattery%');
|
|
} catch (e) {
|
|
Logger.error('lxm--更新电池信息失败: ${e.toString()}');
|
|
Logger.error('lxm--错误堆栈: ${StackTrace.current}');
|
|
}
|
|
}
|
|
|
|
/// 更新版本信息
|
|
void _updateVersionInfoFromData(Map<dynamic, dynamic> data) {
|
|
try {
|
|
// 确保数据中包含版本信息
|
|
if (!data.containsKey('version')) {
|
|
Logger.warning('版本信息数据不完整');
|
|
return;
|
|
}
|
|
|
|
// 提取版本信息
|
|
final String version = data['version'] as String? ?? '';
|
|
|
|
// 更新设备信息
|
|
_updateDeviceInfoIfNeeded(
|
|
firmwareVersion: version,
|
|
);
|
|
|
|
Logger.info('设备版本信息已更新: 版本=$version');
|
|
} catch (e) {
|
|
Logger.error('更新版本信息失败: ${e.toString()}');
|
|
}
|
|
}
|
|
|
|
/// 更新设备id
|
|
void _updateProductIdFromData(Map<dynamic, dynamic> data) {
|
|
try {
|
|
// 确保数据中包含版本信息
|
|
if (!data.containsKey('productId')) {
|
|
Logger.warning('版本信息数据不完整');
|
|
return;
|
|
}
|
|
|
|
// 提取版本信息
|
|
final String productId = data['productId'] as String? ?? '';
|
|
|
|
// 更新设备信息
|
|
_updateDeviceInfoIfNeeded(
|
|
firmwareProductId: productId,
|
|
);
|
|
|
|
Logger.info('设备设备id已更新: 设备id=$productId');
|
|
} catch (e) {
|
|
Logger.error('更新设备id失败: ${e.toString()}');
|
|
}
|
|
}
|
|
|
|
/// 更新唤醒语音版本信息
|
|
void _updateWakeupVersionFromData(Map<dynamic, dynamic> data) {
|
|
try {
|
|
// 确保数据中包含版本信息
|
|
if (!data.containsKey('leftVersionDec') ||
|
|
!data.containsKey('rightVersionDec')) {
|
|
Logger.warning('唤醒语音版本信息数据不完整');
|
|
return;
|
|
}
|
|
|
|
// 提取版本信息
|
|
final String wakeupLeftVersion = data['leftVersionDec'] as String? ?? '';
|
|
final String wakeupRightVersion =
|
|
data['rightVersionDec'] as String? ?? '';
|
|
|
|
// 更新设备信息
|
|
_updateDeviceInfoIfNeeded(
|
|
wakeupLeftVersion: wakeupLeftVersion,
|
|
wakeupRightVersion: wakeupRightVersion,
|
|
);
|
|
|
|
Logger.info('设备唤醒语音版本信息已更新: 左=$wakeupLeftVersion, 右=$wakeupRightVersion');
|
|
} catch (e) {
|
|
Logger.error('更新唤醒语音版本信息失败: ${e.toString()}');
|
|
}
|
|
}
|
|
|
|
/// 更新设备信息(如果已存在设备)
|
|
void _updateDeviceInfoIfNeeded({
|
|
int? batteryLevel,
|
|
int? leftEarBattery,
|
|
int? rightEarBattery,
|
|
int? caseBattery,
|
|
bool? leftEarCharging,
|
|
bool? rightEarCharging,
|
|
bool? caseCharging,
|
|
String? firmwareVersion,
|
|
String? firmwareProductId,
|
|
String? firmwareProductColor,
|
|
String? wakeupLeftVersion,
|
|
String? wakeupRightVersion,
|
|
}) {
|
|
Logger.info('lxm--_updateDeviceInfoIfNeeded被调用');
|
|
Logger.info(
|
|
'lxm--传入参数: batteryLevel=$batteryLevel, leftEarBattery=$leftEarBattery, rightEarBattery=$rightEarBattery, caseBattery=$caseBattery');
|
|
Logger.info(
|
|
'lxm--充电状态: leftEarCharging=$leftEarCharging, rightEarCharging=$rightEarCharging, caseCharging=$caseCharging');
|
|
Logger.info('lxm--当前deviceInfo.value是否为null: ${deviceInfo.value == null}');
|
|
|
|
// 如果设备信息已存在,则更新
|
|
if (deviceInfo.value != null) {
|
|
Logger.info('lxm--设备信息已存在,进行更新操作');
|
|
Logger.info('lxm--更新前的设备信息: ${deviceInfo.value}');
|
|
|
|
deviceInfo.value = deviceInfo.value!.copyWith(
|
|
batteryLevel: batteryLevel ?? deviceInfo.value?.batteryLevel,
|
|
leftEarBattery: _getValidBatteryValue(
|
|
leftEarBattery, deviceInfo.value?.leftEarBattery),
|
|
rightEarBattery: _getValidBatteryValue(
|
|
rightEarBattery, deviceInfo.value?.rightEarBattery),
|
|
caseBattery: caseBattery ?? deviceInfo.value?.caseBattery,
|
|
leftEarCharging: leftEarCharging ?? deviceInfo.value!.leftEarCharging,
|
|
rightEarCharging:
|
|
rightEarCharging ?? deviceInfo.value!.rightEarCharging,
|
|
caseCharging: caseCharging ?? deviceInfo.value!.caseCharging,
|
|
firmwareVersion: firmwareVersion ?? deviceInfo.value!.firmwareVersion,
|
|
firmwareProductId:
|
|
firmwareProductId ?? deviceInfo.value!.firmwareProductId,
|
|
firmwareProductColor:
|
|
firmwareProductColor ?? deviceInfo.value!.firmwareProductColor,
|
|
wakeupLeftVersion:
|
|
wakeupLeftVersion ?? deviceInfo.value!.wakeupLeftVersion,
|
|
wakeupRightVersion:
|
|
wakeupRightVersion ?? deviceInfo.value!.wakeupRightVersion,
|
|
);
|
|
|
|
Logger.info('lxm--更新后的设备信息: ${deviceInfo.value}');
|
|
}
|
|
// 创建设备信息
|
|
// 如果设备信息不存在,但有地址和名称,则创建新的设备信息
|
|
else if (deviceInfo.value == null &&
|
|
_isConnected.value &&
|
|
(firmwareVersion != null || batteryLevel != null)) {
|
|
Logger.info('lxm--设备信息不存在,创建新的设备信息对象');
|
|
// 使用保存的设备信息创建新的DeviceInfo对象
|
|
String deviceAddress = currentDeviceAddress ?? "";
|
|
String deviceName = _currentDeviceName ?? "";
|
|
|
|
Logger.info('lxm--创建新的设备信息对象: address=$deviceAddress, name=$deviceName');
|
|
deviceInfo.value = DeviceInfo(
|
|
address: deviceAddress,
|
|
name: deviceName,
|
|
batteryLevel: batteryLevel ?? 0,
|
|
leftEarBattery: leftEarBattery ?? 0,
|
|
rightEarBattery: rightEarBattery ?? 0,
|
|
caseBattery: caseBattery ?? 0,
|
|
leftEarCharging: leftEarCharging ?? false,
|
|
rightEarCharging: rightEarCharging ?? false,
|
|
caseCharging: caseCharging ?? false,
|
|
firmwareVersion: firmwareVersion ?? '',
|
|
firmwareProductId: firmwareProductId ?? '',
|
|
firmwareProductColor: firmwareProductColor ?? '',
|
|
wakeupLeftVersion: wakeupLeftVersion ?? '',
|
|
wakeupRightVersion: wakeupRightVersion ?? '',
|
|
);
|
|
|
|
Logger.info('lxm--新创建的设备信息: ${deviceInfo.value}');
|
|
} else {
|
|
Logger.info(
|
|
'lxm--不满足更新条件: deviceInfo.value == null: ${deviceInfo.value == null}, _isConnected.value: ${_isConnected.value}, firmwareVersion: $firmwareVersion, batteryLevel: $batteryLevel');
|
|
}
|
|
}
|
|
|
|
// 新增智能电池值选择方法
|
|
int? _getValidBatteryValue(int? newValue, int? currentValue) {
|
|
// 如果新值为null,使用当前值
|
|
if (newValue == null) return currentValue;
|
|
|
|
// 如果当前值为null或0,使用新值(即使新值为0)
|
|
if (currentValue == null || currentValue == 0) return newValue;
|
|
|
|
// 如果新值为0但当前值不为0,保持当前值(避免有效数据被0覆盖)
|
|
if (newValue == 0 && currentValue > 0) {
|
|
Logger.warning('检测到电池数据异常(新值为0),保持当前值: $currentValue');
|
|
return currentValue;
|
|
}
|
|
|
|
// 其他情况使用新值
|
|
return newValue;
|
|
}
|
|
|
|
/// 清除设备信息(用于完全断开连接或切换设备时)
|
|
void clearDeviceInfo() {
|
|
Logger.info('清除设备信息');
|
|
deviceInfo.value = null;
|
|
currentDeviceAddress = null;
|
|
_currentDeviceName = null;
|
|
}
|
|
|
|
/// 连接成功后获取设备信息
|
|
Future<void> fetchDeviceInfo() async {
|
|
Logger.info('开始获取BLE设备详细信息');
|
|
|
|
try {
|
|
// 确保设备信息对象存在
|
|
if (deviceInfo.value == null && _isConnected.value) {
|
|
// 创建初始设备信息对象
|
|
String deviceAddress = currentDeviceAddress ?? "";
|
|
String deviceName = _currentDeviceName ?? "";
|
|
|
|
Logger.info('初始化设备信息对象: address=$deviceAddress, name=$deviceName');
|
|
deviceInfo.value = DeviceInfo(
|
|
address: deviceAddress,
|
|
name: deviceName,
|
|
batteryLevel: 0,
|
|
leftEarBattery: 0,
|
|
rightEarBattery: 0,
|
|
caseBattery: 0,
|
|
leftEarCharging: false,
|
|
rightEarCharging: false,
|
|
caseCharging: false,
|
|
firmwareVersion: '',
|
|
firmwareProductId: '',
|
|
firmwareProductColor: '',
|
|
wakeupLeftVersion: '',
|
|
wakeupRightVersion: '',
|
|
);
|
|
}
|
|
|
|
// 并行获取所有设备信息,不使用延迟
|
|
final results = await Future.wait([
|
|
_bleService.getBatteryInfo(),
|
|
_bleService.getDeviceVersion(),
|
|
_bleService.getProductId(),
|
|
]);
|
|
|
|
Logger.info(
|
|
'设备信息获取结果: 电池=${results[0]}, 版本=${results[1]}, 产品ID=${results[2]}');
|
|
|
|
if (!results[0]) {
|
|
Logger.warning('电池信息获取指令发送失败');
|
|
}
|
|
if (!results[1]) {
|
|
Logger.warning('版本信息获取指令发送失败');
|
|
}
|
|
if (!results[2]) {
|
|
Logger.warning('产品ID获取指令发送失败');
|
|
}
|
|
} catch (e) {
|
|
Logger.error('获取BLE设备信息失败: ${e.toString()}');
|
|
}
|
|
}
|
|
|
|
/// 检查BLE连接状态
|
|
Future<int> getConnectionState() async {
|
|
try {
|
|
final isConnected = await _bleService.isConnected();
|
|
_connectionState.value = isConnected
|
|
? BleConnectionState.connected
|
|
: BleConnectionState.disconnected;
|
|
_isConnected.value = isConnected;
|
|
|
|
return _connectionState.value;
|
|
} catch (e) {
|
|
Logger.error('获取BLE连接状态失败: ${e.toString()}');
|
|
return BleConnectionState.error;
|
|
}
|
|
}
|
|
|
|
String getDeviceName() {
|
|
if (deviceInfo.value != null) {
|
|
return deviceInfo.value!.name;
|
|
}
|
|
return "";
|
|
}
|
|
|
|
// 加载TTS偏好设置
|
|
Future<bool> _loadTtsInterrupe() async {
|
|
try {
|
|
if (!_storage.hasData("agent_tts_interrupt")) {
|
|
// 获取设备类型以确定检查策略
|
|
String deviceName = getDeviceName();
|
|
DBProduct? product = AppConfig.getproduct(deviceName);
|
|
if (deviceName != "" && product != null) {
|
|
// Logger.d('AgentController',
|
|
// 'liwe----------product $deviceName ${product.toJson()}');
|
|
return !product.iscontinuouschat!;
|
|
} else {
|
|
return false;
|
|
}
|
|
} else {
|
|
return _storage.read('agent_tts_interrupt') ?? false;
|
|
}
|
|
} catch (e) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// 启动BLE服务
|
|
Future<bool> startAgentService() async {
|
|
try {
|
|
// 从.env文件直接读取环境变量
|
|
var serverurl = DioManager().baseUrl;
|
|
|
|
var jsonString = _storage.read<String>("logintoken");
|
|
|
|
final azureSpeechKey = AppConfig.env('AZURE_SPEECH_KEY') ?? '';
|
|
final azureSpeechRegion =
|
|
AppConfig.env('AZURE_SPEECH_REGION') ?? 'eastasia';
|
|
final openaiApiKey = AppConfig.env('OPENAI_API_KEY') ?? '';
|
|
final openaiBaseUrl =
|
|
AppConfig.env('OPENAI_BASE_URL') ?? 'https://api.openai.com/v1';
|
|
final openaiModel = AppConfig.env('OPENAI_MODEL') ?? 'gpt-3.5-turbo';
|
|
final openaiModelMedia = AppConfig.env('OPENAI_API_VISION_MODEL') ??
|
|
'doubao-1-5-vision-pro-32k-250115';
|
|
final openaiagentid =
|
|
AppConfig.env('OPENAI_AGENT_ID') ?? 'personal_assistant';
|
|
final systemPrompt = AppConfig.agentsystemPrompt(openaiagentid);
|
|
var musicServiceType =
|
|
AppConfig.env('APP_ANDROID_MUSICSERVICE_TYPE') ?? 'AUTO';
|
|
if (Platform.isIOS) {
|
|
musicServiceType = AppConfig.env('APP_IOS_MUSICSERVICE_TYPE') ?? 'AUTO';
|
|
}
|
|
final navigationMode =
|
|
AppConfig.env('APP_NAVIGATION_MODE') ?? 'external_auto';
|
|
// 从Flutter资源包中加载.mcp.json
|
|
final jsonData = AppConfig.mcpConfig();
|
|
Logger.info('启动BLE服务,musicServiceType: ${musicServiceType}');
|
|
final isTtsInterruptEnabled = await _loadTtsInterrupe();
|
|
|
|
final vipExpiryTime = userInfo.User.instance.vipexptime;
|
|
Logger.info('liwei------ vipexptime 1: $vipExpiryTime');
|
|
|
|
// 根据APP语言动态配置语音识别语言
|
|
List<String> supportedLanguages = [];
|
|
try {
|
|
final storage = GetStorage();
|
|
final languageManager = Get.find<LanguageManager>();
|
|
|
|
// 从存储中读取用户设置的语言
|
|
String? savedLanguage = storage.read('language');
|
|
|
|
if (savedLanguage != null && savedLanguage != 'system') {
|
|
// 用户设置了特定语言
|
|
final parts = savedLanguage.split('_');
|
|
if (parts.length == 2) {
|
|
final asrCode = languageManager.getAsrCodeByShortCode(parts[0]);
|
|
if (asrCode != null) {
|
|
supportedLanguages.add(asrCode);
|
|
} else {
|
|
// 直接使用语言-国家格式
|
|
supportedLanguages.add('${parts[0]}-${parts[1]}');
|
|
}
|
|
}
|
|
} else {
|
|
// 跟随系统语言或未设置
|
|
final appLocale = Get.locale;
|
|
if (appLocale != null) {
|
|
final lang = appLocale.languageCode;
|
|
final country = appLocale.countryCode;
|
|
|
|
// 尝试从语言管理器获取对应的ASR代码
|
|
final asrCode = languageManager.getAsrCodeByShortCode(lang);
|
|
if (asrCode != null) {
|
|
supportedLanguages.add(asrCode);
|
|
} else if (country != null && country.isNotEmpty) {
|
|
// 构造 Azure SDK 需要的格式 (e.g., 'en-US')
|
|
supportedLanguages.add('$lang-$country');
|
|
} else {
|
|
supportedLanguages.add('en-US'); // 默认英语
|
|
}
|
|
}
|
|
}
|
|
|
|
// 最终兜底
|
|
if (supportedLanguages.isEmpty) {
|
|
supportedLanguages.add('en-US');
|
|
}
|
|
|
|
// Logger.info('动态配置语音识别语言: ${supportedLanguages.join(', ')}');
|
|
} catch (e) {
|
|
Logger.error('获取APP语言配置失败,使用默认语言: $e');
|
|
supportedLanguages = ['zh-CN', 'en-US'];
|
|
}
|
|
|
|
final config = <String, dynamic>{
|
|
// 语音代理配置参数
|
|
'azureSpeechKey': azureSpeechKey,
|
|
'azureSpeechRegion': azureSpeechRegion,
|
|
'openaiApiKey': openaiApiKey,
|
|
'openaiBaseUrl': openaiBaseUrl,
|
|
'openaiModel': openaiModel,
|
|
'openaivisionModel': openaiModelMedia,
|
|
'systemPrompt': systemPrompt,
|
|
'mcpServer': jsonEncode(jsonData),
|
|
'volcanoAppId': '2316081933',
|
|
'volcanoToken': 'mcJTh6OelBqU_L78lgGd77Nyrc_-5-En',
|
|
'serverurl': serverurl,
|
|
'usertoken': jsonString,
|
|
'supportedLanguages': supportedLanguages,
|
|
'musicServiceType': musicServiceType,
|
|
"navigationMode": navigationMode,
|
|
"isttsinterrupt": isTtsInterruptEnabled ? "true" : "false",
|
|
"vipexptime": vipExpiryTime, //会员过期时间
|
|
"callingToolText": "callingTool".tr,
|
|
"insufficientIntegralText": "insufficientIntegral".tr,
|
|
};
|
|
|
|
// 记录日志(不记录敏感信息)
|
|
Logger.info('启动BLE服务,配置参数键名: ${config}');
|
|
|
|
if (azureSpeechKey.isEmpty || openaiApiKey.isEmpty) {
|
|
Logger.warning('缺少必要的API密钥,请检查.env文件配置');
|
|
|
|
// 检查.env中相关密钥是否存在
|
|
if (azureSpeechKey.isEmpty) {
|
|
Logger.warning('AZURE_SPEECH_KEY未配置在.env文件中');
|
|
}
|
|
if (openaiApiKey.isEmpty) {
|
|
Logger.warning('OPENAI_API_KEY未配置在.env文件中');
|
|
}
|
|
}
|
|
|
|
Logger.info('lxm--准备调用AgentService.startAgentService启动BLE服务');
|
|
final result = await AgentService.startAgentService(config);
|
|
Logger.info('lxm--AgentService.startAgentService调用结果: $result');
|
|
|
|
if (result) {
|
|
Logger.info('lxm--BLE服务启动成功');
|
|
|
|
// 添加延迟以等待设备连接
|
|
Logger.info('lxm--等待2秒让设备连接');
|
|
//await Future.delayed(const Duration(seconds: 2));
|
|
|
|
// 检查连接状态
|
|
Logger.info('lxm--检查设备连接状态');
|
|
final isConnected = await _bleService.isConnected();
|
|
Logger.info('lxm--设备连接状态检查结果: $isConnected');
|
|
if (isConnected) {
|
|
Logger.info('lxm--设备已连接,更新连接状态');
|
|
_isConnected.value = true;
|
|
_connectionState.value = BleConnectionState.connected;
|
|
|
|
// 如果设备信息存在,则获取详细信息
|
|
Logger.info('lxm--准备获取设备详细信息');
|
|
if (deviceInfo.value != null) {
|
|
// 获取详细设备信息
|
|
// fetchDeviceInfo();
|
|
}
|
|
}
|
|
} else {
|
|
Logger.error('BLE服务启动失败');
|
|
}
|
|
|
|
return result;
|
|
} catch (e) {
|
|
Logger.error('启动BLE服务失败: ${e.toString()}');
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// 停止BLE服务
|
|
Future<bool> stopAgentService() async {
|
|
try {
|
|
final result = await AgentService.stopAgentService();
|
|
|
|
if (result) {
|
|
Logger.info('BLE服务停止成功');
|
|
_isConnected.value = false;
|
|
_connectionState.value = BleConnectionState.disconnected;
|
|
// 停止服务时清除设备信息
|
|
clearDeviceInfo();
|
|
} else {
|
|
Logger.error('BLE服务停止失败');
|
|
}
|
|
|
|
return result;
|
|
} catch (e) {
|
|
Logger.error('停止BLE服务失败: ${e.toString()}');
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// 获取电池电量
|
|
Future<int> getBatteryLevel() async {
|
|
try {
|
|
return await _bleService.getBatteryLevel();
|
|
} catch (e) {
|
|
Logger.error('获取电池电量失败: ${e.toString()}');
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/// 主动获取电池信息
|
|
Future<bool> fetchBatteryInfo() async {
|
|
try {
|
|
//Logger.info('lxm--fetchBatteryInfo被调用,准备向设备发送获取电池信息指令');
|
|
final result = await _bleService.getBatteryInfo();
|
|
//Logger.info('lxm--getBatteryInfo指令发送结果: $result');
|
|
return result;
|
|
} catch (e) {
|
|
//Logger.error('lxm--获取电池信息失败: ${e.toString()}');
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// 主动产品id
|
|
Future<bool> getProductId() async {
|
|
try {
|
|
return await _bleService.getProductId();
|
|
} catch (e) {
|
|
Logger.error('获取设备版本失败: ${e.toString()}');
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// 主动获取设备版本信息
|
|
Future<bool> fetchDeviceVersion() async {
|
|
try {
|
|
return await _bleService.getDeviceVersion();
|
|
} catch (e) {
|
|
Logger.error('获取设备版本失败: ${e.toString()}');
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// 打开编码器
|
|
Future<bool> openEncoder() async {
|
|
try {
|
|
return await _bleService.openEncoder();
|
|
} catch (e) {
|
|
Logger.error('打开编码器失败: ${e.toString()}');
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// 打开解码器
|
|
Future<bool> openDecoder() async {
|
|
try {
|
|
_awaitingCodecOpen = true;
|
|
_awaitingCodecClose = false;
|
|
_isCodecActive.value = false;
|
|
return await _bleService.openDecoder();
|
|
} catch (e) {
|
|
Logger.error('打开解码器失败: ${e.toString()}');
|
|
_awaitingCodecOpen = false;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// 打开A2DP解码器
|
|
Future<bool> openA2DPDecoder() async {
|
|
try {
|
|
_awaitingCodecOpen = true;
|
|
_awaitingCodecClose = false;
|
|
_isCodecActive.value = false;
|
|
return await _bleService.openA2DPDecoder();
|
|
} catch (e) {
|
|
Logger.error('打开解码器失败: ${e.toString()}');
|
|
_awaitingCodecOpen = false;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// 打开解码器
|
|
Future<bool> openCallRecordDecoder() async {
|
|
try {
|
|
return await _bleService.openCallRecordDecoder();
|
|
} catch (e) {
|
|
Logger.error('打开解码器失败: ${e.toString()}');
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// 关闭编解码器
|
|
Future<bool> closeCodec() async {
|
|
try {
|
|
_awaitingCodecOpen = false;
|
|
_awaitingCodecClose = true;
|
|
_isCodecActive.value = false;
|
|
return await _bleService.closeCodec();
|
|
} catch (e) {
|
|
Logger.error('关闭编解码器失败: ${e.toString()}');
|
|
_awaitingCodecClose = false;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// 播放A2DP
|
|
Future<bool> playA2DP() async {
|
|
try {
|
|
return await _bleService.playA2DP();
|
|
} catch (e) {
|
|
Logger.error('播放A2DP失败: ${e.toString()}');
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// ==================== 配对相关方法 ====================
|
|
|
|
/// 检查设备是否支持Companion Device Manager
|
|
Future<bool> isCompanionSupported() async {
|
|
try {
|
|
return await _bleService.isCompanionSupported();
|
|
} catch (e) {
|
|
Logger.error('检查Companion支持失败: ${e.toString()}');
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// 获取已配对的MAC地址
|
|
Future<String?> getPairedMacAddress() async {
|
|
try {
|
|
return await _bleService.getPairedMacAddress();
|
|
} catch (e) {
|
|
Logger.error('获取已配对MAC地址失败: ${e.toString()}');
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/// 检查BLE连接状态
|
|
Future<bool> isBleConnected() async {
|
|
try {
|
|
return await _bleService.isBleConnected();
|
|
} catch (e) {
|
|
Logger.error('检查BLE连接状态失败: ${e.toString()}');
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// 设置是否是ota模式
|
|
Future<void> setEnterOta(bool enterOta) async {
|
|
try {
|
|
await _bleService.setEnterOta(enterOta);
|
|
} catch (e) {
|
|
Logger.error('设置是否是ota模式失败: ${e.toString()}');
|
|
}
|
|
}
|
|
|
|
/// 断开连接
|
|
Future<void> disconnect() async {
|
|
try {
|
|
await _bleService.disconnect();
|
|
} catch (e) {
|
|
Logger.error('断开连接失败: ${e.toString()}');
|
|
}
|
|
}
|
|
|
|
/// 验证设备是否可以配对
|
|
Future<void> startScan(List<String> uuids) async {
|
|
try {
|
|
await _bleService.startScan(uuids);
|
|
} catch (e) {
|
|
Logger.error('开始扫描设备: ${e.toString()}');
|
|
}
|
|
}
|
|
|
|
/// 验证设备是否可以配对
|
|
Future<void> stopScan() async {
|
|
try {
|
|
await _bleService.stopScan();
|
|
} catch (e) {
|
|
Logger.error('停止扫描设备: ${e.toString()}');
|
|
}
|
|
}
|
|
|
|
Future<Map<String, String>?> getDeviceInfo(String deviceName) async {
|
|
try {
|
|
final result = _bleService.getDeviceInfo(deviceName);
|
|
return result;
|
|
} catch (e) {
|
|
Logger.error('获取设备信息: ${e.toString()}');
|
|
return null;
|
|
}
|
|
}
|
|
|
|
Future<List<Map<String, String>>?> getDeviceList(String deviceName) async {
|
|
try {
|
|
final result = _bleService.getDeviceList(deviceName);
|
|
return result;
|
|
} catch (e) {
|
|
Logger.error('获取设备信息: ${e.toString()}');
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/// 验证设备是否可以配对
|
|
Future<bool> verifyDeviceCanPair(String macAddress) async {
|
|
try {
|
|
return true;
|
|
} catch (e) {
|
|
Logger.error('验证设备配对失败: ${e.toString()}');
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// 启动设备关联
|
|
Future<bool> startDeviceAssociation({
|
|
required String deviceNamePattern,
|
|
required String macAddress,
|
|
}) async {
|
|
try {
|
|
return await _bleService.startDeviceAssociation(
|
|
deviceNamePattern: deviceNamePattern,
|
|
macAddress: macAddress,
|
|
);
|
|
} catch (e) {
|
|
Logger.error('启动设备关联失败: ${e.toString()}');
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// 启动设备关联
|
|
Future<void> connect() async {
|
|
try {
|
|
await _bleService.connect();
|
|
} catch (e) {
|
|
Logger.error('连接设备失败: ${e.toString()}');
|
|
}
|
|
}
|
|
|
|
/// 注册后台扫描
|
|
Future<bool> registerBackgroundScan({
|
|
String? macAddress,
|
|
List<String>? uuids,
|
|
}) async {
|
|
try {
|
|
// 在注册新设备前先清除旧设备信息
|
|
if (macAddress != null && macAddress != currentDeviceAddress) {
|
|
clearDeviceInfo(); // 清除上一个设备的信息
|
|
}
|
|
|
|
// 保存设备地址信息
|
|
if (macAddress != null) {
|
|
currentDeviceAddress = macAddress;
|
|
// 从蓝牙管理器获取设备名称
|
|
final bluetoothManager = Get.find<BluetoothManager>();
|
|
_currentDeviceName = bluetoothManager.currentDevice?.name ?? "";
|
|
|
|
Logger.info(
|
|
'保存设备信息: address=$currentDeviceAddress, name=$_currentDeviceName');
|
|
}
|
|
|
|
return await _bleService.registerBackgroundScan(
|
|
macAddress: macAddress,
|
|
uuids: uuids,
|
|
);
|
|
} catch (e) {
|
|
Logger.error('注册后台扫描失败: ${e.toString()}');
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// 注销后台扫描
|
|
Future<bool> unregisterBackgroundScan() async {
|
|
try {
|
|
return await _bleService.unregisterBackgroundScan();
|
|
} catch (e) {
|
|
Logger.error('注销后台扫描失败: ${e.toString()}');
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// 清除BLE配对设备
|
|
Future<bool> clearPairedDevices() async {
|
|
try {
|
|
return await _bleService.clearAssociations();
|
|
} catch (e) {
|
|
Logger.error('清除BLE配对设备失败: ${e.toString()}');
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// 注册服务
|
|
static Future<BleManager> init() async {
|
|
if (!Get.isRegistered<BleManager>()) {
|
|
Get.put(BleManager(), permanent: true);
|
|
}
|
|
return Future.value(Get.find<BleManager>());
|
|
}
|
|
|
|
/// 请求蓝牙权限
|
|
Future<bool> requestBluetoothPermission() async {
|
|
try {
|
|
return await _bleService.requestBluetoothPermission();
|
|
} catch (e) {
|
|
Logger.error('请求蓝牙权限失败: ${e.toString()}');
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// 开始唤醒词升级
|
|
Future<bool> startWakeupVoicesUpgrade(List<int> wakeupVoiceBytes) async {
|
|
try {
|
|
return await _bleService.startWakeupVoicesUpgrade(wakeupVoiceBytes);
|
|
} catch (e) {
|
|
Logger.error('开始唤醒词升级失败: ${e.toString()}');
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|