diff --git a/app/src/main/java/com/geeksville/mesh/service/MeshService.kt b/app/src/main/java/com/geeksville/mesh/service/MeshService.kt
index 2b3dec165..4895fa872 100644
--- a/app/src/main/java/com/geeksville/mesh/service/MeshService.kt
+++ b/app/src/main/java/com/geeksville/mesh/service/MeshService.kt
@@ -204,7 +204,9 @@ class MeshService : Service(), Logging {
debug("Sending to radio ${built.toPIIString()}")
val b = built.toByteArray()
- if (SoftwareUpdateService.isUpdating) throw IsUpdatingException()
+ if (false) { // TODO check if radio is updating
+ throw IsUpdatingException()
+ }
radioInterfaceService.sendToRadio(b)
changeStatus(p.packet.id, MessageStatus.ENROUTE)
@@ -1133,13 +1135,7 @@ class MeshService : Service(), Logging {
// Do our startup init
try {
connectTimeMsec = System.currentTimeMillis()
- SoftwareUpdateService.sendProgress(
- this,
- SoftwareUpdateService.ProgressNotStarted,
- true
- ) // Kinda crufty way of reiniting software update
startConfig()
-
} catch (ex: InvalidProtocolBufferException) {
errormsg(
"Invalid protocol buffer sent by device - update device software and try again",
@@ -1342,10 +1338,7 @@ class MeshService : Service(), Logging {
hwModelStr,
firmwareVersion,
firmwareUpdateFilename?.appLoad != null && firmwareUpdateFilename?.littlefs != null,
- isBluetoothInterface && SoftwareUpdateService.shouldUpdate(
- this@MeshService,
- DeviceVersion(firmwareVersion)
- ),
+ shouldUpdate = false, // TODO add check after re-implementing firmware updates
currentPacketId and 0xffffffffL,
5 * 60 * 1000, // constants from current device code
minAppVersion,
@@ -1632,10 +1625,8 @@ class MeshService : Service(), Logging {
private fun setFirmwareUpdateFilename(model: String?) {
firmwareUpdateFilename = try {
if (model != null)
- SoftwareUpdateService.getUpdateFilename(
- this,
- model
- )
+ // TODO reimplement this after we have a new firmware update mechanism
+ null
else
null
} catch (ex: Exception) {
@@ -1664,7 +1655,7 @@ class MeshService : Service(), Logging {
updateJob = serviceScope.handledLaunch {
exceptionReporter {
debug("Starting firmware update coroutine")
- SoftwareUpdateService.doUpdate(this@MeshService, safe, filename)
+ // TODO perform update with new firmware update mechanism
}
}
}
@@ -1691,7 +1682,7 @@ class MeshService : Service(), Logging {
clientPackages[receiverName] = packageName
}
- override fun getUpdateStatus(): Int = SoftwareUpdateService.progress
+ override fun getUpdateStatus(): Int = 0 // TODO reimplement this after we have a new firmware update mechanism
override fun startFirmwareUpdate() = toRemoteExceptions {
doFirmwareUpdate()
diff --git a/app/src/main/java/com/geeksville/mesh/service/SoftwareUpdateService.kt b/app/src/main/java/com/geeksville/mesh/service/SoftwareUpdateService.kt
index 3e76e0726..16ac63e59 100644
--- a/app/src/main/java/com/geeksville/mesh/service/SoftwareUpdateService.kt
+++ b/app/src/main/java/com/geeksville/mesh/service/SoftwareUpdateService.kt
@@ -1,18 +1,6 @@
package com.geeksville.mesh.service
-import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothGattCharacteristic
-import android.bluetooth.BluetoothManager
-import android.content.Context
-import android.content.Intent
-import androidx.core.app.JobIntentService
-import com.geeksville.mesh.android.Logging
-import com.geeksville.mesh.MainActivity
-import com.geeksville.mesh.R
-import com.geeksville.mesh.model.DeviceVersion
-import com.geeksville.mesh.util.exceptionReporter
-import java.util.*
-import java.util.zip.CRC32
/**
* Some misformatted ESP32s have problems
@@ -69,379 +57,4 @@ fun toNetworkByteArray(value: Int, formatType: Int): ByteArray {
return mValue
}
-
-data class UpdateFilenames(val appLoad: String?, val littlefs: String?)
-
-/**
- * typical flow
- *
- * startScan
- * startUpdate
- *
- * stopScan
- *
- * FIXME - if we don't find a device stop our scan
- * FIXME - broadcast when we found devices, made progress sending blocks or when the update is complete
- * FIXME - make the user decide to start an update on a particular device
- */
-class SoftwareUpdateService : JobIntentService(), Logging {
-
-
- private val bluetoothAdapter: BluetoothAdapter by lazy(LazyThreadSafetyMode.NONE) {
- val bluetoothManager = getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
- bluetoothManager.adapter!!
- }
-
-
- private fun startUpdate(macaddr: String) {
- info("starting update to $macaddr")
-
- val device = bluetoothAdapter.getRemoteDevice(macaddr)
-
- val sync =
- SafeBluetooth(
- this@SoftwareUpdateService,
- device
- )
-
- sync.connect()
- sync.use { _ ->
- // we begin by setting our MTU size as high as it can go
- sync.requestMtu(512)
-
- sync.discoverServices() // Get our services
-
- val updateFilename = getUpdateFilename(this, sync)
- if (updateFilename != null) {
- doUpdate(this, sync, updateFilename)
- } else
- warn("Device is already up-to-date no update needed.")
- }
- }
-
-
- override fun onHandleWork(intent: Intent) {
- // We have received work to do. The system or framework is already
-// holding a wake lock for us at this point, so we can just go.
-
- // Report failures but do not crash the app
- exceptionReporter {
- debug("Executing work: $intent")
- when (intent.action) {
- ACTION_START_UPDATE -> {
- val addr = intent.getStringExtra(EXTRA_MACADDR)
- ?: throw Exception("EXTRA_MACADDR not specified")
- startUpdate(addr) // FIXME, pass in as an intent arg instead
- }
- else -> TODO("Unhandled case")
- }
- }
- }
-
- companion object : Logging {
- /**
- * Unique job ID for this service. Must be the same for all work.
- */
- private const val JOB_ID = 1000
-
- fun startUpdateIntent(macAddress: String): Intent {
- val i = Intent(ACTION_START_UPDATE)
- i.putExtra(EXTRA_MACADDR, macAddress)
-
- return i
- }
-
- const val ACTION_START_UPDATE = "$prefix.START_UPDATE"
-
- const val ACTION_UPDATE_PROGRESS = "$prefix.UPDATE_PROGRESS"
-
- const val EXTRA_MACADDR = "macaddr"
-
- private const val SCAN_PERIOD: Long = 10000
-
- private val TAG =
- MainActivity::class.java.simpleName // FIXME - use my logging class instead
-
- private val SW_UPDATE_UUID = UUID.fromString("cb0b9a0b-a84c-4c0d-bdbb-442e3144ee30")
- private val SW_UPDATE_TOTALSIZE_CHARACTER =
- UUID.fromString("e74dd9c0-a301-4a6f-95a1-f0e1dbea8e1e") // write|read total image size, 32 bit, write this first, then read read back to see if it was acceptable (0 mean not accepted)
- private val SW_UPDATE_DATA_CHARACTER =
- UUID.fromString("e272ebac-d463-4b98-bc84-5cc1a39ee517") // write data, variable sized, recommended 512 bytes, write one for each block of file
- private val SW_UPDATE_CRC32_CHARACTER =
- UUID.fromString("4826129c-c22a-43a3-b066-ce8f0d5bacc6") // write crc32, write last - writing this will complete the OTA operation, now you can read result
- private val SW_UPDATE_RESULT_CHARACTER =
- UUID.fromString("5e134862-7411-4424-ac4a-210937432c77") // read|notify result code, readable but will notify when the OTA operation completes
- private val SW_UPDATE_REGION_CHARACTER =
- UUID.fromString("5e134862-7411-4424-ac4a-210937432c67") // write - used to set the region we are setting (appload vs littlefs)
-
- private val SW_VERSION_CHARACTER = longBLEUUID("2a28")
- private val MANUFACTURE_CHARACTER = longBLEUUID("2a29")
- private val HW_VERSION_CHARACTER = longBLEUUID("2a27")
-
- const val ProgressSuccess = -1
- const val ProgressUpdateFailed = -2
- const val ProgressBleException = -3
- const val ProgressNotStarted = -4
-
- /**
- * % progress through the update
- */
- var progress = ProgressNotStarted
-
- /**
- * Convenience method for enqueuing work in to this service.
- */
- fun enqueueWork(context: Context, work: Intent) {
- enqueueWork(
- context,
- SoftwareUpdateService::class.java,
- JOB_ID, work
- )
- }
-
-
- /**
- * true if we are busy with an update right now
- */
- val isUpdating get() = progress >= 0
-
- /**
- * Update our progress indication for GUIs
- *
- * @param isAppload if false, we don't report failure indications (because we consider littlefs non critical for now). But do report to analytics
- */
- fun sendProgress(context: Context, p: Int, isAppload: Boolean) {
- if (!isAppload && p < 0)
- errormsg("Error while writing littlefs $p") // treat errors writing littlefs as non fatal for now (user partition probably missized and most people don't need it)
- else
- if (progress != p) {
- progress = p
-
- val intent = Intent(ACTION_UPDATE_PROGRESS).putExtra(
- EXTRA_PROGRESS,
- p
- )
- context.sendBroadcast(intent)
- }
- }
-
- /** Return true if we thing the firmwarte shoulde be updated
- *
- * @param swVer the version of the software running on the target
- */
- fun shouldUpdate(
- context: Context,
- deviceVersion: DeviceVersion
- ): Boolean = try {
- val curVer = DeviceVersion(context.getString(R.string.cur_firmware_version))
- val minVer =
- DeviceVersion("0.7.8") // The oldest device version with a working software update service
-
- ((curVer > deviceVersion) && (deviceVersion >= minVer))
- } catch (ex: Exception) {
- errormsg("Error finding swupdate info", ex)
- false // If we fail parsing our update info
- }
-
- /** Return a Pair of appload filename, littlefs filename this device needs to use as an update (or null if no update needed)
- */
- fun getUpdateFilename(
- context: Context,
- mfg: String
- ): UpdateFilenames {
- val curVer = context.getString(R.string.cur_firmware_version)
-
- // Check to see if the file exists (some builds might not include update files for size reasons)
- val firmwareFiles = context.assets.list("firmware") ?: arrayOf()
-
- val appLoad = "firmware-$mfg-$curVer.bin"
- val littlefs = "littlefs-$curVer.bin"
-
- return UpdateFilenames(
- if (firmwareFiles.contains(appLoad))
- "firmware/$appLoad"
- else
- null,
- if (firmwareFiles.contains(littlefs))
- "firmware/$littlefs"
- else
- null
- )
- }
-
- /** Return the filename this device needs to use as an update (or null if no update needed)
- * No longer used, because we get update info inband from our radio API
- */
- fun getUpdateFilename(context: Context, sync: SafeBluetooth): UpdateFilenames? {
- val service = sync.gatt!!.services.find { it.uuid == SW_UPDATE_UUID }!!
-
- //val hwVerDesc = service.getCharacteristic(HW_VERSION_CHARACTER)
- val mfgDesc = service.getCharacteristic(MANUFACTURE_CHARACTER)
- //val swVerDesc = service.getCharacteristic(SW_VERSION_CHARACTER)
-
- // looks like HELTEC
- val mfg = sync.readCharacteristic(mfgDesc).getStringValue(0)
-
- return getUpdateFilename(context, mfg)
- }
-
- /**
- * A public function so that if you have your own SafeBluetooth connection already open
- * you can use it for the software update.
- */
- fun doUpdate(context: Context, sync: SafeBluetooth, assets: UpdateFilenames) {
- // calculate total firmware size (littlefs + appLoad)
- var totalFirmwareSize = 0
- if (assets.appLoad != null && assets.littlefs != null) {
- totalFirmwareSize += context.assets.open(assets.appLoad).available()
- totalFirmwareSize += context.assets.open(assets.littlefs).available()
- }
- // we must attempt littlefs first, because if we update the appload the device will reboot afterwards
- try {
- assets.littlefs?.let { doUpdate(context, sync, it, FLASH_REGION_LITTLEFS, totalFirmwareSize) }
- } catch (_: BLECharacteristicNotFoundException) {
- // If we can't update littlefs (because not supported by target), do not fail
- errormsg("Ignoring failure to update littlefs on old appload")
- } catch (_: DeviceRejectedException) {
- // the spi filesystem of this device is malformatted, fail silently because most users don't need the web server
- errormsg("Device rejected invalid littlefs partition")
- }
-
- assets.appLoad?.let { doUpdate(context, sync, it, FLASH_REGION_APPLOAD, totalFirmwareSize) }
- sendProgress(context, ProgressSuccess, true)
- }
-
- // writable region codes in the ESP32 update code
- private val FLASH_REGION_APPLOAD = 0
- private val FLASH_REGION_LITTLEFS = 100
-
- /**
- * A public function so that if you have your own SafeBluetooth connection already open
- * you can use it for the software update.
- */
- private fun doUpdate(
- context: Context,
- sync: SafeBluetooth,
- assetName: String,
- flashRegion: Int = FLASH_REGION_APPLOAD,
- totalFirmwareSize: Int = 0
- ) {
- val isAppload = flashRegion == FLASH_REGION_APPLOAD
-
- try {
- val g = sync.gatt!!
- val service = g.services.find { it.uuid == SW_UPDATE_UUID }
- ?: throw BLEException("Couldn't find update service")
-
- /**
- * Get a chracteristic, but in a safe manner because some buggy BLE implementations might return null
- */
- fun getCharacteristic(uuid: UUID) =
- service.getCharacteristic(uuid)
- ?: throw BLECharacteristicNotFoundException(uuid)
-
- info("Starting firmware update for $assetName, flash region $flashRegion")
-
- sendProgress(context, 0, isAppload)
- val totalSizeDesc = getCharacteristic(SW_UPDATE_TOTALSIZE_CHARACTER)
- val dataDesc = getCharacteristic(SW_UPDATE_DATA_CHARACTER)
- val crc32Desc = getCharacteristic(SW_UPDATE_CRC32_CHARACTER)
- val updateResultDesc = getCharacteristic(SW_UPDATE_RESULT_CHARACTER)
-
- /// Try to set the destination region for programming (littlefs vs appload etc)
- /// Old apploads don't have this feature, but we only fail if the user was trying to set a
- /// littlefs - otherwise we assume appload.
- try {
- val updateRegionDesc = getCharacteristic(SW_UPDATE_REGION_CHARACTER)
- sync.writeCharacteristic(
- updateRegionDesc,
- toNetworkByteArray(flashRegion, BluetoothGattCharacteristic.FORMAT_UINT8)
- )
- } catch (ex: BLECharacteristicNotFoundException) {
- errormsg("Can't set flash programming region (old appload?")
- if (flashRegion != FLASH_REGION_APPLOAD) {
- throw ex
- }
- warn("Ignoring setting appload flashRegion")
- }
-
- context.assets.open(assetName).use { firmwareStream ->
- val firmwareCrc = CRC32()
- var firmwareNumSent = 0
- val firmwareSize = firmwareStream.available()
-
- // Start the update by writing the # of bytes in the image
- sync.writeCharacteristic(
- totalSizeDesc,
- toNetworkByteArray(firmwareSize, BluetoothGattCharacteristic.FORMAT_UINT32)
- )
-
- // Our write completed, queue up a readback
- val totalSizeReadback = sync.readCharacteristic(totalSizeDesc)
- .getIntValue(BluetoothGattCharacteristic.FORMAT_UINT32, 0)
- if (totalSizeReadback == 0)
- throw DeviceRejectedException()
-
- // Send all the blocks
- var oldProgress = -1 // used to limit # of log spam
- while (firmwareNumSent < firmwareSize) {
- // If we are doing the littlefs partition, we limit progress to a max of maxProgress
- // when updating the appload partition, progress from (100 - maxProgress) to 100%
- // maxProgress = littlefs% = 100% - appLoad%; (int * 10 + 5) / 10 used for rounding
- val maxProgress = ((firmwareSize * 1000 / totalFirmwareSize) + 5) / 10
- val minProgress = if (flashRegion != FLASH_REGION_APPLOAD)
- 0 else (100 - maxProgress)
- sendProgress(
- context,
- minProgress + firmwareNumSent * maxProgress / firmwareSize,
- isAppload
- )
- if (progress != oldProgress) {
- debug("sending block ${progress}%")
- oldProgress = progress
- }
- var blockSize = 512 - 3 // Max size MTU excluding framing
-
- if (blockSize > firmwareStream.available())
- blockSize = firmwareStream.available()
- val buffer = ByteArray(blockSize)
-
- // slightly expensive to keep reallocing this buffer, but whatever
- logAssert(firmwareStream.read(buffer) == blockSize)
- firmwareCrc.update(buffer)
-
- sync.writeCharacteristic(dataDesc, buffer)
- firmwareNumSent += blockSize
- }
-
- try {
- // We have finished sending all our blocks, so post the CRC so our state machine can advance
- val c = firmwareCrc.value
- info("Sent all blocks, crc is $c")
- sync.writeCharacteristic(
- crc32Desc,
- toNetworkByteArray(c.toInt(), BluetoothGattCharacteristic.FORMAT_UINT32)
- )
-
- // we just read the update result if !0 we have an error
- val updateResult =
- sync.readCharacteristic(updateResultDesc)
- .getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, 0)
- if (updateResult != 0) {
- sendProgress(context, ProgressUpdateFailed, isAppload)
- throw Exception("Device update failed, reason=$updateResult")
- }
-
- // Device will now reboot
- } catch (ex: BLEException) {
- // We might get SyncContinuation timeout on the final write, assume the device simply rebooted to run the new load and we missed it
- errormsg("Assuming successful update", ex)
- }
- }
- } catch (ex: BLEException) {
- sendProgress(context, ProgressBleException, isAppload)
- throw ex // Unexpected BLE exception
- }
- }
- }
-}
+data class UpdateFilenames(val appLoad: String?, val littlefs: String?)
\ No newline at end of file
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 c3aab5e09..e619dcafb 100644
--- a/app/src/main/java/com/geeksville/mesh/ui/SettingsFragment.kt
+++ b/app/src/main/java/com/geeksville/mesh/ui/SettingsFragment.kt
@@ -1,12 +1,11 @@
package com.geeksville.mesh.ui
-import android.content.BroadcastReceiver
-import android.content.Context
-import android.content.Intent
-import android.content.IntentFilter
+import android.net.InetAddresses
+import android.os.Build
import android.os.Bundle
import android.os.Handler
import android.os.Looper
+import android.text.Editable
import android.util.Patterns
import android.view.LayoutInflater
import android.view.View
@@ -21,7 +20,6 @@ import androidx.fragment.app.activityViewModels
import androidx.lifecycle.asLiveData
import com.geeksville.mesh.ConfigProtos
import com.geeksville.mesh.R
-import com.geeksville.mesh.analytics.DataPair
import com.geeksville.mesh.ModuleConfigProtos
import com.geeksville.mesh.android.*
import com.geeksville.mesh.databinding.SettingsFragmentBinding
@@ -31,7 +29,6 @@ import com.geeksville.mesh.model.UIViewModel
import com.geeksville.mesh.model.getInitials
import com.geeksville.mesh.repository.location.LocationRepository
import com.geeksville.mesh.service.MeshService
-import com.geeksville.mesh.service.SoftwareUpdateService
import com.geeksville.mesh.util.exceptionToSnackbar
import com.geeksville.mesh.util.getAssociationResult
import com.geeksville.mesh.util.onEditorAction
@@ -56,25 +53,6 @@ class SettingsFragment : ScreenFragment("Settings"), Logging {
private val hasGps by lazy { requireContext().hasGps() }
private val hasCompanionDeviceApi by lazy { requireContext().hasCompanionDeviceApi() }
- private fun doFirmwareUpdate() {
- model.meshService?.let { service ->
-
- debug("User started firmware update")
- GeeksvilleApplication.analytics.track(
- "firmware_update",
- DataPair("content_type", "start")
- )
- binding.updateFirmwareButton.isEnabled = false // Disable until things complete
- binding.updateProgressBar.visibility = View.VISIBLE
- binding.updateProgressBar.progress = 0 // start from scratch
-
- exceptionToSnackbar(requireView()) {
- // We rely on our broadcast receiver to show progress as this progresses
- service.startFirmwareUpdate()
- }
- }
- }
-
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
@@ -83,56 +61,6 @@ class SettingsFragment : ScreenFragment("Settings"), Logging {
return binding.root
}
- /// Set the correct update button configuration based on current progress
- private fun refreshUpdateButton(enable: Boolean) {
- debug("Reiniting the update button")
- val info = model.myNodeInfo.value
- val service = model.meshService
- if (model.isConnected() && info != null && info.shouldUpdate && info.couldUpdate && service != null) {
- binding.updateFirmwareButton.visibility = View.VISIBLE
- binding.updateFirmwareButton.text =
- getString(R.string.update_to).format(getString(R.string.short_firmware_version))
-
- val progress = service.updateStatus
-
- binding.updateFirmwareButton.isEnabled = enable &&
- (progress < 0) // if currently doing an upgrade disable button
-
- if (progress >= 0) {
- binding.updateProgressBar.progress = progress // update partial progress
- binding.scanStatusText.setText(R.string.updating_firmware)
- binding.updateProgressBar.visibility = View.VISIBLE
- } else
- when (progress) {
- SoftwareUpdateService.ProgressSuccess -> {
- GeeksvilleApplication.analytics.track(
- "firmware_update",
- DataPair("content_type", "success")
- )
- binding.scanStatusText.setText(R.string.update_successful)
- binding.updateProgressBar.visibility = View.GONE
- }
- SoftwareUpdateService.ProgressNotStarted -> {
- // Do nothing - because we don't want to overwrite the status text in this case
- binding.updateProgressBar.visibility = View.GONE
- }
- else -> {
- GeeksvilleApplication.analytics.track(
- "firmware_update",
- DataPair("content_type", "failure")
- )
- binding.scanStatusText.setText(R.string.update_failed)
- binding.updateProgressBar.visibility = View.VISIBLE
- }
- }
- binding.updateProgressBar.isEnabled = false
-
- } else {
- binding.updateFirmwareButton.visibility = View.GONE
- binding.updateProgressBar.visibility = View.GONE
- }
- }
-
/**
* Pull the latest device info from the model and into the GUI
*/
@@ -168,9 +96,6 @@ class SettingsFragment : ScreenFragment("Settings"), Logging {
spinner.onItemSelectedListener = regionSpinnerListener
spinner.isEnabled = !model.isManaged
- // If actively connected possibly let the user update firmware
- refreshUpdateButton(isConnected)
-
// Update the status string (highest priority messages first)
val info = model.myNodeInfo.value
when (connectionState) {
@@ -313,17 +238,6 @@ class SettingsFragment : ScreenFragment("Settings"), Logging {
}
}
- binding.updateFirmwareButton.setOnClickListener {
- MaterialAlertDialogBuilder(requireContext())
- .setMessage("${getString(R.string.update_firmware)}?")
- .setNeutralButton(R.string.cancel) { _, _ ->
- }
- .setPositiveButton(getString(R.string.okay)) { _, _ ->
- doFirmwareUpdate()
- }
- .show()
- }
-
binding.usernameEditText.onEditorAction(EditorInfo.IME_ACTION_DONE) {
debug("received IME_ACTION_DONE")
val n = binding.usernameEditText.text.toString().trim()
@@ -390,6 +304,7 @@ class SettingsFragment : ScreenFragment("Settings"), Logging {
binding.reportBugButton.setOnClickListener(::showReportBugDialog)
}
+ @Suppress("UNUSED_PARAMETER")
private fun showReportBugDialog(view: View) {
MaterialAlertDialogBuilder(requireContext())
.setTitle(R.string.report_a_bug)
@@ -420,19 +335,19 @@ class SettingsFragment : ScreenFragment("Settings"), Logging {
}
private fun addManualDeviceButton() {
- val b = binding.radioButtonManual
- val e = binding.editManualAddress
+ val deviceSelectIPAddress = binding.radioButtonManual
+ val inputIPAddress = binding.editManualAddress
- b.isEnabled = false
-
- binding.deviceRadioGroup.addView(b)
-
- b.setOnClickListener {
- b.isChecked = scanModel.onSelected(BTScanModel.DeviceListEntry("", "t" + e.text, true))
+ deviceSelectIPAddress.isEnabled = false
+ deviceSelectIPAddress.setOnClickListener {
+ deviceSelectIPAddress.isChecked = scanModel.onSelected(BTScanModel.DeviceListEntry("", "t" + inputIPAddress.text, true))
}
- binding.deviceRadioGroup.addView(e)
- e.doAfterTextChanged {
- b.isEnabled = Patterns.IP_ADDRESS.matcher(e.text).matches()
+
+ binding.deviceRadioGroup.addView(deviceSelectIPAddress)
+ binding.deviceRadioGroup.addView(inputIPAddress)
+
+ inputIPAddress.doAfterTextChanged {
+ deviceSelectIPAddress.isEnabled = inputIPAddress.text.isIPAddress()
}
}
@@ -545,25 +460,9 @@ class SettingsFragment : ScreenFragment("Settings"), Logging {
}
}
- private val updateProgressFilter = IntentFilter(SoftwareUpdateService.ACTION_UPDATE_PROGRESS)
-
- private val updateProgressReceiver: BroadcastReceiver = object : BroadcastReceiver() {
- override fun onReceive(context: Context?, intent: Intent?) {
- refreshUpdateButton(true)
- }
- }
-
- override fun onPause() {
- super.onPause()
-
- requireActivity().unregisterReceiver(updateProgressReceiver)
- }
-
override fun onResume() {
super.onResume()
- requireActivity().registerReceiver(updateProgressReceiver, updateProgressFilter)
-
// Warn user if BLE device is selected but BLE disabled
if (scanModel.selectedBluetooth) checkBTEnabled()
@@ -580,4 +479,14 @@ class SettingsFragment : ScreenFragment("Settings"), Logging {
companion object {
const val SCAN_PERIOD: Long = 10000 // Stops scanning after 10 seconds
}
+
+ private fun Editable.isIPAddress(): Boolean {
+ return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
+ InetAddresses.isNumericAddress(this.toString())
+ } else {
+ @Suppress("DEPRECATION")
+ Patterns.IP_ADDRESS.matcher(this).matches()
+ }
+ }
+
}
diff --git a/app/src/main/res/layout/settings_fragment.xml b/app/src/main/res/layout/settings_fragment.xml
index 21e3b510e..31f080f9c 100644
--- a/app/src/main/res/layout/settings_fragment.xml
+++ b/app/src/main/res/layout/settings_fragment.xml
@@ -74,9 +74,10 @@
android:layout_marginTop="16dp"
android:layout_marginEnd="8dp"
android:text="@string/looking_for_meshtastic_devices"
- app:layout_constraintEnd_toStartOf="@+id/updateFirmwareButton"
app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/nodeSettings" />
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/nodeSettings"
+ />
+ android:visibility="visible"
+ android:importantForAutofill="no"
+ />
@@ -137,25 +140,6 @@
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toTopOf="@+id/reportBugButton" />
-
-
-
-