fix: device name display
This commit is contained in:
parent
c86ef81c4a
commit
e168f08aa4
|
@ -79,16 +79,7 @@ fun SettingsList(viewModel: CarViewModel) {
|
||||||
SettingConnectDeviceItem(viewModel)
|
SettingConnectDeviceItem(viewModel)
|
||||||
}
|
}
|
||||||
item {
|
item {
|
||||||
ListItem(
|
SettingDeviceNameItem(viewModel)
|
||||||
headlineContent = { Text("设备名称") },
|
|
||||||
supportingContent = { Text("当前名称: Name") },
|
|
||||||
trailingContent = {
|
|
||||||
Icon(
|
|
||||||
ImageVector.vectorResource(R.drawable.arrow_right_24),
|
|
||||||
contentDescription = "设备名称"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
item {
|
item {
|
||||||
ListItem(
|
ListItem(
|
||||||
|
@ -180,3 +171,19 @@ fun SettingConnectDeviceItem(viewModel: CarViewModel) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun SettingDeviceNameItem(viewModel: CarViewModel) {
|
||||||
|
val connectionInfoState by viewModel.connectionInfoState.collectAsState()
|
||||||
|
|
||||||
|
ListItem(
|
||||||
|
headlineContent = { Text("设备名称") },
|
||||||
|
supportingContent = { Text("当前名称: ${connectionInfoState.name}") },
|
||||||
|
trailingContent = {
|
||||||
|
Icon(
|
||||||
|
ImageVector.vectorResource(R.drawable.arrow_right_24),
|
||||||
|
contentDescription = "设备名称"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
|
@ -41,6 +41,8 @@ interface BluetoothRepository {
|
||||||
fun observeLogs(): Flow<List<LogEntry>>
|
fun observeLogs(): Flow<List<LogEntry>>
|
||||||
fun clearLogs()
|
fun clearLogs()
|
||||||
val connectionState: StateFlow<ConnectionState>
|
val connectionState: StateFlow<ConnectionState>
|
||||||
|
val deviceName: StateFlow<String?>
|
||||||
|
val deviceAddress: StateFlow<String?>
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加连接状态枚举
|
// 添加连接状态枚举
|
||||||
|
@ -55,6 +57,9 @@ val serviceUUID = "6E400001-B5A3-F393-E0A9-E50E24DCCA9E"
|
||||||
val rxCharUUID = "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
|
val rxCharUUID = "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
|
||||||
val txCharUUID = "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"
|
val txCharUUID = "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"
|
||||||
|
|
||||||
|
val deviceInfoServiceUUID = "0000180a-0000-1000-8000-00805f9b34fb"
|
||||||
|
val deviceNameCharUUID = "00002a00-0000-1000-8000-00805f9b34fb"
|
||||||
|
|
||||||
// 蓝牙通信实现
|
// 蓝牙通信实现
|
||||||
class BluetoothRepositoryImpl(
|
class BluetoothRepositoryImpl(
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
|
@ -80,6 +85,12 @@ class BluetoothRepositoryImpl(
|
||||||
private val _connectionState = MutableStateFlow(ConnectionState.DISCONNECTED)
|
private val _connectionState = MutableStateFlow(ConnectionState.DISCONNECTED)
|
||||||
override val connectionState: StateFlow<ConnectionState> = _connectionState.asStateFlow()
|
override val connectionState: StateFlow<ConnectionState> = _connectionState.asStateFlow()
|
||||||
|
|
||||||
|
private val _deviceName = MutableStateFlow<String?>(null)
|
||||||
|
override val deviceName: StateFlow<String?> = _deviceName.asStateFlow()
|
||||||
|
|
||||||
|
private val _deviceAddress = MutableStateFlow<String?>(null)
|
||||||
|
override val deviceAddress: StateFlow<String?> = _deviceAddress.asStateFlow()
|
||||||
|
|
||||||
private val scanCallback = object : ScanCallback() {
|
private val scanCallback = object : ScanCallback() {
|
||||||
override fun onScanResult(callbackType: Int, result: ScanResult) {
|
override fun onScanResult(callbackType: Int, result: ScanResult) {
|
||||||
val bleDevice = BleDevice(
|
val bleDevice = BleDevice(
|
||||||
|
@ -132,7 +143,10 @@ class BluetoothRepositoryImpl(
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("MissingPermission")
|
@SuppressLint("MissingPermission")
|
||||||
fun connectToDevice(device: BluetoothDevice, callback: ((Boolean) -> Unit)? = null) {
|
fun connectToDevice(
|
||||||
|
device: BluetoothDevice,
|
||||||
|
callback: ((Boolean, BluetoothDevice?) -> Unit)? = null
|
||||||
|
) {
|
||||||
_connectionState.value = ConnectionState.CONNECTING
|
_connectionState.value = ConnectionState.CONNECTING
|
||||||
device.connectGatt(
|
device.connectGatt(
|
||||||
context,
|
context,
|
||||||
|
@ -164,21 +178,23 @@ class BluetoothRepositoryImpl(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (callback != null) {
|
if (callback != null) {
|
||||||
callback(true)
|
callback(true, gatt.device)
|
||||||
}
|
}
|
||||||
|
_deviceAddress.value = gatt.device.address
|
||||||
|
_deviceName.value = gatt.device.name ?: "未知设备"
|
||||||
}
|
}
|
||||||
|
|
||||||
BluetoothProfile.STATE_CONNECTING -> {
|
BluetoothProfile.STATE_CONNECTING -> {
|
||||||
_connectionState.value = ConnectionState.CONNECTING
|
_connectionState.value = ConnectionState.CONNECTING
|
||||||
if (callback != null) {
|
if (callback != null) {
|
||||||
callback(false)
|
callback(false, null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BluetoothProfile.STATE_DISCONNECTING -> {
|
BluetoothProfile.STATE_DISCONNECTING -> {
|
||||||
_connectionState.value = ConnectionState.DISCONNECTING
|
_connectionState.value = ConnectionState.DISCONNECTING
|
||||||
if (callback != null) {
|
if (callback != null) {
|
||||||
callback(false)
|
callback(false, null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,8 +203,10 @@ class BluetoothRepositoryImpl(
|
||||||
rxCharacteristic = null
|
rxCharacteristic = null
|
||||||
_connectionState.value = ConnectionState.DISCONNECTED
|
_connectionState.value = ConnectionState.DISCONNECTED
|
||||||
if (callback != null) {
|
if (callback != null) {
|
||||||
callback(false)
|
callback(false, null)
|
||||||
}
|
}
|
||||||
|
_deviceName.value = null
|
||||||
|
_deviceAddress.value = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -196,6 +214,15 @@ class BluetoothRepositoryImpl(
|
||||||
override fun onServicesDiscovered(gatt: BluetoothGatt?, status: Int) {
|
override fun onServicesDiscovered(gatt: BluetoothGatt?, status: Int) {
|
||||||
super.onServicesDiscovered(gatt, status)
|
super.onServicesDiscovered(gatt, status)
|
||||||
if (status == BluetoothGatt.GATT_SUCCESS) {
|
if (status == BluetoothGatt.GATT_SUCCESS) {
|
||||||
|
// 读取设备名称
|
||||||
|
val genericService =
|
||||||
|
gatt?.getService(UUID.fromString("00001800-0000-1000-8000-00805f9b34fb"))
|
||||||
|
val deviceNameChar =
|
||||||
|
genericService?.getCharacteristic(UUID.fromString("00002a00-0000-1000-8000-00805f9b34fb"))
|
||||||
|
if (deviceNameChar != null) {
|
||||||
|
gatt.readCharacteristic(deviceNameChar)
|
||||||
|
}
|
||||||
|
|
||||||
gatt?.getService(UUID.fromString(serviceUUID))?.let { service ->
|
gatt?.getService(UUID.fromString(serviceUUID))?.let { service ->
|
||||||
bluetoothGatt = gatt
|
bluetoothGatt = gatt
|
||||||
rxCharacteristic =
|
rxCharacteristic =
|
||||||
|
@ -213,6 +240,20 @@ class BluetoothRepositoryImpl(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onCharacteristicRead(
|
||||||
|
gatt: BluetoothGatt,
|
||||||
|
characteristic: BluetoothGattCharacteristic,
|
||||||
|
value: ByteArray,
|
||||||
|
status: Int
|
||||||
|
) {
|
||||||
|
super.onCharacteristicRead(gatt, characteristic, value, status)
|
||||||
|
if (characteristic.uuid == UUID.fromString(deviceNameCharUUID)) {
|
||||||
|
val deviceName = String(value)
|
||||||
|
_deviceName.value = deviceName
|
||||||
|
Log.d("DeviceName", "Device name: $deviceName")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCharacteristicChanged(
|
override fun onCharacteristicChanged(
|
||||||
gatt: BluetoothGatt,
|
gatt: BluetoothGatt,
|
||||||
characteristic: BluetoothGattCharacteristic,
|
characteristic: BluetoothGattCharacteristic,
|
||||||
|
@ -222,6 +263,11 @@ class BluetoothRepositoryImpl(
|
||||||
if (characteristic.uuid == UUID.fromString(txCharUUID)) {
|
if (characteristic.uuid == UUID.fromString(txCharUUID)) {
|
||||||
onReceivePacket(value)
|
onReceivePacket(value)
|
||||||
}
|
}
|
||||||
|
if (characteristic.uuid == UUID.fromString(deviceNameCharUUID)) {
|
||||||
|
val deviceName = String(value)
|
||||||
|
_deviceName.value = deviceName
|
||||||
|
_deviceAddress.value = gatt.device.address
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
TRANSPORT_LE
|
TRANSPORT_LE
|
||||||
|
@ -237,8 +283,8 @@ class BluetoothRepositoryImpl(
|
||||||
context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
|
context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
|
||||||
val device = bluetoothManager.adapter.getRemoteDevice(address)
|
val device = bluetoothManager.adapter.getRemoteDevice(address)
|
||||||
if (callback != null) {
|
if (callback != null) {
|
||||||
connectToDevice(device) { isConnected ->
|
connectToDevice(device) { isConnected, deviceDetail ->
|
||||||
callback(isConnected, device)
|
callback(isConnected, deviceDetail ?: device)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
connectToDevice(device)
|
connectToDevice(device)
|
||||||
|
@ -246,6 +292,28 @@ class BluetoothRepositoryImpl(
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressLint("MissingPermission")
|
||||||
|
private fun setupDeviceNameNotification(gatt: BluetoothGatt) {
|
||||||
|
val service = gatt.getService(UUID.fromString(deviceInfoServiceUUID))
|
||||||
|
val characteristic = service?.getCharacteristic(UUID.fromString(deviceNameCharUUID))
|
||||||
|
|
||||||
|
characteristic?.let { char ->
|
||||||
|
// 启用通知
|
||||||
|
gatt.setCharacteristicNotification(char, true)
|
||||||
|
|
||||||
|
// 获取 descriptor 并写入通知使能值
|
||||||
|
val descriptor =
|
||||||
|
char.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"))
|
||||||
|
descriptor?.let {
|
||||||
|
it.value = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE
|
||||||
|
gatt.writeDescriptor(it)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 同时也读取一次当前值
|
||||||
|
gatt.readCharacteristic(char)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressLint("MissingPermission")
|
@SuppressLint("MissingPermission")
|
||||||
override fun sendCommand(command: ByteArray) {
|
override fun sendCommand(command: ByteArray) {
|
||||||
rxCharacteristic?.let { characteristic ->
|
rxCharacteristic?.let { characteristic ->
|
||||||
|
@ -321,7 +389,8 @@ class BluetoothRepositoryImpl(
|
||||||
|
|
||||||
private fun createInfraredState(irPinCount: Int, irData: UByte) = InfraredState(
|
private fun createInfraredState(irPinCount: Int, irData: UByte) = InfraredState(
|
||||||
enable = true,
|
enable = true,
|
||||||
statusList = irData.toString(2).padStart(irPinCount, '0').reversed().map { if (it == '1') 1u else 0u }
|
statusList = irData.toString(2).padStart(irPinCount, '0').reversed()
|
||||||
|
.map { if (it == '1') 1u else 0u }
|
||||||
)
|
)
|
||||||
|
|
||||||
// 断开连接方法
|
// 断开连接方法
|
||||||
|
@ -330,6 +399,12 @@ class BluetoothRepositoryImpl(
|
||||||
bluetoothGatt?.let { gatt ->
|
bluetoothGatt?.let { gatt ->
|
||||||
_connectionState.value = ConnectionState.DISCONNECTING
|
_connectionState.value = ConnectionState.DISCONNECTING
|
||||||
gatt.disconnect()
|
gatt.disconnect()
|
||||||
|
gatt.close() // 重要:需要调用 close() 释放资源
|
||||||
|
bluetoothGatt = null
|
||||||
|
rxCharacteristic = null
|
||||||
|
_deviceName.value = null
|
||||||
|
_deviceAddress.value = null
|
||||||
|
_connectionState.value = ConnectionState.DISCONNECTED
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -21,6 +21,7 @@ import kotlinx.coroutines.flow.asStateFlow
|
||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import android.view.WindowManager
|
import android.view.WindowManager
|
||||||
|
import kotlinx.coroutines.flow.combine
|
||||||
|
|
||||||
|
|
||||||
// 用例
|
// 用例
|
||||||
|
@ -82,20 +83,14 @@ class CarViewModel(
|
||||||
fun startScan() = (repository as BluetoothRepositoryImpl).startScan()
|
fun startScan() = (repository as BluetoothRepositoryImpl).startScan()
|
||||||
fun stopScan() = (repository as BluetoothRepositoryImpl).stopScan()
|
fun stopScan() = (repository as BluetoothRepositoryImpl).stopScan()
|
||||||
|
|
||||||
|
@SuppressLint("MissingPermission")
|
||||||
fun connectToDevice(device: BluetoothDevice) {
|
fun connectToDevice(device: BluetoothDevice) {
|
||||||
(repository as BluetoothRepositoryImpl).connectToDevice(device) { isConnected ->
|
(repository as BluetoothRepositoryImpl).connectToDevice(device)
|
||||||
if (isConnected) {
|
|
||||||
updateDeviceInfo(device)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressLint("MissingPermission")
|
||||||
fun connectToDeviceByAddress(address: String) {
|
fun connectToDeviceByAddress(address: String) {
|
||||||
(repository as BluetoothRepositoryImpl).connectToDeviceByAddress(address) { isConnected, device ->
|
(repository as BluetoothRepositoryImpl).connectToDeviceByAddress(address)
|
||||||
if (isConnected) {
|
|
||||||
updateDeviceInfo(device)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val carState: StateFlow<CarState> = repository.observeCarState()
|
val carState: StateFlow<CarState> = repository.observeCarState()
|
||||||
|
@ -116,24 +111,43 @@ class CarViewModel(
|
||||||
initialValue = ConnectionState.DISCONNECTED
|
initialValue = ConnectionState.DISCONNECTED
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// 添加断开连接方法
|
||||||
|
fun disconnect() {
|
||||||
|
(repository as BluetoothRepositoryImpl).disconnect()
|
||||||
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
// 监听连接状态变化
|
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
|
// 监听连接状态变化
|
||||||
connectionState.collect { state ->
|
connectionState.collect { state ->
|
||||||
if (state == ConnectionState.DISCONNECTED) {
|
when (state) {
|
||||||
|
ConnectionState.DISCONNECTED -> {
|
||||||
// 断开连接时清空设备信息
|
// 断开连接时清空设备信息
|
||||||
_connectionInfoState.value = ConnectionInfoState()
|
_connectionInfoState.value = ConnectionInfoState()
|
||||||
}
|
}
|
||||||
|
else -> {
|
||||||
|
// 其他状态处理...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModelScope.launch {
|
||||||
|
repository.deviceName.combine(repository.deviceAddress) { name, address ->
|
||||||
|
Pair(name, address)
|
||||||
|
}.collect { (name, address) ->
|
||||||
|
if (name != null && address != null) {
|
||||||
|
updateDeviceInfo(name, address)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新设备信息的方法
|
// 更新设备信息的方法
|
||||||
@SuppressLint("MissingPermission")
|
private fun updateDeviceInfo(deviceName: String?, deviceAddress: String) {
|
||||||
fun updateDeviceInfo(device: BluetoothDevice) {
|
|
||||||
_connectionInfoState.value = ConnectionInfoState(
|
_connectionInfoState.value = ConnectionInfoState(
|
||||||
name = device.name ?: "未知设备",
|
name = deviceName ?: "未知设备 (${deviceAddress})",
|
||||||
address = device.address,
|
address = deviceAddress,
|
||||||
version = "001"
|
version = "001"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue