diff --git a/app/src/main/java/com/geeksville/mesh/ui/SettingsFragment.kt b/app/src/main/java/com/geeksville/mesh/ui/SettingsFragment.kt index 8ece3085f..5710464fb 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/SettingsFragment.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/SettingsFragment.kt @@ -152,7 +152,7 @@ class BTScanModel @Inject constructor( debug("BTScanModel cleared") } - val bluetoothAdapter = context.bluetoothManager?.adapter + private val bluetoothAdapter = context.bluetoothManager?.adapter private val deviceManager get() = context.deviceManager val hasCompanionDeviceApi get() = context.hasCompanionDeviceApi() private val hasConnectPermission get() = context.hasConnectPermission() @@ -232,8 +232,6 @@ class BTScanModel @Inject constructor( } } - - private fun addDevice(entry: DeviceListEntry) { val oldDevs = devices.value!! oldDevs[entry.address] = entry // Add/replace entry @@ -302,8 +300,8 @@ class BTScanModel @Inject constructor( // Include a placeholder for "None" addDevice(DeviceListEntry(context.getString(R.string.none), "n", true)) - if (hasCompanionDeviceApi && hasConnectPermission) - addAssociations() + // Include CompanionDeviceManager valid associations + addDeviceAssociations() serialDevices.forEach { (_, d) -> addDevice(USBDeviceListEntry(usbManager, d)) @@ -341,18 +339,33 @@ class BTScanModel @Inject constructor( } } - @SuppressLint("MissingPermission", "NewApi") - private fun addAssociations() { - deviceManager?.associations?.forEach { bleAddress -> - bluetoothAdapter?.getRemoteDevice(bleAddress)?.let { device -> - if (device.name.startsWith("Mesh")) { - val entry = DeviceListEntry( - device.name, - "x${device.address}", // full address with the bluetooth prefix added - device.bondState == BOND_BONDED - ) - addDevice(entry) - } + /** + * @return DeviceListEntry from Bluetooth Address. + * Only valid if name begins with "Meshtastic"... + */ + @SuppressLint("MissingPermission") + fun bleDeviceFrom(bleAddress: String): DeviceListEntry { + val device = + if (hasConnectPermission) bluetoothAdapter?.getRemoteDevice(bleAddress) else null + + return if (device != null && device.name != null) { + DeviceListEntry( + device.name, + "x${device.address}", // full address with the bluetooth prefix added + device.bondState == BOND_BONDED + ) + } else DeviceListEntry("", "", false) + } + + @SuppressLint("NewApi") + private fun addDeviceAssociations() { + if (hasCompanionDeviceApi) deviceManager?.associations?.forEach { bleAddress -> + val bleDevice = bleDeviceFrom(bleAddress) + if (!bleDevice.bonded) { // Clean up associations after pairing is removed + debug("Forgetting old BLE association ${bleAddress.anonymize}") + deviceManager?.disassociate(bleAddress) + } else if (bleDevice.name.startsWith("Mesh")) { + addDevice(bleDevice) } } } @@ -372,7 +385,7 @@ class BTScanModel @Inject constructor( */ override fun onInactive() { super.onInactive() - // stopScan() + if (!hasCompanionDeviceApi) stopScan() } } @@ -789,8 +802,7 @@ class SettingsFragment : ScreenFragment("Settings"), Logging { b.text = device.name b.id = View.generateViewId() b.isEnabled = enabled - b.isChecked = - device.address == scanModel.selectedNotNull && device.bonded // Only show checkbox if device is still paired + b.isChecked = device.address == scanModel.selectedNotNull binding.deviceRadioGroup.addView(b) b.setOnClickListener { @@ -799,21 +811,15 @@ class SettingsFragment : ScreenFragment("Settings"), Logging { b.isChecked = scanModel.onSelected(myActivity, device) - - if (!b.isSelected) { - binding.scanStatusText.text = getString(R.string.please_pair) - } } } - @SuppressLint("MissingPermission") private fun updateDevicesButtons(devices: MutableMap?) { // Remove the old radio buttons and repopulate binding.deviceRadioGroup.removeAllViews() if (devices == null) return - val adapter = scanModel.bluetoothAdapter var hasShownOurDevice = false devices.values.forEach { device -> if (device.address == scanModel.selectedNotNull) @@ -829,14 +835,14 @@ class SettingsFragment : ScreenFragment("Settings"), Logging { // and before use val bleAddr = scanModel.selectedBluetooth - if (bleAddr != null && adapter != null && myActivity.hasConnectPermission()) { - val bDevice = - adapter.getRemoteDevice(bleAddr) - if (bDevice.name != null) { // ignore nodes that node have a name, that means we've lost them since they appeared + if (bleAddr != null) { + debug("bleAddr= $bleAddr selected= ${scanModel.selectedAddress}") + val bleDevice = scanModel.bleDeviceFrom(bleAddr) + if (bleDevice.name.startsWith("Mesh")) { // ignore nodes that node have a name, that means we've lost them since they appeared val curDevice = BTScanModel.DeviceListEntry( - bDevice.name, - scanModel.selectedAddress!!, - bDevice.bondState == BOND_BONDED + bleDevice.name, + bleDevice.address, + bleDevice.bonded ) addDeviceButton( curDevice, @@ -1087,7 +1093,7 @@ class SettingsFragment : ScreenFragment("Settings"), Logging { val hasUSB = usbRepository.serialDevicesWithDrivers.value.isNotEmpty() if (!hasUSB) { // Warn user if BLE is disabled - if (scanModel.bluetoothAdapter?.isEnabled != true) { + if (bluetoothViewModel.enabled.value == false) { showSnackbar(getString(R.string.error_bluetooth)) } else { if (binding.provideLocationCheckbox.isChecked)