From 875c1542ea3ac195fbf5b21125c51c472b4cb4f3 Mon Sep 17 00:00:00 2001 From: andrekir Date: Sat, 12 Feb 2022 18:54:10 -0300 Subject: [PATCH 1/6] catch snackbar exception --- .../java/com/geeksville/mesh/MainActivity.kt | 38 +++++++++++-------- .../geeksville/mesh/ui/SettingsFragment.kt | 35 +++++++++-------- 2 files changed, 42 insertions(+), 31 deletions(-) diff --git a/app/src/main/java/com/geeksville/mesh/MainActivity.kt b/app/src/main/java/com/geeksville/mesh/MainActivity.kt index 34a36b807..044dbf6f9 100644 --- a/app/src/main/java/com/geeksville/mesh/MainActivity.kt +++ b/app/src/main/java/com/geeksville/mesh/MainActivity.kt @@ -737,24 +737,32 @@ class MainActivity : AppCompatActivity(), Logging, } private fun showSnackbar(msgId: Int) { - Snackbar.make( - findViewById(android.R.id.content), - msgId, - Snackbar.LENGTH_LONG - ).show() + try { + Snackbar.make( + findViewById(android.R.id.content), + msgId, + Snackbar.LENGTH_LONG + ).show() + } catch (ex: IllegalStateException) { + reportError("Snackbar couldn't find view for msgId $msgId") + } } private fun showSnackbar(msg: String) { - Snackbar.make( - findViewById(android.R.id.content), - msg, - Snackbar.LENGTH_INDEFINITE - ) - .apply { view.findViewById(R.id.snackbar_text).isSingleLine = false } - .setAction(R.string.okay) { - // dismiss - } - .show() + try { + Snackbar.make( + findViewById(android.R.id.content), + msg, + Snackbar.LENGTH_INDEFINITE + ) + .apply { view.findViewById(R.id.snackbar_text).isSingleLine = false } + .setAction(R.string.okay) { + // dismiss + } + .show() + } catch (ex: IllegalStateException) { + reportError("Snackbar couldn't find view for msgString $msg") + } } fun perhapsChangeChannel(url: Uri? = requestedChannelUrl) { 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 fd2d82bc8..116d5f3ea 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/SettingsFragment.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/SettingsFragment.kt @@ -952,13 +952,7 @@ class SettingsFragment : ScreenFragment("Settings"), Logging { fun weNeedAccess(warningReason: String) { warn("Telling user we need need location access") - - Snackbar.make(requireView(), warningReason, Snackbar.LENGTH_INDEFINITE) - .apply { view.findViewById(R.id.snackbar_text).isSingleLine = false } - .setAction(R.string.okay) { - // dismiss - } - .show() + showSnackbar(warningReason) } locationSettingsResponse.addOnSuccessListener { @@ -1001,6 +995,23 @@ class SettingsFragment : ScreenFragment("Settings"), Logging { } } + private fun showSnackbar(msg: String) { + try { + Snackbar.make( + requireView(), + msg, + Snackbar.LENGTH_INDEFINITE + ) + .apply { view.findViewById(R.id.snackbar_text).isSingleLine = false } + .setAction(R.string.okay) { + // dismiss + } + .show() + } catch (ex: IllegalStateException) { + reportError("Snackbar couldn't find view for msgString $msg") + } + } + override fun onPause() { super.onPause() @@ -1022,15 +1033,7 @@ class SettingsFragment : ScreenFragment("Settings"), Logging { if (!hasUSB) { // Warn user if BLE is disabled if (scanModel.bluetoothAdapter?.isEnabled != true) { - Snackbar.make( - requireView(), - R.string.error_bluetooth, - Snackbar.LENGTH_INDEFINITE - ) - .setAction(R.string.okay) { - // dismiss - } - .show() + showSnackbar(getString(R.string.error_bluetooth)) } else { if (binding.provideLocationCheckbox.isChecked) checkLocationEnabled(getString(R.string.location_disabled)) From 0f3135978ca15ca20a61b1d5e01e31b541df2bec Mon Sep 17 00:00:00 2001 From: andrekir Date: Sat, 12 Feb 2022 18:55:42 -0300 Subject: [PATCH 2/6] update CompanionDevice Bluetooth bonding --- .../com/geeksville/mesh/ui/SettingsFragment.kt | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) 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 116d5f3ea..199e55bba 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/SettingsFragment.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/SettingsFragment.kt @@ -883,7 +883,6 @@ class SettingsFragment : ScreenFragment("Settings"), Logging { deviceManager.associate( pairingRequest, object : CompanionDeviceManager.Callback() { - override fun onDeviceFound(chooserLauncher: IntentSender) { debug("Found one device - enabling changeRadioButton") binding.changeRadioButton.isEnabled = true @@ -914,8 +913,6 @@ class SettingsFragment : ScreenFragment("Settings"), Logging { updateDevicesButtons(devices) startCompanionScan() } - - startCompanionScan() } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { @@ -1041,17 +1038,22 @@ class SettingsFragment : ScreenFragment("Settings"), Logging { } } + @SuppressLint("MissingPermission") override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O + if (hasCompanionDeviceApi && myActivity.hasConnectPermission() && requestCode == MainActivity.SELECT_DEVICE_REQUEST_CODE && resultCode == Activity.RESULT_OK ) { val deviceToPair: BluetoothDevice = data?.getParcelableExtra(CompanionDeviceManager.EXTRA_DEVICE)!! - if (deviceToPair.bondState != BOND_BONDED) { - deviceToPair.createBond() - } - scanModel.changeScanSelection(myActivity, "x${deviceToPair.address}") + scanModel.onSelected( + myActivity, + BTScanModel.DeviceListEntry( + deviceToPair.name, + "x${deviceToPair.address}", + deviceToPair.bondState == BOND_BONDED + ) + ) } else { super.onActivityResult(requestCode, resultCode, data) } From c04c1b4addec42c511a456dda5fde251454869c5 Mon Sep 17 00:00:00 2001 From: andrekir Date: Sat, 12 Feb 2022 19:28:49 -0300 Subject: [PATCH 3/6] move disassociate to SettingsFragment --- .../mesh/service/RadioInterfaceService.kt | 16 ---------------- .../com/geeksville/mesh/ui/SettingsFragment.kt | 8 ++++++++ 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/com/geeksville/mesh/service/RadioInterfaceService.kt b/app/src/main/java/com/geeksville/mesh/service/RadioInterfaceService.kt index ee8d00e0f..bd9b5eead 100644 --- a/app/src/main/java/com/geeksville/mesh/service/RadioInterfaceService.kt +++ b/app/src/main/java/com/geeksville/mesh/service/RadioInterfaceService.kt @@ -286,22 +286,6 @@ class RadioInterfaceService : Service(), Logging { debug("Setting bonded device to ${address.anonymize}") - // We only keep an association to one device at a time... (move to BluetoothInterface?) - if (BluetoothInterface.hasCompanionDeviceApi(this)) { - if (address != null) { - val deviceManager = getSystemService(CompanionDeviceManager::class.java) - val c = address[0] - val rest = address.substring(1) - - deviceManager.associations.forEach { old -> - if (rest != old) { - debug("Forgetting old BLE association ${old.anonymize}") - deviceManager.disassociate(old) - } - } - } - } - getPrefs(this).edit(commit = true) { if (address == null) this.remove(DEVADDR_KEY) 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 199e55bba..69df4b3d3 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/SettingsFragment.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/SettingsFragment.kt @@ -1046,6 +1046,14 @@ class SettingsFragment : ScreenFragment("Settings"), Logging { ) { val deviceToPair: BluetoothDevice = data?.getParcelableExtra(CompanionDeviceManager.EXTRA_DEVICE)!! + + // We only keep an association to one device at a time... + deviceManager.associations.forEach { old -> + if (deviceToPair.address != old) { + debug("Forgetting old BLE association ${old.anonymize}") + deviceManager.disassociate(old) + } + } scanModel.onSelected( myActivity, BTScanModel.DeviceListEntry( From eb5abb4be91d668d49ff7674307ff6b2fa35c683 Mon Sep 17 00:00:00 2001 From: andrekir Date: Sat, 12 Feb 2022 19:33:30 -0300 Subject: [PATCH 4/6] only consider BLE pairing for addressValid --- .../java/com/geeksville/mesh/service/BluetoothInterface.kt | 7 +++---- .../main/java/com/geeksville/mesh/ui/SettingsFragment.kt | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/geeksville/mesh/service/BluetoothInterface.kt b/app/src/main/java/com/geeksville/mesh/service/BluetoothInterface.kt index 1eba742a1..5fdd12b3f 100644 --- a/app/src/main/java/com/geeksville/mesh/service/BluetoothInterface.kt +++ b/app/src/main/java/com/geeksville/mesh/service/BluetoothInterface.kt @@ -112,15 +112,14 @@ class BluetoothInterface(val service: RadioInterfaceService, val address: String /** Return true if this address is still acceptable. For BLE that means, still bonded */ @SuppressLint("NewApi", "MissingPermission") override fun addressValid(context: Context, rest: String): Boolean { - val allPaired = if (hasCompanionDeviceApi(context)) { + /* val allPaired = if (hasCompanionDeviceApi(context)) { val deviceManager: CompanionDeviceManager by lazy { context.getSystemService(Context.COMPANION_DEVICE_SERVICE) as CompanionDeviceManager } deviceManager.associations.map { it }.toSet() - } else { - getBluetoothAdapter(context)?.bondedDevices.orEmpty() + } else { */ + val allPaired = getBluetoothAdapter(context)?.bondedDevices.orEmpty() .map { it.address }.toSet() - } return if (!allPaired.contains(rest)) { warn("Ignoring stale bond to ${rest.anonymize}") false 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 69df4b3d3..b44a31fd1 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/SettingsFragment.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/SettingsFragment.kt @@ -813,7 +813,7 @@ class SettingsFragment : ScreenFragment("Settings"), Logging { if (curRadio != null && !MockInterface.addressValid(requireContext(), "")) { binding.warningNotPaired.visibility = View.GONE // binding.scanStatusText.text = getString(R.string.current_pair).format(curRadio) - } else { + } else if (model.bluetoothEnabled.value == true){ binding.warningNotPaired.visibility = View.VISIBLE binding.scanStatusText.text = getString(R.string.not_paired_yet) } From 130808f6eaf77e97f93031ec9ce6eaa8ad526a02 Mon Sep 17 00:00:00 2001 From: andrekir Date: Sat, 12 Feb 2022 20:08:20 -0300 Subject: [PATCH 5/6] 1.2.58 --- app/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 1fbdf2431..9dcd3403e 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -43,8 +43,8 @@ android { applicationId "com.geeksville.mesh" minSdkVersion 21 // The oldest emulator image I have tried is 22 (though 21 probably works) targetSdkVersion 30 // 30 can't work until an explicit location permissions dialog is added - versionCode 20257 // format is Mmmss (where M is 1+the numeric major number - versionName "1.2.57" + versionCode 20258 // format is Mmmss (where M is 1+the numeric major number + versionName "1.2.58" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" // per https://developer.android.com/studio/write/vector-asset-studio From 12cb8f070c0e91daefbb0acd49279a903e675537 Mon Sep 17 00:00:00 2001 From: andrekir Date: Sun, 13 Feb 2022 08:09:26 -0300 Subject: [PATCH 6/6] catch file write exception --- .../main/java/com/geeksville/mesh/model/UIState.kt | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/geeksville/mesh/model/UIState.kt b/app/src/main/java/com/geeksville/mesh/model/UIState.kt index c6ede21b8..6b0600e2e 100644 --- a/app/src/main/java/com/geeksville/mesh/model/UIState.kt +++ b/app/src/main/java/com/geeksville/mesh/model/UIState.kt @@ -25,6 +25,7 @@ import kotlinx.coroutines.flow.first import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import java.io.BufferedWriter +import java.io.FileNotFoundException import java.io.FileWriter import java.text.SimpleDateFormat import java.util.* @@ -350,12 +351,16 @@ class UIViewModel @Inject constructor( private suspend inline fun writeToUri(uri: Uri, crossinline block: suspend (BufferedWriter) -> Unit) { withContext(Dispatchers.IO) { - app.contentResolver.openFileDescriptor(uri, "wt")?.use { parcelFileDescriptor -> - FileWriter(parcelFileDescriptor.fileDescriptor).use { fileWriter -> - BufferedWriter(fileWriter).use { writer -> - block.invoke(writer) + try { + app.contentResolver.openFileDescriptor(uri, "wt")?.use { parcelFileDescriptor -> + FileWriter(parcelFileDescriptor.fileDescriptor).use { fileWriter -> + BufferedWriter(fileWriter).use { writer -> + block.invoke(writer) + } } } + } catch (ex: FileNotFoundException) { + errormsg("Can't write file error: ${ex.message}") } } }