|
|
|
@ -11,27 +11,27 @@ import '../../../core/utils/permission_util.dart'; |
|
|
|
|
|
|
|
/// 配对状态枚举 - 简化版本 |
|
|
|
enum PairingState { |
|
|
|
idle, // 空闲/初始状态 |
|
|
|
checking, // 检查中(蓝牙、权限等) |
|
|
|
waitingClassic, // 等待经典蓝牙连接 |
|
|
|
verifying, // 验证设备 |
|
|
|
associating, // 正在进行BLE设备关联 |
|
|
|
waitingBle, // 等待BLE连接 |
|
|
|
completed, // 配对完成 |
|
|
|
error, // 错误状态 |
|
|
|
idle, // 空闲/初始状态 |
|
|
|
checking, // 检查中(蓝牙、权限等) |
|
|
|
waitingClassic, // 等待经典蓝牙连接 |
|
|
|
verifying, // 验证设备 |
|
|
|
associating, // 正在进行BLE设备关联 |
|
|
|
waitingBle, // 等待BLE连接 |
|
|
|
completed, // 配对完成 |
|
|
|
error, // 错误状态 |
|
|
|
} |
|
|
|
|
|
|
|
/// 错误类型枚举 |
|
|
|
enum ErrorType { |
|
|
|
none, |
|
|
|
bluetoothOff, // 蓝牙关闭 |
|
|
|
noPermission, // 无权限 |
|
|
|
noClassicDevice, // 无经典蓝牙设备 |
|
|
|
deviceNotMatch, // 设备不匹配 |
|
|
|
deviceBound, // 设备已被绑定 |
|
|
|
bluetoothOff, // 蓝牙关闭 |
|
|
|
noPermission, // 无权限 |
|
|
|
noClassicDevice, // 无经典蓝牙设备 |
|
|
|
deviceNotMatch, // 设备不匹配 |
|
|
|
deviceBound, // 设备已被绑定 |
|
|
|
associationFailed, // 关联失败 |
|
|
|
bleTimeout, // BLE连接超时 |
|
|
|
networkError, // 网络错误 |
|
|
|
bleTimeout, // BLE连接超时 |
|
|
|
networkError, // 网络错误 |
|
|
|
} |
|
|
|
|
|
|
|
/// 配对控制器 - 基于简化状态机的实现 |
|
|
|
@ -43,7 +43,7 @@ class PairingController extends GetxController { |
|
|
|
final _currentState = PairingState.idle.obs; |
|
|
|
final _errorType = ErrorType.none.obs; |
|
|
|
final _errorMessage = ''.obs; |
|
|
|
|
|
|
|
|
|
|
|
PairingState get currentState => _currentState.value; |
|
|
|
ErrorType get errorType => _errorType.value; |
|
|
|
String get errorMessage => _errorMessage.value; |
|
|
|
@ -68,7 +68,7 @@ class PairingController extends GetxController { |
|
|
|
// ========== 当前设备信息 ========== |
|
|
|
BluetoothDevice? _currentClassicDevice; |
|
|
|
String? _verifiedDeviceAddress; |
|
|
|
|
|
|
|
|
|
|
|
// Public getter for view access |
|
|
|
BluetoothDevice? get currentDevice => _currentClassicDevice; |
|
|
|
|
|
|
|
@ -76,14 +76,14 @@ class PairingController extends GetxController { |
|
|
|
void onInit() { |
|
|
|
super.onInit(); |
|
|
|
Logger.i(_tag, '配对控制器初始化'); |
|
|
|
|
|
|
|
|
|
|
|
// 确保服务已初始化 |
|
|
|
_bluetoothManager = Get.find<BluetoothManager>(); |
|
|
|
_bleManager = Get.find<BleManager>(); |
|
|
|
|
|
|
|
|
|
|
|
// 集中设置所有监听器 |
|
|
|
_setupAllListeners(); |
|
|
|
|
|
|
|
|
|
|
|
// 开始初始状态检查 |
|
|
|
// 延迟稍长时间,确保BluetoothManager有足够时间获取已连接设备 |
|
|
|
Future.delayed(const Duration(milliseconds: 300), () { |
|
|
|
@ -99,10 +99,10 @@ class PairingController extends GetxController { |
|
|
|
worker.dispose(); |
|
|
|
} |
|
|
|
_workers.clear(); |
|
|
|
|
|
|
|
|
|
|
|
// 清理定时器 |
|
|
|
_bleTimeoutTimer?.cancel(); |
|
|
|
|
|
|
|
|
|
|
|
super.onClose(); |
|
|
|
} |
|
|
|
|
|
|
|
@ -112,42 +112,37 @@ class PairingController extends GetxController { |
|
|
|
void _setupAllListeners() { |
|
|
|
// 1. 监听蓝牙开关状态 |
|
|
|
_setupBluetoothStateListener(); |
|
|
|
|
|
|
|
|
|
|
|
// 2. 监听经典蓝牙连接状态 |
|
|
|
_setupClassicConnectionListener(); |
|
|
|
|
|
|
|
|
|
|
|
// 3. 监听BLE连接状态 |
|
|
|
_setupBleConnectionListener(); |
|
|
|
} |
|
|
|
|
|
|
|
/// 监听蓝牙开关状态 |
|
|
|
void _setupBluetoothStateListener() { |
|
|
|
_workers.add( |
|
|
|
ever(_bluetoothManager.bluetoothStateRx, (String state) { |
|
|
|
Logger.d(_tag, '蓝牙状态变化: $state'); |
|
|
|
_handleBluetoothStateChange(state); |
|
|
|
}) |
|
|
|
); |
|
|
|
_workers.add(ever(_bluetoothManager.bluetoothStateRx, (String state) { |
|
|
|
Logger.d(_tag, '蓝牙状态变化: $state'); |
|
|
|
_handleBluetoothStateChange(state); |
|
|
|
})); |
|
|
|
} |
|
|
|
|
|
|
|
/// 监听经典蓝牙连接状态 |
|
|
|
void _setupClassicConnectionListener() { |
|
|
|
_workers.add( |
|
|
|
ever(_bluetoothManager.currentDeviceRx, (BluetoothDevice? device) { |
|
|
|
Logger.d(_tag, '经典蓝牙设备变化: ${device?.name}'); |
|
|
|
_handleClassicDeviceChange(device); |
|
|
|
}) |
|
|
|
); |
|
|
|
_workers |
|
|
|
.add(ever(_bluetoothManager.currentDeviceRx, (BluetoothDevice? device) { |
|
|
|
Logger.d(_tag, '经典蓝牙设备变化: ${device?.name}'); |
|
|
|
_handleClassicDeviceChange(device); |
|
|
|
})); |
|
|
|
} |
|
|
|
|
|
|
|
/// 监听BLE连接状态 |
|
|
|
void _setupBleConnectionListener() { |
|
|
|
_workers.add( |
|
|
|
ever(_bleManager.connectionStateRx, (int state) { |
|
|
|
Logger.d(_tag, 'BLE连接状态变化: $state'); |
|
|
|
_handleBleStateChange(state); |
|
|
|
}) |
|
|
|
); |
|
|
|
_workers.add(ever(_bleManager.connectionStateRx, (int state) { |
|
|
|
Logger.d(_tag, 'BLE连接状态变化: $state'); |
|
|
|
_handleBleStateChange(state); |
|
|
|
})); |
|
|
|
} |
|
|
|
|
|
|
|
// ==================== 状态处理 ==================== |
|
|
|
@ -171,7 +166,7 @@ class PairingController extends GetxController { |
|
|
|
/// 处理经典蓝牙设备变化 |
|
|
|
void _handleClassicDeviceChange(BluetoothDevice? device) { |
|
|
|
_currentClassicDevice = device; |
|
|
|
|
|
|
|
|
|
|
|
switch (_currentState.value) { |
|
|
|
case PairingState.waitingClassic: |
|
|
|
if (device != null) { |
|
|
|
@ -181,7 +176,7 @@ class PairingController extends GetxController { |
|
|
|
_verifyDevice(device); |
|
|
|
} |
|
|
|
break; |
|
|
|
|
|
|
|
|
|
|
|
case PairingState.error: |
|
|
|
// 如果在错误状态下检测到设备连接,且错误是无设备连接,则自动恢复 |
|
|
|
if (device != null && _errorType.value == ErrorType.noClassicDevice) { |
|
|
|
@ -191,7 +186,7 @@ class PairingController extends GetxController { |
|
|
|
_verifyDevice(device); |
|
|
|
} |
|
|
|
break; |
|
|
|
|
|
|
|
|
|
|
|
case PairingState.verifying: |
|
|
|
case PairingState.waitingBle: |
|
|
|
case PairingState.completed: |
|
|
|
@ -200,7 +195,7 @@ class PairingController extends GetxController { |
|
|
|
_setError(ErrorType.noClassicDevice, '设备已断开'); |
|
|
|
} |
|
|
|
break; |
|
|
|
|
|
|
|
|
|
|
|
default: |
|
|
|
break; |
|
|
|
} |
|
|
|
@ -209,12 +204,13 @@ class PairingController extends GetxController { |
|
|
|
/// 处理BLE状态变化 |
|
|
|
void _handleBleStateChange(int state) { |
|
|
|
if (_currentState.value == PairingState.waitingBle) { |
|
|
|
if (state == 2) { // BLE已连接 |
|
|
|
if (state == 2) { |
|
|
|
// BLE已连接 |
|
|
|
_bleTimeoutTimer?.cancel(); |
|
|
|
_transition(PairingState.completed); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 如果在完成状态下BLE断开,显示警告但不改变状态 |
|
|
|
if (_currentState.value == PairingState.completed && state != 2) { |
|
|
|
Logger.w(_tag, 'BLE连接已断开,但配对流程已完成'); |
|
|
|
@ -228,7 +224,7 @@ class PairingController extends GetxController { |
|
|
|
final oldState = _currentState.value; |
|
|
|
_currentState.value = newState; |
|
|
|
Logger.i(_tag, '状态转换: $oldState -> $newState'); |
|
|
|
|
|
|
|
|
|
|
|
// 根据新状态执行相应操作 |
|
|
|
_onStateChanged(newState); |
|
|
|
} |
|
|
|
@ -240,29 +236,29 @@ class PairingController extends GetxController { |
|
|
|
showConnectButton.value = false; |
|
|
|
showRetryButton.value = false; |
|
|
|
showSkipButton.value = false; |
|
|
|
|
|
|
|
|
|
|
|
switch (state) { |
|
|
|
case PairingState.idle: |
|
|
|
statusText.value = '准备开始配对'; |
|
|
|
break; |
|
|
|
|
|
|
|
|
|
|
|
case PairingState.checking: |
|
|
|
statusText.value = '正在检查环境...'; |
|
|
|
isLoading.value = true; |
|
|
|
break; |
|
|
|
|
|
|
|
|
|
|
|
case PairingState.waitingClassic: |
|
|
|
statusText.value = '请确保耳机已开启并进入配对模式'; |
|
|
|
showConnectButton.value = true; |
|
|
|
showSkipButton.value = true; |
|
|
|
connectButtonText.value = '前往蓝牙设置'; |
|
|
|
break; |
|
|
|
|
|
|
|
|
|
|
|
case PairingState.verifying: |
|
|
|
statusText.value = '正在验证设备...'; |
|
|
|
isLoading.value = true; |
|
|
|
break; |
|
|
|
|
|
|
|
|
|
|
|
case PairingState.associating: |
|
|
|
statusText.value = '正在关联设备...'; |
|
|
|
isLoading.value = true; |
|
|
|
@ -271,7 +267,7 @@ class PairingController extends GetxController { |
|
|
|
_startDeviceAssociation(); |
|
|
|
}); |
|
|
|
break; |
|
|
|
|
|
|
|
|
|
|
|
case PairingState.waitingBle: |
|
|
|
statusText.value = '正在建立安全连接...'; |
|
|
|
isLoading.value = true; |
|
|
|
@ -280,18 +276,18 @@ class PairingController extends GetxController { |
|
|
|
_startBleConnection(); |
|
|
|
}); |
|
|
|
break; |
|
|
|
|
|
|
|
|
|
|
|
case PairingState.completed: |
|
|
|
statusText.value = '配对成功!'; |
|
|
|
isLoading.value = false; |
|
|
|
_navigateToHome(); |
|
|
|
break; |
|
|
|
|
|
|
|
|
|
|
|
case PairingState.error: |
|
|
|
statusText.value = _errorMessage.value; |
|
|
|
isLoading.value = false; |
|
|
|
showSkipButton.value = true; |
|
|
|
|
|
|
|
|
|
|
|
// 根据错误类型决定显示哪个按钮和按钮文本 |
|
|
|
switch (_errorType.value) { |
|
|
|
case ErrorType.bluetoothOff: |
|
|
|
@ -350,28 +346,27 @@ class PairingController extends GetxController { |
|
|
|
_setError(ErrorType.bluetoothOff, '请开启蓝牙'); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 2. 检查权限 |
|
|
|
if (!await _checkPermissions()) { |
|
|
|
_setError(ErrorType.noPermission, '请授予必要权限'); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 3. 先刷新设备连接状态,确保获取最新的连接信息 |
|
|
|
await _bluetoothManager.refreshDeviceConnection(); |
|
|
|
|
|
|
|
|
|
|
|
// 4. 检查经典蓝牙连接 |
|
|
|
final classicDevice = _bluetoothManager.currentDevice; |
|
|
|
if (classicDevice == null) { |
|
|
|
_transition(PairingState.waitingClassic); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 5. 如果有设备,进行验证 |
|
|
|
_currentClassicDevice = classicDevice; |
|
|
|
_transition(PairingState.verifying); |
|
|
|
await _verifyDevice(classicDevice); |
|
|
|
|
|
|
|
} catch (e) { |
|
|
|
Logger.e(_tag, '状态检查失败: $e'); |
|
|
|
_setError(ErrorType.networkError, '检查失败,请重试'); |
|
|
|
@ -386,10 +381,10 @@ class PairingController extends GetxController { |
|
|
|
final bluetoothScan = await Permission.bluetoothScan.request(); |
|
|
|
final bluetoothConnect = await Permission.bluetoothConnect.request(); |
|
|
|
final location = await Permission.locationWhenInUse.request(); |
|
|
|
|
|
|
|
return bluetoothScan.isGranted && |
|
|
|
bluetoothConnect.isGranted && |
|
|
|
location.isGranted; |
|
|
|
|
|
|
|
return bluetoothScan.isGranted && |
|
|
|
bluetoothConnect.isGranted && |
|
|
|
location.isGranted; |
|
|
|
} |
|
|
|
return true; |
|
|
|
} |
|
|
|
@ -398,28 +393,31 @@ class PairingController extends GetxController { |
|
|
|
Future<void> _verifyDevice(BluetoothDevice device) async { |
|
|
|
try { |
|
|
|
Logger.i(_tag, '开始验证设备: ${device.name} (${device.address})'); |
|
|
|
|
|
|
|
|
|
|
|
// TODO: 实现API验证逻辑 |
|
|
|
// 暂时模拟验证通过 |
|
|
|
await Future.delayed(const Duration(seconds: 2)); |
|
|
|
|
|
|
|
|
|
|
|
// 检查设备名称是否包含 DeepSound 或 DeapSound |
|
|
|
final deviceName = device.name ?? ''; |
|
|
|
if (deviceName.contains('DeepSound') || deviceName.contains('DeapSound')) { |
|
|
|
if (deviceName.contains('DeepSound') || |
|
|
|
deviceName.contains('DeapSound')) { |
|
|
|
Logger.i(_tag, '设备验证通过'); |
|
|
|
_verifiedDeviceAddress = device.address; |
|
|
|
|
|
|
|
|
|
|
|
// 检查是否已有BLE关联 |
|
|
|
final pairedMacAddress = await _bleManager.getPairedMacAddress(); |
|
|
|
Logger.i(_tag, '已关联的MAC地址: $pairedMacAddress'); |
|
|
|
|
|
|
|
if (pairedMacAddress != null && pairedMacAddress.toUpperCase() == device.address.toUpperCase()) { |
|
|
|
|
|
|
|
if (pairedMacAddress != null && |
|
|
|
pairedMacAddress.toUpperCase() == device.address.toUpperCase()) { |
|
|
|
// 已有关联,检查BLE连接状态 |
|
|
|
Logger.i(_tag, '设备已关联,检查BLE连接状态'); |
|
|
|
final currentBleState = await _bleManager.getConnectionState(); |
|
|
|
Logger.i(_tag, '验证时BLE状态: $currentBleState'); |
|
|
|
|
|
|
|
if (currentBleState == 2) { // BleConnectionState.connected |
|
|
|
|
|
|
|
if (currentBleState == 2) { |
|
|
|
// BleConnectionState.connected |
|
|
|
Logger.i(_tag, 'BLE已连接,直接完成配对'); |
|
|
|
_transition(PairingState.completed); |
|
|
|
} else { |
|
|
|
@ -447,15 +445,15 @@ class PairingController extends GetxController { |
|
|
|
_setError(ErrorType.associationFailed, '设备地址无效'); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Logger.i(_tag, '开始BLE设备关联: $_verifiedDeviceAddress'); |
|
|
|
|
|
|
|
|
|
|
|
// 调用BLE管理器的关联方法 |
|
|
|
final success = await _bleManager.startDeviceAssociation( |
|
|
|
deviceNamePattern: 'DeapSound', // 或者使用 _currentClassicDevice?.name |
|
|
|
deviceNamePattern: 'DeapSound', // 或者使用 _currentClassicDevice?.name |
|
|
|
macAddress: _verifiedDeviceAddress!, |
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
if (success) { |
|
|
|
Logger.i(_tag, 'BLE设备关联成功'); |
|
|
|
// 关联成功后,转到等待BLE连接状态 |
|
|
|
@ -479,21 +477,23 @@ class PairingController extends GetxController { |
|
|
|
_setError(ErrorType.bleTimeout, 'BLE连接超时,请重试'); |
|
|
|
} |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
// 检查是否已连接 - 直接从原生层获取最新状态 |
|
|
|
final currentBleState = await _bleManager.getConnectionState(); |
|
|
|
Logger.i(_tag, 'BLE当前连接状态: $currentBleState'); |
|
|
|
|
|
|
|
if (currentBleState == 2) { // BleConnectionState.connected |
|
|
|
|
|
|
|
if (currentBleState == 2) { |
|
|
|
// BleConnectionState.connected |
|
|
|
Logger.i(_tag, 'BLE已经连接,直接完成配对'); |
|
|
|
_bleTimeoutTimer?.cancel(); |
|
|
|
_transition(PairingState.completed); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 注册后台扫描以开始BLE配对 |
|
|
|
if (_verifiedDeviceAddress != null) { |
|
|
|
final success = await _bleManager.registerBackgroundScan(macAddress: _verifiedDeviceAddress); |
|
|
|
final success = await _bleManager.registerBackgroundScan( |
|
|
|
macAddress: _verifiedDeviceAddress); |
|
|
|
if (!success && _currentState.value == PairingState.waitingBle) { |
|
|
|
_setError(ErrorType.bleTimeout, 'BLE配对启动失败'); |
|
|
|
} |
|
|
|
@ -505,7 +505,8 @@ class PairingController extends GetxController { |
|
|
|
} |
|
|
|
|
|
|
|
/// 导航到主页 |
|
|
|
void _navigateToHome() { |
|
|
|
void _navigateToHome() async { |
|
|
|
await BleManager.to.startAgentService(); |
|
|
|
Future.delayed(const Duration(seconds: 1), () { |
|
|
|
Get.offAllNamed(Routes.home); |
|
|
|
}); |
|
|
|
@ -516,7 +517,7 @@ class PairingController extends GetxController { |
|
|
|
/// 用户点击连接按钮 |
|
|
|
void onConnectTap() { |
|
|
|
Logger.i(_tag, '用户点击连接按钮'); |
|
|
|
|
|
|
|
|
|
|
|
// 根据当前状态或错误类型决定行为 |
|
|
|
if (_currentState.value == PairingState.error) { |
|
|
|
switch (_errorType.value) { |
|
|
|
@ -550,7 +551,7 @@ class PairingController extends GetxController { |
|
|
|
/// 用户点击重试按钮 |
|
|
|
void onRetryTap() { |
|
|
|
Logger.i(_tag, '用户点击重试按钮'); |
|
|
|
|
|
|
|
|
|
|
|
// 如果是权限问题,引导去设置 |
|
|
|
if (_errorType.value == ErrorType.noPermission) { |
|
|
|
Logger.i(_tag, '引导用户去应用设置授予权限'); |
|
|
|
@ -563,7 +564,8 @@ class PairingController extends GetxController { |
|
|
|
} |
|
|
|
|
|
|
|
/// 用户点击跳过按钮 |
|
|
|
void onSkipTap() { |
|
|
|
void onSkipTap() async { |
|
|
|
await BleManager.to.startAgentService(); |
|
|
|
Logger.i(_tag, '用户选择跳过配对'); |
|
|
|
Get.offAllNamed(Routes.home); |
|
|
|
} |
|
|
|
@ -572,7 +574,7 @@ class PairingController extends GetxController { |
|
|
|
void openBluetoothSettings() { |
|
|
|
AppSettings.openAppSettings(type: AppSettingsType.bluetooth); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// 清除设备关联(在需要重新配对时调用) |
|
|
|
Future<void> clearDeviceAssociation() async { |
|
|
|
try { |
|
|
|
@ -582,4 +584,4 @@ class PairingController extends GetxController { |
|
|
|
Logger.e(_tag, '清除设备关联失败: $e'); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|